MCPcopy Create free account
hub / github.com/UsefulSoftwareCo/executor / layer

Function layer

packages/core/analytics/src/analytics.ts:151–236  ·  view source on GitHub ↗
(
  config: AnalyticsConfig,
)

Source from the content-addressed store, hash-verified

149}
150
151export const layer = (
152 config: AnalyticsConfig,
153): Layer.Layer<Analytics, never, HttpClient.HttpClient | FileSystem.FileSystem> =>
154 Layer.effect(Analytics)(
155 Effect.gen(function* () {
156 const disabled = config.disabled ?? isAnalyticsDisabled();
157 if (disabled) return analyticsNoop;
158
159 const http = yield* HttpClient.HttpClient;
160 const distinctId = yield* loadOrMintAnonymousId(config.dataDir);
161 const buffer = yield* Ref.make<ReadonlyArray<BufferedEvent>>([]);
162
163 const posthogHost = config.posthogHost ?? DEFAULT_POSTHOG_HOST;
164 const posthogKey = config.posthogKey ?? DEFAULT_POSTHOG_KEY;
165
166 const sendBatch = (events: ReadonlyArray<BufferedEvent>) =>
167 HttpClientRequest.post(`${posthogHost}/batch/`).pipe(
168 HttpClientRequest.bodyJson({
169 api_key: posthogKey,
170 batch: events.map((entry) => ({
171 event: entry.event,
172 distinct_id: distinctId,
173 timestamp: entry.timestamp,
174 properties: {
175 ...entry.properties,
176 // Anonymous events only: never materialize a person profile.
177 $process_person_profile: false,
178 surface: config.surface,
179 channel: config.channel,
180 app_version: config.version,
181 },
182 })),
183 }),
184 Effect.flatMap(http.execute),
185 Effect.flatMap(HttpClientResponse.filterStatusOk),
186 Effect.asVoid,
187 Effect.timeout(Duration.seconds(10)),
188 );
189
190 const flush: Effect.Effect<void> = Effect.gen(function* () {
191 while (true) {
192 const batch = yield* Ref.modify(buffer, (current) => {
193 const next = current.slice(0, FLUSH_BATCH_SIZE);
194 return [next, current.slice(next.length)] as const;
195 });
196 if (batch.length === 0) return;
197 yield* sendBatch(batch).pipe(
198 // Delivery failed: put the batch back for the next cadence tick and
199 // stop draining (the endpoint is unreachable, later batches would
200 // fail the same way).
201 Effect.tapError(() => Ref.update(buffer, (current) => [...batch, ...current])),
202 );
203 }
204 }).pipe(
205 Effect.catchCause((cause) =>
206 Effect.logDebug("Analytics.flush failed").pipe(Effect.annotateLogs("cause", cause)),
207 ),
208 );

Callers 7

analytics.test.tsFile · 0.90
defaultLayerFunction · 0.70
testing.test.tsFile · 0.50
testing.test.tsFile · 0.50
testing.test.tsFile · 0.50

Calls 4

isAnalyticsDisabledFunction · 0.85
loadOrMintAnonymousIdFunction · 0.85
sendBatchFunction · 0.85
updateMethod · 0.65

Tested by

no test coverage detected