@baukit/analytics-posthog-native 0.4.0 → 0.5.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 CHANGED
@@ -52,6 +52,34 @@ The adapter exports a minimal structural `PostHogNativeClient` interface for moc
52
52
  while its initializer options compile against `posthog-react-native`'s published types. This keeps
53
53
  unit tests runnable without installing or booting a React Native runtime.
54
54
 
55
+ ## Persisted identity storage
56
+
57
+ `AnalyticsClient` reads storage synchronously, while React Native storage is asynchronous. The
58
+ `/storage` subpath bridges the two. `HydratedAnalyticsStorage.load` reads the listed keys once,
59
+ serves later reads from memory, and writes those keys through without waiting. Other keys stay in
60
+ memory. The subpath does not import `posthog-react-native`, so apps with another transport can use
61
+ it without the SDK.
62
+
63
+ ```ts
64
+ import AsyncStorage from '@react-native-async-storage/async-storage';
65
+ import { AnalyticsClient, analyticsStorageKeys } from '@baukit/analytics-core';
66
+ import { HydratedAnalyticsStorage } from '@baukit/analytics-posthog-native/storage';
67
+
68
+ const keys = analyticsStorageKeys(storageKeyPrefix);
69
+ const storage = await HydratedAnalyticsStorage.load({
70
+ persistence: AsyncStorage,
71
+ persistentKeys: [keys.anonymousId, keys.userId, keys.aliasedUserId],
72
+ });
73
+ const analytics = new AnalyticsClient({ context, allowlist, storage, storageKeyPrefix });
74
+ ```
75
+
76
+ Include `keys.consent` only when analytics consent has no other durable home. A key that fails to
77
+ read starts absent, and the other keys still load. A failed write keeps the in-memory value and is
78
+ not reported. The storage holds only what the client writes: the consent state and pseudonymous
79
+ UUIDs.
80
+
81
+ `posthog-react-native` is an optional peer. Install it only when you use the transport.
82
+
55
83
  ## Mapping
56
84
 
57
85
  - `capture` flattens the core-stamped context and already-scrubbed event properties, preserving the
@@ -0,0 +1,25 @@
1
+ import type { AnalyticsStorage } from '@baukit/analytics-core';
2
+ /** Asynchronous key-value store, such as React Native AsyncStorage. */
3
+ export interface AsyncKeyValueStorage {
4
+ getItem(key: string): Promise<string | null>;
5
+ setItem(key: string, value: string): Promise<void>;
6
+ removeItem(key: string): Promise<void>;
7
+ }
8
+ export interface HydratedAnalyticsStorageOptions {
9
+ readonly persistence: AsyncKeyValueStorage;
10
+ /** Keys copied from and written through to `persistence`. Other keys stay in memory. */
11
+ readonly persistentKeys: readonly string[];
12
+ }
13
+ /**
14
+ * Synchronous `AnalyticsStorage` over an asynchronous store. `load` reads the persistent keys
15
+ * once, then reads are served from memory and writes go through without being awaited.
16
+ */
17
+ export declare class HydratedAnalyticsStorage implements AnalyticsStorage {
18
+ #private;
19
+ private constructor();
20
+ static load(options: HydratedAnalyticsStorageOptions): Promise<HydratedAnalyticsStorage>;
21
+ getItem(key: string): string | undefined;
22
+ setItem(key: string, value: string): void;
23
+ removeItem(key: string): void;
24
+ }
25
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,uEAAuE;AACvE,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7C,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,WAAW,EAAE,oBAAoB,CAAC;IAC3C,wFAAwF;IACxF,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5C;AAED;;;GAGG;AACH,qBAAa,wBAAyB,YAAW,gBAAgB;;IAK/D,OAAO;WASa,IAAI,CACtB,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,wBAAwB,CAAC;IAU7B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIxC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAMzC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;CAKrC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Synchronous `AnalyticsStorage` over an asynchronous store. `load` reads the persistent keys
3
+ * once, then reads are served from memory and writes go through without being awaited.
4
+ */
5
+ export class HydratedAnalyticsStorage {
6
+ #values;
7
+ #persistence;
8
+ #persistentKeys;
9
+ constructor(options, entries) {
10
+ this.#persistence = options.persistence;
11
+ this.#persistentKeys = new Set(options.persistentKeys);
12
+ this.#values = new Map(entries);
13
+ }
14
+ static async load(options) {
15
+ const keys = [...new Set(options.persistentKeys)];
16
+ const stored = await Promise.all(keys.map((key) => readOrAbsent(options.persistence, key)));
17
+ const entries = keys.flatMap((key, index) => {
18
+ const value = stored[index];
19
+ return value === undefined ? [] : [[key, value]];
20
+ });
21
+ return new HydratedAnalyticsStorage(options, entries);
22
+ }
23
+ getItem(key) {
24
+ return this.#values.get(key);
25
+ }
26
+ setItem(key, value) {
27
+ this.#values.set(key, value);
28
+ if (!this.#persistentKeys.has(key))
29
+ return;
30
+ ignoreFailure(() => this.#persistence.setItem(key, value));
31
+ }
32
+ removeItem(key) {
33
+ this.#values.delete(key);
34
+ if (!this.#persistentKeys.has(key))
35
+ return;
36
+ ignoreFailure(() => this.#persistence.removeItem(key));
37
+ }
38
+ }
39
+ async function readOrAbsent(persistence, key) {
40
+ try {
41
+ return (await persistence.getItem(key)) ?? undefined;
42
+ }
43
+ catch {
44
+ return undefined;
45
+ }
46
+ }
47
+ function ignoreFailure(write) {
48
+ try {
49
+ void write().catch(() => undefined);
50
+ }
51
+ catch {
52
+ return;
53
+ }
54
+ }
55
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAeA;;;GAGG;AACH,MAAM,OAAO,wBAAwB;IAC1B,OAAO,CAAsB;IAC7B,YAAY,CAAuB;IACnC,eAAe,CAAsB;IAE9C,YACE,OAAwC,EACxC,OAA+C;QAE/C,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;QACxC,IAAI,CAAC,eAAe,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QACvD,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IAEM,MAAM,CAAC,KAAK,CAAC,IAAI,CACtB,OAAwC;QAExC,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QAC5F,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5B,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAU,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;QACH,OAAO,IAAI,wBAAwB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACxD,CAAC;IAEM,OAAO,CAAC,GAAW;QACxB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IAEM,OAAO,CAAC,GAAW,EAAE,KAAa;QACvC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7B,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO;QAC3C,aAAa,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;IAC7D,CAAC;IAEM,UAAU,CAAC,GAAW;QAC3B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO;QAC3C,aAAa,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IACzD,CAAC;CACF;AAED,KAAK,UAAU,YAAY,CACzB,WAAiC,EACjC,GAAW;IAEX,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,SAAS,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAA0B;IAC/C,IAAI,CAAC;QACH,KAAK,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;IACT,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@baukit/analytics-posthog-native",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "PostHog React Native transport for @baukit/analytics-core.",
5
5
  "license": "MIT",
6
6
  "author": "Patrick Koss",
@@ -24,7 +24,13 @@
24
24
  "exports": {
25
25
  ".": {
26
26
  "types": "./dist/index.d.ts",
27
- "import": "./dist/index.js"
27
+ "import": "./dist/index.js",
28
+ "default": "./dist/index.js"
29
+ },
30
+ "./storage": {
31
+ "types": "./dist/storage.d.ts",
32
+ "import": "./dist/storage.js",
33
+ "default": "./dist/storage.js"
28
34
  }
29
35
  },
30
36
  "files": [
@@ -32,19 +38,25 @@
32
38
  "README.md",
33
39
  "LICENSE"
34
40
  ],
41
+ "scripts": {
42
+ "build": "tsc -p tsconfig.json",
43
+ "prepare": "pnpm run build",
44
+ "test": "tsc -p tsconfig.test.json && vitest run --config ../../vitest.config.ts && node ../../scripts/test-packed-exports.mjs",
45
+ "lint": "eslint src --max-warnings=0",
46
+ "format:check": "prettier --check src package.json tsconfig.json tsconfig.test.json"
47
+ },
35
48
  "devDependencies": {
49
+ "@baukit/analytics-core": "workspace:*",
36
50
  "posthog-react-native": "4.62.0",
37
- "typescript": "6.0.3",
38
- "@baukit/analytics-core": "0.4.0"
51
+ "typescript": "6.0.3"
39
52
  },
40
53
  "peerDependencies": {
41
- "@baukit/analytics-core": "^0.4.0",
54
+ "@baukit/analytics-core": "^0.5.0",
42
55
  "posthog-react-native": "^4.62.0"
43
56
  },
44
- "scripts": {
45
- "build": "tsc -p tsconfig.json",
46
- "test": "vitest run --config ../../vitest.config.ts",
47
- "lint": "eslint src --max-warnings=0",
48
- "format:check": "prettier --check src package.json tsconfig.json"
57
+ "peerDependenciesMeta": {
58
+ "posthog-react-native": {
59
+ "optional": true
60
+ }
49
61
  }
50
- }
62
+ }