@reopt-ai/data-contract 0.6.3 → 0.7.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 (103) hide show
  1. package/dist/client.cjs +228 -321
  2. package/dist/client.cjs.map +1 -1
  3. package/dist/client.d.cts +57 -71
  4. package/dist/client.d.cts.map +1 -0
  5. package/dist/client.d.ts +57 -71
  6. package/dist/client.d.ts.map +1 -0
  7. package/dist/client.js +228 -322
  8. package/dist/client.js.map +1 -1
  9. package/dist/control.cjs +158 -54
  10. package/dist/control.cjs.map +1 -1
  11. package/dist/control.d.cts +121 -137
  12. package/dist/control.d.cts.map +1 -0
  13. package/dist/control.d.ts +121 -137
  14. package/dist/control.d.ts.map +1 -0
  15. package/dist/control.js +134 -54
  16. package/dist/control.js.map +1 -1
  17. package/dist/events-BUIeU60t.d.cts +142 -0
  18. package/dist/events-BUIeU60t.d.cts.map +1 -0
  19. package/dist/events-BUIeU60t.d.ts +142 -0
  20. package/dist/events-BUIeU60t.d.ts.map +1 -0
  21. package/dist/events.cjs +110 -15
  22. package/dist/events.cjs.map +1 -1
  23. package/dist/events.d.cts +2 -59
  24. package/dist/events.d.ts +2 -59
  25. package/dist/events.js +101 -15
  26. package/dist/events.js.map +1 -1
  27. package/dist/identity.cjs +150 -55
  28. package/dist/identity.cjs.map +1 -1
  29. package/dist/identity.d.cts +21 -20
  30. package/dist/identity.d.cts.map +1 -0
  31. package/dist/identity.d.ts +21 -20
  32. package/dist/identity.d.ts.map +1 -0
  33. package/dist/identity.js +126 -56
  34. package/dist/identity.js.map +1 -1
  35. package/dist/index.cjs +46 -25
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.d.cts +37 -54
  38. package/dist/index.d.cts.map +1 -0
  39. package/dist/index.d.ts +37 -54
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +36 -25
  42. package/dist/index.js.map +1 -1
  43. package/dist/ingest.cjs +152 -57
  44. package/dist/ingest.cjs.map +1 -1
  45. package/dist/ingest.d.cts +182 -193
  46. package/dist/ingest.d.cts.map +1 -0
  47. package/dist/ingest.d.ts +182 -193
  48. package/dist/ingest.d.ts.map +1 -0
  49. package/dist/ingest.js +126 -57
  50. package/dist/ingest.js.map +1 -1
  51. package/dist/query.cjs +284 -84
  52. package/dist/query.cjs.map +1 -1
  53. package/dist/query.d.cts +456 -469
  54. package/dist/query.d.cts.map +1 -0
  55. package/dist/query.d.ts +456 -469
  56. package/dist/query.d.ts.map +1 -0
  57. package/dist/query.js +245 -84
  58. package/dist/query.js.map +1 -1
  59. package/dist/report.cjs +104 -74
  60. package/dist/report.cjs.map +1 -1
  61. package/dist/report.d.cts +182 -136
  62. package/dist/report.d.cts.map +1 -0
  63. package/dist/report.d.ts +182 -136
  64. package/dist/report.d.ts.map +1 -0
  65. package/dist/report.js +93 -74
  66. package/dist/report.js.map +1 -1
  67. package/dist/version-B_0qb1_K.cjs +53 -0
  68. package/dist/version-B_0qb1_K.cjs.map +1 -0
  69. package/dist/version-C09Cyf4R.js +12 -0
  70. package/dist/version-C09Cyf4R.js.map +1 -0
  71. package/dist/{version-DJ2Grb_N.d.ts → version-CGujUGWd.d.cts} +5 -3
  72. package/dist/version-CGujUGWd.d.cts.map +1 -0
  73. package/dist/{version-DJ2Grb_N.d.cts → version-CGujUGWd.d.ts} +5 -3
  74. package/dist/version-CGujUGWd.d.ts.map +1 -0
  75. package/package.json +69 -28
  76. package/dist/chunk-3EEANNYN.cjs +0 -62
  77. package/dist/chunk-3EEANNYN.cjs.map +0 -1
  78. package/dist/chunk-7W33YGRO.js +0 -160
  79. package/dist/chunk-7W33YGRO.js.map +0 -1
  80. package/dist/chunk-F2RNXJGO.cjs +0 -19
  81. package/dist/chunk-F2RNXJGO.cjs.map +0 -1
  82. package/dist/chunk-FP2X3PRK.js +0 -62
  83. package/dist/chunk-FP2X3PRK.js.map +0 -1
  84. package/dist/chunk-JCEWUSUM.js +0 -53
  85. package/dist/chunk-JCEWUSUM.js.map +0 -1
  86. package/dist/chunk-L3JPDRVG.cjs +0 -160
  87. package/dist/chunk-L3JPDRVG.cjs.map +0 -1
  88. package/dist/chunk-L4KBQAOO.js +0 -204
  89. package/dist/chunk-L4KBQAOO.js.map +0 -1
  90. package/dist/chunk-NJ4JKNBX.js +0 -361
  91. package/dist/chunk-NJ4JKNBX.js.map +0 -1
  92. package/dist/chunk-ORNTN6AK.cjs +0 -53
  93. package/dist/chunk-ORNTN6AK.cjs.map +0 -1
  94. package/dist/chunk-PSUINLW7.js +0 -19
  95. package/dist/chunk-PSUINLW7.js.map +0 -1
  96. package/dist/chunk-RU26QFM2.js +0 -179
  97. package/dist/chunk-RU26QFM2.js.map +0 -1
  98. package/dist/chunk-XDH5QQYF.cjs +0 -361
  99. package/dist/chunk-XDH5QQYF.cjs.map +0 -1
  100. package/dist/chunk-YCTGHWTP.cjs +0 -204
  101. package/dist/chunk-YCTGHWTP.cjs.map +0 -1
  102. package/dist/chunk-ZI6A3WQP.cjs +0 -179
  103. package/dist/chunk-ZI6A3WQP.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"sourcesContent":["/**\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 | undefined;\n /** First backoff step; doubles each attempt, with jitter. Default 500ms. */\n baseDelayMs?: number | undefined;\n /** Cap on a single backoff step. Default 20s. */\n maxDelayMs?: number | undefined;\n /** Prefer the server's `Retry-After` over the computed backoff. Default true. */\n respectRetryAfter?: boolean | undefined;\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 | undefined;\n /** Per-attempt timeout. Default 10s. */\n timeoutMs?: number | undefined;\n retry?: DataClientRetryOptions | undefined;\n /** Appended to the default `reopt-data-contract/<version>`. */\n userAgent?: string | undefined;\n}\n\nexport interface DataRequestInit {\n signal?: AbortSignal | undefined;\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\n/**\n * Every option filled in.\n *\n * Not `Required<T>`: that strips the `?` but keeps the `| undefined` the\n * property declares — which the option types now do, so that callers with\n * `exactOptionalPropertyTypes` can pass a value that may be absent. The whole\n * point of a resolved config is that nothing is absent any more.\n */\ntype Resolved<T> = { [K in keyof T]-?: Exclude<T[K], undefined> };\n\nfunction backoffDelay(attempt: number, retry: Resolved<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: Resolved<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"],"mappings":"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","names":[]}
1
+ {"version":3,"file":"client.js","names":[],"sources":["../src/client.ts"],"sourcesContent":["/**\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 | undefined;\n /** First backoff step; doubles each attempt, with jitter. Default 500ms. */\n baseDelayMs?: number | undefined;\n /** Cap on a single backoff step. Default 20s. */\n maxDelayMs?: number | undefined;\n /** Prefer the server's `Retry-After` over the computed backoff. Default true. */\n respectRetryAfter?: boolean | undefined;\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 | undefined;\n /** Per-attempt timeout. Default 10s. */\n timeoutMs?: number | undefined;\n retry?: DataClientRetryOptions | undefined;\n /** Appended to the default `reopt-data-contract/<version>`. */\n userAgent?: string | undefined;\n}\n\nexport interface DataRequestInit {\n signal?: AbortSignal | undefined;\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\n/**\n * Every option filled in.\n *\n * Not `Required<T>`: that strips the `?` but keeps the `| undefined` the\n * property declares — which the option types now do, so that callers with\n * `exactOptionalPropertyTypes` can pass a value that may be absent. The whole\n * point of a resolved config is that nothing is absent any more.\n */\ntype Resolved<T> = { [K in keyof T]-?: Exclude<T[K], undefined> };\n\nfunction backoffDelay(attempt: number, retry: Resolved<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: Resolved<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"],"mappings":"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"}
package/dist/control.cjs CHANGED
@@ -1,56 +1,160 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_index = require("./index.cjs");
3
+ const require_query = require("./query.cjs");
4
+ let zod = require("zod");
5
+ //#region src/control.ts
6
+ const PLATFORM_KEY_HEADER = "reopt-platform-key";
7
+ const ORG_KEY_HEADER = "reopt-org-key";
8
+ const zExternalId = zod.z.string().min(1).max(191);
9
+ const zCreateOrganizationInput = zod.z.object({
10
+ externalId: zExternalId,
11
+ name: zod.z.string().min(1).max(200),
12
+ slug: zod.z.string().min(1).max(100).regex(/^[a-z0-9-]+$/, "lowercase letters, digits and hyphens only").optional(),
13
+ monthlyEventQuota: zod.z.number().int().nonnegative().optional(),
14
+ monthlyCreditQuota: zod.z.number().int().nonnegative().optional()
15
+ });
16
+ const zOrganization = zod.z.object({
17
+ id: zod.z.string(),
18
+ externalId: zExternalId,
19
+ name: zod.z.string(),
20
+ slug: zod.z.string(),
21
+ monthlyEventQuota: zod.z.number().int(),
22
+ monthlyCreditQuota: zod.z.number().int()
23
+ });
24
+ const zCreateOrganizationResponse = zod.z.object({
25
+ created: zod.z.boolean(),
26
+ organization: zOrganization,
27
+ orgKey: zod.z.string().optional()
28
+ });
29
+ const zRotateOrganizationKeyResponse = zod.z.object({
30
+ organizationId: zod.z.string(),
31
+ keyPrefix: zod.z.string(),
32
+ orgKey: zod.z.string()
33
+ });
34
+ const zUpdateOrganizationQuotaInput = zod.z.object({
35
+ monthlyEventQuota: zod.z.number().int().nonnegative().optional(),
36
+ monthlyCreditQuota: zod.z.number().int().nonnegative().optional()
37
+ }).refine((value) => value.monthlyEventQuota !== void 0 || value.monthlyCreditQuota !== void 0, { message: "at least one quota must be given" });
38
+ const zUpdateOrganizationQuotaResponse = zod.z.object({ organization: zOrganization });
39
+ const zCreateProjectInput = zod.z.object({
40
+ externalId: zExternalId,
41
+ name: zod.z.string().min(1).max(200),
42
+ domain: zod.z.string().max(253).optional(),
43
+ timezone: require_query.zTimezone.optional(),
44
+ retentionDays: zod.z.number().int().min(1).max(3650).optional()
45
+ });
46
+ const zProject = zod.z.object({
47
+ id: zod.z.string(),
48
+ externalId: zExternalId,
49
+ organizationId: zod.z.string(),
50
+ name: zod.z.string(),
51
+ timezone: zod.z.string(),
52
+ retentionDays: zod.z.number().int().nullable()
53
+ });
54
+ const zCreateProjectResponse = zod.z.object({
55
+ created: zod.z.boolean(),
56
+ project: zProject,
57
+ clients: zod.z.object({
58
+ browser: zod.z.object({
59
+ id: zod.z.string(),
60
+ writeKey: zod.z.string(),
61
+ scopes: zod.z.array(zod.z.string())
62
+ }),
63
+ server: zod.z.object({
64
+ id: zod.z.string(),
65
+ clientSecret: zod.z.string().optional(),
66
+ scopes: zod.z.array(zod.z.string())
67
+ })
68
+ })
69
+ });
70
+ const zRotateClientSecretResponse = zod.z.object({
71
+ projectId: zod.z.string(),
72
+ clientId: zod.z.string(),
73
+ clientSecret: zod.z.string()
74
+ });
75
+ const zDeleteProjectInput = zod.z.object({
76
+ purge: zod.z.literal(true),
77
+ externalId: zExternalId
78
+ });
79
+ const zDeleteProjectResponse = zod.z.object({
80
+ projectId: zod.z.string(),
81
+ purge: zod.z.enum(["queued", "already-absent"]),
82
+ purgingAt: require_index.zInstant.optional()
83
+ });
84
+ const EVENT_META_STATUSES = [
85
+ "active",
86
+ "deprecated",
87
+ "archived",
88
+ "internal"
89
+ ];
90
+ const zEventMetaStatus = zod.z.enum(EVENT_META_STATUSES);
91
+ const zEventName = zod.z.string().min(1).max(200);
92
+ const zUpsertEventMetaInput = zod.z.object({
93
+ conversion: zod.z.boolean().optional(),
94
+ status: zEventMetaStatus.optional(),
95
+ rollupProperties: zod.z.array(zod.z.string().min(1).max(200)).max(20).optional()
96
+ }).strict();
97
+ const zEventMetaResponse = zod.z.object({
98
+ projectId: zod.z.string(),
99
+ name: zod.z.string(),
100
+ conversion: zod.z.boolean(),
101
+ status: zEventMetaStatus,
102
+ rollupProperties: zod.z.array(zod.z.string()),
103
+ changed: zod.z.array(zod.z.string()),
104
+ updatedAt: require_index.zInstant
105
+ });
106
+ const CONTROL_ERROR_CODES = [
107
+ "unauthorized",
108
+ "organization_scope_mismatch",
109
+ "external_id_conflict",
110
+ "project_external_id_mismatch",
111
+ "not_found",
112
+ "validation_failed",
113
+ "rate_limited",
114
+ "internal_error"
115
+ ];
116
+ const zControlErrorCode = zod.z.enum(CONTROL_ERROR_CODES);
117
+ const zControlError = zod.z.object({
118
+ status: zod.z.number().int(),
119
+ code: zControlErrorCode,
120
+ error: zod.z.string(),
121
+ message: zod.z.string().optional(),
122
+ errors: zod.z.unknown().optional(),
123
+ requestId: zod.z.string().optional()
124
+ });
125
+ const CONTROL_API_PATHS = {
126
+ organizations: "/api/v1/organizations",
127
+ organization: (id) => `/api/v1/organizations/${encodeURIComponent(id)}`,
128
+ organizationKeys: (id) => `/api/v1/organizations/${encodeURIComponent(id)}/keys`,
129
+ projects: "/api/v1/projects",
130
+ project: (id) => `/api/v1/projects/${encodeURIComponent(id)}`,
131
+ clientRotate: (projectId, clientId) => `/api/v1/projects/${encodeURIComponent(projectId)}/clients/${encodeURIComponent(clientId)}/rotate`,
132
+ projectEvent: (projectId, name) => `/api/v1/projects/${encodeURIComponent(projectId)}/events/${encodeURIComponent(name)}`
133
+ };
134
+ //#endregion
135
+ exports.CONTROL_API_PATHS = CONTROL_API_PATHS;
136
+ exports.CONTROL_ERROR_CODES = CONTROL_ERROR_CODES;
137
+ exports.EVENT_META_STATUSES = EVENT_META_STATUSES;
138
+ exports.ORG_KEY_HEADER = ORG_KEY_HEADER;
139
+ exports.PLATFORM_KEY_HEADER = PLATFORM_KEY_HEADER;
140
+ exports.zControlError = zControlError;
141
+ exports.zControlErrorCode = zControlErrorCode;
142
+ exports.zCreateOrganizationInput = zCreateOrganizationInput;
143
+ exports.zCreateOrganizationResponse = zCreateOrganizationResponse;
144
+ exports.zCreateProjectInput = zCreateProjectInput;
145
+ exports.zCreateProjectResponse = zCreateProjectResponse;
146
+ exports.zDeleteProjectInput = zDeleteProjectInput;
147
+ exports.zDeleteProjectResponse = zDeleteProjectResponse;
148
+ exports.zEventMetaResponse = zEventMetaResponse;
149
+ exports.zEventMetaStatus = zEventMetaStatus;
150
+ exports.zEventName = zEventName;
151
+ exports.zExternalId = zExternalId;
152
+ exports.zOrganization = zOrganization;
153
+ exports.zProject = zProject;
154
+ exports.zRotateClientSecretResponse = zRotateClientSecretResponse;
155
+ exports.zRotateOrganizationKeyResponse = zRotateOrganizationKeyResponse;
156
+ exports.zUpdateOrganizationQuotaInput = zUpdateOrganizationQuotaInput;
157
+ exports.zUpdateOrganizationQuotaResponse = zUpdateOrganizationQuotaResponse;
158
+ exports.zUpsertEventMetaInput = zUpsertEventMetaInput;
2
159
 
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
- var _chunkYCTGHWTPcjs = require('./chunk-YCTGHWTP.cjs');
27
- require('./chunk-XDH5QQYF.cjs');
28
- require('./chunk-ORNTN6AK.cjs');
29
- require('./chunk-F2RNXJGO.cjs');
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
- exports.CONTROL_API_PATHS = _chunkYCTGHWTPcjs.CONTROL_API_PATHS; exports.CONTROL_ERROR_CODES = _chunkYCTGHWTPcjs.CONTROL_ERROR_CODES; exports.EVENT_META_STATUSES = _chunkYCTGHWTPcjs.EVENT_META_STATUSES; exports.ORG_KEY_HEADER = _chunkYCTGHWTPcjs.ORG_KEY_HEADER; exports.PLATFORM_KEY_HEADER = _chunkYCTGHWTPcjs.PLATFORM_KEY_HEADER; exports.zControlError = _chunkYCTGHWTPcjs.zControlError; exports.zControlErrorCode = _chunkYCTGHWTPcjs.zControlErrorCode; exports.zCreateOrganizationInput = _chunkYCTGHWTPcjs.zCreateOrganizationInput; exports.zCreateOrganizationResponse = _chunkYCTGHWTPcjs.zCreateOrganizationResponse; exports.zCreateProjectInput = _chunkYCTGHWTPcjs.zCreateProjectInput; exports.zCreateProjectResponse = _chunkYCTGHWTPcjs.zCreateProjectResponse; exports.zDeleteProjectInput = _chunkYCTGHWTPcjs.zDeleteProjectInput; exports.zDeleteProjectResponse = _chunkYCTGHWTPcjs.zDeleteProjectResponse; exports.zEventMetaResponse = _chunkYCTGHWTPcjs.zEventMetaResponse; exports.zEventMetaStatus = _chunkYCTGHWTPcjs.zEventMetaStatus; exports.zEventName = _chunkYCTGHWTPcjs.zEventName; exports.zExternalId = _chunkYCTGHWTPcjs.zExternalId; exports.zOrganization = _chunkYCTGHWTPcjs.zOrganization; exports.zProject = _chunkYCTGHWTPcjs.zProject; exports.zRotateClientSecretResponse = _chunkYCTGHWTPcjs.zRotateClientSecretResponse; exports.zRotateOrganizationKeyResponse = _chunkYCTGHWTPcjs.zRotateOrganizationKeyResponse; exports.zUpdateOrganizationQuotaInput = _chunkYCTGHWTPcjs.zUpdateOrganizationQuotaInput; exports.zUpdateOrganizationQuotaResponse = _chunkYCTGHWTPcjs.zUpdateOrganizationQuotaResponse; exports.zUpsertEventMetaInput = _chunkYCTGHWTPcjs.zUpsertEventMetaInput;
56
160
  //# sourceMappingURL=control.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/eric/reopt-ai/reopt-data/packages/data-contract/dist/control.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,2oDAAC","file":"/Users/eric/reopt-ai/reopt-data/packages/data-contract/dist/control.cjs"}
1
+ {"version":3,"file":"control.cjs","names":["z","zTimezone","zInstant"],"sources":["../src/control.ts"],"sourcesContent":["/**\n * `POST /api/v1/organizations` · `/api/v1/projects` and friends — the\n * provisioning contract.\n *\n * A project-scoped client credential cannot authenticate the creation of the\n * project it is scoped to, and an organization key cannot authenticate the\n * creation of its own organization. So provisioning runs on two credentials\n * above the client one: a platform key that creates organizations and writes\n * quotas, and an organization key that creates and deletes projects inside one\n * organization.\n *\n * Quota writes sit with the platform key on purpose. Organization keys are held\n * one-per-workspace by the caller and so have a wide exposure surface; a leaked\n * one that could raise its own limits would turn a credential leak into an\n * unbounded bill.\n */\nimport { z } from \"zod\";\nimport { zInstant } from \"./index.js\";\nimport { zTimezone } from \"./query.js\";\n\nexport const PLATFORM_KEY_HEADER = \"reopt-platform-key\";\nexport const ORG_KEY_HEADER = \"reopt-org-key\";\n\n/**\n * The caller's own id for the thing being provisioned.\n *\n * Preferred over an `Idempotency-Key` header because this domain has a real\n * natural key — the caller already has a stable id for the workspace or brand —\n * and a header would make the caller store a second one just to retry safely.\n */\nexport const zExternalId = z.string().min(1).max(191);\n\n// ─── Organizations ──────────────────────────────────────────────────────────\n\nexport const zCreateOrganizationInput = z.object({\n externalId: zExternalId,\n name: z.string().min(1).max(200),\n slug: z\n .string()\n .min(1)\n .max(100)\n .regex(/^[a-z0-9-]+$/, \"lowercase letters, digits and hyphens only\")\n .optional(),\n monthlyEventQuota: z.number().int().nonnegative().optional(),\n monthlyCreditQuota: z.number().int().nonnegative().optional(),\n});\nexport type CreateOrganizationInput = z.input<typeof zCreateOrganizationInput>;\n\nexport const zOrganization = z.object({\n id: z.string(),\n externalId: zExternalId,\n name: z.string(),\n slug: z.string(),\n monthlyEventQuota: z.number().int(),\n monthlyCreditQuota: z.number().int(),\n});\n\nexport const zCreateOrganizationResponse = z.object({\n /** `false` when this externalId already had an organization. */\n created: z.boolean(),\n organization: zOrganization,\n /**\n * Plaintext, returned here and nowhere else.\n *\n * Absent when `created` is `false`: re-issuing on every retry would let a\n * retry quietly multiply live credentials. A caller that lost the key rotates\n * instead — see `POST /api/v1/organizations/{id}/keys`.\n */\n orgKey: z.string().optional(),\n});\nexport type CreateOrganizationResponse = z.infer<typeof zCreateOrganizationResponse>;\n\nexport const zRotateOrganizationKeyResponse = z.object({\n organizationId: z.string(),\n keyPrefix: z.string(),\n /** Plaintext, returned once. Every previously issued key is revoked immediately. */\n orgKey: z.string(),\n});\nexport type RotateOrganizationKeyResponse = z.infer<typeof zRotateOrganizationKeyResponse>;\n\nexport const zUpdateOrganizationQuotaInput = z\n .object({\n monthlyEventQuota: z.number().int().nonnegative().optional(),\n monthlyCreditQuota: z.number().int().nonnegative().optional(),\n })\n .refine((value) => value.monthlyEventQuota !== undefined || value.monthlyCreditQuota !== undefined, {\n message: \"at least one quota must be given\",\n });\nexport type UpdateOrganizationQuotaInput = z.input<typeof zUpdateOrganizationQuotaInput>;\n\nexport const zUpdateOrganizationQuotaResponse = z.object({ organization: zOrganization });\nexport type UpdateOrganizationQuotaResponse = z.infer<typeof zUpdateOrganizationQuotaResponse>;\n\n// ─── Projects ───────────────────────────────────────────────────────────────\n\nexport const zCreateProjectInput = z.object({\n externalId: zExternalId,\n name: z.string().min(1).max(200),\n domain: z.string().max(253).optional(),\n /** Becomes the project's default for every query that omits one. */\n timezone: zTimezone.optional(),\n retentionDays: z.number().int().min(1).max(3650).optional(),\n});\nexport type CreateProjectInput = z.input<typeof zCreateProjectInput>;\n\nexport const zProject = z.object({\n id: z.string(),\n externalId: zExternalId,\n organizationId: z.string(),\n name: z.string(),\n /** The applied value — `\"UTC\"` when none was given. */\n timezone: z.string(),\n retentionDays: z.number().int().nullable(),\n});\n\nexport const zCreateProjectResponse = z.object({\n created: z.boolean(),\n project: zProject,\n /**\n * Two credentials, not one. A key embedded in a browser bundle must not also\n * be able to read the project's analytics, so the browser write key and the\n * server secret are separate rows with different reach.\n */\n clients: z.object({\n browser: z.object({\n id: z.string(),\n /** Public by design, and recoverable — it ships in page source anyway. */\n writeKey: z.string(),\n scopes: z.array(z.string()),\n }),\n server: z.object({\n id: z.string(),\n /** Plaintext, returned once. Absent when `created` is `false`. */\n clientSecret: z.string().optional(),\n scopes: z.array(z.string()),\n }),\n }),\n});\nexport type CreateProjectResponse = z.infer<typeof zCreateProjectResponse>;\n\nexport const zRotateClientSecretResponse = z.object({\n projectId: z.string(),\n clientId: z.string(),\n /** Plaintext, returned once. The previous secret stops working immediately. */\n clientSecret: z.string(),\n});\nexport type RotateClientSecretResponse = z.infer<typeof zRotateClientSecretResponse>;\n\nexport const zDeleteProjectInput = z.object({\n /**\n * A field in the body rather than `?purge=true`. This deletes the project's\n * Postgres rows and every analytics row behind it, with no undo — and a query\n * parameter is far too easy to fire from shell history or a mis-copied URL.\n */\n purge: z.literal(true),\n /** Checked against the project on record; a mismatch is refused. */\n externalId: zExternalId,\n});\nexport type DeleteProjectInput = z.input<typeof zDeleteProjectInput>;\n\nexport const zDeleteProjectResponse = z.object({\n projectId: z.string(),\n /** Idempotent, but it still says which of the two happened. */\n purge: z.enum([\"queued\", \"already-absent\"]),\n /** When the purge was marked. Absent for `already-absent`. */\n purgingAt: zInstant.optional(),\n});\nexport type DeleteProjectResponse = z.infer<typeof zDeleteProjectResponse>;\n\n// ─── Errors ─────────────────────────────────────────────────────────────────\n\n// ─── Event metadata ─────────────────────────────────────────────────────────\n\n/**\n * `PUT /api/v1/projects/{projectId}/events/{name}` — catalogue settings for\n * one event name. Provisioning calls it to mark `form.submitted` a conversion\n * and an operational probe `internal`; the call is idempotent so a retried\n * provisioning run is harmless.\n */\nexport const EVENT_META_STATUSES = [\"active\", \"deprecated\", \"archived\", \"internal\"] as const;\nexport const zEventMetaStatus = z.enum(EVENT_META_STATUSES);\nexport type EventMetaStatus = z.infer<typeof zEventMetaStatus>;\n\nexport const zEventName = z.string().min(1).max(200);\n\nexport const zUpsertEventMetaInput = z\n .object({\n conversion: z.boolean().optional(),\n /** `internal` events are left out of every metric unless a query opts in. */\n status: zEventMetaStatus.optional(),\n /** Property keys the hourly rollups break this event down by. */\n rollupProperties: z.array(z.string().min(1).max(200)).max(20).optional(),\n })\n .strict();\nexport type UpsertEventMetaInput = z.infer<typeof zUpsertEventMetaInput>;\n\nexport const zEventMetaResponse = z.object({\n projectId: z.string(),\n name: z.string(),\n conversion: z.boolean(),\n status: zEventMetaStatus,\n rollupProperties: z.array(z.string()),\n /** Fields this call actually changed; empty on a repeat. */\n changed: z.array(z.string()),\n updatedAt: zInstant,\n});\nexport type EventMetaResponse = z.infer<typeof zEventMetaResponse>;\n\nexport const CONTROL_ERROR_CODES = [\n /** 401 — missing or invalid platform key / organization key. */\n \"unauthorized\",\n /** 403 — the organization key belongs to a different organization. */\n \"organization_scope_mismatch\",\n /**\n * 409 — this externalId exists with a materially different configuration.\n * Only fields whose change alters results are compared (see the docs); a\n * renamed brand is not a conflict.\n */\n \"external_id_conflict\",\n /** 409 — the externalId in a delete body does not match the project's. */\n \"project_external_id_mismatch\",\n /** 404 — no such organization or project, on an endpoint that is not idempotent. */\n \"not_found\",\n /** 400 — input failed the schema. */\n \"validation_failed\",\n /** 429 — per-credential rate limit. */\n \"rate_limited\",\n /** 500 — unexpected server failure. */\n \"internal_error\",\n] as const;\nexport const zControlErrorCode = z.enum(CONTROL_ERROR_CODES);\nexport type ControlErrorCode = z.infer<typeof zControlErrorCode>;\n\nexport const zControlError = z.object({\n status: z.number().int(),\n code: zControlErrorCode,\n error: z.string(),\n message: z.string().optional(),\n errors: z.unknown().optional(),\n requestId: z.string().optional(),\n});\nexport type ControlError = z.infer<typeof zControlError>;\n\n/** Paths, so the client and the route handlers cannot drift apart. */\nexport const CONTROL_API_PATHS = {\n organizations: \"/api/v1/organizations\",\n organization: (id: string) => `/api/v1/organizations/${encodeURIComponent(id)}`,\n organizationKeys: (id: string) => `/api/v1/organizations/${encodeURIComponent(id)}/keys`,\n projects: \"/api/v1/projects\",\n project: (id: string) => `/api/v1/projects/${encodeURIComponent(id)}`,\n clientRotate: (projectId: string, clientId: string) =>\n `/api/v1/projects/${encodeURIComponent(projectId)}/clients/${encodeURIComponent(clientId)}/rotate`,\n projectEvent: (projectId: string, name: string) =>\n `/api/v1/projects/${encodeURIComponent(projectId)}/events/${encodeURIComponent(name)}`,\n} as const;\n"],"mappings":"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"}