@teardown/ingest-api 0.1.45 → 0.1.47-alpha-01

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.
@@ -8,6 +8,12 @@ export declare const baseApp: Elysia<"", {
8
8
  }, {
9
9
  typebox: {};
10
10
  error: {};
11
+ } & {
12
+ typebox: {};
13
+ error: {};
14
+ } & {
15
+ typebox: {};
16
+ error: {};
11
17
  } & {
12
18
  typebox: {};
13
19
  error: {
@@ -30,6 +36,20 @@ export declare const baseApp: Elysia<"", {
30
36
  macroFn: {};
31
37
  parser: {};
32
38
  response: {};
39
+ } & {
40
+ schema: {};
41
+ standaloneSchema: {};
42
+ macro: {};
43
+ macroFn: {};
44
+ parser: {};
45
+ response: {};
46
+ } & {
47
+ schema: {};
48
+ standaloneSchema: {};
49
+ macro: {};
50
+ macroFn: {};
51
+ parser: {};
52
+ response: {};
33
53
  } & {
34
54
  schema: {};
35
55
  standaloneSchema: {};
@@ -51,12 +71,23 @@ export declare const baseApp: Elysia<"", {
51
71
  body: unknown;
52
72
  params: {};
53
73
  query: unknown;
54
- headers: unknown;
74
+ headers: {
75
+ "td-api-version"?: string | undefined;
76
+ };
55
77
  response: {
56
78
  200: import("@teardown/errors").ErrorResponse | {
57
79
  message: string;
58
80
  version: string;
59
81
  };
82
+ 422: {
83
+ type: "validation";
84
+ on: string;
85
+ summary?: string;
86
+ message?: string;
87
+ found?: unknown;
88
+ property?: string;
89
+ expected?: string;
90
+ };
60
91
  };
61
92
  };
62
93
  } & {
@@ -65,7 +96,9 @@ export declare const baseApp: Elysia<"", {
65
96
  body: unknown;
66
97
  params: {};
67
98
  query: unknown;
68
- headers: unknown;
99
+ headers: {
100
+ "td-api-version"?: string | undefined;
101
+ };
69
102
  response: {
70
103
  200: import("@teardown/errors").ErrorResponse | {
71
104
  status: string;
@@ -73,6 +106,15 @@ export declare const baseApp: Elysia<"", {
73
106
  build_id: string;
74
107
  service_id: string | undefined;
75
108
  };
109
+ 422: {
110
+ type: "validation";
111
+ on: string;
112
+ summary?: string;
113
+ message?: string;
114
+ found?: unknown;
115
+ property?: string;
116
+ expected?: string;
117
+ };
76
118
  };
77
119
  };
78
120
  };
@@ -85,8 +127,9 @@ export declare const baseApp: Elysia<"", {
85
127
  body: {
86
128
  user?: {
87
129
  name?: string | undefined;
88
- email?: string | undefined;
130
+ persona_id?: string | undefined;
89
131
  user_id?: string | undefined;
132
+ email?: string | undefined;
90
133
  } | undefined;
91
134
  device: {
92
135
  timestamp?: Date | undefined;
@@ -96,19 +139,17 @@ export declare const baseApp: Elysia<"", {
96
139
  platform: import("@teardown/types").DevicePlatformEnum;
97
140
  };
98
141
  application: {
99
- build_number: number;
100
142
  version: string;
143
+ build_number: number;
101
144
  };
102
145
  hardware: {
103
- device_brand: string;
104
146
  device_name: string;
105
147
  device_type: string;
148
+ device_brand: string;
106
149
  };
107
150
  update: {
108
- created_at: string;
109
- is_embedded_launch: boolean;
110
- update_id: string;
111
151
  is_enabled: boolean;
152
+ update_id: string;
112
153
  update_channel: string;
113
154
  runtime_version: string;
114
155
  emergency_launch: {
@@ -118,6 +159,8 @@ export declare const baseApp: Elysia<"", {
118
159
  reason?: undefined;
119
160
  is_emergency_launch: false;
120
161
  };
162
+ is_embedded_launch: boolean;
163
+ created_at: string;
121
164
  } | null;
122
165
  };
123
166
  };
@@ -135,9 +178,9 @@ export declare const baseApp: Elysia<"", {
135
178
  200: {
136
179
  success: true;
137
180
  data: {
138
- device_id: string;
139
181
  user_id: string;
140
182
  session_id: string;
183
+ device_id: string;
141
184
  token: string;
142
185
  version_info: {
143
186
  status: import("@teardown/schemas").IdentifyVersionStatusEnum;
@@ -162,32 +205,32 @@ export declare const baseApp: Elysia<"", {
162
205
  };
163
206
  };
164
207
  400: {
165
- success: false;
166
208
  error: {
167
- message: string;
168
209
  code: "MISSING_ORG_ID";
169
- } | {
170
210
  message: string;
171
- code: "MISSING_PROJECT_ID";
172
211
  } | {
212
+ code: "MISSING_PROJECT_ID";
173
213
  message: string;
174
- code: "MISSING_ENVIRONMENT_SLUG";
175
214
  } | {
215
+ code: "MISSING_ENVIRONMENT_SLUG";
176
216
  message: string;
177
- code: "MISSING_DEVICE_ID";
178
217
  } | {
218
+ code: "MISSING_DEVICE_ID";
179
219
  message: string;
180
- code: "IDENTIFY_FAILED";
181
220
  } | {
221
+ code: "IDENTIFY_FAILED";
182
222
  message: string;
183
- code: "NO_SESSION_ID_GENERATED";
184
223
  } | {
224
+ code: "NO_SESSION_ID_GENERATED";
185
225
  message: string;
186
- code: "NO_DEVICE_ID_GENERATED";
187
226
  } | {
227
+ code: "NO_DEVICE_ID_GENERATED";
188
228
  message: string;
229
+ } | {
189
230
  code: "NO_USER_ID_GENERATED";
231
+ message: string;
190
232
  };
233
+ success: false;
191
234
  };
192
235
  422: {
193
236
  type: "validation";
@@ -209,13 +252,13 @@ export declare const baseApp: Elysia<"", {
209
252
  events: {
210
253
  post: {
211
254
  body: {
212
- device_id?: string | undefined;
213
255
  session_id?: string | undefined;
256
+ device_id?: string | undefined;
214
257
  events: {
215
258
  properties?: {} | undefined;
216
- device_id?: string | undefined;
217
- session_id?: string | undefined;
218
259
  timestamp?: string | undefined;
260
+ session_id?: string | undefined;
261
+ device_id?: string | undefined;
219
262
  event_name: string;
220
263
  event_type: "action" | "screen_view" | "custom";
221
264
  }[];
@@ -240,35 +283,35 @@ export declare const baseApp: Elysia<"", {
240
283
  };
241
284
  };
242
285
  400: {
243
- success: false;
244
286
  error: {
245
- message: string;
246
287
  code: "MISSING_ORG_ID";
247
- } | {
248
288
  message: string;
249
- code: "MISSING_PROJECT_ID";
250
289
  } | {
290
+ code: "MISSING_PROJECT_ID";
251
291
  message: string;
252
- code: "MISSING_ENVIRONMENT_SLUG";
253
292
  } | {
293
+ code: "MISSING_ENVIRONMENT_SLUG";
254
294
  message: string;
255
- code: "MISSING_DEVICE_ID";
256
295
  } | {
296
+ code: "MISSING_DEVICE_ID";
257
297
  message: string;
258
- code: "EVENTS_PROCESSING_FAILED";
259
298
  } | {
299
+ code: "EVENTS_PROCESSING_FAILED";
260
300
  message: string;
261
- code: "INVALID_SESSION";
262
301
  } | {
302
+ code: "INVALID_SESSION";
263
303
  message: string;
264
- code: "INVALID_DEVICE";
265
304
  } | {
305
+ code: "INVALID_DEVICE";
266
306
  message: string;
267
- code: "BATCH_SIZE_EXCEEDED";
268
307
  } | {
308
+ code: "BATCH_SIZE_EXCEEDED";
269
309
  message: string;
310
+ } | {
270
311
  code: "VALIDATION_ERROR";
312
+ message: string;
271
313
  };
314
+ success: false;
272
315
  };
273
316
  422: {
274
317
  type: "validation";
@@ -291,7 +334,10 @@ export declare const baseApp: Elysia<"", {
291
334
  response: {};
292
335
  }, {
293
336
  derive: {};
294
- resolve: {};
337
+ resolve: {
338
+ readonly apiVersion: "2024-12-12";
339
+ readonly requestedVersion: string | null;
340
+ };
295
341
  schema: import("elysia").UnwrapRoute<{
296
342
  headers: z.ZodObject<{
297
343
  authorization: z.ZodOptional<z.ZodString>;
@@ -304,7 +350,10 @@ export declare const baseApp: Elysia<"", {
304
350
  }, z.core.$strip>;
305
351
  }, {}, "">;
306
352
  standaloneSchema: {};
307
- response: {};
353
+ response: import("elysia").ExtractErrorFromHandle<{
354
+ readonly apiVersion: "2024-12-12";
355
+ readonly requestedVersion: string | null;
356
+ }>;
308
357
  } & {
309
358
  derive: {};
310
359
  resolve: {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teardown/ingest-api",
3
- "version": "0.1.45",
3
+ "version": "0.1.47-alpha-01",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -39,9 +39,9 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@elysiajs/eden": "1.4.5",
42
- "@teardown/errors": "0.1.45",
43
- "@teardown/schemas": "0.1.45",
44
- "@teardown/types": "0.1.45",
42
+ "@teardown/errors": "0.1.46",
43
+ "@teardown/schemas": "0.1.46",
44
+ "@teardown/types": "0.1.46",
45
45
  "zod": "4.1.13"
46
46
  },
47
47
  "peerDependencies": {
@@ -50,7 +50,7 @@
50
50
  "devDependencies": {
51
51
  "@biomejs/biome": "2.3.8",
52
52
  "@types/bun": "1.3.4",
53
- "@teardown/tsconfig": "0.1.45",
53
+ "@teardown/tsconfig": "0.1.46",
54
54
  "elysia": "1.4.17"
55
55
  }
56
56
  }
@@ -1,2 +1,3 @@
1
1
  export * from "./client";
2
2
  export * from "./types";
3
+ export * from "./ingest.client";
@@ -0,0 +1,171 @@
1
+ import { edenFetch } from "@elysiajs/eden";
2
+ import { API_VERSION_HEADER } from "@teardown/schemas/contracts";
3
+ import type { IdentifyRequest, IdentifyResponse } from "@teardown/schemas/identify";
4
+ import type { IngestApp } from "../../generated/app";
5
+ import type { ClientConfig, RequestOptions } from "./client";
6
+
7
+ /**
8
+ * Ingest API Target Version
9
+ *
10
+ * This is the API contract version this client is built for.
11
+ * The client will send this version in the td-api-version header.
12
+ * Ingest API will validate and respond with the version used.
13
+ */
14
+ export const INGEST_TARGET_API_VERSION = "2024-12-12";
15
+
16
+ export type IngestApiClientOptions = {
17
+ /**
18
+ * Base URL for the Ingest API
19
+ */
20
+ url: string;
21
+ /**
22
+ * API key for authentication
23
+ */
24
+ apiKey: string;
25
+ /**
26
+ * Organization ID
27
+ */
28
+ orgId: string;
29
+ /**
30
+ * Project ID
31
+ */
32
+ projectId: string;
33
+ /**
34
+ * Environment slug (e.g., "production", "staging")
35
+ */
36
+ environmentSlug: string;
37
+ /**
38
+ * Device ID (unique identifier for this device)
39
+ */
40
+ deviceId: string;
41
+ /**
42
+ * Session ID (optional, set after identify)
43
+ */
44
+ sessionId?: string;
45
+ /**
46
+ * Override the API version to use.
47
+ * Defaults to INGEST_TARGET_API_VERSION.
48
+ */
49
+ apiVersion?: string;
50
+ /**
51
+ * Optional Eden fetch config
52
+ */
53
+ config?: ClientConfig;
54
+ /**
55
+ * Hook to modify request options before each request
56
+ */
57
+ onRequest?: (endpoint: string, options: RequestOptions) => Promise<RequestOptions>;
58
+ };
59
+
60
+ type IngestClient = ReturnType<typeof edenFetch<typeof IngestApp>>;
61
+
62
+ export class IngestApiClient {
63
+ private readonly client: IngestClient;
64
+ private readonly apiVersion: string;
65
+ private sessionId: string | undefined;
66
+
67
+ constructor(private readonly options: IngestApiClientOptions) {
68
+ this.client = edenFetch<typeof IngestApp>(this.options.url, this.options.config);
69
+ this.apiVersion = options.apiVersion ?? INGEST_TARGET_API_VERSION;
70
+ this.sessionId = options.sessionId;
71
+ }
72
+
73
+ /**
74
+ * Get the API version this client is using
75
+ */
76
+ getApiVersion(): string {
77
+ return this.apiVersion;
78
+ }
79
+
80
+ /**
81
+ * Get the current session ID (if set)
82
+ */
83
+ getSessionId(): string | undefined {
84
+ return this.sessionId;
85
+ }
86
+
87
+ /**
88
+ * Set the session ID (typically after identify)
89
+ */
90
+ setSessionId(sessionId: string): void {
91
+ this.sessionId = sessionId;
92
+ }
93
+
94
+ /**
95
+ * Generate base headers for all requests
96
+ */
97
+ generateBaseHeaders(): Record<string, string> {
98
+ const headers: Record<string, string> = {
99
+ // Always send API version header
100
+ [API_VERSION_HEADER]: this.apiVersion,
101
+ "td-api-key": this.options.apiKey,
102
+ "td-org-id": this.options.orgId,
103
+ "td-project-id": this.options.projectId,
104
+ "td-environment-slug": this.options.environmentSlug,
105
+ "td-device-id": this.options.deviceId,
106
+ };
107
+
108
+ if (this.sessionId) {
109
+ headers["td-session-id"] = this.sessionId;
110
+ }
111
+
112
+ return headers;
113
+ }
114
+
115
+ /**
116
+ * Make a fetch request to the Ingest API
117
+ * @internal Use typed convenience methods like identify() instead
118
+ */
119
+ // biome-ignore lint/suspicious/noExplicitAny: Eden types are complex, using any for flexibility
120
+ async fetch(endpoint: string, options?: Record<string, any>): Promise<any> {
121
+ const baseHeaders = this.generateBaseHeaders();
122
+ const baseOptions = {
123
+ ...options,
124
+ headers: {
125
+ ...baseHeaders,
126
+ ...options?.headers,
127
+ },
128
+ };
129
+
130
+ const requestOptions = this.options.onRequest
131
+ ? await this.options.onRequest(endpoint, baseOptions as RequestOptions)
132
+ : baseOptions;
133
+
134
+ // biome-ignore lint/suspicious/noExplicitAny: Eden types require any cast
135
+ const result = await this.client(endpoint as any, requestOptions as any);
136
+
137
+ if (result.error) {
138
+ throw result.error;
139
+ }
140
+
141
+ return result;
142
+ }
143
+
144
+ /**
145
+ * Identify the current device/user
146
+ * This should be called at app startup to establish a session
147
+ */
148
+ async identify(request: IdentifyRequest): Promise<IdentifyResponse> {
149
+ const baseHeaders = this.generateBaseHeaders();
150
+
151
+ // biome-ignore lint/suspicious/noExplicitAny: Eden types are complex
152
+ const result = await this.client("/v1/identify" as any, {
153
+ method: "POST",
154
+ body: request,
155
+ headers: baseHeaders,
156
+ } as any);
157
+
158
+ if (result.error) {
159
+ throw result.error;
160
+ }
161
+
162
+ const data = result.data as IdentifyResponse;
163
+
164
+ // Automatically set session ID from response
165
+ if (data.success && data.data.session_id) {
166
+ this.setSessionId(data.data.session_id);
167
+ }
168
+
169
+ return data;
170
+ }
171
+ }