@interfere/react 0.0.1 → 0.0.2-alpha.1

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 (198) hide show
  1. package/dist/client.d.mts +15 -0
  2. package/dist/client.d.mts.map +1 -0
  3. package/dist/client.mjs +75 -0
  4. package/dist/client.mjs.map +1 -0
  5. package/dist/core/events/event-registry.d.mts +23 -0
  6. package/dist/core/events/event-registry.d.mts.map +1 -0
  7. package/dist/core/events/event-registry.mjs +32 -0
  8. package/dist/core/events/event-registry.mjs.map +1 -0
  9. package/dist/core/events/plugin-event-types.d.mts +92 -0
  10. package/dist/core/events/plugin-event-types.d.mts.map +1 -0
  11. package/dist/core/events/plugin-event-types.mjs +25 -0
  12. package/dist/core/events/plugin-event-types.mjs.map +1 -0
  13. package/dist/core/plugins/dom-utils.d.mts +9 -0
  14. package/dist/core/plugins/dom-utils.d.mts.map +1 -0
  15. package/dist/core/plugins/dom-utils.mjs +25 -0
  16. package/dist/core/plugins/dom-utils.mjs.map +1 -0
  17. package/dist/core/plugins/impl/ai-summary.d.mts +6 -0
  18. package/dist/core/plugins/impl/ai-summary.d.mts.map +1 -0
  19. package/dist/core/plugins/impl/ai-summary.mjs +122 -0
  20. package/dist/core/plugins/impl/ai-summary.mjs.map +1 -0
  21. package/dist/core/plugins/impl/errors.d.mts +9 -0
  22. package/dist/core/plugins/impl/errors.d.mts.map +1 -0
  23. package/dist/core/plugins/impl/errors.mjs +153 -0
  24. package/dist/core/plugins/impl/errors.mjs.map +1 -0
  25. package/dist/core/plugins/impl/page-events.d.mts +15 -0
  26. package/dist/core/plugins/impl/page-events.d.mts.map +1 -0
  27. package/dist/core/plugins/impl/page-events.mjs +131 -0
  28. package/dist/core/plugins/impl/page-events.mjs.map +1 -0
  29. package/dist/core/plugins/impl/rage-click.d.mts +6 -0
  30. package/dist/core/plugins/impl/rage-click.d.mts.map +1 -0
  31. package/dist/core/plugins/impl/rage-click.mjs +53 -0
  32. package/dist/core/plugins/impl/rage-click.mjs.map +1 -0
  33. package/dist/core/plugins/impl/replay.d.mts +9 -0
  34. package/dist/core/plugins/impl/replay.d.mts.map +1 -0
  35. package/dist/core/plugins/impl/replay.mjs +144 -0
  36. package/dist/core/plugins/impl/replay.mjs.map +1 -0
  37. package/dist/core/plugins/impl/server-tracing.d.mts +7 -0
  38. package/dist/core/plugins/impl/server-tracing.d.mts.map +1 -0
  39. package/dist/core/plugins/impl/server-tracing.mjs +160 -0
  40. package/dist/core/plugins/impl/server-tracing.mjs.map +1 -0
  41. package/dist/core/plugins/plugin-event-system.d.mts +47 -0
  42. package/dist/core/plugins/plugin-event-system.d.mts.map +1 -0
  43. package/dist/core/plugins/plugin-event-system.mjs +75 -0
  44. package/dist/core/plugins/plugin-event-system.mjs.map +1 -0
  45. package/dist/core/plugins/plugin-loader.d.mts +22 -0
  46. package/dist/core/plugins/plugin-loader.d.mts.map +1 -0
  47. package/dist/core/plugins/plugin-loader.mjs +142 -0
  48. package/dist/core/plugins/plugin-loader.mjs.map +1 -0
  49. package/dist/core/runtime/config.d.mts +14 -0
  50. package/dist/core/runtime/config.d.mts.map +1 -0
  51. package/dist/core/runtime/config.mjs +39 -0
  52. package/dist/core/runtime/config.mjs.map +1 -0
  53. package/dist/core/runtime/context.d.mts +25 -0
  54. package/dist/core/runtime/context.d.mts.map +1 -0
  55. package/dist/core/runtime/context.mjs +48 -0
  56. package/dist/core/runtime/context.mjs.map +1 -0
  57. package/dist/core/runtime/ingest-target.d.mts +10 -0
  58. package/dist/core/runtime/ingest-target.d.mts.map +1 -0
  59. package/dist/core/runtime/ingest-target.mjs +15 -0
  60. package/dist/core/runtime/ingest-target.mjs.map +1 -0
  61. package/dist/core/schemas.d.mts +85 -0
  62. package/dist/core/schemas.d.mts.map +1 -0
  63. package/dist/core/schemas.mjs +1 -0
  64. package/dist/effect/build-envelope.d.mts +9 -0
  65. package/dist/effect/build-envelope.d.mts.map +1 -0
  66. package/dist/effect/build-envelope.mjs +29 -0
  67. package/dist/effect/build-envelope.mjs.map +1 -0
  68. package/dist/effect/errors.d.mts +36 -0
  69. package/dist/effect/errors.d.mts.map +1 -0
  70. package/dist/effect/errors.mjs +10 -0
  71. package/dist/effect/errors.mjs.map +1 -0
  72. package/dist/effect/layers/config.layer.d.mts +13 -0
  73. package/dist/effect/layers/config.layer.d.mts.map +1 -0
  74. package/dist/effect/layers/config.layer.mjs +21 -0
  75. package/dist/effect/layers/config.layer.mjs.map +1 -0
  76. package/dist/effect/layers/context.layer.d.mts +12 -0
  77. package/dist/effect/layers/context.layer.d.mts.map +1 -0
  78. package/dist/effect/layers/context.layer.mjs +14 -0
  79. package/dist/effect/layers/context.layer.mjs.map +1 -0
  80. package/dist/effect/layers/http.layer.d.mts +21 -0
  81. package/dist/effect/layers/http.layer.d.mts.map +1 -0
  82. package/dist/effect/layers/http.layer.mjs +113 -0
  83. package/dist/effect/layers/http.layer.mjs.map +1 -0
  84. package/dist/effect/layers/queue.layer.d.mts +30 -0
  85. package/dist/effect/layers/queue.layer.d.mts.map +1 -0
  86. package/dist/effect/layers/queue.layer.mjs +232 -0
  87. package/dist/effect/layers/queue.layer.mjs.map +1 -0
  88. package/dist/effect/layers/session.layer.d.mts +26 -0
  89. package/dist/effect/layers/session.layer.d.mts.map +1 -0
  90. package/dist/effect/layers/session.layer.mjs +126 -0
  91. package/dist/effect/layers/session.layer.mjs.map +1 -0
  92. package/dist/effect/layers/storage.layer.d.mts +19 -0
  93. package/dist/effect/layers/storage.layer.d.mts.map +1 -0
  94. package/dist/effect/layers/storage.layer.mjs +200 -0
  95. package/dist/effect/layers/storage.layer.mjs.map +1 -0
  96. package/dist/effect/layers/tracer.layer.d.mts +9 -0
  97. package/dist/effect/layers/tracer.layer.d.mts.map +1 -0
  98. package/dist/effect/layers/tracer.layer.mjs +11 -0
  99. package/dist/effect/layers/tracer.layer.mjs.map +1 -0
  100. package/dist/effect/runtime-services.d.mts +22 -0
  101. package/dist/effect/runtime-services.d.mts.map +1 -0
  102. package/dist/effect/runtime-services.mjs +76 -0
  103. package/dist/effect/runtime-services.mjs.map +1 -0
  104. package/dist/effect/tags.d.mts +50 -0
  105. package/dist/effect/tags.d.mts.map +1 -0
  106. package/dist/effect/tags.mjs +7 -0
  107. package/dist/effect/tags.mjs.map +1 -0
  108. package/dist/hooks/use-runtime-and-plugins.d.mts +7 -0
  109. package/dist/hooks/use-runtime-and-plugins.d.mts.map +1 -0
  110. package/dist/hooks/use-runtime-and-plugins.mjs +153 -0
  111. package/dist/hooks/use-runtime-and-plugins.mjs.map +1 -0
  112. package/dist/hooks/use-session.d.mts +40 -0
  113. package/dist/hooks/use-session.d.mts.map +1 -0
  114. package/dist/hooks/use-session.mjs +96 -0
  115. package/dist/hooks/use-session.mjs.map +1 -0
  116. package/dist/package.mjs +100 -0
  117. package/dist/package.mjs.map +1 -0
  118. package/dist/provider.d.mts +17 -0
  119. package/dist/provider.d.mts.map +1 -0
  120. package/dist/provider.mjs +26 -0
  121. package/dist/provider.mjs.map +1 -0
  122. package/dist/server/auth.d.mts +11 -0
  123. package/dist/server/auth.d.mts.map +1 -0
  124. package/dist/server/auth.mjs +36 -0
  125. package/dist/server/auth.mjs.map +1 -0
  126. package/dist/server/capture.d.mts +18 -0
  127. package/dist/server/capture.d.mts.map +1 -0
  128. package/dist/server/capture.mjs +105 -0
  129. package/dist/server/capture.mjs.map +1 -0
  130. package/package.json +60 -27
  131. package/dist/__tests__/client.test.d.ts +0 -2
  132. package/dist/__tests__/client.test.d.ts.map +0 -1
  133. package/dist/__tests__/client.test.js +0 -447
  134. package/dist/__tests__/client.test.js.map +0 -1
  135. package/dist/__tests__/lib/core/error-handlers.test.d.ts +0 -2
  136. package/dist/__tests__/lib/core/error-handlers.test.d.ts.map +0 -1
  137. package/dist/__tests__/lib/core/error-handlers.test.js +0 -596
  138. package/dist/__tests__/lib/core/error-handlers.test.js.map +0 -1
  139. package/dist/__tests__/lib/core/event-queue.test.d.ts +0 -2
  140. package/dist/__tests__/lib/core/event-queue.test.d.ts.map +0 -1
  141. package/dist/__tests__/lib/core/event-queue.test.js +0 -290
  142. package/dist/__tests__/lib/core/event-queue.test.js.map +0 -1
  143. package/dist/__tests__/lib/core/runtime.test.d.ts +0 -2
  144. package/dist/__tests__/lib/core/runtime.test.d.ts.map +0 -1
  145. package/dist/__tests__/lib/core/runtime.test.js +0 -133
  146. package/dist/__tests__/lib/core/runtime.test.js.map +0 -1
  147. package/dist/__tests__/lib/core/session-manager.test.d.ts +0 -2
  148. package/dist/__tests__/lib/core/session-manager.test.d.ts.map +0 -1
  149. package/dist/__tests__/lib/core/session-manager.test.js +0 -356
  150. package/dist/__tests__/lib/core/session-manager.test.js.map +0 -1
  151. package/dist/__tests__/provider.test.d.ts +0 -2
  152. package/dist/__tests__/provider.test.d.ts.map +0 -1
  153. package/dist/__tests__/provider.test.js +0 -143
  154. package/dist/__tests__/provider.test.js.map +0 -1
  155. package/dist/client.d.ts +0 -78
  156. package/dist/client.d.ts.map +0 -1
  157. package/dist/client.js +0 -219
  158. package/dist/client.js.map +0 -1
  159. package/dist/index.d.ts +0 -6
  160. package/dist/index.d.ts.map +0 -1
  161. package/dist/index.js +0 -5
  162. package/dist/index.js.map +0 -1
  163. package/dist/lib/core/error-handlers.d.ts +0 -14
  164. package/dist/lib/core/error-handlers.d.ts.map +0 -1
  165. package/dist/lib/core/error-handlers.js +0 -191
  166. package/dist/lib/core/error-handlers.js.map +0 -1
  167. package/dist/lib/core/event-queue.d.ts +0 -90
  168. package/dist/lib/core/event-queue.d.ts.map +0 -1
  169. package/dist/lib/core/event-queue.js +0 -286
  170. package/dist/lib/core/event-queue.js.map +0 -1
  171. package/dist/lib/core/runtime.d.ts +0 -7
  172. package/dist/lib/core/runtime.d.ts.map +0 -1
  173. package/dist/lib/core/runtime.js +0 -16
  174. package/dist/lib/core/runtime.js.map +0 -1
  175. package/dist/lib/core/session-manager.d.ts +0 -96
  176. package/dist/lib/core/session-manager.d.ts.map +0 -1
  177. package/dist/lib/core/session-manager.js +0 -431
  178. package/dist/lib/core/session-manager.js.map +0 -1
  179. package/dist/lib/persistence/storage.d.ts +0 -5
  180. package/dist/lib/persistence/storage.d.ts.map +0 -1
  181. package/dist/lib/persistence/storage.js +0 -67
  182. package/dist/lib/persistence/storage.js.map +0 -1
  183. package/dist/lib/session/rage-click.d.ts +0 -2
  184. package/dist/lib/session/rage-click.d.ts.map +0 -1
  185. package/dist/lib/session/rage-click.js +0 -51
  186. package/dist/lib/session/rage-click.js.map +0 -1
  187. package/dist/lib/session/replay.d.ts +0 -3
  188. package/dist/lib/session/replay.d.ts.map +0 -1
  189. package/dist/lib/session/replay.js +0 -106
  190. package/dist/lib/session/replay.js.map +0 -1
  191. package/dist/lib/session/session-summary.d.ts +0 -3
  192. package/dist/lib/session/session-summary.d.ts.map +0 -1
  193. package/dist/lib/session/session-summary.js +0 -79
  194. package/dist/lib/session/session-summary.js.map +0 -1
  195. package/dist/provider.d.ts +0 -76
  196. package/dist/provider.d.ts.map +0 -1
  197. package/dist/provider.js +0 -138
  198. package/dist/provider.js.map +0 -1
@@ -0,0 +1,200 @@
1
+ import { name, version } from "../../package.mjs";
2
+ import { Effect } from "effect";
3
+
4
+ //#region src/effect/layers/storage.layer.ts
5
+ function createLocalStorageAdapter(key) {
6
+ const capacity = 100;
7
+ function loadSync() {
8
+ try {
9
+ if (typeof localStorage === "undefined") return [];
10
+ const raw = localStorage.getItem(key);
11
+ if (!raw) return [];
12
+ const parsed = JSON.parse(raw);
13
+ return Array.isArray(parsed) ? parsed : [];
14
+ } catch {
15
+ return [];
16
+ }
17
+ }
18
+ function saveSync(list) {
19
+ try {
20
+ if (typeof localStorage === "undefined") return;
21
+ localStorage.setItem(key, JSON.stringify(list));
22
+ } catch {}
23
+ }
24
+ const load = () => Effect.sync(loadSync);
25
+ const save = (envelopes) => Effect.sync(() => saveSync(envelopes));
26
+ const append = (envelopes) => Effect.sync(() => {
27
+ const next = [...loadSync(), ...envelopes];
28
+ saveSync(next.length > capacity ? next.slice(next.length - capacity) : next);
29
+ });
30
+ const removeByIds = (ids) => Effect.sync(() => {
31
+ if (ids.length === 0) return;
32
+ const set = new Set(ids);
33
+ saveSync(loadSync().filter((e) => e.uuid ? !set.has(e.uuid) : true));
34
+ });
35
+ const dropOldest = (n) => Effect.sync(() => {
36
+ const current = loadSync();
37
+ saveSync(n >= current.length ? [] : current.slice(n));
38
+ });
39
+ const clear = () => Effect.sync(() => saveSync([]));
40
+ return {
41
+ load,
42
+ save,
43
+ append,
44
+ removeByIds,
45
+ dropOldest,
46
+ clear,
47
+ capacity: () => capacity
48
+ };
49
+ }
50
+ function createIndexedDBAdapter(dbName, storeName) {
51
+ const capacity = 1e3;
52
+ const DB_VERSION = 1;
53
+ const openDB = () => Effect.promise(() => new Promise((resolve, reject) => {
54
+ if (typeof indexedDB === "undefined") {
55
+ reject(/* @__PURE__ */ new Error("IndexedDB not available"));
56
+ return;
57
+ }
58
+ const request = indexedDB.open(dbName, DB_VERSION);
59
+ request.onerror = () => reject(request.error);
60
+ request.onsuccess = () => resolve(request.result);
61
+ request.onupgradeneeded = (event) => {
62
+ const db = event.target.result;
63
+ if (!db.objectStoreNames.contains(storeName)) db.createObjectStore(storeName, { keyPath: "uuid" }).createIndex("timestamp", "client_ts", { unique: false });
64
+ };
65
+ }));
66
+ const withStore = (mode, operation) => Effect.gen(function* () {
67
+ const db = yield* openDB();
68
+ try {
69
+ const request = operation(db.transaction([storeName], mode).objectStore(storeName));
70
+ return yield* Effect.promise(() => new Promise((resolve, reject) => {
71
+ request.onsuccess = () => resolve(request.result);
72
+ request.onerror = () => reject(request.error);
73
+ }));
74
+ } finally {
75
+ db.close();
76
+ }
77
+ });
78
+ return {
79
+ load: () => {
80
+ if (typeof indexedDB === "undefined") return Effect.succeed([]);
81
+ const eff = withStore("readonly", (store) => store.getAll()).pipe(Effect.map((results) => {
82
+ const envelopes = results;
83
+ envelopes.sort((a, b) => {
84
+ return (a.clientTs || 0) - (b.clientTs || 0);
85
+ });
86
+ return envelopes.length > capacity ? envelopes.slice(envelopes.length - capacity) : envelopes;
87
+ }));
88
+ return Effect.sandbox(eff).pipe(Effect.catchAll(() => Effect.succeed([])));
89
+ },
90
+ save: (envelopes) => Effect.gen(function* () {
91
+ const db = yield* openDB();
92
+ try {
93
+ const tx = db.transaction([storeName], "readwrite");
94
+ const store = tx.objectStore(storeName);
95
+ yield* Effect.promise(() => new Promise((resolve, reject) => {
96
+ const clearReq = store.clear();
97
+ clearReq.onsuccess = () => resolve();
98
+ clearReq.onerror = () => reject(clearReq.error);
99
+ }));
100
+ for (const envelope of envelopes) store.add(envelope);
101
+ yield* Effect.promise(() => new Promise((resolve, reject) => {
102
+ tx.oncomplete = () => resolve();
103
+ tx.onerror = () => reject(tx.error);
104
+ }));
105
+ } finally {
106
+ db.close();
107
+ }
108
+ }).pipe(Effect.catchAll(() => Effect.void)),
109
+ append: (envelopes) => Effect.gen(function* () {
110
+ const next = [...yield* withStore("readonly", (store) => store.getAll()).pipe(Effect.catchAll(() => Effect.succeed([]))), ...envelopes];
111
+ const trimmed = next.length > capacity ? next.slice(next.length - capacity) : next;
112
+ yield* Effect.gen(function* () {
113
+ const db = yield* openDB();
114
+ try {
115
+ const tx = db.transaction([storeName], "readwrite");
116
+ const store = tx.objectStore(storeName);
117
+ store.clear();
118
+ for (const env of trimmed) store.add(env);
119
+ yield* Effect.promise(() => new Promise((resolve, reject) => {
120
+ tx.oncomplete = () => resolve();
121
+ tx.onerror = () => reject(tx.error);
122
+ }));
123
+ } finally {
124
+ db.close();
125
+ }
126
+ }).pipe(Effect.catchAll(() => Effect.void));
127
+ }),
128
+ removeByIds: (ids) => Effect.gen(function* () {
129
+ if (ids.length === 0) return;
130
+ const db = yield* openDB();
131
+ try {
132
+ const tx = db.transaction([storeName], "readwrite");
133
+ const store = tx.objectStore(storeName);
134
+ for (const id of ids) store.delete(id);
135
+ yield* Effect.promise(() => new Promise((resolve, reject) => {
136
+ tx.oncomplete = () => resolve();
137
+ tx.onerror = () => reject(tx.error);
138
+ }));
139
+ } finally {
140
+ db.close();
141
+ }
142
+ }).pipe(Effect.catchAll(() => Effect.void)),
143
+ dropOldest: (n) => Effect.gen(function* () {
144
+ const sorted = (yield* withStore("readonly", (store) => store.getAll())).sort((a, b) => {
145
+ return (a.clientTs || 0) - (b.clientTs || 0);
146
+ });
147
+ const keep = n >= sorted.length ? [] : sorted.slice(n);
148
+ const db = yield* openDB();
149
+ try {
150
+ const tx = db.transaction([storeName], "readwrite");
151
+ const store = tx.objectStore(storeName);
152
+ store.clear();
153
+ for (const env of keep) store.add(env);
154
+ yield* Effect.promise(() => new Promise((resolve, reject) => {
155
+ tx.oncomplete = () => resolve();
156
+ tx.onerror = () => reject(tx.error);
157
+ }));
158
+ } finally {
159
+ db.close();
160
+ }
161
+ }).pipe(Effect.catchAll(() => Effect.void)),
162
+ clear: () => withStore("readwrite", (store) => store.clear()).pipe(Effect.as(void 0), Effect.catchAll(() => Effect.void)),
163
+ capacity: () => capacity
164
+ };
165
+ }
166
+ function createMemoryStorageAdapter() {
167
+ const capacity = 500;
168
+ let buffer = [];
169
+ return {
170
+ load: () => Effect.succeed(buffer),
171
+ save: (envelopes) => Effect.sync(() => {
172
+ buffer = envelopes;
173
+ }),
174
+ append: (envelopes) => Effect.sync(() => {
175
+ const next = [...buffer, ...envelopes];
176
+ buffer = next.length > capacity ? next.slice(next.length - capacity) : next;
177
+ }),
178
+ removeByIds: (ids) => Effect.sync(() => {
179
+ if (ids.length === 0) return;
180
+ const set = new Set(ids);
181
+ buffer = buffer.filter((e) => e.uuid ? !set.has(e.uuid) : true);
182
+ }),
183
+ dropOldest: (n) => Effect.sync(() => {
184
+ buffer = n >= buffer.length ? [] : buffer.slice(n);
185
+ }),
186
+ clear: () => Effect.sync(() => {
187
+ buffer = [];
188
+ }),
189
+ capacity: () => capacity
190
+ };
191
+ }
192
+ function createStorageAdapter() {
193
+ const namespace = `${name}:${version}`;
194
+ if (typeof indexedDB !== "undefined") return createIndexedDBAdapter(namespace, "envelopes");
195
+ if (typeof localStorage !== "undefined") return createLocalStorageAdapter(`${namespace}:envelopes`);
196
+ return createMemoryStorageAdapter();
197
+ }
198
+
199
+ //#endregion
200
+ export { createIndexedDBAdapter, createLocalStorageAdapter, createMemoryStorageAdapter, createStorageAdapter };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.layer.mjs","names":["buffer: Envelope[]","packageJson.name","packageJson.version"],"sources":["../../../src/effect/layers/storage.layer.ts"],"sourcesContent":["import type { Envelope } from \"@interfere/types/sdk/envelope\";\n\nimport { Effect } from \"effect\";\n\n// Import SDK version for storage namespacing\nimport packageJson from \"../../../package.json\" with { type: \"json\" };\n\nexport interface StorageAdapter {\n load: () => Effect.Effect<Envelope[]>;\n save: (envelopes: Envelope[]) => Effect.Effect<void>;\n append: (envelopes: Envelope[]) => Effect.Effect<void>;\n removeByIds: (ids: string[]) => Effect.Effect<void>;\n dropOldest: (n: number) => Effect.Effect<void>;\n clear: () => Effect.Effect<void>;\n capacity: () => number;\n}\n\nexport function createLocalStorageAdapter(key: string): StorageAdapter {\n const capacity = 100;\n\n function loadSync(): Envelope[] {\n try {\n if (typeof localStorage === \"undefined\") {\n return [];\n }\n const raw = localStorage.getItem(key);\n if (!raw) {\n return [];\n }\n const parsed = JSON.parse(raw);\n return Array.isArray(parsed) ? (parsed as Envelope[]) : [];\n } catch {\n return [];\n }\n }\n\n function saveSync(list: Envelope[]): void {\n try {\n if (typeof localStorage === \"undefined\") {\n return;\n }\n localStorage.setItem(key, JSON.stringify(list));\n } catch {\n // best-effort only\n }\n }\n\n const load = () => Effect.sync(loadSync);\n\n const save = (envelopes: Envelope[]) =>\n Effect.sync(() => saveSync(envelopes));\n\n const append = (envelopes: Envelope[]) =>\n Effect.sync(() => {\n const current = loadSync();\n const next = [...current, ...envelopes];\n const trimmed =\n next.length > capacity ? next.slice(next.length - capacity) : next;\n saveSync(trimmed);\n });\n\n const removeByIds = (ids: string[]) =>\n Effect.sync(() => {\n if (ids.length === 0) {\n return;\n }\n const set = new Set(ids);\n const current = loadSync();\n const filtered = current.filter((e) =>\n e.uuid ? !set.has(e.uuid) : true\n );\n saveSync(filtered);\n });\n\n const dropOldest = (n: number) =>\n Effect.sync(() => {\n const current = loadSync();\n const trimmed = n >= current.length ? [] : current.slice(n);\n saveSync(trimmed);\n });\n\n const clear = () => Effect.sync(() => saveSync([]));\n\n return {\n load,\n save,\n append,\n removeByIds,\n dropOldest,\n clear,\n capacity: () => capacity,\n };\n}\n\n// IndexedDB adapter for larger payloads\nexport function createIndexedDBAdapter(\n dbName: string,\n storeName: string\n): StorageAdapter {\n const capacity = 1000;\n const DB_VERSION = 1;\n\n const openDB = () =>\n Effect.promise(\n () =>\n new Promise<IDBDatabase>((resolve, reject) => {\n if (typeof indexedDB === \"undefined\") {\n reject(new Error(\"IndexedDB not available\"));\n return;\n }\n\n const request = indexedDB.open(dbName, DB_VERSION);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result);\n\n request.onupgradeneeded = (event) => {\n const db = (event.target as IDBOpenDBRequest).result;\n if (!db.objectStoreNames.contains(storeName)) {\n const store = db.createObjectStore(storeName, {\n keyPath: \"uuid\",\n });\n store.createIndex(\"timestamp\", \"client_ts\", { unique: false });\n }\n };\n })\n );\n\n const withStore = <T>(\n mode: IDBTransactionMode,\n operation: (store: IDBObjectStore) => IDBRequest<T>\n ) =>\n Effect.gen(function* () {\n const db = yield* openDB();\n try {\n const tx = db.transaction([storeName], mode);\n const store = tx.objectStore(storeName);\n const request = operation(store);\n\n const result = yield* Effect.promise(\n () =>\n new Promise<T>((resolve, reject) => {\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n })\n );\n\n return result;\n } finally {\n db.close();\n }\n });\n\n return {\n load: () => {\n if (typeof indexedDB === \"undefined\") {\n return Effect.succeed([] as Envelope[]);\n }\n\n const eff = withStore(\"readonly\", (store) => store.getAll()).pipe(\n Effect.map((results) => {\n const envelopes = results as Envelope[];\n // Sort by timestamp and enforce capacity\n envelopes.sort((a, b) => {\n const aTime = a.clientTs || 0;\n const bTime = b.clientTs || 0;\n\n return aTime - bTime;\n });\n\n return envelopes.length > capacity\n ? envelopes.slice(envelopes.length - capacity)\n : envelopes;\n })\n );\n return Effect.sandbox(eff).pipe(\n Effect.catchAll(() => Effect.succeed([] as Envelope[]))\n );\n },\n\n save: (envelopes) =>\n Effect.gen(function* () {\n const db = yield* openDB();\n try {\n const tx = db.transaction([storeName], \"readwrite\");\n const store = tx.objectStore(storeName);\n\n // Clear existing\n yield* Effect.promise(\n () =>\n new Promise<void>((resolve, reject) => {\n const clearReq = store.clear();\n clearReq.onsuccess = () => resolve();\n clearReq.onerror = () => reject(clearReq.error);\n })\n );\n\n for (const envelope of envelopes) {\n store.add(envelope);\n }\n\n yield* Effect.promise(\n () =>\n new Promise<void>((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n })\n );\n } finally {\n db.close();\n }\n }).pipe(Effect.catchAll(() => Effect.void)),\n\n append: (envelopes) =>\n Effect.gen(function* () {\n const current = (yield* withStore(\"readonly\", (store) =>\n store.getAll()\n ).pipe(\n Effect.catchAll(() => Effect.succeed([] as Envelope[]))\n )) as Envelope[];\n const next = [...current, ...envelopes];\n const trimmed =\n next.length > capacity ? next.slice(next.length - capacity) : next;\n // Reuse save logic to write trimmed set\n yield* Effect.gen(function* () {\n const db = yield* openDB();\n try {\n const tx = db.transaction([storeName], \"readwrite\");\n const store = tx.objectStore(storeName);\n store.clear();\n for (const env of trimmed) {\n store.add(env);\n }\n yield* Effect.promise(\n () =>\n new Promise<void>((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n })\n );\n } finally {\n db.close();\n }\n }).pipe(Effect.catchAll(() => Effect.void));\n }),\n\n removeByIds: (ids) =>\n Effect.gen(function* () {\n if (ids.length === 0) {\n return;\n }\n const db = yield* openDB();\n try {\n const tx = db.transaction([storeName], \"readwrite\");\n const store = tx.objectStore(storeName);\n for (const id of ids) {\n store.delete(id);\n }\n yield* Effect.promise(\n () =>\n new Promise<void>((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n })\n );\n } finally {\n db.close();\n }\n }).pipe(Effect.catchAll(() => Effect.void)),\n\n dropOldest: (n) =>\n Effect.gen(function* () {\n const all = yield* withStore(\"readonly\", (store) => store.getAll());\n const sorted = (all as Envelope[]).sort((a, b) => {\n const aTime = a.clientTs || 0;\n const bTime = b.clientTs || 0;\n\n return aTime - bTime;\n });\n const keep = n >= sorted.length ? [] : sorted.slice(n);\n\n const db = yield* openDB();\n try {\n const tx = db.transaction([storeName], \"readwrite\");\n const store = tx.objectStore(storeName);\n store.clear();\n for (const env of keep) {\n store.add(env);\n }\n yield* Effect.promise(\n () =>\n new Promise<void>((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n })\n );\n } finally {\n db.close();\n }\n }).pipe(Effect.catchAll(() => Effect.void)),\n\n clear: () =>\n withStore(\"readwrite\", (store) => store.clear()).pipe(\n Effect.as(undefined),\n Effect.catchAll(() => Effect.void)\n ),\n capacity: () => capacity,\n };\n}\n\n// In-memory adapter as last-resort fallback\nexport function createMemoryStorageAdapter(): StorageAdapter {\n const capacity = 500;\n\n let buffer: Envelope[] = [];\n\n return {\n load: () => Effect.succeed(buffer),\n save: (envelopes) =>\n Effect.sync(() => {\n buffer = envelopes;\n }),\n append: (envelopes) =>\n Effect.sync(() => {\n const next = [...buffer, ...envelopes];\n buffer =\n next.length > capacity ? next.slice(next.length - capacity) : next;\n }),\n removeByIds: (ids) =>\n Effect.sync(() => {\n if (ids.length === 0) {\n return;\n }\n const set = new Set(ids);\n buffer = buffer.filter((e) => (e.uuid ? !set.has(e.uuid) : true));\n }),\n dropOldest: (n) =>\n Effect.sync(() => {\n buffer = n >= buffer.length ? [] : buffer.slice(n);\n }),\n clear: () =>\n Effect.sync(() => {\n buffer = [];\n }),\n capacity: () => capacity,\n };\n}\n\n// Factory to choose appropriate storage\nexport function createStorageAdapter(): StorageAdapter {\n const sdkName = packageJson.name;\n const sdkVersion = packageJson.version;\n\n const namespace = `${sdkName}:${sdkVersion}`;\n\n // Prefer IndexedDB for all events when available\n if (typeof indexedDB !== \"undefined\") {\n return createIndexedDBAdapter(namespace, \"envelopes\");\n }\n\n if (typeof localStorage !== \"undefined\") {\n return createLocalStorageAdapter(`${namespace}:envelopes`);\n }\n\n // Final fallback: in-memory (lost on refresh)\n return createMemoryStorageAdapter();\n}\n"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { Effect } from "effect";
2
+
3
+ //#region src/effect/layers/tracer.layer.d.ts
4
+ interface SpanOptions {
5
+ attributes?: Record<string, unknown>;
6
+ }
7
+ declare function withSpan<A, E = never, R = never>(name: string, eff: Effect.Effect<A, E, R>, options?: SpanOptions): Effect.Effect<A, E, R>;
8
+ //#endregion
9
+ export { SpanOptions, withSpan };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracer.layer.d.mts","names":[],"sources":["../../../src/effect/layers/tracer.layer.ts"],"sourcesContent":[],"mappings":";;;UAEiB,WAAA;eACF;AADf;AAIgB,iBAAA,QAAQ,CAAA,CAAA,EAAA,IAAA,KAAA,EAAA,IAAA,KAAA,CAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAAA,EAEjB,MAAA,CAAO,MAFU,CAEH,CAFG,EAEA,CAFA,EAEG,CAFH,CAAA,EAAA,OAAA,CAAA,EAGZ,WAHY,CAAA,EAIrB,MAAA,CAAO,MAJc,CAIP,CAJO,EAIJ,CAJI,EAID,CAJC,CAAA"}
@@ -0,0 +1,11 @@
1
+ import { Effect } from "effect";
2
+
3
+ //#region src/effect/layers/tracer.layer.ts
4
+ function withSpan(name, eff, options) {
5
+ const annotated = options?.attributes ? eff.pipe(Effect.annotateLogs(options.attributes)) : eff;
6
+ const spanOptions = options?.attributes ? { attributes: options.attributes } : void 0;
7
+ return Effect.withSpan(name, spanOptions)(annotated);
8
+ }
9
+
10
+ //#endregion
11
+ export { withSpan };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracer.layer.mjs","names":[],"sources":["../../../src/effect/layers/tracer.layer.ts"],"sourcesContent":["import { Effect } from \"effect\";\n\nexport interface SpanOptions {\n attributes?: Record<string, unknown>;\n}\n\nexport function withSpan<A, E = never, R = never>(\n name: string,\n eff: Effect.Effect<A, E, R>,\n options?: SpanOptions\n): Effect.Effect<A, E, R> {\n const annotated = options?.attributes\n ? eff.pipe(Effect.annotateLogs(options.attributes))\n : eff;\n\n const spanOptions = options?.attributes\n ? { attributes: options.attributes }\n : undefined;\n\n return Effect.withSpan(name, spanOptions)(annotated);\n}\n"],"mappings":";;;AAMA,SAAgB,SACd,MACA,KACA,SACwB;CACxB,MAAM,YAAY,SAAS,aACvB,IAAI,KAAK,OAAO,aAAa,QAAQ,WAAW,CAAC,GACjD;CAEJ,MAAM,cAAc,SAAS,aACzB,EAAE,YAAY,QAAQ,YAAY,GAClC;AAEJ,QAAO,OAAO,SAAS,MAAM,YAAY,CAAC,UAAU"}
@@ -0,0 +1,22 @@
1
+ import { SessionServiceTag } from "./layers/session.layer.mjs";
2
+ import { ConfigTag } from "./tags.mjs";
3
+ import { ContextServiceTag } from "./layers/context.layer.mjs";
4
+ import { HttpServiceTag } from "./layers/http.layer.mjs";
5
+ import { QueueServiceTag } from "./layers/queue.layer.mjs";
6
+ import { Effect, Layer, Runtime, Scope } from "effect";
7
+ import { Config } from "@interfere/types/sdk/config";
8
+ import { Layer as Layer$1 } from "effect/Layer";
9
+
10
+ //#region src/effect/runtime-services.d.ts
11
+ declare const createSDKLayer: (config: Config) => Layer.Layer<QueueServiceTag | SessionServiceTag | ConfigTag | ContextServiceTag | HttpServiceTag, never, never>;
12
+ type LayerSuccess<T> = T extends Layer$1<infer ROut, unknown, unknown> ? ROut : never;
13
+ type SDKEnv = LayerSuccess<ReturnType<typeof createSDKLayer>>;
14
+ declare function setSDKRuntime(scope: Scope.CloseableScope, runtime: Runtime.Runtime<SDKEnv>): void;
15
+ declare function initRuntimeServices(input: unknown): void;
16
+ declare function runWithSDK<A, E>(effect: Effect.Effect<A, E, SDKEnv>): Promise<A>;
17
+ declare function forkWithSDK<E, A>(effect: Effect.Effect<A, E, SDKEnv>): void;
18
+ declare function isSDKInitialized(): boolean;
19
+ declare function closeSDK(): Promise<void>;
20
+ declare function flushQueue(timeoutMs: number): Promise<void>;
21
+ //#endregion
22
+ export { closeSDK, flushQueue, forkWithSDK, initRuntimeServices, isSDKInitialized, runWithSDK, setSDKRuntime };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-services.d.mts","names":[],"sources":["../../src/effect/runtime-services.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;cAiBM,yBAA0B,WAAM,KAAA,CAAA,MAAA,kBAAA,iBAAA,GAAA,YAAA,iBAAA,GAAA;KAyBjC,kBACH,UAAU;KAEP,MAAA,GAAS,aAAa,kBAAkB;iBAM7B,aAAA,QACP,KAAA,CAAM,yBACJ,OAAA,CAAQ,QAAQ;iBAMX,mBAAA;AA1CV,iBA6FU,UAtEf,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,MAAA,EAuES,MAAA,CAAO,MAvEhB,CAuEuB,CAvEvB,EAuE0B,CAvE1B,EAuE6B,MAvE7B,CAAA,CAAA,EAwEE,OAxEF,CAwEU,CAxEV,CAAA;AAvB+B,iBAuGhB,WAvGgB,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,MAAA,EAuGU,MAAA,CAAO,MAvGjB,CAuGwB,CAvGxB,EAuG2B,CAvG3B,EAuG8B,MAvG9B,CAAA,CAAA,EAAA,IAAA;AAAM,iBA2HtB,gBAAA,CAAA,CA3HsB,EAAA,OAAA;AAAA,iBA+HhB,QAAA,CAAA,CA/HgB,EA+HJ,OA/HI,CAAA,IAAA,CAAA;AAAA,iBA0IhB,UAAA,CA1IgB,SAAA,EAAA,MAAA,CAAA,EA0Ie,OA1If,CAAA,IAAA,CAAA"}
@@ -0,0 +1,76 @@
1
+ import { getRuntime } from "../core/runtime/config.mjs";
2
+ import { SessionServiceLive } from "./layers/session.layer.mjs";
3
+ import { ConfigTag } from "./tags.mjs";
4
+ import { ContextServiceLive } from "./layers/context.layer.mjs";
5
+ import { HttpServiceLive } from "./layers/http.layer.mjs";
6
+ import { QueueServiceLive, QueueServiceTag } from "./layers/queue.layer.mjs";
7
+ import { Effect, Exit, Layer, Runtime, Scope } from "effect";
8
+ import { configSchema } from "@interfere/types/sdk/config";
9
+ import { InterfereLogger, withInterfereLogger } from "@interfere/effect-utils/observability";
10
+
11
+ //#region src/effect/runtime-services.ts
12
+ const createSDKLayer = (config) => {
13
+ const configWithRuntime = {
14
+ ...config,
15
+ runtime: getRuntime()
16
+ };
17
+ const configLayer = Layer.succeed(ConfigTag, config);
18
+ const contextLayer = ContextServiceLive;
19
+ const httpLayer = HttpServiceLive(configWithRuntime);
20
+ const sessionLayer = SessionServiceLive;
21
+ const queueLayer = QueueServiceLive.pipe(Layer.provide(configLayer), Layer.provide(httpLayer));
22
+ return Layer.mergeAll(configLayer, contextLayer, httpLayer, sessionLayer, queueLayer);
23
+ };
24
+ let sdkRuntime = null;
25
+ let sdkScope = null;
26
+ const shouldEmitConsoleLogs = () => !InterfereLogger.isTestEnvironment();
27
+ function setSDKRuntime(scope, runtime) {
28
+ sdkScope = scope;
29
+ sdkRuntime = runtime;
30
+ }
31
+ function initRuntimeServices(input) {
32
+ if (sdkRuntime) return;
33
+ const config = configSchema.parse(input);
34
+ if (shouldEmitConsoleLogs()) console.debug("[Interfere SDK] Initializing with config:", config);
35
+ (async () => {
36
+ const scope = await Effect.runPromise(Scope.make());
37
+ const runtime = await Effect.runPromise(Layer.toRuntime(createSDKLayer(config)).pipe(Effect.provideService(Scope.Scope, scope)));
38
+ setSDKRuntime(scope, runtime);
39
+ if (shouldEmitConsoleLogs()) console.debug("[Interfere SDK] Runtime initialized successfully");
40
+ Runtime.runPromise(runtime)(withInterfereLogger("react", Effect.gen(function* () {
41
+ yield* (yield* QueueServiceTag).startBatchProcessor().pipe(Effect.provideService(Scope.Scope, scope));
42
+ }))).catch((error) => {
43
+ Runtime.runPromise(runtime)(withInterfereLogger("react", Effect.logError("Failed to start batch processor", { error: String(error) })));
44
+ });
45
+ })();
46
+ }
47
+ function runWithSDK(effect) {
48
+ if (!sdkRuntime) throw new Error("SDK not initialized. Call initRuntimeServices first.");
49
+ return Runtime.runPromise(sdkRuntime)(withInterfereLogger("react", effect));
50
+ }
51
+ function forkWithSDK(effect) {
52
+ if (!sdkRuntime) {
53
+ if (shouldEmitConsoleLogs()) console.warn("[Interfere SDK] Attempted to fork effect before SDK initialized");
54
+ return;
55
+ }
56
+ Runtime.runFork(sdkRuntime)(withInterfereLogger("react", effect).pipe(Effect.catchAllCause((cause) => Effect.logError("Forked effect failed", { cause: String(cause) }))));
57
+ }
58
+ function isSDKInitialized() {
59
+ return sdkRuntime !== null;
60
+ }
61
+ async function closeSDK() {
62
+ if (sdkScope) {
63
+ await Effect.runPromise(withInterfereLogger("react", Scope.close(sdkScope, Exit.void)));
64
+ sdkScope = null;
65
+ sdkRuntime = null;
66
+ }
67
+ }
68
+ async function flushQueue(timeoutMs) {
69
+ if (!sdkRuntime) return;
70
+ await Runtime.runPromise(sdkRuntime)(Effect.gen(function* () {
71
+ yield* (yield* QueueServiceTag).boundedFlush(timeoutMs);
72
+ }));
73
+ }
74
+
75
+ //#endregion
76
+ export { closeSDK, flushQueue, forkWithSDK, initRuntimeServices, isSDKInitialized, runWithSDK, setSDKRuntime };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-services.mjs","names":["sdkRuntime: Runtime.Runtime<SDKEnv> | null","sdkScope: Scope.CloseableScope | null"],"sources":["../../src/effect/runtime-services.ts"],"sourcesContent":["import {\n InterfereLogger,\n withInterfereLogger,\n} from \"@interfere/effect-utils/observability\";\nimport type { Config } from \"@interfere/types/sdk/config\";\nimport { configSchema } from \"@interfere/types/sdk/config\";\n\nimport { Effect, Exit, Layer, Runtime, Scope } from \"effect\";\nimport type { Layer as LayerType } from \"effect/Layer\";\n\nimport { getRuntime } from \"../core/runtime/config.js\";\nimport { ContextServiceLive } from \"./layers/context.layer.js\";\nimport { HttpServiceLive } from \"./layers/http.layer.js\";\nimport { QueueServiceLive, QueueServiceTag } from \"./layers/queue.layer.js\";\nimport { SessionServiceLive } from \"./layers/session.layer.js\";\nimport { ConfigTag } from \"./tags.js\";\n\nconst createSDKLayer = (config: Config) => {\n const configWithRuntime = {\n ...config,\n runtime: getRuntime(),\n };\n\n const configLayer = Layer.succeed(ConfigTag, config);\n const contextLayer = ContextServiceLive;\n const httpLayer = HttpServiceLive(configWithRuntime);\n const sessionLayer = SessionServiceLive;\n\n const queueLayer = QueueServiceLive.pipe(\n Layer.provide(configLayer),\n Layer.provide(httpLayer)\n );\n\n return Layer.mergeAll(\n configLayer,\n contextLayer,\n httpLayer,\n sessionLayer,\n queueLayer\n );\n};\n\ntype LayerSuccess<T> =\n T extends LayerType<infer ROut, unknown, unknown> ? ROut : never;\n\ntype SDKEnv = LayerSuccess<ReturnType<typeof createSDKLayer>>;\n\nlet sdkRuntime: Runtime.Runtime<SDKEnv> | null = null;\nlet sdkScope: Scope.CloseableScope | null = null;\nconst shouldEmitConsoleLogs = () => !InterfereLogger.isTestEnvironment();\n\nexport function setSDKRuntime(\n scope: Scope.CloseableScope,\n runtime: Runtime.Runtime<SDKEnv>\n): void {\n sdkScope = scope;\n sdkRuntime = runtime;\n}\n\nexport function initRuntimeServices(input: unknown): void {\n if (sdkRuntime) {\n return;\n }\n\n const config = configSchema.parse(input);\n if (shouldEmitConsoleLogs()) {\n console.debug(\"[Interfere SDK] Initializing with config:\", config);\n }\n\n // Build the runtime asynchronously to avoid synchronous fiber resolution\n // biome-ignore lint/complexity/noVoid: fire-and-forget initialization\n void (async () => {\n const scope = await Effect.runPromise(Scope.make());\n\n const runtime = await Effect.runPromise(\n Layer.toRuntime(createSDKLayer(config)).pipe(\n Effect.provideService(Scope.Scope, scope)\n )\n );\n\n setSDKRuntime(scope, runtime);\n\n if (shouldEmitConsoleLogs()) {\n console.debug(\"[Interfere SDK] Runtime initialized successfully\");\n }\n\n Runtime.runPromise(runtime)(\n withInterfereLogger(\n \"react\",\n Effect.gen(function* () {\n const queue = yield* QueueServiceTag;\n\n yield* queue\n .startBatchProcessor()\n .pipe(Effect.provideService(Scope.Scope, scope));\n })\n )\n ).catch((error) => {\n Runtime.runPromise(runtime)(\n withInterfereLogger(\n \"react\",\n Effect.logError(\"Failed to start batch processor\", {\n error: String(error),\n })\n )\n );\n });\n })();\n}\n\nexport function runWithSDK<A, E>(\n effect: Effect.Effect<A, E, SDKEnv>\n): Promise<A> {\n if (!sdkRuntime) {\n throw new Error(\"SDK not initialized. Call initRuntimeServices first.\");\n }\n\n return Runtime.runPromise(sdkRuntime)(withInterfereLogger(\"react\", effect));\n}\n\nexport function forkWithSDK<E, A>(effect: Effect.Effect<A, E, SDKEnv>): void {\n if (!sdkRuntime) {\n if (shouldEmitConsoleLogs()) {\n console.warn(\n \"[Interfere SDK] Attempted to fork effect before SDK initialized\"\n );\n }\n\n return;\n }\n\n Runtime.runFork(sdkRuntime)(\n withInterfereLogger(\"react\", effect).pipe(\n Effect.catchAllCause((cause) =>\n Effect.logError(\"Forked effect failed\", { cause: String(cause) })\n )\n )\n );\n}\n\nexport function isSDKInitialized(): boolean {\n return sdkRuntime !== null;\n}\n\nexport async function closeSDK(): Promise<void> {\n if (sdkScope) {\n await Effect.runPromise(\n withInterfereLogger(\"react\", Scope.close(sdkScope, Exit.void))\n );\n\n sdkScope = null;\n sdkRuntime = null;\n }\n}\n\nexport async function flushQueue(timeoutMs: number): Promise<void> {\n if (!sdkRuntime) {\n return;\n }\n await Runtime.runPromise(sdkRuntime)(\n Effect.gen(function* () {\n const queue = yield* QueueServiceTag;\n yield* queue.boundedFlush(timeoutMs);\n })\n );\n}\n"],"mappings":";;;;;;;;;;;AAiBA,MAAM,kBAAkB,WAAmB;CACzC,MAAM,oBAAoB;EACxB,GAAG;EACH,SAAS,YAAY;EACtB;CAED,MAAM,cAAc,MAAM,QAAQ,WAAW,OAAO;CACpD,MAAM,eAAe;CACrB,MAAM,YAAY,gBAAgB,kBAAkB;CACpD,MAAM,eAAe;CAErB,MAAM,aAAa,iBAAiB,KAClC,MAAM,QAAQ,YAAY,EAC1B,MAAM,QAAQ,UAAU,CACzB;AAED,QAAO,MAAM,SACX,aACA,cACA,WACA,cACA,WACD;;AAQH,IAAIA,aAA6C;AACjD,IAAIC,WAAwC;AAC5C,MAAM,8BAA8B,CAAC,gBAAgB,mBAAmB;AAExE,SAAgB,cACd,OACA,SACM;AACN,YAAW;AACX,cAAa;;AAGf,SAAgB,oBAAoB,OAAsB;AACxD,KAAI,WACF;CAGF,MAAM,SAAS,aAAa,MAAM,MAAM;AACxC,KAAI,uBAAuB,CACzB,SAAQ,MAAM,6CAA6C,OAAO;AAKpE,EAAM,YAAY;EAChB,MAAM,QAAQ,MAAM,OAAO,WAAW,MAAM,MAAM,CAAC;EAEnD,MAAM,UAAU,MAAM,OAAO,WAC3B,MAAM,UAAU,eAAe,OAAO,CAAC,CAAC,KACtC,OAAO,eAAe,MAAM,OAAO,MAAM,CAC1C,CACF;AAED,gBAAc,OAAO,QAAQ;AAE7B,MAAI,uBAAuB,CACzB,SAAQ,MAAM,mDAAmD;AAGnE,UAAQ,WAAW,QAAQ,CACzB,oBACE,SACA,OAAO,IAAI,aAAa;AAGtB,WAFc,OAAO,iBAGlB,qBAAqB,CACrB,KAAK,OAAO,eAAe,MAAM,OAAO,MAAM,CAAC;IAClD,CACH,CACF,CAAC,OAAO,UAAU;AACjB,WAAQ,WAAW,QAAQ,CACzB,oBACE,SACA,OAAO,SAAS,mCAAmC,EACjD,OAAO,OAAO,MAAM,EACrB,CAAC,CACH,CACF;IACD;KACA;;AAGN,SAAgB,WACd,QACY;AACZ,KAAI,CAAC,WACH,OAAM,IAAI,MAAM,uDAAuD;AAGzE,QAAO,QAAQ,WAAW,WAAW,CAAC,oBAAoB,SAAS,OAAO,CAAC;;AAG7E,SAAgB,YAAkB,QAA2C;AAC3E,KAAI,CAAC,YAAY;AACf,MAAI,uBAAuB,CACzB,SAAQ,KACN,kEACD;AAGH;;AAGF,SAAQ,QAAQ,WAAW,CACzB,oBAAoB,SAAS,OAAO,CAAC,KACnC,OAAO,eAAe,UACpB,OAAO,SAAS,wBAAwB,EAAE,OAAO,OAAO,MAAM,EAAE,CAAC,CAClE,CACF,CACF;;AAGH,SAAgB,mBAA4B;AAC1C,QAAO,eAAe;;AAGxB,eAAsB,WAA0B;AAC9C,KAAI,UAAU;AACZ,QAAM,OAAO,WACX,oBAAoB,SAAS,MAAM,MAAM,UAAU,KAAK,KAAK,CAAC,CAC/D;AAED,aAAW;AACX,eAAa;;;AAIjB,eAAsB,WAAW,WAAkC;AACjE,KAAI,CAAC,WACH;AAEF,OAAM,QAAQ,WAAW,WAAW,CAClC,OAAO,IAAI,aAAa;AAEtB,UADc,OAAO,iBACR,aAAa,UAAU;GACpC,CACH"}
@@ -0,0 +1,50 @@
1
+ import { Context } from "effect";
2
+
3
+ //#region src/effect/tags.d.ts
4
+ declare const ConfigTag_base: Context.TagClass<ConfigTag, "@interfere/react/Config", ({
5
+ features: {
6
+ errors?: boolean | undefined;
7
+ replay?: boolean | undefined;
8
+ rageClick?: boolean | undefined;
9
+ aiSummary?: boolean | undefined;
10
+ pageEvents?: boolean | undefined;
11
+ serverTracing?: boolean | undefined;
12
+ };
13
+ metadata: {
14
+ buildId: string | null;
15
+ releaseId: string | null;
16
+ environment: "development" | "preview" | "production" | null;
17
+ runtime: "edge" | "browser" | "node" | null;
18
+ };
19
+ batch: {
20
+ size: number;
21
+ ms: number;
22
+ };
23
+ } & {
24
+ proxyUrl: string;
25
+ }) | ({
26
+ features: {
27
+ errors?: boolean | undefined;
28
+ replay?: boolean | undefined;
29
+ rageClick?: boolean | undefined;
30
+ aiSummary?: boolean | undefined;
31
+ pageEvents?: boolean | undefined;
32
+ serverTracing?: boolean | undefined;
33
+ };
34
+ metadata: {
35
+ buildId: string | null;
36
+ releaseId: string | null;
37
+ environment: "development" | "preview" | "production" | null;
38
+ runtime: "edge" | "browser" | "node" | null;
39
+ };
40
+ batch: {
41
+ size: number;
42
+ ms: number;
43
+ };
44
+ } & {
45
+ ingestUrl: string;
46
+ surfaceToken: string;
47
+ })>;
48
+ declare class ConfigTag extends ConfigTag_base {}
49
+ //#endregion
50
+ export { ConfigTag };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tags.d.mts","names":[],"sources":["../../src/effect/tags.ts"],"sourcesContent":[],"mappings":";;;cAEiC,gBAAA,OAAA,CAAA,SAAA;;IAAA,MAAA,CAAA,EAAA,OAAA,GAAA,SAAA;IAEpB,MAAA,CAAA,EAAU,OAAA,GAAA,SAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAlB,SAAA,SAAkB,cAAA"}
@@ -0,0 +1,7 @@
1
+ import { Context } from "effect";
2
+
3
+ //#region src/effect/tags.ts
4
+ var ConfigTag = class extends Context.Tag("@interfere/react/Config")() {};
5
+
6
+ //#endregion
7
+ export { ConfigTag };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tags.mjs","names":[],"sources":["../../src/effect/tags.ts"],"sourcesContent":["import type { Config } from \"@interfere/types/sdk/config\";\n\nimport { Context } from \"effect\";\n\nexport class ConfigTag extends Context.Tag(\"@interfere/react/Config\")<\n ConfigTag,\n Config\n>() {}\n"],"mappings":";;;AAIA,IAAa,YAAb,cAA+B,QAAQ,IAAI,0BAA0B,EAGlE,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { Plugin, PluginApiMap } from "../core/schemas.mjs";
2
+ import { Config } from "@interfere/types/sdk/config";
3
+
4
+ //#region src/hooks/use-runtime-and-plugins.d.ts
5
+ declare function useRuntimeAndPlugins(config: Config, plugins?: Plugin[]): Partial<PluginApiMap>;
6
+ //#endregion
7
+ export { useRuntimeAndPlugins };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-runtime-and-plugins.d.mts","names":[],"sources":["../../src/hooks/use-runtime-and-plugins.ts"],"sourcesContent":[],"mappings":";;;;iBAqGgB,oBAAA,SACN,kBACE,WACT,QAAQ"}
@@ -0,0 +1,153 @@
1
+ "use client";
2
+
3
+ import { getRuntime, initConfig } from "../core/runtime/config.mjs";
4
+ import { SessionServiceLive } from "../effect/layers/session.layer.mjs";
5
+ import { ConfigTag } from "../effect/tags.mjs";
6
+ import { ContextServiceLive } from "../effect/layers/context.layer.mjs";
7
+ import { deriveIngestTarget } from "../core/runtime/ingest-target.mjs";
8
+ import { HttpServiceLive } from "../effect/layers/http.layer.mjs";
9
+ import { QueueServiceLive, QueueServiceTag } from "../effect/layers/queue.layer.mjs";
10
+ import { withSpan } from "../effect/layers/tracer.layer.mjs";
11
+ import { closeSDK, flushQueue, forkWithSDK, isSDKInitialized, runWithSDK, setSDKRuntime } from "../effect/runtime-services.mjs";
12
+ import { captureEffect } from "../client.mjs";
13
+ import { loadAndSetupPluginsEffect } from "../core/plugins/plugin-loader.mjs";
14
+ import { Cause, Effect, Exit, Layer, Runtime, Scope } from "effect";
15
+ import { configSchema } from "@interfere/types/sdk/config";
16
+ import { useEffect, useRef, useState } from "react";
17
+
18
+ //#region src/hooks/use-runtime-and-plugins.ts
19
+ const createSDKLayer = (config) => {
20
+ const configWithRuntime = {
21
+ ...config,
22
+ runtime: getRuntime()
23
+ };
24
+ const configLayer = Layer.succeed(ConfigTag, configWithRuntime);
25
+ const contextLayer = ContextServiceLive;
26
+ const httpLayer = HttpServiceLive(configWithRuntime);
27
+ const sessionLayer = SessionServiceLive;
28
+ const queueLayer = QueueServiceLive.pipe(Layer.provide(configLayer), Layer.provide(httpLayer));
29
+ return Layer.mergeAll(configLayer, contextLayer, httpLayer, sessionLayer, queueLayer);
30
+ };
31
+ const initRuntimeServices = async (input) => {
32
+ if (isSDKInitialized()) return;
33
+ const config = configSchema.parse(input);
34
+ initConfig(config);
35
+ const scope = await Effect.runPromise(Scope.make());
36
+ const runtime = await Effect.runPromise(Layer.toRuntime(createSDKLayer(config)).pipe(Effect.provideService(Scope.Scope, scope)));
37
+ setSDKRuntime(scope, runtime);
38
+ await Runtime.runPromise(runtime)(Effect.gen(function* () {
39
+ yield* Effect.logDebug("Runtime initialized successfully");
40
+ yield* Effect.forkDaemon(Effect.gen(function* () {
41
+ yield* (yield* QueueServiceTag).startBatchProcessor().pipe(Effect.provideService(Scope.Scope, scope));
42
+ }).pipe(Effect.catchAll((error) => Effect.logError("Failed to start batch processor", { error: String(error) }))));
43
+ }));
44
+ };
45
+ function useRuntimeAndPlugins(config, plugins) {
46
+ const [pluginApis, setPluginApis] = useState({});
47
+ const pluginHandlersRef = useRef([]);
48
+ const initRef = useRef(false);
49
+ useEffect(() => {
50
+ if (typeof window === "undefined" || initRef.current) return;
51
+ initRef.current = true;
52
+ const runCleanup = (cleanups) => Effect.gen(function* () {
53
+ const TIMEOUT_MS = 1500;
54
+ yield* Effect.tryPromise({
55
+ try: () => flushQueue(TIMEOUT_MS),
56
+ catch: (error) => Effect.logDebug("Bounded flush timed out during cleanup", {
57
+ timeoutMs: TIMEOUT_MS,
58
+ error: String(error)
59
+ })
60
+ }).pipe(Effect.ignore);
61
+ for (const dispose of cleanups) {
62
+ yield* Effect.logTrace(`Running cleanup for plugin ${dispose.name}`);
63
+ yield* Effect.try({
64
+ try: () => dispose(),
65
+ catch: (error) => Effect.logDebug("Plugin cleanup failed", { error: String(error) })
66
+ }).pipe(Effect.ignore);
67
+ }
68
+ yield* Effect.logTrace("Closing SDK");
69
+ yield* Effect.promise(() => closeSDK());
70
+ });
71
+ const initialize = async () => {
72
+ try {
73
+ await initRuntimeServices(config);
74
+ deriveIngestTarget(config);
75
+ } catch (error) {
76
+ console.error("[Interfere SDK] Failed to initialize:", error);
77
+ return;
78
+ }
79
+ const pluginContext = {
80
+ capture: captureEffect,
81
+ config,
82
+ run: (eff) => {
83
+ if (!isSDKInitialized()) {
84
+ console.warn("[Interfere SDK] Attempted to run effect before SDK initialized");
85
+ return;
86
+ }
87
+ forkWithSDK(eff);
88
+ },
89
+ span: (label, eff) => {
90
+ if (!isSDKInitialized()) {
91
+ console.warn("[Interfere SDK] Attempted to run span before SDK initialized");
92
+ return;
93
+ }
94
+ forkWithSDK(withSpan(label, eff));
95
+ },
96
+ captureNow: (type, payload) => {
97
+ if (!isSDKInitialized()) {
98
+ console.warn("[Interfere SDK] Attempted to capture event before SDK initialized");
99
+ return;
100
+ }
101
+ forkWithSDK(captureEffect(type, payload));
102
+ },
103
+ log: {
104
+ trace: (...message) => forkWithSDK(Effect.logTrace(...message)),
105
+ debug: (...message) => forkWithSDK(Effect.logDebug(...message)),
106
+ info: (...message) => forkWithSDK(Effect.logInfo(...message)),
107
+ warn: (...message) => forkWithSDK(Effect.logWarning(...message)),
108
+ error: (...message) => forkWithSDK(Effect.logError(...message)),
109
+ fatal: (...message) => forkWithSDK(Effect.logFatal(...message))
110
+ }
111
+ };
112
+ const result = await runWithSDK(Effect.gen(function* () {
113
+ const exit = yield* Effect.exit(loadAndSetupPluginsEffect(config, pluginContext, plugins));
114
+ if (Exit.isFailure(exit)) {
115
+ const cause = exit.cause;
116
+ yield* Effect.logFatal("Failed to load plugins", {
117
+ cause: Cause.pretty(cause),
118
+ features: config.features,
119
+ userPluginCount: Array.isArray(plugins) ? plugins.length : 0
120
+ });
121
+ return;
122
+ }
123
+ const { cleanups, apis, keys } = exit.value;
124
+ yield* Effect.logDebug(`${keys.size} plugins loaded, ${Object.keys(apis).length} APIs exposed`, {
125
+ plugins: Array.from(keys),
126
+ apis: Object.keys(apis)
127
+ });
128
+ yield* (yield* QueueServiceTag).setReady(true);
129
+ return {
130
+ cleanups,
131
+ apis
132
+ };
133
+ }));
134
+ if (result) {
135
+ pluginHandlersRef.current = result.cleanups;
136
+ setPluginApis(result.apis);
137
+ }
138
+ };
139
+ initialize();
140
+ return () => {
141
+ if (isSDKInitialized()) runWithSDK(runCleanup(pluginHandlersRef.current)).catch((error) => {
142
+ console.error("[Interfere SDK] Provider cleanup failed:", error);
143
+ });
144
+ else Effect.runPromise(runCleanup(pluginHandlersRef.current)).catch((error) => {
145
+ console.error("[Interfere SDK] Provider cleanup failed:", error);
146
+ });
147
+ };
148
+ }, [config, plugins]);
149
+ return pluginApis;
150
+ }
151
+
152
+ //#endregion
153
+ export { useRuntimeAndPlugins };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-runtime-and-plugins.mjs","names":["pluginContext: PluginContext"],"sources":["../../src/hooks/use-runtime-and-plugins.ts"],"sourcesContent":["\"use client\";\n\nimport type { Config } from \"@interfere/types/sdk/config\";\nimport { configSchema } from \"@interfere/types/sdk/config\";\n\nimport { Cause, Effect, Exit, Layer, Runtime, Scope } from \"effect\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport { captureEffect } from \"../client.js\";\nimport { loadAndSetupPluginsEffect } from \"../core/plugins/plugin-loader.js\";\nimport { getRuntime, initConfig } from \"../core/runtime/config.js\";\nimport { deriveIngestTarget } from \"../core/runtime/ingest-target.js\";\nimport type { Plugin, PluginApiMap, PluginContext } from \"../core/schemas.js\";\nimport { ContextServiceLive } from \"../effect/layers/context.layer.js\";\nimport { HttpServiceLive } from \"../effect/layers/http.layer.js\";\nimport {\n QueueServiceLive,\n QueueServiceTag,\n} from \"../effect/layers/queue.layer.js\";\nimport { SessionServiceLive } from \"../effect/layers/session.layer.js\";\nimport { withSpan } from \"../effect/layers/tracer.layer.js\";\nimport {\n closeSDK,\n flushQueue,\n forkWithSDK,\n isSDKInitialized,\n runWithSDK,\n setSDKRuntime,\n} from \"../effect/runtime-services.js\";\nimport { ConfigTag } from \"../effect/tags.js\";\n\nconst createSDKLayer = (config: Config) => {\n const configWithRuntime = {\n ...config,\n runtime: getRuntime(),\n };\n\n const configLayer = Layer.succeed(ConfigTag, configWithRuntime);\n const contextLayer = ContextServiceLive;\n const httpLayer = HttpServiceLive(configWithRuntime);\n const sessionLayer = SessionServiceLive;\n\n const queueLayer = QueueServiceLive.pipe(\n Layer.provide(configLayer),\n Layer.provide(httpLayer)\n );\n\n return Layer.mergeAll(\n configLayer,\n contextLayer,\n httpLayer,\n sessionLayer,\n queueLayer\n );\n};\n\nconst initRuntimeServices = async (input: unknown): Promise<void> => {\n if (isSDKInitialized()) {\n return;\n }\n\n const config = configSchema.parse(input);\n\n // Seed config for runtime consumers that don't use Effect tags\n initConfig(config);\n\n const scope = await Effect.runPromise(Scope.make());\n\n const runtime = await Effect.runPromise(\n Layer.toRuntime(createSDKLayer(config)).pipe(\n Effect.provideService(Scope.Scope, scope)\n )\n );\n\n setSDKRuntime(scope, runtime);\n\n await Runtime.runPromise(runtime)(\n Effect.gen(function* () {\n yield* Effect.logDebug(\"Runtime initialized successfully\");\n\n // Start batch processor\n yield* Effect.forkDaemon(\n Effect.gen(function* () {\n const queue = yield* QueueServiceTag;\n yield* queue\n .startBatchProcessor()\n .pipe(Effect.provideService(Scope.Scope, scope));\n }).pipe(\n Effect.catchAll((error) =>\n Effect.logError(\"Failed to start batch processor\", {\n error: String(error),\n })\n )\n )\n );\n })\n );\n};\n\n// removed Effect wrapper; plugin loading now handled with runPromise + try/catch in initialize\n\nexport function useRuntimeAndPlugins(\n config: Config,\n plugins?: Plugin[]\n): Partial<PluginApiMap> {\n const [pluginApis, setPluginApis] = useState<Partial<PluginApiMap>>({});\n const pluginHandlersRef = useRef<Array<() => void>>([]);\n const initRef = useRef(false);\n\n useEffect(() => {\n if (typeof window === \"undefined\" || initRef.current) {\n return;\n }\n\n initRef.current = true;\n\n const runCleanup = (cleanups: Array<() => void>) =>\n Effect.gen(function* () {\n const TIMEOUT_MS = 1500;\n\n yield* Effect.tryPromise({\n try: () => flushQueue(TIMEOUT_MS),\n catch: (error) =>\n Effect.logDebug(\"Bounded flush timed out during cleanup\", {\n timeoutMs: TIMEOUT_MS,\n error: String(error),\n }),\n }).pipe(Effect.ignore);\n\n for (const dispose of cleanups) {\n yield* Effect.logTrace(`Running cleanup for plugin ${dispose.name}`);\n\n yield* Effect.try({\n try: () => dispose(),\n catch: (error) =>\n Effect.logDebug(\"Plugin cleanup failed\", {\n error: String(error),\n }),\n }).pipe(Effect.ignore);\n }\n\n yield* Effect.logTrace(\"Closing SDK\");\n\n yield* Effect.promise(() => closeSDK());\n });\n\n const initialize = async () => {\n try {\n await initRuntimeServices(config);\n // Early ingest target validation (fail fast) without singleton reliance\n deriveIngestTarget(config);\n } catch (error) {\n console.error(\"[Interfere SDK] Failed to initialize:\", error);\n return;\n }\n\n const pluginContext: PluginContext = {\n capture: captureEffect,\n config,\n run: (eff) => {\n if (!isSDKInitialized()) {\n console.warn(\n \"[Interfere SDK] Attempted to run effect before SDK initialized\"\n );\n\n return;\n }\n forkWithSDK(eff);\n },\n span: (label, eff) => {\n if (!isSDKInitialized()) {\n console.warn(\n \"[Interfere SDK] Attempted to run span before SDK initialized\"\n );\n\n return;\n }\n forkWithSDK(withSpan(label, eff));\n },\n captureNow: (type, payload) => {\n if (!isSDKInitialized()) {\n console.warn(\n \"[Interfere SDK] Attempted to capture event before SDK initialized\"\n );\n\n return;\n }\n forkWithSDK(captureEffect(type, payload));\n },\n log: {\n trace: (...message) => forkWithSDK(Effect.logTrace(...message)),\n debug: (...message) => forkWithSDK(Effect.logDebug(...message)),\n info: (...message) => forkWithSDK(Effect.logInfo(...message)),\n warn: (...message) => forkWithSDK(Effect.logWarning(...message)),\n error: (...message) => forkWithSDK(Effect.logError(...message)),\n fatal: (...message) => forkWithSDK(Effect.logFatal(...message)),\n },\n };\n\n const result = await runWithSDK(\n Effect.gen(function* () {\n const exit = yield* Effect.exit(\n loadAndSetupPluginsEffect(config, pluginContext, plugins)\n );\n\n if (Exit.isFailure(exit)) {\n const cause = exit.cause;\n\n yield* Effect.logFatal(\"Failed to load plugins\", {\n cause: Cause.pretty(cause),\n features: config.features,\n userPluginCount: Array.isArray(plugins) ? plugins.length : 0,\n });\n\n return;\n }\n\n const { cleanups, apis, keys } = exit.value;\n\n yield* Effect.logDebug(\n `${keys.size} plugins loaded, ${Object.keys(apis).length} APIs exposed`,\n {\n plugins: Array.from(keys),\n apis: Object.keys(apis),\n }\n );\n\n // Signal queue readiness now that plugins have loaded\n const queue = yield* QueueServiceTag;\n yield* queue.setReady(true);\n\n return { cleanups, apis };\n })\n );\n\n if (result) {\n pluginHandlersRef.current = result.cleanups;\n\n setPluginApis(result.apis);\n }\n };\n\n // biome-ignore lint/complexity/noVoid: fire-and-forget initialization\n void initialize();\n\n return () => {\n if (isSDKInitialized()) {\n runWithSDK(runCleanup(pluginHandlersRef.current)).catch((error) => {\n console.error(\"[Interfere SDK] Provider cleanup failed:\", error);\n });\n } else {\n // If SDK never initialized, run cleanup directly\n Effect.runPromise(runCleanup(pluginHandlersRef.current)).catch(\n (error) => {\n console.error(\"[Interfere SDK] Provider cleanup failed:\", error);\n }\n );\n }\n };\n }, [config, plugins]);\n\n return pluginApis;\n}\n"],"mappings":"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"}