@drakkar.software/sunglasses-core 0.6.0 → 0.7.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/dist/index.d.mts CHANGED
@@ -667,15 +667,11 @@ declare class MiddlewarePipeline {
667
667
  /**
668
668
  * Persists per-event counts bucketed by time period (daily, weekly, monthly, all-time).
669
669
  *
670
- * Storage key format:
671
- * `sg:count:{period}:{bucket}:{eventName}`
672
- *
673
- * where `bucket` is:
674
- * - daily: "2024-01-15"
675
- * - weekly: "2024-W03" (ISO week)
676
- * - monthly: "2024-01"
677
- * - all-time: "all"
670
+ * All counts are stored in a single `sg:counts` JSON blob, keyed internally by
671
+ * `{period}:{bucket}:{eventName}` within the object:
672
+ * `{ "daily:2024-01-15:click": 3, "weekly:2024-W03:click": 7, ... }`
678
673
  *
674
+ * One storage key regardless of how many event types are tracked.
679
675
  * Counts survive app restarts (persisted to IStorageAdapter).
680
676
  * Designed to be written from the enqueue hot path — must not throw.
681
677
  */
@@ -683,17 +679,12 @@ declare class EventCounter implements IEventCounter {
683
679
  private readonly storage;
684
680
  private readonly logger;
685
681
  /**
686
- * In-memory cache of counts keyed by storage key.
687
- * Updated synchronously on increment so getCount() can return immediately
688
- * without waiting for storage writes to complete.
682
+ * In-memory cache of counts keyed by sub-key (`{period}:{bucket}:{eventName}`).
683
+ * Updated synchronously on increment so getCount() can return immediately.
689
684
  */
690
685
  private readonly cache;
691
- /**
692
- * Tracks all storage keys written during this session.
693
- * Used to reliably clear an event's timed buckets on reset(),
694
- * even when they fall outside the 90-day sweep window.
695
- */
696
- private readonly writtenKeys;
686
+ /** Whether the counts blob has been loaded from storage into cache. */
687
+ private loaded;
697
688
  constructor(storage: IStorageAdapter, logger: Logger);
698
689
  /**
699
690
  * Increment the count for `eventName` across all four periods for `date`.
@@ -702,20 +693,21 @@ declare class EventCounter implements IEventCounter {
702
693
  getCount(eventName: string, period: EventCountPeriod, date?: Date): Promise<number>;
703
694
  /**
704
695
  * Reset counts for a specific event (all periods), or all events if omitted.
705
- *
706
- * Note: resetting all events requires listing storage keys. This is a best-effort
707
- * operation — adapters that don't support key enumeration will only clear
708
- * the provided event name's keys.
709
696
  */
710
697
  reset(eventName?: string): Promise<void>;
711
- private incrementPeriod;
712
- private clearEvent;
713
- /** Build the storage key for a given event, period, and date. */
714
- storageKey(eventName: string, period: EventCountPeriod, date: Date): string;
698
+ /**
699
+ * Load the counts blob from storage into the in-memory cache.
700
+ * Only runs once; subsequent calls are no-ops.
701
+ */
702
+ private loadIfNeeded;
703
+ /** Serialize the full in-memory cache to `sg:counts`. */
704
+ private persist;
705
+ /** Build the sub-key within the counts blob for a given event, period, and date. */
706
+ private subKey;
715
707
  /**
716
708
  * Return the time-bucket string for a given period and date.
717
709
  * - daily: "2024-01-15"
718
- * - weekly: "2024-W03"
710
+ * - weekly: "2024-W03" (ISO week)
719
711
  * - monthly: "2024-01"
720
712
  * - all-time: "all"
721
713
  */
package/dist/index.d.ts CHANGED
@@ -667,15 +667,11 @@ declare class MiddlewarePipeline {
667
667
  /**
668
668
  * Persists per-event counts bucketed by time period (daily, weekly, monthly, all-time).
669
669
  *
670
- * Storage key format:
671
- * `sg:count:{period}:{bucket}:{eventName}`
672
- *
673
- * where `bucket` is:
674
- * - daily: "2024-01-15"
675
- * - weekly: "2024-W03" (ISO week)
676
- * - monthly: "2024-01"
677
- * - all-time: "all"
670
+ * All counts are stored in a single `sg:counts` JSON blob, keyed internally by
671
+ * `{period}:{bucket}:{eventName}` within the object:
672
+ * `{ "daily:2024-01-15:click": 3, "weekly:2024-W03:click": 7, ... }`
678
673
  *
674
+ * One storage key regardless of how many event types are tracked.
679
675
  * Counts survive app restarts (persisted to IStorageAdapter).
680
676
  * Designed to be written from the enqueue hot path — must not throw.
681
677
  */
@@ -683,17 +679,12 @@ declare class EventCounter implements IEventCounter {
683
679
  private readonly storage;
684
680
  private readonly logger;
685
681
  /**
686
- * In-memory cache of counts keyed by storage key.
687
- * Updated synchronously on increment so getCount() can return immediately
688
- * without waiting for storage writes to complete.
682
+ * In-memory cache of counts keyed by sub-key (`{period}:{bucket}:{eventName}`).
683
+ * Updated synchronously on increment so getCount() can return immediately.
689
684
  */
690
685
  private readonly cache;
691
- /**
692
- * Tracks all storage keys written during this session.
693
- * Used to reliably clear an event's timed buckets on reset(),
694
- * even when they fall outside the 90-day sweep window.
695
- */
696
- private readonly writtenKeys;
686
+ /** Whether the counts blob has been loaded from storage into cache. */
687
+ private loaded;
697
688
  constructor(storage: IStorageAdapter, logger: Logger);
698
689
  /**
699
690
  * Increment the count for `eventName` across all four periods for `date`.
@@ -702,20 +693,21 @@ declare class EventCounter implements IEventCounter {
702
693
  getCount(eventName: string, period: EventCountPeriod, date?: Date): Promise<number>;
703
694
  /**
704
695
  * Reset counts for a specific event (all periods), or all events if omitted.
705
- *
706
- * Note: resetting all events requires listing storage keys. This is a best-effort
707
- * operation — adapters that don't support key enumeration will only clear
708
- * the provided event name's keys.
709
696
  */
710
697
  reset(eventName?: string): Promise<void>;
711
- private incrementPeriod;
712
- private clearEvent;
713
- /** Build the storage key for a given event, period, and date. */
714
- storageKey(eventName: string, period: EventCountPeriod, date: Date): string;
698
+ /**
699
+ * Load the counts blob from storage into the in-memory cache.
700
+ * Only runs once; subsequent calls are no-ops.
701
+ */
702
+ private loadIfNeeded;
703
+ /** Serialize the full in-memory cache to `sg:counts`. */
704
+ private persist;
705
+ /** Build the sub-key within the counts blob for a given event, period, and date. */
706
+ private subKey;
715
707
  /**
716
708
  * Return the time-bucket string for a given period and date.
717
709
  * - daily: "2024-01-15"
718
- * - weekly: "2024-W03"
710
+ * - weekly: "2024-W03" (ISO week)
719
711
  * - monthly: "2024-01"
720
712
  * - all-time: "all"
721
713
  */
package/dist/index.js CHANGED
@@ -205,150 +205,91 @@ var ConsentManager = class {
205
205
  };
206
206
 
207
207
  // src/EventCounter.ts
208
- var KEY_PREFIX = "sg:count";
208
+ var COUNTS_KEY = "sg:counts";
209
209
  var EventCounter = class {
210
210
  constructor(storage, logger) {
211
211
  this.storage = storage;
212
212
  this.logger = logger;
213
213
  /**
214
- * In-memory cache of counts keyed by storage key.
215
- * Updated synchronously on increment so getCount() can return immediately
216
- * without waiting for storage writes to complete.
214
+ * In-memory cache of counts keyed by sub-key (`{period}:{bucket}:{eventName}`).
215
+ * Updated synchronously on increment so getCount() can return immediately.
217
216
  */
218
217
  this.cache = /* @__PURE__ */ new Map();
219
- /**
220
- * Tracks all storage keys written during this session.
221
- * Used to reliably clear an event's timed buckets on reset(),
222
- * even when they fall outside the 90-day sweep window.
223
- */
224
- this.writtenKeys = /* @__PURE__ */ new Set();
218
+ /** Whether the counts blob has been loaded from storage into cache. */
219
+ this.loaded = false;
225
220
  }
226
221
  /**
227
222
  * Increment the count for `eventName` across all four periods for `date`.
228
223
  */
229
224
  async increment(eventName, date = /* @__PURE__ */ new Date()) {
225
+ await this.loadIfNeeded();
230
226
  const periods = ["daily", "weekly", "monthly", "all-time"];
231
- await Promise.all(periods.map((period) => this.incrementPeriod(eventName, period, date)));
227
+ for (const period of periods) {
228
+ const key = this.subKey(eventName, period, date);
229
+ this.cache.set(key, (this.cache.get(key) ?? 0) + 1);
230
+ }
231
+ await this.persist();
232
232
  }
233
233
  async getCount(eventName, period, date = /* @__PURE__ */ new Date()) {
234
- const key = this.storageKey(eventName, period, date);
235
- const cached = this.cache.get(key);
236
- if (cached !== void 0) return cached;
237
- try {
238
- const raw = await this.storage.read(key);
239
- if (raw === null) return 0;
240
- const n = parseInt(raw, 10);
241
- const count = Number.isNaN(n) ? 0 : n;
242
- this.cache.set(key, count);
243
- return count;
244
- } catch (err) {
245
- this.logger.warn("EventCounter: failed to read count", err);
246
- return 0;
247
- }
234
+ await this.loadIfNeeded();
235
+ return this.cache.get(this.subKey(eventName, period, date)) ?? 0;
248
236
  }
249
237
  /**
250
238
  * Reset counts for a specific event (all periods), or all events if omitted.
251
- *
252
- * Note: resetting all events requires listing storage keys. This is a best-effort
253
- * operation — adapters that don't support key enumeration will only clear
254
- * the provided event name's keys.
255
239
  */
256
240
  async reset(eventName) {
241
+ await this.loadIfNeeded();
257
242
  if (eventName) {
258
- await this.clearEvent(eventName);
259
- } else {
260
- const allKeys = [...this.writtenKeys];
261
- for (const key of allKeys) {
262
- try {
263
- await this.storage.delete(key);
264
- } catch {
265
- }
266
- this.writtenKeys.delete(key);
267
- this.cache.delete(key);
268
- }
269
- const now = /* @__PURE__ */ new Date();
270
- const seenKeys = new Set(allKeys);
271
- const periods = ["daily", "weekly", "monthly", "all-time"];
272
- const eventNames = new Set(
273
- allKeys.map((k) => k.split(":").pop()).filter(Boolean)
274
- );
275
- for (let i = 0; i < 90; i++) {
276
- const d = new Date(now);
277
- d.setDate(d.getDate() - i);
278
- for (const name of eventNames) {
279
- for (const period of periods) {
280
- const key = this.storageKey(name, period, d);
281
- if (!seenKeys.has(key)) {
282
- seenKeys.add(key);
283
- try {
284
- await this.storage.delete(key);
285
- } catch {
286
- }
287
- }
288
- }
243
+ const safeEvent = eventName.replace(/[^a-zA-Z0-9_\-]/g, "_");
244
+ for (const key of this.cache.keys()) {
245
+ if (key.endsWith(`:${safeEvent}`)) {
246
+ this.cache.delete(key);
289
247
  }
290
248
  }
291
- this.logger.debug("EventCounter.reset(): cleared all tracked event counters");
249
+ } else {
250
+ this.cache.clear();
292
251
  }
252
+ await this.persist();
253
+ this.logger.debug("EventCounter.reset(): cleared event counters");
293
254
  }
294
255
  // ── Private ──────────────────────────────────────────────────────────────
295
- async incrementPeriod(eventName, period, date) {
296
- const key = this.storageKey(eventName, period, date);
297
- this.writtenKeys.add(key);
298
- const currentCached = this.cache.get(key) ?? 0;
299
- const next = currentCached + 1;
300
- this.cache.set(key, next);
256
+ /**
257
+ * Load the counts blob from storage into the in-memory cache.
258
+ * Only runs once; subsequent calls are no-ops.
259
+ */
260
+ async loadIfNeeded() {
261
+ if (this.loaded) return;
262
+ this.loaded = true;
301
263
  try {
302
- await this.storage.write(key, String(next));
264
+ const raw = await this.storage.read(COUNTS_KEY);
265
+ if (!raw) return;
266
+ const parsed = JSON.parse(raw);
267
+ for (const [k, v] of Object.entries(parsed)) {
268
+ if (typeof v === "number") this.cache.set(k, v);
269
+ }
303
270
  } catch (err) {
304
- this.logger.warn("EventCounter: failed to persist count", err);
271
+ this.logger.warn("EventCounter: failed to load counts blob", err);
305
272
  }
306
273
  }
307
- async clearEvent(eventName) {
308
- const safeEvent = eventName.replace(/[^a-zA-Z0-9_\-]/g, "_");
309
- const sessionKeys = [...this.writtenKeys].filter(
310
- (k) => k.endsWith(`:${safeEvent}`)
311
- );
312
- for (const key of sessionKeys) {
313
- try {
314
- await this.storage.delete(key);
315
- } catch {
316
- }
317
- this.writtenKeys.delete(key);
318
- this.cache.delete(key);
319
- }
320
- const now = /* @__PURE__ */ new Date();
321
- const seenBuckets = new Set(sessionKeys);
322
- for (let i = 0; i < 90; i++) {
323
- const d = new Date(now);
324
- d.setDate(d.getDate() - i);
325
- const periods = ["daily", "weekly", "monthly"];
326
- for (const period of periods) {
327
- const key = this.storageKey(eventName, period, d);
328
- if (!seenBuckets.has(key)) {
329
- seenBuckets.add(key);
330
- try {
331
- await this.storage.delete(key);
332
- } catch {
333
- }
334
- }
335
- }
336
- }
274
+ /** Serialize the full in-memory cache to `sg:counts`. */
275
+ async persist() {
276
+ const obj = {};
277
+ for (const [k, v] of this.cache) obj[k] = v;
337
278
  try {
338
- await this.storage.delete(this.storageKey(eventName, "all-time", /* @__PURE__ */ new Date()));
339
- } catch {
279
+ await this.storage.write(COUNTS_KEY, JSON.stringify(obj));
280
+ } catch (err) {
281
+ this.logger.warn("EventCounter: failed to persist counts blob", err);
340
282
  }
341
283
  }
342
- /** Build the storage key for a given event, period, and date. */
343
- storageKey(eventName, period, date) {
344
- const bucket = this.bucketFor(period, date);
284
+ /** Build the sub-key within the counts blob for a given event, period, and date. */
285
+ subKey(eventName, period, date) {
345
286
  const safeEvent = eventName.replace(/[^a-zA-Z0-9_\-]/g, "_");
346
- return `${KEY_PREFIX}:${period}:${bucket}:${safeEvent}`;
287
+ return `${period}:${this.bucketFor(period, date)}:${safeEvent}`;
347
288
  }
348
289
  /**
349
290
  * Return the time-bucket string for a given period and date.
350
291
  * - daily: "2024-01-15"
351
- * - weekly: "2024-W03"
292
+ * - weekly: "2024-W03" (ISO week)
352
293
  * - monthly: "2024-01"
353
294
  * - all-time: "all"
354
295
  */
@@ -357,10 +298,9 @@ var EventCounter = class {
357
298
  case "daily":
358
299
  return date.toISOString().slice(0, 10);
359
300
  // "YYYY-MM-DD"
360
- case "weekly": {
361
- const iso = toISOWeek(date);
362
- return iso;
363
- }
301
+ case "weekly":
302
+ return toISOWeek(date);
303
+ // "YYYY-Www"
364
304
  case "monthly":
365
305
  return date.toISOString().slice(0, 7);
366
306
  // "YYYY-MM"
package/dist/index.mjs CHANGED
@@ -162,150 +162,91 @@ var ConsentManager = class {
162
162
  };
163
163
 
164
164
  // src/EventCounter.ts
165
- var KEY_PREFIX = "sg:count";
165
+ var COUNTS_KEY = "sg:counts";
166
166
  var EventCounter = class {
167
167
  constructor(storage, logger) {
168
168
  this.storage = storage;
169
169
  this.logger = logger;
170
170
  /**
171
- * In-memory cache of counts keyed by storage key.
172
- * Updated synchronously on increment so getCount() can return immediately
173
- * without waiting for storage writes to complete.
171
+ * In-memory cache of counts keyed by sub-key (`{period}:{bucket}:{eventName}`).
172
+ * Updated synchronously on increment so getCount() can return immediately.
174
173
  */
175
174
  this.cache = /* @__PURE__ */ new Map();
176
- /**
177
- * Tracks all storage keys written during this session.
178
- * Used to reliably clear an event's timed buckets on reset(),
179
- * even when they fall outside the 90-day sweep window.
180
- */
181
- this.writtenKeys = /* @__PURE__ */ new Set();
175
+ /** Whether the counts blob has been loaded from storage into cache. */
176
+ this.loaded = false;
182
177
  }
183
178
  /**
184
179
  * Increment the count for `eventName` across all four periods for `date`.
185
180
  */
186
181
  async increment(eventName, date = /* @__PURE__ */ new Date()) {
182
+ await this.loadIfNeeded();
187
183
  const periods = ["daily", "weekly", "monthly", "all-time"];
188
- await Promise.all(periods.map((period) => this.incrementPeriod(eventName, period, date)));
184
+ for (const period of periods) {
185
+ const key = this.subKey(eventName, period, date);
186
+ this.cache.set(key, (this.cache.get(key) ?? 0) + 1);
187
+ }
188
+ await this.persist();
189
189
  }
190
190
  async getCount(eventName, period, date = /* @__PURE__ */ new Date()) {
191
- const key = this.storageKey(eventName, period, date);
192
- const cached = this.cache.get(key);
193
- if (cached !== void 0) return cached;
194
- try {
195
- const raw = await this.storage.read(key);
196
- if (raw === null) return 0;
197
- const n = parseInt(raw, 10);
198
- const count = Number.isNaN(n) ? 0 : n;
199
- this.cache.set(key, count);
200
- return count;
201
- } catch (err) {
202
- this.logger.warn("EventCounter: failed to read count", err);
203
- return 0;
204
- }
191
+ await this.loadIfNeeded();
192
+ return this.cache.get(this.subKey(eventName, period, date)) ?? 0;
205
193
  }
206
194
  /**
207
195
  * Reset counts for a specific event (all periods), or all events if omitted.
208
- *
209
- * Note: resetting all events requires listing storage keys. This is a best-effort
210
- * operation — adapters that don't support key enumeration will only clear
211
- * the provided event name's keys.
212
196
  */
213
197
  async reset(eventName) {
198
+ await this.loadIfNeeded();
214
199
  if (eventName) {
215
- await this.clearEvent(eventName);
216
- } else {
217
- const allKeys = [...this.writtenKeys];
218
- for (const key of allKeys) {
219
- try {
220
- await this.storage.delete(key);
221
- } catch {
222
- }
223
- this.writtenKeys.delete(key);
224
- this.cache.delete(key);
225
- }
226
- const now = /* @__PURE__ */ new Date();
227
- const seenKeys = new Set(allKeys);
228
- const periods = ["daily", "weekly", "monthly", "all-time"];
229
- const eventNames = new Set(
230
- allKeys.map((k) => k.split(":").pop()).filter(Boolean)
231
- );
232
- for (let i = 0; i < 90; i++) {
233
- const d = new Date(now);
234
- d.setDate(d.getDate() - i);
235
- for (const name of eventNames) {
236
- for (const period of periods) {
237
- const key = this.storageKey(name, period, d);
238
- if (!seenKeys.has(key)) {
239
- seenKeys.add(key);
240
- try {
241
- await this.storage.delete(key);
242
- } catch {
243
- }
244
- }
245
- }
200
+ const safeEvent = eventName.replace(/[^a-zA-Z0-9_\-]/g, "_");
201
+ for (const key of this.cache.keys()) {
202
+ if (key.endsWith(`:${safeEvent}`)) {
203
+ this.cache.delete(key);
246
204
  }
247
205
  }
248
- this.logger.debug("EventCounter.reset(): cleared all tracked event counters");
206
+ } else {
207
+ this.cache.clear();
249
208
  }
209
+ await this.persist();
210
+ this.logger.debug("EventCounter.reset(): cleared event counters");
250
211
  }
251
212
  // ── Private ──────────────────────────────────────────────────────────────
252
- async incrementPeriod(eventName, period, date) {
253
- const key = this.storageKey(eventName, period, date);
254
- this.writtenKeys.add(key);
255
- const currentCached = this.cache.get(key) ?? 0;
256
- const next = currentCached + 1;
257
- this.cache.set(key, next);
213
+ /**
214
+ * Load the counts blob from storage into the in-memory cache.
215
+ * Only runs once; subsequent calls are no-ops.
216
+ */
217
+ async loadIfNeeded() {
218
+ if (this.loaded) return;
219
+ this.loaded = true;
258
220
  try {
259
- await this.storage.write(key, String(next));
221
+ const raw = await this.storage.read(COUNTS_KEY);
222
+ if (!raw) return;
223
+ const parsed = JSON.parse(raw);
224
+ for (const [k, v] of Object.entries(parsed)) {
225
+ if (typeof v === "number") this.cache.set(k, v);
226
+ }
260
227
  } catch (err) {
261
- this.logger.warn("EventCounter: failed to persist count", err);
228
+ this.logger.warn("EventCounter: failed to load counts blob", err);
262
229
  }
263
230
  }
264
- async clearEvent(eventName) {
265
- const safeEvent = eventName.replace(/[^a-zA-Z0-9_\-]/g, "_");
266
- const sessionKeys = [...this.writtenKeys].filter(
267
- (k) => k.endsWith(`:${safeEvent}`)
268
- );
269
- for (const key of sessionKeys) {
270
- try {
271
- await this.storage.delete(key);
272
- } catch {
273
- }
274
- this.writtenKeys.delete(key);
275
- this.cache.delete(key);
276
- }
277
- const now = /* @__PURE__ */ new Date();
278
- const seenBuckets = new Set(sessionKeys);
279
- for (let i = 0; i < 90; i++) {
280
- const d = new Date(now);
281
- d.setDate(d.getDate() - i);
282
- const periods = ["daily", "weekly", "monthly"];
283
- for (const period of periods) {
284
- const key = this.storageKey(eventName, period, d);
285
- if (!seenBuckets.has(key)) {
286
- seenBuckets.add(key);
287
- try {
288
- await this.storage.delete(key);
289
- } catch {
290
- }
291
- }
292
- }
293
- }
231
+ /** Serialize the full in-memory cache to `sg:counts`. */
232
+ async persist() {
233
+ const obj = {};
234
+ for (const [k, v] of this.cache) obj[k] = v;
294
235
  try {
295
- await this.storage.delete(this.storageKey(eventName, "all-time", /* @__PURE__ */ new Date()));
296
- } catch {
236
+ await this.storage.write(COUNTS_KEY, JSON.stringify(obj));
237
+ } catch (err) {
238
+ this.logger.warn("EventCounter: failed to persist counts blob", err);
297
239
  }
298
240
  }
299
- /** Build the storage key for a given event, period, and date. */
300
- storageKey(eventName, period, date) {
301
- const bucket = this.bucketFor(period, date);
241
+ /** Build the sub-key within the counts blob for a given event, period, and date. */
242
+ subKey(eventName, period, date) {
302
243
  const safeEvent = eventName.replace(/[^a-zA-Z0-9_\-]/g, "_");
303
- return `${KEY_PREFIX}:${period}:${bucket}:${safeEvent}`;
244
+ return `${period}:${this.bucketFor(period, date)}:${safeEvent}`;
304
245
  }
305
246
  /**
306
247
  * Return the time-bucket string for a given period and date.
307
248
  * - daily: "2024-01-15"
308
- * - weekly: "2024-W03"
249
+ * - weekly: "2024-W03" (ISO week)
309
250
  * - monthly: "2024-01"
310
251
  * - all-time: "all"
311
252
  */
@@ -314,10 +255,9 @@ var EventCounter = class {
314
255
  case "daily":
315
256
  return date.toISOString().slice(0, 10);
316
257
  // "YYYY-MM-DD"
317
- case "weekly": {
318
- const iso = toISOWeek(date);
319
- return iso;
320
- }
258
+ case "weekly":
259
+ return toISOWeek(date);
260
+ // "YYYY-Www"
321
261
  case "monthly":
322
262
  return date.toISOString().slice(0, 7);
323
263
  // "YYYY-MM"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drakkar.software/sunglasses-core",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Platform-agnostic event tracking engine for SunGlasses",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",