@hardlydifficult/usage-tracker 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -0
- package/dist/UsageTracker.d.ts +33 -0
- package/dist/UsageTracker.d.ts.map +1 -0
- package/dist/UsageTracker.js +85 -0
- package/dist/UsageTracker.js.map +1 -0
- package/dist/deepAdd.d.ts +7 -0
- package/dist/deepAdd.d.ts.map +1 -0
- package/dist/deepAdd.js +31 -0
- package/dist/deepAdd.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +30 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +31 -0
package/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# @hardlydifficult/usage-tracker
|
|
2
|
+
|
|
3
|
+
Accumulate numeric metrics over time with automatic session vs. cumulative dual-tracking, backed by persistent storage.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @hardlydifficult/usage-tracker @hardlydifficult/state-tracker
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { UsageTracker } from "@hardlydifficult/usage-tracker";
|
|
15
|
+
|
|
16
|
+
// Type is inferred from defaults — no interface needed
|
|
17
|
+
const tracker = await UsageTracker.create({
|
|
18
|
+
key: "my-usage",
|
|
19
|
+
default: {
|
|
20
|
+
api: { requests: 0, tokens: 0, costUsd: 0 },
|
|
21
|
+
audio: { requests: 0, durationSeconds: 0 },
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Record metrics — deeply adds to both session and cumulative
|
|
26
|
+
tracker.record({ api: { requests: 1, tokens: 500, costUsd: 0.01 } });
|
|
27
|
+
|
|
28
|
+
// Read state
|
|
29
|
+
tracker.session; // { api: { requests: 1, ... }, audio: { ... } }
|
|
30
|
+
tracker.cumulative; // all-time totals (persists across restarts)
|
|
31
|
+
tracker.sessionStartedAt; // ISO string
|
|
32
|
+
tracker.trackingSince; // ISO string
|
|
33
|
+
tracker.isPersistent; // true if persisted to disk
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## API Reference
|
|
37
|
+
|
|
38
|
+
### `UsageTracker.create(options)`
|
|
39
|
+
|
|
40
|
+
Static async factory — the only way to create an instance. Loads persisted state and starts a new session.
|
|
41
|
+
|
|
42
|
+
| Option | Type | Required | Description |
|
|
43
|
+
|--------|------|----------|-------------|
|
|
44
|
+
| `key` | `string` | Yes | Unique persistence key |
|
|
45
|
+
| `default` | `T` | Yes | Default metrics shape (all leaves must be 0) |
|
|
46
|
+
| `stateDirectory` | `string` | No | Directory for state files |
|
|
47
|
+
| `autoSaveMs` | `number` | No | Auto-save interval in ms |
|
|
48
|
+
| `onEvent` | `(event) => void` | No | Logging callback |
|
|
49
|
+
|
|
50
|
+
### `tracker.record(values)`
|
|
51
|
+
|
|
52
|
+
Deeply adds numeric values to both session and cumulative counters. Only provide the fields you are incrementing.
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// Only increments the specified fields
|
|
56
|
+
tracker.record({ api: { requests: 1, tokens: 500 } });
|
|
57
|
+
// audio fields are unchanged
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### `tracker.save()`
|
|
61
|
+
|
|
62
|
+
Force-save current state to disk immediately. Returns a promise.
|
|
63
|
+
|
|
64
|
+
### Getters
|
|
65
|
+
|
|
66
|
+
| Getter | Type | Description |
|
|
67
|
+
|--------|------|-------------|
|
|
68
|
+
| `session` | `Readonly<T>` | Current session metrics |
|
|
69
|
+
| `cumulative` | `Readonly<T>` | All-time metrics |
|
|
70
|
+
| `sessionStartedAt` | `string` | ISO timestamp of session start |
|
|
71
|
+
| `trackingSince` | `string` | ISO timestamp of first tracking |
|
|
72
|
+
| `isPersistent` | `boolean` | Whether data persists to disk |
|
|
73
|
+
|
|
74
|
+
## `deepAdd(target, source)`
|
|
75
|
+
|
|
76
|
+
Exported utility that recursively adds numeric values from source into target. Mutates target in place. Useful for merging metrics snapshots outside of UsageTracker.
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { deepAdd } from "@hardlydifficult/usage-tracker";
|
|
80
|
+
|
|
81
|
+
const totals = { requests: 5, tokens: 1000 };
|
|
82
|
+
deepAdd(totals, { requests: 1, tokens: 500 });
|
|
83
|
+
// totals is now { requests: 6, tokens: 1500 }
|
|
84
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { DeepPartial, NumericRecord, UsageTrackerOptions } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Accumulates numeric metrics over time with automatic session vs. cumulative
|
|
4
|
+
* dual-tracking, backed by persistent storage via StateTracker.
|
|
5
|
+
*
|
|
6
|
+
* Type is inferred from the `default` value — no explicit interface needed.
|
|
7
|
+
* Use the static `create()` factory to construct and load in one step.
|
|
8
|
+
*/
|
|
9
|
+
export declare class UsageTracker<T extends NumericRecord> {
|
|
10
|
+
private readonly tracker;
|
|
11
|
+
private readonly defaultMetrics;
|
|
12
|
+
private constructor();
|
|
13
|
+
/** Create a UsageTracker, load persisted state, and start a new session. */
|
|
14
|
+
static create<T extends NumericRecord>(options: UsageTrackerOptions<T>): Promise<UsageTracker<T>>;
|
|
15
|
+
/** Current session metrics (since last create() call). */
|
|
16
|
+
get session(): Readonly<T>;
|
|
17
|
+
/** All-time cumulative metrics. */
|
|
18
|
+
get cumulative(): Readonly<T>;
|
|
19
|
+
/** ISO string of when the current session started. */
|
|
20
|
+
get sessionStartedAt(): string;
|
|
21
|
+
/** ISO string of when cumulative tracking first started. */
|
|
22
|
+
get trackingSince(): string;
|
|
23
|
+
/** Whether state is being persisted to disk. */
|
|
24
|
+
get isPersistent(): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Record metrics by deeply adding numeric values to both session and cumulative.
|
|
27
|
+
* Only provide the fields you are incrementing — unspecified fields are unchanged.
|
|
28
|
+
*/
|
|
29
|
+
record(values: DeepPartial<T>): void;
|
|
30
|
+
/** Force-save current state to disk immediately. */
|
|
31
|
+
save(): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=UsageTracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UsageTracker.d.ts","sourceRoot":"","sources":["../src/UsageTracker.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,WAAW,EACX,aAAa,EAEb,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AACH,qBAAa,YAAY,CAAC,CAAC,SAAS,aAAa;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAI;IAEnC,OAAO;IAQP,4EAA4E;WAC/D,MAAM,CAAC,CAAC,SAAS,aAAa,EACzC,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAC9B,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IA4B3B,0DAA0D;IAC1D,IAAI,OAAO,IAAI,QAAQ,CAAC,CAAC,CAAC,CAEzB;IAED,mCAAmC;IACnC,IAAI,UAAU,IAAI,QAAQ,CAAC,CAAC,CAAC,CAE5B;IAED,sDAAsD;IACtD,IAAI,gBAAgB,IAAI,MAAM,CAE7B;IAED,4DAA4D;IAC5D,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,gDAAgD;IAChD,IAAI,YAAY,IAAI,OAAO,CAE1B;IAED;;;OAGG;IACH,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI;IAcpC,oDAAoD;IAC9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAG5B"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UsageTracker = void 0;
|
|
4
|
+
const state_tracker_1 = require("@hardlydifficult/state-tracker");
|
|
5
|
+
const deepAdd_js_1 = require("./deepAdd.js");
|
|
6
|
+
/**
|
|
7
|
+
* Accumulates numeric metrics over time with automatic session vs. cumulative
|
|
8
|
+
* dual-tracking, backed by persistent storage via StateTracker.
|
|
9
|
+
*
|
|
10
|
+
* Type is inferred from the `default` value — no explicit interface needed.
|
|
11
|
+
* Use the static `create()` factory to construct and load in one step.
|
|
12
|
+
*/
|
|
13
|
+
class UsageTracker {
|
|
14
|
+
tracker;
|
|
15
|
+
defaultMetrics;
|
|
16
|
+
constructor(options, tracker) {
|
|
17
|
+
this.defaultMetrics = structuredClone(options.default);
|
|
18
|
+
this.tracker = tracker;
|
|
19
|
+
}
|
|
20
|
+
/** Create a UsageTracker, load persisted state, and start a new session. */
|
|
21
|
+
static async create(options) {
|
|
22
|
+
const now = new Date().toISOString();
|
|
23
|
+
const tracker = new state_tracker_1.StateTracker({
|
|
24
|
+
key: options.key,
|
|
25
|
+
default: {
|
|
26
|
+
cumulative: structuredClone(options.default),
|
|
27
|
+
session: structuredClone(options.default),
|
|
28
|
+
trackingSince: now,
|
|
29
|
+
sessionStartedAt: now,
|
|
30
|
+
},
|
|
31
|
+
stateDirectory: options.stateDirectory,
|
|
32
|
+
autoSaveMs: options.autoSaveMs,
|
|
33
|
+
onEvent: options.onEvent,
|
|
34
|
+
});
|
|
35
|
+
await tracker.loadAsync();
|
|
36
|
+
const instance = new UsageTracker(options, tracker);
|
|
37
|
+
// Reset session counters for the new session, preserving cumulative
|
|
38
|
+
tracker.update({
|
|
39
|
+
session: structuredClone(options.default),
|
|
40
|
+
sessionStartedAt: new Date().toISOString(),
|
|
41
|
+
});
|
|
42
|
+
return instance;
|
|
43
|
+
}
|
|
44
|
+
/** Current session metrics (since last create() call). */
|
|
45
|
+
get session() {
|
|
46
|
+
return this.tracker.state.session;
|
|
47
|
+
}
|
|
48
|
+
/** All-time cumulative metrics. */
|
|
49
|
+
get cumulative() {
|
|
50
|
+
return this.tracker.state.cumulative;
|
|
51
|
+
}
|
|
52
|
+
/** ISO string of when the current session started. */
|
|
53
|
+
get sessionStartedAt() {
|
|
54
|
+
return this.tracker.state.sessionStartedAt;
|
|
55
|
+
}
|
|
56
|
+
/** ISO string of when cumulative tracking first started. */
|
|
57
|
+
get trackingSince() {
|
|
58
|
+
return this.tracker.state.trackingSince;
|
|
59
|
+
}
|
|
60
|
+
/** Whether state is being persisted to disk. */
|
|
61
|
+
get isPersistent() {
|
|
62
|
+
return this.tracker.isPersistent;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Record metrics by deeply adding numeric values to both session and cumulative.
|
|
66
|
+
* Only provide the fields you are incrementing — unspecified fields are unchanged.
|
|
67
|
+
*/
|
|
68
|
+
record(values) {
|
|
69
|
+
const { state } = this.tracker;
|
|
70
|
+
const newSession = structuredClone(state.session);
|
|
71
|
+
const newCumulative = structuredClone(state.cumulative);
|
|
72
|
+
(0, deepAdd_js_1.deepAdd)(newSession, values);
|
|
73
|
+
(0, deepAdd_js_1.deepAdd)(newCumulative, values);
|
|
74
|
+
this.tracker.update({
|
|
75
|
+
session: newSession,
|
|
76
|
+
cumulative: newCumulative,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/** Force-save current state to disk immediately. */
|
|
80
|
+
async save() {
|
|
81
|
+
await this.tracker.saveAsync();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.UsageTracker = UsageTracker;
|
|
85
|
+
//# sourceMappingURL=UsageTracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UsageTracker.js","sourceRoot":"","sources":["../src/UsageTracker.ts"],"names":[],"mappings":";;;AAAA,kEAA8D;AAE9D,6CAAuC;AAQvC;;;;;;GAMG;AACH,MAAa,YAAY;IACN,OAAO,CAAuC;IAC9C,cAAc,CAAI;IAEnC,YACE,OAA+B,EAC/B,OAA6C;QAE7C,IAAI,CAAC,cAAc,GAAG,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACvD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,4EAA4E;IAC5E,MAAM,CAAC,KAAK,CAAC,MAAM,CACjB,OAA+B;QAE/B,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,IAAI,4BAAY,CAAyB;YACvD,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,OAAO,EAAE;gBACP,UAAU,EAAE,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC;gBAC5C,OAAO,EAAE,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC;gBACzC,aAAa,EAAE,GAAG;gBAClB,gBAAgB,EAAE,GAAG;aACtB;YACD,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,OAAO,EAAE,OAAO,CAAC,OAAO;SACzB,CAAC,CAAC;QAEH,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC;QAE1B,MAAM,QAAQ,GAAG,IAAI,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAEpD,oEAAoE;QACpE,OAAO,CAAC,MAAM,CAAC;YACb,OAAO,EAAE,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC;YACzC,gBAAgB,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACR,CAAC,CAAC;QAEtC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,0DAA0D;IAC1D,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;IACpC,CAAC;IAED,mCAAmC;IACnC,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC;IACvC,CAAC;IAED,sDAAsD;IACtD,IAAI,gBAAgB;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC;IAC7C,CAAC;IAED,4DAA4D;IAC5D,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC;IAC1C,CAAC;IAED,gDAAgD;IAChD,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;IACnC,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,MAAsB;QAC3B,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAC/B,MAAM,UAAU,GAAG,eAAe,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAClD,MAAM,aAAa,GAAG,eAAe,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAExD,IAAA,oBAAO,EAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC5B,IAAA,oBAAO,EAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QAE/B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;YAClB,OAAO,EAAE,UAAU;YACnB,UAAU,EAAE,aAAa;SACS,CAAC,CAAC;IACxC,CAAC;IAED,oDAAoD;IACpD,KAAK,CAAC,IAAI;QACR,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;IACjC,CAAC;CACF;AA1FD,oCA0FC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DeepPartial, NumericRecord } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Recursively adds numeric values from source into target. Mutates target in place.
|
|
4
|
+
* Keys in source that are not present in target are ignored.
|
|
5
|
+
*/
|
|
6
|
+
export declare function deepAdd<T extends NumericRecord>(target: T, source: DeepPartial<T>): void;
|
|
7
|
+
//# sourceMappingURL=deepAdd.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deepAdd.d.ts","sourceRoot":"","sources":["../src/deepAdd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE7D;;;GAGG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,aAAa,EAC7C,MAAM,EAAE,CAAC,EACT,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GACrB,IAAI,CA6BN"}
|
package/dist/deepAdd.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deepAdd = deepAdd;
|
|
4
|
+
/**
|
|
5
|
+
* Recursively adds numeric values from source into target. Mutates target in place.
|
|
6
|
+
* Keys in source that are not present in target are ignored.
|
|
7
|
+
*/
|
|
8
|
+
function deepAdd(target, source) {
|
|
9
|
+
const src = source;
|
|
10
|
+
const tgt = target;
|
|
11
|
+
for (const key in src) {
|
|
12
|
+
if (!Object.prototype.hasOwnProperty.call(src, key)) {
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
if (!(key in tgt)) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
const sourceValue = src[key];
|
|
19
|
+
const targetValue = tgt[key];
|
|
20
|
+
if (typeof sourceValue === "number" && typeof targetValue === "number") {
|
|
21
|
+
tgt[key] = targetValue + sourceValue;
|
|
22
|
+
}
|
|
23
|
+
else if (typeof sourceValue === "object" &&
|
|
24
|
+
sourceValue !== null &&
|
|
25
|
+
typeof targetValue === "object" &&
|
|
26
|
+
targetValue !== null) {
|
|
27
|
+
deepAdd(targetValue, sourceValue);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=deepAdd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deepAdd.js","sourceRoot":"","sources":["../src/deepAdd.ts"],"names":[],"mappings":";;AAMA,0BAgCC;AApCD;;;GAGG;AACH,SAAgB,OAAO,CACrB,MAAS,EACT,MAAsB;IAEtB,MAAM,GAAG,GAAG,MAAiC,CAAC;IAC9C,MAAM,GAAG,GAAG,MAAiC,CAAC;IAE9C,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;QACtB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;YACpD,SAAS;QACX,CAAC;QACD,IAAI,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC;YAClB,SAAS;QACX,CAAC;QAED,MAAM,WAAW,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,WAAW,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QAE7B,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE,CAAC;YACvE,GAAG,CAAC,GAAG,CAAC,GAAG,WAAW,GAAG,WAAW,CAAC;QACvC,CAAC;aAAM,IACL,OAAO,WAAW,KAAK,QAAQ;YAC/B,WAAW,KAAK,IAAI;YACpB,OAAO,WAAW,KAAK,QAAQ;YAC/B,WAAW,KAAK,IAAI,EACpB,CAAC;YACD,OAAO,CACL,WAA4B,EAC5B,WAAyC,CAC1C,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EACV,aAAa,EACb,WAAW,EACX,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deepAdd = exports.UsageTracker = void 0;
|
|
4
|
+
var UsageTracker_js_1 = require("./UsageTracker.js");
|
|
5
|
+
Object.defineProperty(exports, "UsageTracker", { enumerable: true, get: function () { return UsageTracker_js_1.UsageTracker; } });
|
|
6
|
+
var deepAdd_js_1 = require("./deepAdd.js");
|
|
7
|
+
Object.defineProperty(exports, "deepAdd", { enumerable: true, get: function () { return deepAdd_js_1.deepAdd; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,qDAAiD;AAAxC,+GAAA,YAAY,OAAA;AACrB,2CAAuC;AAA9B,qGAAA,OAAO,OAAA"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { StateTrackerEvent } from "@hardlydifficult/state-tracker";
|
|
2
|
+
/** Constrains T to a nested object where every leaf is a number. */
|
|
3
|
+
export interface NumericRecord {
|
|
4
|
+
[key: string]: number | NumericRecord;
|
|
5
|
+
}
|
|
6
|
+
/** Recursive partial — only provide the fields you are incrementing. */
|
|
7
|
+
export type DeepPartial<T> = {
|
|
8
|
+
[K in keyof T]?: T[K] extends number ? number : T[K] extends NumericRecord ? DeepPartial<T[K]> : never;
|
|
9
|
+
};
|
|
10
|
+
/** Internal persisted state wrapping consumer metrics T. */
|
|
11
|
+
export interface PersistedUsageState<T extends NumericRecord> {
|
|
12
|
+
cumulative: T;
|
|
13
|
+
session: T;
|
|
14
|
+
trackingSince: string;
|
|
15
|
+
sessionStartedAt: string;
|
|
16
|
+
}
|
|
17
|
+
/** Configuration for UsageTracker.create(). */
|
|
18
|
+
export interface UsageTrackerOptions<T extends NumericRecord> {
|
|
19
|
+
/** Unique persistence key (alphanumeric, hyphens, underscores). */
|
|
20
|
+
key: string;
|
|
21
|
+
/** Default metrics shape — all leaves must be 0. */
|
|
22
|
+
default: T;
|
|
23
|
+
/** Directory for state persistence. */
|
|
24
|
+
stateDirectory?: string;
|
|
25
|
+
/** Auto-save interval in ms (passed through to StateTracker). */
|
|
26
|
+
autoSaveMs?: number;
|
|
27
|
+
/** Event callback for logging (same shape as StateTracker). */
|
|
28
|
+
onEvent?: (event: StateTrackerEvent) => void;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAExE,oEAAoE;AACpE,MAAM,WAAW,aAAa;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,CAAC;CACvC;AAED,wEAAwE;AACxE,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;KAC1B,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAChC,MAAM,GACN,CAAC,CAAC,CAAC,CAAC,SAAS,aAAa,GACxB,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GACjB,KAAK;CACZ,CAAC;AAEF,4DAA4D;AAC5D,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,aAAa;IAC1D,UAAU,EAAE,CAAC,CAAC;IACd,OAAO,EAAE,CAAC,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,+CAA+C;AAC/C,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,aAAa;IAC1D,mEAAmE;IACnE,GAAG,EAAE,MAAM,CAAC;IACZ,oDAAoD;IACpD,OAAO,EAAE,CAAC,CAAC;IACX,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC9C"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hardlydifficult/usage-tracker",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "./dist/index.js",
|
|
5
|
+
"types": "./dist/index.d.ts",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"test:watch": "vitest",
|
|
13
|
+
"test:coverage": "vitest run --coverage",
|
|
14
|
+
"lint": "tsc --noEmit",
|
|
15
|
+
"clean": "rm -rf dist"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@hardlydifficult/state-tracker": "file:../state-tracker"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/node": "20.19.31",
|
|
22
|
+
"typescript": "5.8.3",
|
|
23
|
+
"vitest": "1.6.1"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"@hardlydifficult/state-tracker": ">=2.0.0"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=18.0.0"
|
|
30
|
+
}
|
|
31
|
+
}
|