@reopt-ai/data-contract 0.3.0 → 0.6.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.
Files changed (84) hide show
  1. package/README.md +11 -4
  2. package/dist/{chunk-2LJ7JLDX.js → chunk-33BCA2LH.js} +8 -16
  3. package/dist/chunk-33BCA2LH.js.map +1 -0
  4. package/dist/chunk-3EEANNYN.cjs +62 -0
  5. package/dist/chunk-3EEANNYN.cjs.map +1 -0
  6. package/dist/{chunk-3A7WZ7L6.js → chunk-5BRCHDS3.js} +26 -7
  7. package/dist/chunk-5BRCHDS3.js.map +1 -0
  8. package/dist/chunk-6ZJOC4NJ.js +111 -0
  9. package/dist/chunk-6ZJOC4NJ.js.map +1 -0
  10. package/dist/chunk-FP2X3PRK.js +62 -0
  11. package/dist/chunk-FP2X3PRK.js.map +1 -0
  12. package/dist/{chunk-I2T4HRBM.cjs → chunk-FUGY5ANJ.cjs} +131 -19
  13. package/dist/chunk-FUGY5ANJ.cjs.map +1 -0
  14. package/dist/chunk-IXPP5K4I.js +19 -0
  15. package/dist/chunk-IXPP5K4I.js.map +1 -0
  16. package/dist/{chunk-J4VD3TLV.js → chunk-IY4MXH35.js} +30 -4
  17. package/dist/chunk-IY4MXH35.js.map +1 -0
  18. package/dist/chunk-JHHCT3GA.cjs +19 -0
  19. package/dist/chunk-JHHCT3GA.cjs.map +1 -0
  20. package/dist/chunk-KRJPEMFD.cjs +111 -0
  21. package/dist/chunk-KRJPEMFD.cjs.map +1 -0
  22. package/dist/{chunk-55IWO4S3.js → chunk-L3WJGIKD.js} +123 -11
  23. package/dist/chunk-L3WJGIKD.js.map +1 -0
  24. package/dist/{chunk-ATPS4UV6.cjs → chunk-LA5F5KR6.cjs} +33 -7
  25. package/dist/chunk-LA5F5KR6.cjs.map +1 -0
  26. package/dist/{chunk-RDPPPFGO.cjs → chunk-OGL3P7IH.cjs} +30 -11
  27. package/dist/chunk-OGL3P7IH.cjs.map +1 -0
  28. package/dist/{chunk-KXEQGD3E.cjs → chunk-YSAEOYPD.cjs} +9 -17
  29. package/dist/chunk-YSAEOYPD.cjs.map +1 -0
  30. package/dist/client.cjs +87 -43
  31. package/dist/client.cjs.map +1 -1
  32. package/dist/client.d.cts +8 -2
  33. package/dist/client.d.ts +8 -2
  34. package/dist/client.js +50 -6
  35. package/dist/client.js.map +1 -1
  36. package/dist/control.cjs +15 -4
  37. package/dist/control.cjs.map +1 -1
  38. package/dist/control.d.cts +43 -1
  39. package/dist/control.d.ts +43 -1
  40. package/dist/control.js +16 -5
  41. package/dist/events.cjs +17 -0
  42. package/dist/events.cjs.map +1 -0
  43. package/dist/events.d.cts +59 -0
  44. package/dist/events.d.ts +59 -0
  45. package/dist/events.js +17 -0
  46. package/dist/events.js.map +1 -0
  47. package/dist/identity.cjs +47 -0
  48. package/dist/identity.cjs.map +1 -0
  49. package/dist/identity.d.cts +90 -0
  50. package/dist/identity.d.ts +90 -0
  51. package/dist/identity.js +47 -0
  52. package/dist/identity.js.map +1 -0
  53. package/dist/index.cjs +4 -2
  54. package/dist/index.cjs.map +1 -1
  55. package/dist/index.d.cts +7 -17
  56. package/dist/index.d.ts +7 -17
  57. package/dist/index.js +7 -5
  58. package/dist/ingest.cjs +16 -2
  59. package/dist/ingest.cjs.map +1 -1
  60. package/dist/ingest.d.cts +6 -3
  61. package/dist/ingest.d.ts +6 -3
  62. package/dist/ingest.js +16 -2
  63. package/dist/query.cjs +28 -3
  64. package/dist/query.cjs.map +1 -1
  65. package/dist/query.d.cts +299 -18
  66. package/dist/query.d.ts +299 -18
  67. package/dist/query.js +29 -4
  68. package/dist/report.cjs +85 -0
  69. package/dist/report.cjs.map +1 -0
  70. package/dist/report.d.cts +167 -0
  71. package/dist/report.d.ts +167 -0
  72. package/dist/report.js +85 -0
  73. package/dist/report.js.map +1 -0
  74. package/dist/version-CC4_BBvq.d.cts +26 -0
  75. package/dist/version-CC4_BBvq.d.ts +26 -0
  76. package/package.json +18 -2
  77. package/dist/chunk-2LJ7JLDX.js.map +0 -1
  78. package/dist/chunk-3A7WZ7L6.js.map +0 -1
  79. package/dist/chunk-55IWO4S3.js.map +0 -1
  80. package/dist/chunk-ATPS4UV6.cjs.map +0 -1
  81. package/dist/chunk-I2T4HRBM.cjs.map +0 -1
  82. package/dist/chunk-J4VD3TLV.js.map +0 -1
  83. package/dist/chunk-KXEQGD3E.cjs.map +0 -1
  84. package/dist/chunk-RDPPPFGO.cjs.map +0 -1
package/dist/client.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
- var _chunkRDPPPFGOcjs = require('./chunk-RDPPPFGO.cjs');
3
+ var _chunkOGL3P7IHcjs = require('./chunk-OGL3P7IH.cjs');
4
4
 
5
5
 
6
6
 
@@ -11,20 +11,28 @@ var _chunkRDPPPFGOcjs = require('./chunk-RDPPPFGO.cjs');
11
11
 
12
12
 
13
13
 
14
- var _chunkATPS4UV6cjs = require('./chunk-ATPS4UV6.cjs');
15
14
 
15
+ var _chunkLA5F5KR6cjs = require('./chunk-LA5F5KR6.cjs');
16
16
 
17
17
 
18
18
 
19
19
 
20
- var _chunkI2T4HRBMcjs = require('./chunk-I2T4HRBM.cjs');
21
20
 
22
21
 
23
22
 
23
+ var _chunkFUGY5ANJcjs = require('./chunk-FUGY5ANJ.cjs');
24
24
 
25
25
 
26
+ var _chunkYSAEOYPDcjs = require('./chunk-YSAEOYPD.cjs');
27
+ require('./chunk-KRJPEMFD.cjs');
26
28
 
27
- var _chunkKXEQGD3Ecjs = require('./chunk-KXEQGD3E.cjs');
29
+
30
+
31
+
32
+
33
+
34
+ var _chunkJHHCT3GAcjs = require('./chunk-JHHCT3GA.cjs');
35
+ require('./chunk-3EEANNYN.cjs');
28
36
 
29
37
  // src/client.ts
30
38
  var TRACK_PATH = "/api/track";
@@ -72,7 +80,7 @@ function toApiError(status, rawBody, retryAfterMs, requestId) {
72
80
  try {
73
81
  parsed = JSON.parse(rawBody);
74
82
  } catch (e) {
75
- return new (0, _chunkKXEQGD3Ecjs.DataApiError)({
83
+ return new (0, _chunkYSAEOYPDcjs.DataApiError)({
76
84
  message: `reopt-data responded ${status} with a non-JSON body`,
77
85
  status,
78
86
  code: status >= 500 ? "internal_error" : "unknown_error",
@@ -84,7 +92,7 @@ function toApiError(status, rawBody, retryAfterMs, requestId) {
84
92
  const body = _nullishCoalesce(parsed, () => ( {}));
85
93
  const code = typeof body.code === "string" ? body.code : status >= 500 ? "internal_error" : "unknown_error";
86
94
  const message = typeof body.message === "string" && body.message || typeof body.error === "string" && body.error || `reopt-data responded ${status}`;
87
- return new (0, _chunkKXEQGD3Ecjs.DataApiError)({
95
+ return new (0, _chunkYSAEOYPDcjs.DataApiError)({
88
96
  message,
89
97
  status,
90
98
  code,
@@ -106,10 +114,10 @@ function createDataClient(options) {
106
114
  maxDelayMs: _nullishCoalesce(_optionalChain([options, 'access', _11 => _11.retry, 'optionalAccess', _12 => _12.maxDelayMs]), () => ( DEFAULTS.maxDelayMs)),
107
115
  respectRetryAfter: _nullishCoalesce(_optionalChain([options, 'access', _13 => _13.retry, 'optionalAccess', _14 => _14.respectRetryAfter]), () => ( true))
108
116
  };
109
- const userAgent = options.userAgent ? `reopt-data-contract/${_chunkKXEQGD3Ecjs.CONTRACT_VERSION} ${options.userAgent}` : `reopt-data-contract/${_chunkKXEQGD3Ecjs.CONTRACT_VERSION}`;
117
+ const userAgent = options.userAgent ? `reopt-data-contract/${_chunkJHHCT3GAcjs.CONTRACT_VERSION} ${options.userAgent}` : `reopt-data-contract/${_chunkJHHCT3GAcjs.CONTRACT_VERSION}`;
110
118
  function requireClientCredentials() {
111
119
  if (!options.clientId || !options.clientSecret) {
112
- throw new (0, _chunkKXEQGD3Ecjs.DataApiError)({
120
+ throw new (0, _chunkYSAEOYPDcjs.DataApiError)({
113
121
  message: "createDataClient was given no client credentials \u2014 pass clientId and clientSecret to use the ingest or query planes",
114
122
  status: 0,
115
123
  code: "credentials_missing"
@@ -131,7 +139,7 @@ function createDataClient(options) {
131
139
  headers: {
132
140
  "content-type": "application/json",
133
141
  "user-agent": userAgent,
134
- ...options.clientId && options.clientSecret ? { [_chunkKXEQGD3Ecjs.CLIENT_ID_HEADER]: options.clientId, [_chunkKXEQGD3Ecjs.CLIENT_SECRET_HEADER]: options.clientSecret } : {},
142
+ ...options.clientId && options.clientSecret ? { [_chunkJHHCT3GAcjs.CLIENT_ID_HEADER]: options.clientId, [_chunkJHHCT3GAcjs.CLIENT_SECRET_HEADER]: options.clientSecret } : {},
135
143
  ...extraHeaders
136
144
  },
137
145
  body: JSON.stringify(body),
@@ -150,7 +158,7 @@ function createDataClient(options) {
150
158
  response = await requestOnce(method, path, body, extraHeaders, signal);
151
159
  } catch (cause) {
152
160
  if (_optionalChain([signal, 'optionalAccess', _20 => _20.aborted])) throw cause;
153
- lastError = new (0, _chunkKXEQGD3Ecjs.DataApiError)({
161
+ lastError = new (0, _chunkYSAEOYPDcjs.DataApiError)({
154
162
  message: cause instanceof Error ? cause.message : String(cause),
155
163
  status: 0,
156
164
  code: "network_error",
@@ -162,14 +170,24 @@ function createDataClient(options) {
162
170
  }
163
171
  throw lastError;
164
172
  }
165
- const requestId = _nullishCoalesce(response.headers.get(_chunkKXEQGD3Ecjs.REQUEST_ID_HEADER), () => ( void 0));
173
+ const requestId = _nullishCoalesce(response.headers.get(_chunkJHHCT3GAcjs.REQUEST_ID_HEADER), () => ( void 0));
174
+ const serverContractVersion = response.headers.get(_chunkJHHCT3GAcjs.CONTRACT_VERSION_HEADER);
166
175
  const rawBody = await response.text();
176
+ if (serverContractVersion !== _chunkJHHCT3GAcjs.CONTRACT_VERSION) {
177
+ throw new (0, _chunkYSAEOYPDcjs.DataApiError)({
178
+ message: serverContractVersion ? `reopt-data contract ${serverContractVersion} does not match client contract ${_chunkJHHCT3GAcjs.CONTRACT_VERSION}` : "reopt-data response did not declare its contract version",
179
+ status: response.status,
180
+ code: "contract_mismatch",
181
+ requestId,
182
+ details: { expected: _chunkJHHCT3GAcjs.CONTRACT_VERSION, received: serverContractVersion }
183
+ });
184
+ }
167
185
  if (response.ok) {
168
186
  let json;
169
187
  try {
170
188
  json = JSON.parse(rawBody);
171
189
  } catch (cause) {
172
- throw new (0, _chunkKXEQGD3Ecjs.DataApiError)({
190
+ throw new (0, _chunkYSAEOYPDcjs.DataApiError)({
173
191
  message: "reopt-data returned a 2xx with an unparseable body",
174
192
  status: response.status,
175
193
  code: "contract_mismatch",
@@ -180,7 +198,7 @@ function createDataClient(options) {
180
198
  try {
181
199
  return parse(json);
182
200
  } catch (cause) {
183
- throw new (0, _chunkKXEQGD3Ecjs.DataApiError)({
201
+ throw new (0, _chunkYSAEOYPDcjs.DataApiError)({
184
202
  message: "reopt-data returned a 2xx that does not match the contract",
185
203
  status: response.status,
186
204
  code: "contract_mismatch",
@@ -194,7 +212,7 @@ function createDataClient(options) {
194
212
  if (!lastError.retryable || attempt === retry.maxRetries) throw lastError;
195
213
  await sleep(_nullishCoalesce(retryAfterMs, () => ( backoffDelay(attempt, retry))), signal);
196
214
  }
197
- throw _nullishCoalesce(lastError, () => ( new (0, _chunkKXEQGD3Ecjs.DataApiError)({ message: "reopt-data request failed", status: 0, code: "network_error" })));
215
+ throw _nullishCoalesce(lastError, () => ( new (0, _chunkYSAEOYPDcjs.DataApiError)({ message: "reopt-data request failed", status: 0, code: "network_error" })));
198
216
  }
199
217
  async function post(path, body, parse, signal) {
200
218
  requireClientCredentials();
@@ -203,84 +221,110 @@ function createDataClient(options) {
203
221
  return {
204
222
  ingest: {
205
223
  track(events, init) {
206
- return post(TRACK_PATH, events, (value) => _chunkRDPPPFGOcjs.zIngestResponse.parse(value), _optionalChain([init, 'optionalAccess', _21 => _21.signal]));
224
+ return post(TRACK_PATH, events, (value) => _chunkOGL3P7IHcjs.zIngestResponse.parse(value), _optionalChain([init, 'optionalAccess', _21 => _21.signal]));
207
225
  }
208
226
  },
209
227
  query: {
210
228
  eventsTimeseries(input, init) {
211
229
  return post(
212
- _chunkI2T4HRBMcjs.QUERY_API_PATHS.eventsTimeseries,
230
+ _chunkFUGY5ANJcjs.QUERY_API_PATHS.eventsTimeseries,
213
231
  input,
214
- (value) => _chunkI2T4HRBMcjs.zEventsTimeseriesResponse.parse(value),
232
+ (value) => _chunkFUGY5ANJcjs.zEventsTimeseriesResponse.parse(value),
215
233
  _optionalChain([init, 'optionalAccess', _22 => _22.signal])
216
234
  );
217
235
  },
218
236
  funnel(input, init) {
219
- return post(_chunkI2T4HRBMcjs.QUERY_API_PATHS.funnel, input, (value) => _chunkI2T4HRBMcjs.zFunnelResponse.parse(value), _optionalChain([init, 'optionalAccess', _23 => _23.signal]));
237
+ return post(_chunkFUGY5ANJcjs.QUERY_API_PATHS.funnel, input, (value) => _chunkFUGY5ANJcjs.zFunnelResponse.parse(value), _optionalChain([init, 'optionalAccess', _23 => _23.signal]));
220
238
  },
221
239
  retention(input, init) {
222
- return post(_chunkI2T4HRBMcjs.QUERY_API_PATHS.retention, input, (value) => _chunkI2T4HRBMcjs.zRetentionResponse.parse(value), _optionalChain([init, 'optionalAccess', _24 => _24.signal]));
240
+ return post(_chunkFUGY5ANJcjs.QUERY_API_PATHS.retention, input, (value) => _chunkFUGY5ANJcjs.zRetentionResponse.parse(value), _optionalChain([init, 'optionalAccess', _24 => _24.signal]));
241
+ },
242
+ trafficOverview(input, init) {
243
+ return post(
244
+ _chunkFUGY5ANJcjs.QUERY_API_PATHS.trafficOverview,
245
+ input,
246
+ (value) => _chunkFUGY5ANJcjs.zTrafficOverviewResponse.parse(value),
247
+ _optionalChain([init, 'optionalAccess', _25 => _25.signal])
248
+ );
249
+ },
250
+ trafficSources(input, init) {
251
+ return post(
252
+ _chunkFUGY5ANJcjs.QUERY_API_PATHS.trafficSources,
253
+ input,
254
+ (value) => _chunkFUGY5ANJcjs.zTrafficSourcesResponse.parse(value),
255
+ _optionalChain([init, 'optionalAccess', _26 => _26.signal])
256
+ );
223
257
  }
224
258
  },
225
259
  control: {
226
260
  createOrganization(input, auth, init) {
227
261
  return send(
228
262
  "POST",
229
- _chunkATPS4UV6cjs.CONTROL_API_PATHS.organizations,
263
+ _chunkLA5F5KR6cjs.CONTROL_API_PATHS.organizations,
230
264
  input,
231
- (value) => _chunkATPS4UV6cjs.zCreateOrganizationResponse.parse(value),
232
- { [_chunkATPS4UV6cjs.PLATFORM_KEY_HEADER]: auth.platformKey },
233
- _optionalChain([init, 'optionalAccess', _25 => _25.signal])
265
+ (value) => _chunkLA5F5KR6cjs.zCreateOrganizationResponse.parse(value),
266
+ { [_chunkLA5F5KR6cjs.PLATFORM_KEY_HEADER]: auth.platformKey },
267
+ _optionalChain([init, 'optionalAccess', _27 => _27.signal])
234
268
  );
235
269
  },
236
270
  rotateOrgKey(organizationId, auth, init) {
237
271
  return send(
238
272
  "POST",
239
- _chunkATPS4UV6cjs.CONTROL_API_PATHS.organizationKeys(organizationId),
273
+ _chunkLA5F5KR6cjs.CONTROL_API_PATHS.organizationKeys(organizationId),
240
274
  {},
241
- (value) => _chunkATPS4UV6cjs.zRotateOrganizationKeyResponse.parse(value),
242
- { [_chunkATPS4UV6cjs.PLATFORM_KEY_HEADER]: auth.platformKey },
243
- _optionalChain([init, 'optionalAccess', _26 => _26.signal])
275
+ (value) => _chunkLA5F5KR6cjs.zRotateOrganizationKeyResponse.parse(value),
276
+ { [_chunkLA5F5KR6cjs.PLATFORM_KEY_HEADER]: auth.platformKey },
277
+ _optionalChain([init, 'optionalAccess', _28 => _28.signal])
244
278
  );
245
279
  },
246
280
  updateOrganizationQuota(organizationId, input, auth, init) {
247
281
  return send(
248
282
  "PATCH",
249
- _chunkATPS4UV6cjs.CONTROL_API_PATHS.organization(organizationId),
283
+ _chunkLA5F5KR6cjs.CONTROL_API_PATHS.organization(organizationId),
250
284
  input,
251
- (value) => _chunkATPS4UV6cjs.zUpdateOrganizationQuotaResponse.parse(value),
252
- { [_chunkATPS4UV6cjs.PLATFORM_KEY_HEADER]: auth.platformKey },
253
- _optionalChain([init, 'optionalAccess', _27 => _27.signal])
285
+ (value) => _chunkLA5F5KR6cjs.zUpdateOrganizationQuotaResponse.parse(value),
286
+ { [_chunkLA5F5KR6cjs.PLATFORM_KEY_HEADER]: auth.platformKey },
287
+ _optionalChain([init, 'optionalAccess', _29 => _29.signal])
254
288
  );
255
289
  },
256
290
  createProject(input, auth, init) {
257
291
  return send(
258
292
  "POST",
259
- _chunkATPS4UV6cjs.CONTROL_API_PATHS.projects,
293
+ _chunkLA5F5KR6cjs.CONTROL_API_PATHS.projects,
260
294
  input,
261
- (value) => _chunkATPS4UV6cjs.zCreateProjectResponse.parse(value),
262
- { [_chunkATPS4UV6cjs.ORG_KEY_HEADER]: auth.orgKey },
263
- _optionalChain([init, 'optionalAccess', _28 => _28.signal])
295
+ (value) => _chunkLA5F5KR6cjs.zCreateProjectResponse.parse(value),
296
+ { [_chunkLA5F5KR6cjs.ORG_KEY_HEADER]: auth.orgKey },
297
+ _optionalChain([init, 'optionalAccess', _30 => _30.signal])
264
298
  );
265
299
  },
266
300
  rotateServerClientSecret(projectId, clientId, auth, init) {
267
301
  return send(
268
302
  "POST",
269
- _chunkATPS4UV6cjs.CONTROL_API_PATHS.clientRotate(projectId, clientId),
303
+ _chunkLA5F5KR6cjs.CONTROL_API_PATHS.clientRotate(projectId, clientId),
270
304
  {},
271
- (value) => _chunkATPS4UV6cjs.zRotateClientSecretResponse.parse(value),
272
- { [_chunkATPS4UV6cjs.ORG_KEY_HEADER]: auth.orgKey },
273
- _optionalChain([init, 'optionalAccess', _29 => _29.signal])
305
+ (value) => _chunkLA5F5KR6cjs.zRotateClientSecretResponse.parse(value),
306
+ { [_chunkLA5F5KR6cjs.ORG_KEY_HEADER]: auth.orgKey },
307
+ _optionalChain([init, 'optionalAccess', _31 => _31.signal])
274
308
  );
275
309
  },
276
310
  deleteProject(projectId, input, auth, init) {
277
311
  return send(
278
312
  "DELETE",
279
- _chunkATPS4UV6cjs.CONTROL_API_PATHS.project(projectId),
313
+ _chunkLA5F5KR6cjs.CONTROL_API_PATHS.project(projectId),
280
314
  input,
281
- (value) => _chunkATPS4UV6cjs.zDeleteProjectResponse.parse(value),
282
- { [_chunkATPS4UV6cjs.ORG_KEY_HEADER]: auth.orgKey },
283
- _optionalChain([init, 'optionalAccess', _30 => _30.signal])
315
+ (value) => _chunkLA5F5KR6cjs.zDeleteProjectResponse.parse(value),
316
+ { [_chunkLA5F5KR6cjs.ORG_KEY_HEADER]: auth.orgKey },
317
+ _optionalChain([init, 'optionalAccess', _32 => _32.signal])
318
+ );
319
+ },
320
+ upsertEventMeta(projectId, name, input, auth, init) {
321
+ return send(
322
+ "PUT",
323
+ _chunkLA5F5KR6cjs.CONTROL_API_PATHS.projectEvent(projectId, name),
324
+ input,
325
+ (value) => _chunkLA5F5KR6cjs.zEventMetaResponse.parse(value),
326
+ { [_chunkLA5F5KR6cjs.ORG_KEY_HEADER]: auth.orgKey },
327
+ _optionalChain([init, 'optionalAccess', _33 => _33.signal])
284
328
  );
285
329
  }
286
330
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/eric/reopt-ai/reopt-data/packages/data-contract/dist/client.cjs","../src/client.ts"],"names":[],"mappings":"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","file":"/Users/eric/reopt-ai/reopt-data/packages/data-contract/dist/client.cjs","sourcesContent":[null,"/**\n * `createDataClient` — typed fetch over the ingest and query planes.\n *\n * Deliberately stateless: no queue, no buffer, no background flush. Batch\n * assembly and cursor management belong to the caller (a forwarder already has\n * a cursor and byte-batching; duplicating that here would give it two).\n *\n * Every response is parsed with the contract schema, so a server that drifts\n * from the contract surfaces as `contract_mismatch` instead of quietly\n * returning something the caller then mis-reads.\n */\nimport {\n CLIENT_ID_HEADER,\n CLIENT_SECRET_HEADER,\n CONTRACT_VERSION,\n DataApiError,\n REQUEST_ID_HEADER,\n type OptionalClientCredentials,\n} from \"./index.js\";\nimport { zIngestResponse, type IngestResponse, type ITrackHandlerPayload } from \"./ingest.js\";\nimport {\n CONTROL_API_PATHS,\n ORG_KEY_HEADER,\n PLATFORM_KEY_HEADER,\n zCreateOrganizationResponse,\n zCreateProjectResponse,\n zDeleteProjectResponse,\n zRotateClientSecretResponse,\n zRotateOrganizationKeyResponse,\n zUpdateOrganizationQuotaResponse,\n type CreateOrganizationInput,\n type CreateOrganizationResponse,\n type CreateProjectInput,\n type CreateProjectResponse,\n type DeleteProjectInput,\n type DeleteProjectResponse,\n type RotateClientSecretResponse,\n type RotateOrganizationKeyResponse,\n type UpdateOrganizationQuotaInput,\n type UpdateOrganizationQuotaResponse,\n} from \"./control.js\";\nimport {\n QUERY_API_PATHS,\n zEventsTimeseriesResponse,\n zFunnelResponse,\n zRetentionResponse,\n type EventsTimeseriesInput,\n type EventsTimeseriesResponse,\n type FunnelInput,\n type FunnelResponse,\n type RetentionInput,\n type RetentionResponse,\n} from \"./query.js\";\n\nconst TRACK_PATH = \"/api/track\";\n\nexport interface DataClientRetryOptions {\n /** Attempts after the first. Only 429 and 5xx are retried. Default 2. */\n maxRetries?: number;\n /** First backoff step; doubles each attempt, with jitter. Default 500ms. */\n baseDelayMs?: number;\n /** Cap on a single backoff step. Default 20s. */\n maxDelayMs?: number;\n /** Prefer the server's `Retry-After` over the computed backoff. Default true. */\n respectRetryAfter?: boolean;\n}\n\nexport interface DataClientOptions extends OptionalClientCredentials {\n /** Origin of the reopt-data deployment, e.g. `https://data.reopt.app`. Trailing slash ignored. */\n baseUrl: string;\n /** Injected so callers can pass a framework-instrumented fetch. Defaults to `globalThis.fetch`. */\n fetch?: typeof globalThis.fetch;\n /** Per-attempt timeout. Default 10s. */\n timeoutMs?: number;\n retry?: DataClientRetryOptions;\n /** Appended to the default `reopt-data-contract/<version>`. */\n userAgent?: string;\n}\n\nexport interface DataRequestInit {\n signal?: AbortSignal;\n}\n\n/**\n * Provisioning credentials are passed per call rather than held on the client,\n * because they are a different authority from the client credential the rest of\n * the surface uses — and because a long-lived object holding the platform key\n * is a wider blast radius than a value the caller reads at the moment it needs\n * it.\n */\nexport interface PlatformAuth {\n platformKey: string;\n}\n\nexport interface OrganizationAuth {\n orgKey: string;\n}\n\nexport interface DataClient {\n ingest: {\n /**\n * `POST /api/track`. Send events as one batch; splitting to stay under\n * the 512KB body cap is the caller's job, since only the caller knows how\n * to resume a partially-sent range.\n */\n track(events: ITrackHandlerPayload[], init?: DataRequestInit): Promise<IngestResponse>;\n };\n query: {\n eventsTimeseries(input: EventsTimeseriesInput, init?: DataRequestInit): Promise<EventsTimeseriesResponse>;\n funnel(input: FunnelInput, init?: DataRequestInit): Promise<FunnelResponse>;\n retention(input: RetentionInput, init?: DataRequestInit): Promise<RetentionResponse>;\n };\n control: {\n /** Idempotent on `externalId`. `orgKey` comes back only on first creation. */\n createOrganization(\n input: CreateOrganizationInput,\n auth: PlatformAuth,\n init?: DataRequestInit\n ): Promise<CreateOrganizationResponse>;\n /** Issues a new key and revokes every previous one. The recovery path for a lost key. */\n rotateOrgKey(\n organizationId: string,\n auth: PlatformAuth,\n init?: DataRequestInit\n ): Promise<RotateOrganizationKeyResponse>;\n updateOrganizationQuota(\n organizationId: string,\n input: UpdateOrganizationQuotaInput,\n auth: PlatformAuth,\n init?: DataRequestInit\n ): Promise<UpdateOrganizationQuotaResponse>;\n /** Idempotent on `externalId`. `clientSecret` comes back only on first creation. */\n createProject(\n input: CreateProjectInput,\n auth: OrganizationAuth,\n init?: DataRequestInit\n ): Promise<CreateProjectResponse>;\n rotateServerClientSecret(\n projectId: string,\n clientId: string,\n auth: OrganizationAuth,\n init?: DataRequestInit\n ): Promise<RotateClientSecretResponse>;\n /** Irreversible. Idempotent: a project that is already gone still answers 202. */\n deleteProject(\n projectId: string,\n input: DeleteProjectInput,\n auth: OrganizationAuth,\n init?: DataRequestInit\n ): Promise<DeleteProjectResponse>;\n };\n}\n\nconst DEFAULTS = {\n timeoutMs: 10_000,\n maxRetries: 2,\n baseDelayMs: 500,\n maxDelayMs: 20_000,\n} as const;\n\nfunction normalizeBaseUrl(baseUrl: string): string {\n return baseUrl.replace(/\\/+$/, \"\");\n}\n\n/** `Retry-After` is either delta-seconds or an HTTP date; both are legal. */\nfunction parseRetryAfter(header: string | null): number | undefined {\n if (!header) return undefined;\n\n const seconds = Number(header);\n if (Number.isFinite(seconds) && seconds >= 0) return Math.round(seconds * 1000);\n\n const at = Date.parse(header);\n if (Number.isFinite(at)) return Math.max(0, at - Date.now());\n\n return undefined;\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason ?? new Error(\"Aborted\"));\n return;\n }\n const timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal?.reason ?? new Error(\"Aborted\"));\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nfunction backoffDelay(attempt: number, retry: Required<DataClientRetryOptions>): number {\n const exponential = retry.baseDelayMs * 2 ** attempt;\n const capped = Math.min(exponential, retry.maxDelayMs);\n // Full jitter — a fleet of forwarders that all got 429 should not all come\n // back at the same instant.\n return Math.round(capped * (0.5 + Math.random() * 0.5));\n}\n\n/**\n * Body of a non-2xx response. Both planes share `{ status, code, error, ... }`,\n * so one reader covers them; anything else is reported as `internal_error`\n * with the raw text kept in `details`.\n */\nfunction toApiError(\n status: number,\n rawBody: string,\n retryAfterMs: number | undefined,\n requestId?: string\n): DataApiError {\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawBody);\n } catch {\n return new DataApiError({\n message: `reopt-data responded ${status} with a non-JSON body`,\n status,\n code: status >= 500 ? \"internal_error\" : \"unknown_error\",\n requestId,\n retryAfterMs,\n details: rawBody.slice(0, 2000),\n });\n }\n\n const body = (parsed ?? {}) as Record<string, unknown>;\n const code = typeof body.code === \"string\" ? body.code : status >= 500 ? \"internal_error\" : \"unknown_error\";\n const message =\n (typeof body.message === \"string\" && body.message) ||\n (typeof body.error === \"string\" && body.error) ||\n `reopt-data responded ${status}`;\n\n return new DataApiError({\n message,\n status,\n code,\n requestId: (typeof body.requestId === \"string\" ? body.requestId : undefined) ?? requestId,\n retryAfterMs,\n details: body.errors ?? undefined,\n });\n}\n\nexport function createDataClient(options: DataClientOptions): DataClient {\n const baseUrl = normalizeBaseUrl(options.baseUrl);\n const doFetch = options.fetch ?? globalThis.fetch;\n if (typeof doFetch !== \"function\") {\n throw new TypeError(\"createDataClient: no fetch implementation available — pass options.fetch\");\n }\n\n const timeoutMs = options.timeoutMs ?? DEFAULTS.timeoutMs;\n const retry: Required<DataClientRetryOptions> = {\n maxRetries: options.retry?.maxRetries ?? DEFAULTS.maxRetries,\n baseDelayMs: options.retry?.baseDelayMs ?? DEFAULTS.baseDelayMs,\n maxDelayMs: options.retry?.maxDelayMs ?? DEFAULTS.maxDelayMs,\n respectRetryAfter: options.retry?.respectRetryAfter ?? true,\n };\n\n const userAgent = options.userAgent\n ? `reopt-data-contract/${CONTRACT_VERSION} ${options.userAgent}`\n : `reopt-data-contract/${CONTRACT_VERSION}`;\n\n /**\n * Client credentials, or a clear failure. The ingest and query planes cannot\n * run without them; the provisioning plane never uses them.\n */\n function requireClientCredentials(): { clientId: string; clientSecret: string } {\n if (!options.clientId || !options.clientSecret) {\n throw new DataApiError({\n message:\n \"createDataClient was given no client credentials — pass clientId and clientSecret to use the ingest or query planes\",\n status: 0,\n code: \"credentials_missing\",\n });\n }\n return { clientId: options.clientId, clientSecret: options.clientSecret };\n }\n\n async function requestOnce(\n method: \"POST\" | \"PATCH\" | \"DELETE\",\n path: string,\n body: unknown,\n extraHeaders: Record<string, string>,\n signal?: AbortSignal\n ): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(\n () => controller.abort(new Error(`reopt-data request timed out after ${timeoutMs}ms`)),\n timeoutMs\n );\n const onCallerAbort = () => controller.abort(signal?.reason ?? new Error(\"Aborted\"));\n signal?.addEventListener(\"abort\", onCallerAbort, { once: true });\n\n try {\n return await doFetch(`${baseUrl}${path}`, {\n method,\n headers: {\n \"content-type\": \"application/json\",\n \"user-agent\": userAgent,\n ...(options.clientId && options.clientSecret\n ? { [CLIENT_ID_HEADER]: options.clientId, [CLIENT_SECRET_HEADER]: options.clientSecret }\n : {}),\n ...extraHeaders,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n signal?.removeEventListener(\"abort\", onCallerAbort);\n }\n }\n\n async function send<T>(\n method: \"POST\" | \"PATCH\" | \"DELETE\",\n path: string,\n body: unknown,\n parse: (value: unknown) => T,\n extraHeaders: Record<string, string> = {},\n signal?: AbortSignal\n ): Promise<T> {\n let lastError: DataApiError | undefined;\n\n for (let attempt = 0; attempt <= retry.maxRetries; attempt++) {\n let response: Response;\n try {\n response = await requestOnce(method, path, body, extraHeaders, signal);\n } catch (cause) {\n // A caller-initiated abort is not a transport failure — propagate it.\n if (signal?.aborted) throw cause;\n lastError = new DataApiError({\n message: cause instanceof Error ? cause.message : String(cause),\n status: 0,\n code: \"network_error\",\n details: cause,\n });\n if (attempt < retry.maxRetries) {\n await sleep(backoffDelay(attempt, retry), signal);\n continue;\n }\n throw lastError;\n }\n\n const requestId = response.headers.get(REQUEST_ID_HEADER) ?? undefined;\n const rawBody = await response.text();\n\n if (response.ok) {\n let json: unknown;\n try {\n json = JSON.parse(rawBody);\n } catch (cause) {\n throw new DataApiError({\n message: \"reopt-data returned a 2xx with an unparseable body\",\n status: response.status,\n code: \"contract_mismatch\",\n requestId,\n details: cause,\n });\n }\n\n try {\n return parse(json);\n } catch (cause) {\n throw new DataApiError({\n message: \"reopt-data returned a 2xx that does not match the contract\",\n status: response.status,\n code: \"contract_mismatch\",\n requestId,\n details: cause,\n });\n }\n }\n\n const retryAfterMs = retry.respectRetryAfter ? parseRetryAfter(response.headers.get(\"retry-after\")) : undefined;\n lastError = toApiError(response.status, rawBody, retryAfterMs, requestId);\n\n if (!lastError.retryable || attempt === retry.maxRetries) throw lastError;\n await sleep(retryAfterMs ?? backoffDelay(attempt, retry), signal);\n }\n\n /* c8 ignore next -- the loop either returns or throws */\n throw lastError ?? new DataApiError({ message: \"reopt-data request failed\", status: 0, code: \"network_error\" });\n }\n\n /**\n * The ingest and query planes; both require client credentials.\n *\n * `async` so a missing credential rejects rather than throwing\n * synchronously — an async method that sometimes throws before returning a\n * promise slips past every `.catch()` a caller writes.\n */\n async function post<T>(path: string, body: unknown, parse: (value: unknown) => T, signal?: AbortSignal): Promise<T> {\n requireClientCredentials();\n return send(\"POST\", path, body, parse, {}, signal);\n }\n\n return {\n ingest: {\n track(events, init) {\n return post(TRACK_PATH, events, (value) => zIngestResponse.parse(value), init?.signal);\n },\n },\n query: {\n eventsTimeseries(input, init) {\n return post(\n QUERY_API_PATHS.eventsTimeseries,\n input,\n (value) => zEventsTimeseriesResponse.parse(value),\n init?.signal\n );\n },\n funnel(input, init) {\n return post(QUERY_API_PATHS.funnel, input, (value) => zFunnelResponse.parse(value), init?.signal);\n },\n retention(input, init) {\n return post(QUERY_API_PATHS.retention, input, (value) => zRetentionResponse.parse(value), init?.signal);\n },\n },\n control: {\n createOrganization(input, auth, init) {\n return send(\n \"POST\",\n CONTROL_API_PATHS.organizations,\n input,\n (value) => zCreateOrganizationResponse.parse(value),\n { [PLATFORM_KEY_HEADER]: auth.platformKey },\n init?.signal\n );\n },\n rotateOrgKey(organizationId, auth, init) {\n return send(\n \"POST\",\n CONTROL_API_PATHS.organizationKeys(organizationId),\n {},\n (value) => zRotateOrganizationKeyResponse.parse(value),\n { [PLATFORM_KEY_HEADER]: auth.platformKey },\n init?.signal\n );\n },\n updateOrganizationQuota(organizationId, input, auth, init) {\n return send(\n \"PATCH\",\n CONTROL_API_PATHS.organization(organizationId),\n input,\n (value) => zUpdateOrganizationQuotaResponse.parse(value),\n { [PLATFORM_KEY_HEADER]: auth.platformKey },\n init?.signal\n );\n },\n createProject(input, auth, init) {\n return send(\n \"POST\",\n CONTROL_API_PATHS.projects,\n input,\n (value) => zCreateProjectResponse.parse(value),\n { [ORG_KEY_HEADER]: auth.orgKey },\n init?.signal\n );\n },\n rotateServerClientSecret(projectId, clientId, auth, init) {\n return send(\n \"POST\",\n CONTROL_API_PATHS.clientRotate(projectId, clientId),\n {},\n (value) => zRotateClientSecretResponse.parse(value),\n { [ORG_KEY_HEADER]: auth.orgKey },\n init?.signal\n );\n },\n deleteProject(projectId, input, auth, init) {\n return send(\n \"DELETE\",\n CONTROL_API_PATHS.project(projectId),\n input,\n (value) => zDeleteProjectResponse.parse(value),\n { [ORG_KEY_HEADER]: auth.orgKey },\n init?.signal\n );\n },\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["/Users/eric/reopt-ai/reopt-data/packages/data-contract/dist/client.cjs","../src/client.ts"],"names":[],"mappings":"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","file":"/Users/eric/reopt-ai/reopt-data/packages/data-contract/dist/client.cjs","sourcesContent":[null,"/**\n * `createDataClient` — typed fetch over the ingest and query planes.\n *\n * Deliberately stateless: no queue, no buffer, no background flush. Batch\n * assembly and cursor management belong to the caller (a forwarder already has\n * a cursor and byte-batching; duplicating that here would give it two).\n *\n * Every response is parsed with the contract schema, so a server that drifts\n * from the contract surfaces as `contract_mismatch` instead of quietly\n * returning something the caller then mis-reads.\n */\nimport {\n CLIENT_ID_HEADER,\n CLIENT_SECRET_HEADER,\n CONTRACT_VERSION,\n CONTRACT_VERSION_HEADER,\n DataApiError,\n REQUEST_ID_HEADER,\n type OptionalClientCredentials,\n} from \"./index.js\";\nimport { zIngestResponse, type IngestResponse, type ITrackHandlerPayload } from \"./ingest.js\";\nimport {\n CONTROL_API_PATHS,\n ORG_KEY_HEADER,\n PLATFORM_KEY_HEADER,\n zCreateOrganizationResponse,\n zCreateProjectResponse,\n zDeleteProjectResponse,\n zRotateClientSecretResponse,\n zRotateOrganizationKeyResponse,\n zUpdateOrganizationQuotaResponse,\n zEventMetaResponse,\n type CreateOrganizationInput,\n type EventMetaResponse,\n type UpsertEventMetaInput,\n type CreateOrganizationResponse,\n type CreateProjectInput,\n type CreateProjectResponse,\n type DeleteProjectInput,\n type DeleteProjectResponse,\n type RotateClientSecretResponse,\n type RotateOrganizationKeyResponse,\n type UpdateOrganizationQuotaInput,\n type UpdateOrganizationQuotaResponse,\n} from \"./control.js\";\nimport {\n QUERY_API_PATHS,\n zEventsTimeseriesResponse,\n zFunnelResponse,\n zRetentionResponse,\n zTrafficOverviewResponse,\n zTrafficSourcesResponse,\n type EventsTimeseriesInput,\n type EventsTimeseriesResponse,\n type FunnelInput,\n type FunnelResponse,\n type RetentionInput,\n type RetentionResponse,\n type TrafficOverviewInput,\n type TrafficOverviewResponse,\n type TrafficSourcesInput,\n type TrafficSourcesResponse,\n} from \"./query.js\";\n\nconst TRACK_PATH = \"/api/track\";\n\nexport interface DataClientRetryOptions {\n /** Attempts after the first. Only 429 and 5xx are retried. Default 2. */\n maxRetries?: number;\n /** First backoff step; doubles each attempt, with jitter. Default 500ms. */\n baseDelayMs?: number;\n /** Cap on a single backoff step. Default 20s. */\n maxDelayMs?: number;\n /** Prefer the server's `Retry-After` over the computed backoff. Default true. */\n respectRetryAfter?: boolean;\n}\n\nexport interface DataClientOptions extends OptionalClientCredentials {\n /** Origin of the reopt-data deployment, e.g. `https://data.reopt.app`. Trailing slash ignored. */\n baseUrl: string;\n /** Injected so callers can pass a framework-instrumented fetch. Defaults to `globalThis.fetch`. */\n fetch?: typeof globalThis.fetch;\n /** Per-attempt timeout. Default 10s. */\n timeoutMs?: number;\n retry?: DataClientRetryOptions;\n /** Appended to the default `reopt-data-contract/<version>`. */\n userAgent?: string;\n}\n\nexport interface DataRequestInit {\n signal?: AbortSignal;\n}\n\n/**\n * Provisioning credentials are passed per call rather than held on the client,\n * because they are a different authority from the client credential the rest of\n * the surface uses — and because a long-lived object holding the platform key\n * is a wider blast radius than a value the caller reads at the moment it needs\n * it.\n */\nexport interface PlatformAuth {\n platformKey: string;\n}\n\nexport interface OrganizationAuth {\n orgKey: string;\n}\n\nexport interface DataClient {\n ingest: {\n /**\n * `POST /api/track`. Send events as one batch; splitting to stay under\n * the 512KB body cap is the caller's job, since only the caller knows how\n * to resume a partially-sent range.\n */\n track(events: ITrackHandlerPayload[], init?: DataRequestInit): Promise<IngestResponse>;\n };\n query: {\n eventsTimeseries(input: EventsTimeseriesInput, init?: DataRequestInit): Promise<EventsTimeseriesResponse>;\n funnel(input: FunnelInput, init?: DataRequestInit): Promise<FunnelResponse>;\n retention(input: RetentionInput, init?: DataRequestInit): Promise<RetentionResponse>;\n trafficOverview(input: TrafficOverviewInput, init?: DataRequestInit): Promise<TrafficOverviewResponse>;\n trafficSources(input: TrafficSourcesInput, init?: DataRequestInit): Promise<TrafficSourcesResponse>;\n };\n control: {\n /** Idempotent on `externalId`. `orgKey` comes back only on first creation. */\n createOrganization(\n input: CreateOrganizationInput,\n auth: PlatformAuth,\n init?: DataRequestInit\n ): Promise<CreateOrganizationResponse>;\n /** Issues a new key and revokes every previous one. The recovery path for a lost key. */\n rotateOrgKey(\n organizationId: string,\n auth: PlatformAuth,\n init?: DataRequestInit\n ): Promise<RotateOrganizationKeyResponse>;\n updateOrganizationQuota(\n organizationId: string,\n input: UpdateOrganizationQuotaInput,\n auth: PlatformAuth,\n init?: DataRequestInit\n ): Promise<UpdateOrganizationQuotaResponse>;\n /** Idempotent on `externalId`. `clientSecret` comes back only on first creation. */\n createProject(\n input: CreateProjectInput,\n auth: OrganizationAuth,\n init?: DataRequestInit\n ): Promise<CreateProjectResponse>;\n rotateServerClientSecret(\n projectId: string,\n clientId: string,\n auth: OrganizationAuth,\n init?: DataRequestInit\n ): Promise<RotateClientSecretResponse>;\n /** Irreversible. Idempotent: a project that is already gone still answers 202. */\n deleteProject(\n projectId: string,\n input: DeleteProjectInput,\n auth: OrganizationAuth,\n init?: DataRequestInit\n ): Promise<DeleteProjectResponse>;\n /** Idempotent: a repeat with the same body changes nothing and answers 200. */\n upsertEventMeta(\n projectId: string,\n name: string,\n input: UpsertEventMetaInput,\n auth: OrganizationAuth,\n init?: DataRequestInit\n ): Promise<EventMetaResponse>;\n };\n}\n\nconst DEFAULTS = {\n timeoutMs: 10_000,\n maxRetries: 2,\n baseDelayMs: 500,\n maxDelayMs: 20_000,\n} as const;\n\nfunction normalizeBaseUrl(baseUrl: string): string {\n return baseUrl.replace(/\\/+$/, \"\");\n}\n\n/** `Retry-After` is either delta-seconds or an HTTP date; both are legal. */\nfunction parseRetryAfter(header: string | null): number | undefined {\n if (!header) return undefined;\n\n const seconds = Number(header);\n if (Number.isFinite(seconds) && seconds >= 0) return Math.round(seconds * 1000);\n\n const at = Date.parse(header);\n if (Number.isFinite(at)) return Math.max(0, at - Date.now());\n\n return undefined;\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason ?? new Error(\"Aborted\"));\n return;\n }\n const timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal?.reason ?? new Error(\"Aborted\"));\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nfunction backoffDelay(attempt: number, retry: Required<DataClientRetryOptions>): number {\n const exponential = retry.baseDelayMs * 2 ** attempt;\n const capped = Math.min(exponential, retry.maxDelayMs);\n // Full jitter — a fleet of forwarders that all got 429 should not all come\n // back at the same instant.\n return Math.round(capped * (0.5 + Math.random() * 0.5));\n}\n\n/**\n * Body of a non-2xx response. Both planes share `{ status, code, error, ... }`,\n * so one reader covers them; anything else is reported as `internal_error`\n * with the raw text kept in `details`.\n */\nfunction toApiError(\n status: number,\n rawBody: string,\n retryAfterMs: number | undefined,\n requestId?: string\n): DataApiError {\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawBody);\n } catch {\n return new DataApiError({\n message: `reopt-data responded ${status} with a non-JSON body`,\n status,\n code: status >= 500 ? \"internal_error\" : \"unknown_error\",\n requestId,\n retryAfterMs,\n details: rawBody.slice(0, 2000),\n });\n }\n\n const body = (parsed ?? {}) as Record<string, unknown>;\n const code = typeof body.code === \"string\" ? body.code : status >= 500 ? \"internal_error\" : \"unknown_error\";\n const message =\n (typeof body.message === \"string\" && body.message) ||\n (typeof body.error === \"string\" && body.error) ||\n `reopt-data responded ${status}`;\n\n return new DataApiError({\n message,\n status,\n code,\n requestId: (typeof body.requestId === \"string\" ? body.requestId : undefined) ?? requestId,\n retryAfterMs,\n details: body.errors ?? undefined,\n });\n}\n\nexport function createDataClient(options: DataClientOptions): DataClient {\n const baseUrl = normalizeBaseUrl(options.baseUrl);\n const doFetch = options.fetch ?? globalThis.fetch;\n if (typeof doFetch !== \"function\") {\n throw new TypeError(\"createDataClient: no fetch implementation available — pass options.fetch\");\n }\n\n const timeoutMs = options.timeoutMs ?? DEFAULTS.timeoutMs;\n const retry: Required<DataClientRetryOptions> = {\n maxRetries: options.retry?.maxRetries ?? DEFAULTS.maxRetries,\n baseDelayMs: options.retry?.baseDelayMs ?? DEFAULTS.baseDelayMs,\n maxDelayMs: options.retry?.maxDelayMs ?? DEFAULTS.maxDelayMs,\n respectRetryAfter: options.retry?.respectRetryAfter ?? true,\n };\n\n const userAgent = options.userAgent\n ? `reopt-data-contract/${CONTRACT_VERSION} ${options.userAgent}`\n : `reopt-data-contract/${CONTRACT_VERSION}`;\n\n /**\n * Client credentials, or a clear failure. The ingest and query planes cannot\n * run without them; the provisioning plane never uses them.\n */\n function requireClientCredentials(): { clientId: string; clientSecret: string } {\n if (!options.clientId || !options.clientSecret) {\n throw new DataApiError({\n message:\n \"createDataClient was given no client credentials — pass clientId and clientSecret to use the ingest or query planes\",\n status: 0,\n code: \"credentials_missing\",\n });\n }\n return { clientId: options.clientId, clientSecret: options.clientSecret };\n }\n\n async function requestOnce(\n method: \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\",\n path: string,\n body: unknown,\n extraHeaders: Record<string, string>,\n signal?: AbortSignal\n ): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(\n () => controller.abort(new Error(`reopt-data request timed out after ${timeoutMs}ms`)),\n timeoutMs\n );\n const onCallerAbort = () => controller.abort(signal?.reason ?? new Error(\"Aborted\"));\n signal?.addEventListener(\"abort\", onCallerAbort, { once: true });\n\n try {\n return await doFetch(`${baseUrl}${path}`, {\n method,\n headers: {\n \"content-type\": \"application/json\",\n \"user-agent\": userAgent,\n ...(options.clientId && options.clientSecret\n ? { [CLIENT_ID_HEADER]: options.clientId, [CLIENT_SECRET_HEADER]: options.clientSecret }\n : {}),\n ...extraHeaders,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n signal?.removeEventListener(\"abort\", onCallerAbort);\n }\n }\n\n async function send<T>(\n method: \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\",\n path: string,\n body: unknown,\n parse: (value: unknown) => T,\n extraHeaders: Record<string, string> = {},\n signal?: AbortSignal\n ): Promise<T> {\n let lastError: DataApiError | undefined;\n\n for (let attempt = 0; attempt <= retry.maxRetries; attempt++) {\n let response: Response;\n try {\n response = await requestOnce(method, path, body, extraHeaders, signal);\n } catch (cause) {\n // A caller-initiated abort is not a transport failure — propagate it.\n if (signal?.aborted) throw cause;\n lastError = new DataApiError({\n message: cause instanceof Error ? cause.message : String(cause),\n status: 0,\n code: \"network_error\",\n details: cause,\n });\n if (attempt < retry.maxRetries) {\n await sleep(backoffDelay(attempt, retry), signal);\n continue;\n }\n throw lastError;\n }\n\n const requestId = response.headers.get(REQUEST_ID_HEADER) ?? undefined;\n const serverContractVersion = response.headers.get(CONTRACT_VERSION_HEADER);\n const rawBody = await response.text();\n\n if (serverContractVersion !== CONTRACT_VERSION) {\n throw new DataApiError({\n message: serverContractVersion\n ? `reopt-data contract ${serverContractVersion} does not match client contract ${CONTRACT_VERSION}`\n : \"reopt-data response did not declare its contract version\",\n status: response.status,\n code: \"contract_mismatch\",\n requestId,\n details: { expected: CONTRACT_VERSION, received: serverContractVersion },\n });\n }\n\n if (response.ok) {\n let json: unknown;\n try {\n json = JSON.parse(rawBody);\n } catch (cause) {\n throw new DataApiError({\n message: \"reopt-data returned a 2xx with an unparseable body\",\n status: response.status,\n code: \"contract_mismatch\",\n requestId,\n details: cause,\n });\n }\n\n try {\n return parse(json);\n } catch (cause) {\n throw new DataApiError({\n message: \"reopt-data returned a 2xx that does not match the contract\",\n status: response.status,\n code: \"contract_mismatch\",\n requestId,\n details: cause,\n });\n }\n }\n\n const retryAfterMs = retry.respectRetryAfter ? parseRetryAfter(response.headers.get(\"retry-after\")) : undefined;\n lastError = toApiError(response.status, rawBody, retryAfterMs, requestId);\n\n if (!lastError.retryable || attempt === retry.maxRetries) throw lastError;\n await sleep(retryAfterMs ?? backoffDelay(attempt, retry), signal);\n }\n\n /* c8 ignore next -- the loop either returns or throws */\n throw lastError ?? new DataApiError({ message: \"reopt-data request failed\", status: 0, code: \"network_error\" });\n }\n\n /**\n * The ingest and query planes; both require client credentials.\n *\n * `async` so a missing credential rejects rather than throwing\n * synchronously — an async method that sometimes throws before returning a\n * promise slips past every `.catch()` a caller writes.\n */\n async function post<T>(path: string, body: unknown, parse: (value: unknown) => T, signal?: AbortSignal): Promise<T> {\n requireClientCredentials();\n return send(\"POST\", path, body, parse, {}, signal);\n }\n\n return {\n ingest: {\n track(events, init) {\n return post(TRACK_PATH, events, (value) => zIngestResponse.parse(value), init?.signal);\n },\n },\n query: {\n eventsTimeseries(input, init) {\n return post(\n QUERY_API_PATHS.eventsTimeseries,\n input,\n (value) => zEventsTimeseriesResponse.parse(value),\n init?.signal\n );\n },\n funnel(input, init) {\n return post(QUERY_API_PATHS.funnel, input, (value) => zFunnelResponse.parse(value), init?.signal);\n },\n retention(input, init) {\n return post(QUERY_API_PATHS.retention, input, (value) => zRetentionResponse.parse(value), init?.signal);\n },\n trafficOverview(input, init) {\n return post(\n QUERY_API_PATHS.trafficOverview,\n input,\n (value) => zTrafficOverviewResponse.parse(value),\n init?.signal\n );\n },\n trafficSources(input, init) {\n return post(\n QUERY_API_PATHS.trafficSources,\n input,\n (value) => zTrafficSourcesResponse.parse(value),\n init?.signal\n );\n },\n },\n control: {\n createOrganization(input, auth, init) {\n return send(\n \"POST\",\n CONTROL_API_PATHS.organizations,\n input,\n (value) => zCreateOrganizationResponse.parse(value),\n { [PLATFORM_KEY_HEADER]: auth.platformKey },\n init?.signal\n );\n },\n rotateOrgKey(organizationId, auth, init) {\n return send(\n \"POST\",\n CONTROL_API_PATHS.organizationKeys(organizationId),\n {},\n (value) => zRotateOrganizationKeyResponse.parse(value),\n { [PLATFORM_KEY_HEADER]: auth.platformKey },\n init?.signal\n );\n },\n updateOrganizationQuota(organizationId, input, auth, init) {\n return send(\n \"PATCH\",\n CONTROL_API_PATHS.organization(organizationId),\n input,\n (value) => zUpdateOrganizationQuotaResponse.parse(value),\n { [PLATFORM_KEY_HEADER]: auth.platformKey },\n init?.signal\n );\n },\n createProject(input, auth, init) {\n return send(\n \"POST\",\n CONTROL_API_PATHS.projects,\n input,\n (value) => zCreateProjectResponse.parse(value),\n { [ORG_KEY_HEADER]: auth.orgKey },\n init?.signal\n );\n },\n rotateServerClientSecret(projectId, clientId, auth, init) {\n return send(\n \"POST\",\n CONTROL_API_PATHS.clientRotate(projectId, clientId),\n {},\n (value) => zRotateClientSecretResponse.parse(value),\n { [ORG_KEY_HEADER]: auth.orgKey },\n init?.signal\n );\n },\n deleteProject(projectId, input, auth, init) {\n return send(\n \"DELETE\",\n CONTROL_API_PATHS.project(projectId),\n input,\n (value) => zDeleteProjectResponse.parse(value),\n { [ORG_KEY_HEADER]: auth.orgKey },\n init?.signal\n );\n },\n upsertEventMeta(projectId, name, input, auth, init) {\n return send(\n \"PUT\",\n CONTROL_API_PATHS.projectEvent(projectId, name),\n input,\n (value) => zEventMetaResponse.parse(value),\n { [ORG_KEY_HEADER]: auth.orgKey },\n init?.signal\n );\n },\n },\n };\n}\n"]}
package/dist/client.d.cts CHANGED
@@ -1,8 +1,10 @@
1
1
  import { OptionalClientCredentials } from './index.cjs';
2
2
  import { ITrackHandlerPayload, IngestResponse } from './ingest.cjs';
3
- import { CreateOrganizationInput, CreateOrganizationResponse, RotateOrganizationKeyResponse, UpdateOrganizationQuotaInput, UpdateOrganizationQuotaResponse, CreateProjectInput, CreateProjectResponse, RotateClientSecretResponse, DeleteProjectInput, DeleteProjectResponse } from './control.cjs';
4
- import { EventsTimeseriesInput, EventsTimeseriesResponse, FunnelInput, FunnelResponse, RetentionInput, RetentionResponse } from './query.cjs';
3
+ import { CreateOrganizationInput, CreateOrganizationResponse, RotateOrganizationKeyResponse, UpdateOrganizationQuotaInput, UpdateOrganizationQuotaResponse, CreateProjectInput, CreateProjectResponse, RotateClientSecretResponse, DeleteProjectInput, DeleteProjectResponse, UpsertEventMetaInput, EventMetaResponse } from './control.cjs';
4
+ import { EventsTimeseriesInput, EventsTimeseriesResponse, FunnelInput, FunnelResponse, RetentionInput, RetentionResponse, TrafficOverviewInput, TrafficOverviewResponse, TrafficSourcesInput, TrafficSourcesResponse } from './query.cjs';
5
5
  import 'zod';
6
+ import './version-CC4_BBvq.cjs';
7
+ import './events.cjs';
6
8
 
7
9
  /**
8
10
  * `createDataClient` — typed fetch over the ingest and query planes.
@@ -66,6 +68,8 @@ interface DataClient {
66
68
  eventsTimeseries(input: EventsTimeseriesInput, init?: DataRequestInit): Promise<EventsTimeseriesResponse>;
67
69
  funnel(input: FunnelInput, init?: DataRequestInit): Promise<FunnelResponse>;
68
70
  retention(input: RetentionInput, init?: DataRequestInit): Promise<RetentionResponse>;
71
+ trafficOverview(input: TrafficOverviewInput, init?: DataRequestInit): Promise<TrafficOverviewResponse>;
72
+ trafficSources(input: TrafficSourcesInput, init?: DataRequestInit): Promise<TrafficSourcesResponse>;
69
73
  };
70
74
  control: {
71
75
  /** Idempotent on `externalId`. `orgKey` comes back only on first creation. */
@@ -78,6 +82,8 @@ interface DataClient {
78
82
  rotateServerClientSecret(projectId: string, clientId: string, auth: OrganizationAuth, init?: DataRequestInit): Promise<RotateClientSecretResponse>;
79
83
  /** Irreversible. Idempotent: a project that is already gone still answers 202. */
80
84
  deleteProject(projectId: string, input: DeleteProjectInput, auth: OrganizationAuth, init?: DataRequestInit): Promise<DeleteProjectResponse>;
85
+ /** Idempotent: a repeat with the same body changes nothing and answers 200. */
86
+ upsertEventMeta(projectId: string, name: string, input: UpsertEventMetaInput, auth: OrganizationAuth, init?: DataRequestInit): Promise<EventMetaResponse>;
81
87
  };
82
88
  }
83
89
  declare function createDataClient(options: DataClientOptions): DataClient;
package/dist/client.d.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import { OptionalClientCredentials } from './index.js';
2
2
  import { ITrackHandlerPayload, IngestResponse } from './ingest.js';
3
- import { CreateOrganizationInput, CreateOrganizationResponse, RotateOrganizationKeyResponse, UpdateOrganizationQuotaInput, UpdateOrganizationQuotaResponse, CreateProjectInput, CreateProjectResponse, RotateClientSecretResponse, DeleteProjectInput, DeleteProjectResponse } from './control.js';
4
- import { EventsTimeseriesInput, EventsTimeseriesResponse, FunnelInput, FunnelResponse, RetentionInput, RetentionResponse } from './query.js';
3
+ import { CreateOrganizationInput, CreateOrganizationResponse, RotateOrganizationKeyResponse, UpdateOrganizationQuotaInput, UpdateOrganizationQuotaResponse, CreateProjectInput, CreateProjectResponse, RotateClientSecretResponse, DeleteProjectInput, DeleteProjectResponse, UpsertEventMetaInput, EventMetaResponse } from './control.js';
4
+ import { EventsTimeseriesInput, EventsTimeseriesResponse, FunnelInput, FunnelResponse, RetentionInput, RetentionResponse, TrafficOverviewInput, TrafficOverviewResponse, TrafficSourcesInput, TrafficSourcesResponse } from './query.js';
5
5
  import 'zod';
6
+ import './version-CC4_BBvq.js';
7
+ import './events.js';
6
8
 
7
9
  /**
8
10
  * `createDataClient` — typed fetch over the ingest and query planes.
@@ -66,6 +68,8 @@ interface DataClient {
66
68
  eventsTimeseries(input: EventsTimeseriesInput, init?: DataRequestInit): Promise<EventsTimeseriesResponse>;
67
69
  funnel(input: FunnelInput, init?: DataRequestInit): Promise<FunnelResponse>;
68
70
  retention(input: RetentionInput, init?: DataRequestInit): Promise<RetentionResponse>;
71
+ trafficOverview(input: TrafficOverviewInput, init?: DataRequestInit): Promise<TrafficOverviewResponse>;
72
+ trafficSources(input: TrafficSourcesInput, init?: DataRequestInit): Promise<TrafficSourcesResponse>;
69
73
  };
70
74
  control: {
71
75
  /** Idempotent on `externalId`. `orgKey` comes back only on first creation. */
@@ -78,6 +82,8 @@ interface DataClient {
78
82
  rotateServerClientSecret(projectId: string, clientId: string, auth: OrganizationAuth, init?: DataRequestInit): Promise<RotateClientSecretResponse>;
79
83
  /** Irreversible. Idempotent: a project that is already gone still answers 202. */
80
84
  deleteProject(projectId: string, input: DeleteProjectInput, auth: OrganizationAuth, init?: DataRequestInit): Promise<DeleteProjectResponse>;
85
+ /** Idempotent: a repeat with the same body changes nothing and answers 200. */
86
+ upsertEventMeta(projectId: string, name: string, input: UpsertEventMetaInput, auth: OrganizationAuth, init?: DataRequestInit): Promise<EventMetaResponse>;
81
87
  };
82
88
  }
83
89
  declare function createDataClient(options: DataClientOptions): DataClient;
package/dist/client.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  zIngestResponse
3
- } from "./chunk-3A7WZ7L6.js";
3
+ } from "./chunk-5BRCHDS3.js";
4
4
  import {
5
5
  CONTROL_API_PATHS,
6
6
  ORG_KEY_HEADER,
@@ -8,23 +8,31 @@ import {
8
8
  zCreateOrganizationResponse,
9
9
  zCreateProjectResponse,
10
10
  zDeleteProjectResponse,
11
+ zEventMetaResponse,
11
12
  zRotateClientSecretResponse,
12
13
  zRotateOrganizationKeyResponse,
13
14
  zUpdateOrganizationQuotaResponse
14
- } from "./chunk-J4VD3TLV.js";
15
+ } from "./chunk-IY4MXH35.js";
15
16
  import {
16
17
  QUERY_API_PATHS,
17
18
  zEventsTimeseriesResponse,
18
19
  zFunnelResponse,
19
- zRetentionResponse
20
- } from "./chunk-55IWO4S3.js";
20
+ zRetentionResponse,
21
+ zTrafficOverviewResponse,
22
+ zTrafficSourcesResponse
23
+ } from "./chunk-L3WJGIKD.js";
24
+ import {
25
+ DataApiError
26
+ } from "./chunk-33BCA2LH.js";
27
+ import "./chunk-6ZJOC4NJ.js";
21
28
  import {
22
29
  CLIENT_ID_HEADER,
23
30
  CLIENT_SECRET_HEADER,
24
31
  CONTRACT_VERSION,
25
- DataApiError,
32
+ CONTRACT_VERSION_HEADER,
26
33
  REQUEST_ID_HEADER
27
- } from "./chunk-2LJ7JLDX.js";
34
+ } from "./chunk-IXPP5K4I.js";
35
+ import "./chunk-FP2X3PRK.js";
28
36
 
29
37
  // src/client.ts
30
38
  var TRACK_PATH = "/api/track";
@@ -163,7 +171,17 @@ function createDataClient(options) {
163
171
  throw lastError;
164
172
  }
165
173
  const requestId = response.headers.get(REQUEST_ID_HEADER) ?? void 0;
174
+ const serverContractVersion = response.headers.get(CONTRACT_VERSION_HEADER);
166
175
  const rawBody = await response.text();
176
+ if (serverContractVersion !== CONTRACT_VERSION) {
177
+ throw new DataApiError({
178
+ message: serverContractVersion ? `reopt-data contract ${serverContractVersion} does not match client contract ${CONTRACT_VERSION}` : "reopt-data response did not declare its contract version",
179
+ status: response.status,
180
+ code: "contract_mismatch",
181
+ requestId,
182
+ details: { expected: CONTRACT_VERSION, received: serverContractVersion }
183
+ });
184
+ }
167
185
  if (response.ok) {
168
186
  let json;
169
187
  try {
@@ -220,6 +238,22 @@ function createDataClient(options) {
220
238
  },
221
239
  retention(input, init) {
222
240
  return post(QUERY_API_PATHS.retention, input, (value) => zRetentionResponse.parse(value), init?.signal);
241
+ },
242
+ trafficOverview(input, init) {
243
+ return post(
244
+ QUERY_API_PATHS.trafficOverview,
245
+ input,
246
+ (value) => zTrafficOverviewResponse.parse(value),
247
+ init?.signal
248
+ );
249
+ },
250
+ trafficSources(input, init) {
251
+ return post(
252
+ QUERY_API_PATHS.trafficSources,
253
+ input,
254
+ (value) => zTrafficSourcesResponse.parse(value),
255
+ init?.signal
256
+ );
223
257
  }
224
258
  },
225
259
  control: {
@@ -282,6 +316,16 @@ function createDataClient(options) {
282
316
  { [ORG_KEY_HEADER]: auth.orgKey },
283
317
  init?.signal
284
318
  );
319
+ },
320
+ upsertEventMeta(projectId, name, input, auth, init) {
321
+ return send(
322
+ "PUT",
323
+ CONTROL_API_PATHS.projectEvent(projectId, name),
324
+ input,
325
+ (value) => zEventMetaResponse.parse(value),
326
+ { [ORG_KEY_HEADER]: auth.orgKey },
327
+ init?.signal
328
+ );
285
329
  }
286
330
  }
287
331
  };