@reopt-ai/data-contract 0.6.2 → 0.6.3
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.
- package/dist/{chunk-FMOKJTQD.js → chunk-7W33YGRO.js} +2 -2
- package/dist/chunk-7W33YGRO.js.map +1 -0
- package/dist/{chunk-AOS53KAV.cjs → chunk-F2RNXJGO.cjs} +2 -2
- package/dist/{chunk-AOS53KAV.cjs.map → chunk-F2RNXJGO.cjs.map} +1 -1
- package/dist/{chunk-33BCA2LH.js → chunk-JCEWUSUM.js} +1 -1
- package/dist/{chunk-33BCA2LH.js.map → chunk-JCEWUSUM.js.map} +1 -1
- package/dist/{chunk-FQSCQSMP.cjs → chunk-L3JPDRVG.cjs} +3 -3
- package/dist/chunk-L3JPDRVG.cjs.map +1 -0
- package/dist/{chunk-IY4MXH35.js → chunk-L4KBQAOO.js} +3 -3
- package/dist/{chunk-L3WJGIKD.js → chunk-NJ4JKNBX.js} +2 -2
- package/dist/{chunk-YSAEOYPD.cjs → chunk-ORNTN6AK.cjs} +1 -1
- package/dist/{chunk-YSAEOYPD.cjs.map → chunk-ORNTN6AK.cjs.map} +1 -1
- package/dist/{chunk-ZCKVMUIQ.js → chunk-PSUINLW7.js} +2 -2
- package/dist/{chunk-ZCKVMUIQ.js.map → chunk-PSUINLW7.js.map} +1 -1
- package/dist/{chunk-DUJSYMYY.js → chunk-RU26QFM2.js} +2 -2
- package/dist/{chunk-FUGY5ANJ.cjs → chunk-XDH5QQYF.cjs} +13 -13
- package/dist/{chunk-FUGY5ANJ.cjs.map → chunk-XDH5QQYF.cjs.map} +1 -1
- package/dist/{chunk-LA5F5KR6.cjs → chunk-YCTGHWTP.cjs} +6 -6
- package/dist/{chunk-LA5F5KR6.cjs.map → chunk-YCTGHWTP.cjs.map} +1 -1
- package/dist/{chunk-BA52YA7N.cjs → chunk-ZI6A3WQP.cjs} +4 -4
- package/dist/{chunk-BA52YA7N.cjs.map → chunk-ZI6A3WQP.cjs.map} +1 -1
- package/dist/client.cjs +51 -51
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +10 -10
- package/dist/client.d.ts +10 -10
- package/dist/client.js +6 -6
- package/dist/client.js.map +1 -1
- package/dist/control.cjs +5 -5
- package/dist/control.d.cts +6 -6
- package/dist/control.d.ts +6 -6
- package/dist/control.js +4 -4
- package/dist/identity.cjs +3 -3
- package/dist/identity.d.cts +3 -3
- package/dist/identity.d.ts +3 -3
- package/dist/identity.js +2 -2
- package/dist/index.cjs +3 -3
- package/dist/index.d.cts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +2 -2
- package/dist/ingest.cjs +4 -4
- package/dist/ingest.d.cts +6 -6
- package/dist/ingest.d.ts +6 -6
- package/dist/ingest.js +3 -3
- package/dist/query.cjs +4 -4
- package/dist/query.d.cts +5 -5
- package/dist/query.d.ts +5 -5
- package/dist/query.js +3 -3
- package/dist/{version-BANKB6Og.d.ts → version-DJ2Grb_N.d.cts} +1 -1
- package/dist/{version-BANKB6Og.d.cts → version-DJ2Grb_N.d.ts} +1 -1
- package/package.json +1 -1
- package/dist/chunk-FMOKJTQD.js.map +0 -1
- package/dist/chunk-FQSCQSMP.cjs.map +0 -1
- /package/dist/{chunk-IY4MXH35.js.map → chunk-L4KBQAOO.js.map} +0 -0
- /package/dist/{chunk-L3WJGIKD.js.map → chunk-NJ4JKNBX.js.map} +0 -0
- /package/dist/{chunk-DUJSYMYY.js.map → chunk-RU26QFM2.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/eric/reopt-ai/reopt-data/packages/data-contract/dist/chunk-LA5F5KR6.cjs","../src/control.ts"],"names":[],"mappings":"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","file":"/Users/eric/reopt-ai/reopt-data/packages/data-contract/dist/chunk-LA5F5KR6.cjs","sourcesContent":[null,"/**\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"]}
|
|
1
|
+
{"version":3,"sources":["/Users/eric/reopt-ai/reopt-data/packages/data-contract/dist/chunk-YCTGHWTP.cjs","../src/control.ts"],"names":[],"mappings":"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","file":"/Users/eric/reopt-ai/reopt-data/packages/data-contract/dist/chunk-YCTGHWTP.cjs","sourcesContent":[null,"/**\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"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkL3JPDRVGcjs = require('./chunk-L3JPDRVG.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var _chunk3EEANNYNcjs = require('./chunk-3EEANNYN.cjs');
|
|
@@ -30,7 +30,7 @@ var zClientEventMetadata = {
|
|
|
30
30
|
* header is authoritative and a body field would be trivially forged.
|
|
31
31
|
* Same character set as every identity id.
|
|
32
32
|
*/
|
|
33
|
-
deviceId: _zod.z.string().regex(
|
|
33
|
+
deviceId: _zod.z.string().regex(_chunkL3JPDRVGcjs.IDENTITY_ID_PATTERN, "expected an identity id").optional()
|
|
34
34
|
};
|
|
35
35
|
var zTrackPayload = _zod.z.object({
|
|
36
36
|
name: _zod.z.string().min(1).max(200),
|
|
@@ -96,7 +96,7 @@ var ingestCounts = {
|
|
|
96
96
|
rejected: _zod.z.array(zIngestRejection)
|
|
97
97
|
};
|
|
98
98
|
var zSessionCredential = _zod.z.object({
|
|
99
|
-
id: _zod.z.string().regex(
|
|
99
|
+
id: _zod.z.string().regex(_chunkL3JPDRVGcjs.IDENTITY_ID_PATTERN),
|
|
100
100
|
token: _zod.z.string().regex(/^[A-Za-z0-9_-]{43}$/)
|
|
101
101
|
});
|
|
102
102
|
var zIngestOkResponse = _zod.z.object({
|
|
@@ -176,4 +176,4 @@ var zIngestError = _zod.z.object({
|
|
|
176
176
|
|
|
177
177
|
|
|
178
178
|
exports.MAX_TRACK_PAYLOAD_BYTES = MAX_TRACK_PAYLOAD_BYTES; exports.zTrackPayload = zTrackPayload; exports.zIdentifyPayload = zIdentifyPayload; exports.zIncrementPayload = zIncrementPayload; exports.zDecrementPayload = zDecrementPayload; exports.zTrackHandlerPayload = zTrackHandlerPayload; exports.INGEST_MODES = INGEST_MODES; exports.zIngestMode = zIngestMode; exports.INGEST_REJECTION_REASONS = INGEST_REJECTION_REASONS; exports.zIngestRejectionReason = zIngestRejectionReason; exports.zIngestRejection = zIngestRejection; exports.zSessionCredential = zSessionCredential; exports.zIngestOkResponse = zIngestOkResponse; exports.zIngestAcceptedResponse = zIngestAcceptedResponse; exports.zIngestResponse = zIngestResponse; exports.reconcileIngestResponse = reconcileIngestResponse; exports.INGEST_ERROR_CODES = INGEST_ERROR_CODES; exports.zIngestErrorCode = zIngestErrorCode; exports.zIngestError = zIngestError;
|
|
179
|
-
//# sourceMappingURL=chunk-
|
|
179
|
+
//# sourceMappingURL=chunk-ZI6A3WQP.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/eric/reopt-ai/reopt-data/packages/data-contract/dist/chunk-BA52YA7N.cjs","../src/ingest.ts"],"names":[],"mappings":"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","file":"/Users/eric/reopt-ai/reopt-data/packages/data-contract/dist/chunk-BA52YA7N.cjs","sourcesContent":[null,"/**\n * `POST /api/track` — the ingest contract.\n *\n * The request shape is shared by both credential modes. The *response* shape\n * is where server-ingest differs: it reports per-event rejections instead of\n * failing a whole batch, because a forwarder that stalls on one malformed row\n * stops forwarding forever.\n *\n * Absorbed from the former internal `@reopt/ingest-contract`; that package is\n * now a deprecated re-export of this module.\n */\nimport { z } from \"zod\";\nimport { IDENTITY_ID_PATTERN } from \"./identity.js\";\n\nexport {\n AUTO_EVENT_NAMES,\n AUTO_EVENT_PROPERTIES,\n AUTO_EVENT_ROLLUP_KEYS,\n RESERVED_EVENT_NAMES,\n SCROLL_DEPTH_BUCKETS,\n scrollDepthBucket,\n type AutoEventName,\n type ScrollDepthBucket,\n} from \"./events.js\";\nimport { RESERVED_EVENT_NAMES } from \"./events.js\";\n\n/** Hard cap enforced by the route before the body is even parsed. */\nexport const MAX_TRACK_PAYLOAD_BYTES = 512_000;\n\nconst zClientEventMetadata = {\n /**\n * Client-generated UUID. This is the project-scoped idempotency key stored as\n * `RawEvent.clientEventId`; the server uses a separate globally unique raw\n * event id internally. Re-sending the same eventId to the same project is\n * always safe and always reported as a duplicate.\n */\n eventId: z.uuid(),\n /** Event time, epoch milliseconds. */\n timestamp: z.number().int().nonnegative(),\n /**\n * The browser device this event belongs to, for events a server records\n * on a visitor's behalf (a form submission, an order). Lets one server\n * batch carry events from many visitors — a forwarder cannot split its\n * batches per device without breaking its failure model and its\n * `accepted + duplicates + rejected === sent` invariant.\n *\n * Honoured in `server` mode only, where it takes precedence over the\n * `reopt-device-id` request header. Ignored in `browser` mode: there the\n * header is authoritative and a body field would be trivially forged.\n * Same character set as every identity id.\n */\n deviceId: z.string().regex(IDENTITY_ID_PATTERN, \"expected an identity id\").optional(),\n};\n\nexport const zTrackPayload = z\n .object({\n name: z.string().min(1).max(200),\n properties: z.record(z.string(), z.unknown()).optional(),\n profileId: z.string().max(500).or(z.number()).optional(),\n })\n .refine((data) => !RESERVED_EVENT_NAMES.includes(data.name as never), {\n message: `Event name cannot be one of the reserved names: ${RESERVED_EVENT_NAMES.join(\", \")}`,\n path: [\"name\"],\n });\n\nexport const zIdentifyPayload = z.object({\n profileId: z.string().min(1).max(500).or(z.number()),\n firstName: z.string().max(200).optional(),\n lastName: z.string().max(200).optional(),\n email: z.email().max(320).optional(),\n avatar: z.url().max(2000).optional(),\n properties: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport const zIncrementPayload = z.object({\n profileId: z.string().min(1).max(500).or(z.number()),\n property: z.string().min(1).max(200),\n value: z.number().positive().optional(),\n});\n\nexport const zDecrementPayload = z.object({\n profileId: z.string().min(1).max(500).or(z.number()),\n property: z.string().min(1).max(200),\n value: z.number().positive().optional(),\n});\n\nexport const zTrackHandlerPayload = z.discriminatedUnion(\"type\", [\n z.object({ type: z.literal(\"track\"), payload: zTrackPayload, ...zClientEventMetadata }),\n z.object({ type: z.literal(\"identify\"), payload: zIdentifyPayload, ...zClientEventMetadata }),\n z.object({ type: z.literal(\"increment\"), payload: zIncrementPayload, ...zClientEventMetadata }),\n z.object({ type: z.literal(\"decrement\"), payload: zDecrementPayload, ...zClientEventMetadata }),\n]);\n\nexport type ITrackPayload = z.infer<typeof zTrackPayload>;\nexport type IIdentifyPayload = z.infer<typeof zIdentifyPayload>;\nexport type IIncrementPayload = z.infer<typeof zIncrementPayload>;\nexport type IDecrementPayload = z.infer<typeof zDecrementPayload>;\nexport type ITrackHandlerPayload = z.infer<typeof zTrackHandlerPayload>;\n\n// ─── Ingest mode ────────────────────────────────────────────────────────────\n\n/**\n * Decided by the credential presented, never by a header the caller sets:\n * `reopt-write-key` alone → `browser`, `reopt-client-id` + `reopt-client-secret`\n * → `server`. A separate mode header could disagree with the credential; this\n * cannot.\n *\n * `browser` keeps the 5-second click dedup and device-scoped sessions.\n * `server` drops both and relies solely on `eventId` idempotency — a server\n * batch legitimately contains the same event name many times within one second,\n * and its \"device\" is a process, not a person.\n */\nexport const INGEST_MODES = [\"browser\", \"server\"] as const;\nexport const zIngestMode = z.enum(INGEST_MODES);\nexport type IngestMode = z.infer<typeof zIngestMode>;\n\n// ─── Response ───────────────────────────────────────────────────────────────\n\n/**\n * Why a single event in a batch was dropped. These are permanent: re-sending\n * the same row produces the same rejection, so a forwarder should count it as\n * skipped and advance its cursor rather than retry.\n */\nexport const INGEST_REJECTION_REASONS = [\n /** Failed the zod schema (bad eventId, missing name, wrong types…). */\n \"validation_failed\",\n /** Used one of RESERVED_EVENT_NAMES. */\n \"reserved_name\",\n /** Another row earlier in the same batch already claimed this eventId. */\n \"duplicate_in_batch\",\n] as const;\nexport const zIngestRejectionReason = z.enum(INGEST_REJECTION_REASONS);\nexport type IngestRejectionReason = z.infer<typeof zIngestRejectionReason>;\n\nexport const zIngestRejection = z.object({\n /** May be absent or malformed on `validation_failed` — hence `string`, not `uuid`. */\n eventId: z.string(),\n /** Position in the submitted batch. The only reliable identifier when eventId itself is bad. */\n index: z.number().int().nonnegative(),\n reason: zIngestRejectionReason,\n message: z.string().optional(),\n});\nexport type IngestRejection = z.infer<typeof zIngestRejection>;\n\nconst ingestCounts = {\n /** Raw events newly persisted by this request. */\n accepted: z.number().int().nonnegative(),\n /**\n * Events the server already had. In `server` mode this is exactly the\n * eventId-idempotency count; in `browser` mode it also includes the\n * 5-second click dedup.\n */\n duplicates: z.number().int().nonnegative(),\n /** Always `[]` in `browser` mode, where a bad row fails the whole batch. */\n rejected: z.array(zIngestRejection),\n};\n\n/**\n * The session ingest filed this batch under, with the token that lets the\n * browser (or a server acting for it) join the same session later with\n * authority — see `signSessionToken` in `./identity`. Browser mode only;\n * absent when the batch carried no sessionable event.\n */\nexport const zSessionCredential = z.object({\n id: z.string().regex(IDENTITY_ID_PATTERN),\n token: z.string().regex(/^[A-Za-z0-9_-]{43}$/),\n});\nexport type SessionCredential = z.infer<typeof zSessionCredential>;\n\n/** 200 — accepted and handed to the materialize queue. */\nexport const zIngestOkResponse = z.object({\n status: z.literal(\"ok\"),\n requestId: z.string(),\n mode: zIngestMode,\n ...ingestCounts,\n queued: z.boolean(),\n session: zSessionCredential.optional(),\n});\n\n/**\n * 202 — raw events landed, but enqueueing the materialize task failed. No data\n * is lost: the `replay-unmaterialized` cron picks these up. A forwarder should\n * treat this as success and advance its cursor. Carries the same counts as 200\n * so the reconciliation below works here too.\n */\nexport const zIngestAcceptedResponse = z.object({\n status: z.literal(\"accepted\"),\n requestId: z.string(),\n mode: zIngestMode,\n ...ingestCounts,\n backgroundQueued: z.literal(false),\n replay: z.literal(\"unmaterialized-raw-events\"),\n session: zSessionCredential.optional(),\n});\n\nexport const zIngestResponse = z.discriminatedUnion(\"status\", [zIngestOkResponse, zIngestAcceptedResponse]);\n\nexport type IngestOkResponse = z.infer<typeof zIngestOkResponse>;\nexport type IngestAcceptedResponse = z.infer<typeof zIngestAcceptedResponse>;\nexport type IngestResponse = z.infer<typeof zIngestResponse>;\n\n/**\n * The reconciliation a forwarder runs on every 2xx:\n *\n * accepted + duplicates + rejected.length === events sent\n *\n * A mismatch means the server silently dropped something, which is exactly the\n * failure mode this contract exists to make impossible to miss.\n */\nexport function reconcileIngestResponse(response: IngestResponse, sentCount: number): boolean {\n return response.accepted + response.duplicates + response.rejected.length === sentCount;\n}\n\n// ─── Errors ─────────────────────────────────────────────────────────────────\n\n/**\n * Stable machine-readable codes. Branch on these, never on `error`/`message`,\n * which are prose and may be reworded.\n */\nexport const INGEST_ERROR_CODES = [\n /** 401 — unknown or mismatched credentials. Stop and alert; do not retry. */\n \"unauthorized\",\n /** 400 — body was not valid JSON. */\n \"invalid_json\",\n /** 400 — request exceeded MAX_TRACK_PAYLOAD_BYTES. Split the batch. */\n \"payload_too_large\",\n /** 400 — zero events submitted. */\n \"empty_batch\",\n /** 400 — batch contained a `type: \"alias\"` event, which is not supported. */\n \"alias_unsupported\",\n /** 400 — the project has no organization; it cannot be billed or quota-checked. */\n \"project_without_organization\",\n /** 400 — `browser` mode only: a row failed validation. `server` mode reports these in `rejected[]`. */\n \"validation_failed\",\n /** 429 — per-project request rate limit. `Retry-After` set. Pause this tick, keep the cursor. */\n \"rate_limited\",\n /** 429 — the organization's monthly event quota is exhausted. `Retry-After` set (capped at 1h). Alert: a human must raise the limit. */\n \"quota_exceeded\",\n /** 410 — the project is being deleted. Permanent; stop sending. */\n \"project_purging\",\n /** 500 — unexpected server failure. Back off and retry. */\n \"internal_error\",\n] as const;\nexport const zIngestErrorCode = z.enum(INGEST_ERROR_CODES);\nexport type IngestErrorCode = z.infer<typeof zIngestErrorCode>;\n\nexport const zIngestError = z.object({\n status: z.number().int(),\n code: zIngestErrorCode,\n error: z.string(),\n message: z.string().optional(),\n /** zod issues, when `code === \"validation_failed\"`. */\n errors: z.unknown().optional(),\n requestId: z.string().optional(),\n});\nexport type IngestError = z.infer<typeof zIngestError>;\n"]}
|
|
1
|
+
{"version":3,"sources":["/Users/eric/reopt-ai/reopt-data/packages/data-contract/dist/chunk-ZI6A3WQP.cjs","../src/ingest.ts"],"names":[],"mappings":"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","file":"/Users/eric/reopt-ai/reopt-data/packages/data-contract/dist/chunk-ZI6A3WQP.cjs","sourcesContent":[null,"/**\n * `POST /api/track` — the ingest contract.\n *\n * The request shape is shared by both credential modes. The *response* shape\n * is where server-ingest differs: it reports per-event rejections instead of\n * failing a whole batch, because a forwarder that stalls on one malformed row\n * stops forwarding forever.\n *\n * Absorbed from the former internal `@reopt/ingest-contract`; that package is\n * now a deprecated re-export of this module.\n */\nimport { z } from \"zod\";\nimport { IDENTITY_ID_PATTERN } from \"./identity.js\";\n\nexport {\n AUTO_EVENT_NAMES,\n AUTO_EVENT_PROPERTIES,\n AUTO_EVENT_ROLLUP_KEYS,\n RESERVED_EVENT_NAMES,\n SCROLL_DEPTH_BUCKETS,\n scrollDepthBucket,\n type AutoEventName,\n type ScrollDepthBucket,\n} from \"./events.js\";\nimport { RESERVED_EVENT_NAMES } from \"./events.js\";\n\n/** Hard cap enforced by the route before the body is even parsed. */\nexport const MAX_TRACK_PAYLOAD_BYTES = 512_000;\n\nconst zClientEventMetadata = {\n /**\n * Client-generated UUID. This is the project-scoped idempotency key stored as\n * `RawEvent.clientEventId`; the server uses a separate globally unique raw\n * event id internally. Re-sending the same eventId to the same project is\n * always safe and always reported as a duplicate.\n */\n eventId: z.uuid(),\n /** Event time, epoch milliseconds. */\n timestamp: z.number().int().nonnegative(),\n /**\n * The browser device this event belongs to, for events a server records\n * on a visitor's behalf (a form submission, an order). Lets one server\n * batch carry events from many visitors — a forwarder cannot split its\n * batches per device without breaking its failure model and its\n * `accepted + duplicates + rejected === sent` invariant.\n *\n * Honoured in `server` mode only, where it takes precedence over the\n * `reopt-device-id` request header. Ignored in `browser` mode: there the\n * header is authoritative and a body field would be trivially forged.\n * Same character set as every identity id.\n */\n deviceId: z.string().regex(IDENTITY_ID_PATTERN, \"expected an identity id\").optional(),\n};\n\nexport const zTrackPayload = z\n .object({\n name: z.string().min(1).max(200),\n properties: z.record(z.string(), z.unknown()).optional(),\n profileId: z.string().max(500).or(z.number()).optional(),\n })\n .refine((data) => !RESERVED_EVENT_NAMES.includes(data.name as never), {\n message: `Event name cannot be one of the reserved names: ${RESERVED_EVENT_NAMES.join(\", \")}`,\n path: [\"name\"],\n });\n\nexport const zIdentifyPayload = z.object({\n profileId: z.string().min(1).max(500).or(z.number()),\n firstName: z.string().max(200).optional(),\n lastName: z.string().max(200).optional(),\n email: z.email().max(320).optional(),\n avatar: z.url().max(2000).optional(),\n properties: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport const zIncrementPayload = z.object({\n profileId: z.string().min(1).max(500).or(z.number()),\n property: z.string().min(1).max(200),\n value: z.number().positive().optional(),\n});\n\nexport const zDecrementPayload = z.object({\n profileId: z.string().min(1).max(500).or(z.number()),\n property: z.string().min(1).max(200),\n value: z.number().positive().optional(),\n});\n\nexport const zTrackHandlerPayload = z.discriminatedUnion(\"type\", [\n z.object({ type: z.literal(\"track\"), payload: zTrackPayload, ...zClientEventMetadata }),\n z.object({ type: z.literal(\"identify\"), payload: zIdentifyPayload, ...zClientEventMetadata }),\n z.object({ type: z.literal(\"increment\"), payload: zIncrementPayload, ...zClientEventMetadata }),\n z.object({ type: z.literal(\"decrement\"), payload: zDecrementPayload, ...zClientEventMetadata }),\n]);\n\nexport type ITrackPayload = z.infer<typeof zTrackPayload>;\nexport type IIdentifyPayload = z.infer<typeof zIdentifyPayload>;\nexport type IIncrementPayload = z.infer<typeof zIncrementPayload>;\nexport type IDecrementPayload = z.infer<typeof zDecrementPayload>;\nexport type ITrackHandlerPayload = z.infer<typeof zTrackHandlerPayload>;\n\n// ─── Ingest mode ────────────────────────────────────────────────────────────\n\n/**\n * Decided by the credential presented, never by a header the caller sets:\n * `reopt-write-key` alone → `browser`, `reopt-client-id` + `reopt-client-secret`\n * → `server`. A separate mode header could disagree with the credential; this\n * cannot.\n *\n * `browser` keeps the 5-second click dedup and device-scoped sessions.\n * `server` drops both and relies solely on `eventId` idempotency — a server\n * batch legitimately contains the same event name many times within one second,\n * and its \"device\" is a process, not a person.\n */\nexport const INGEST_MODES = [\"browser\", \"server\"] as const;\nexport const zIngestMode = z.enum(INGEST_MODES);\nexport type IngestMode = z.infer<typeof zIngestMode>;\n\n// ─── Response ───────────────────────────────────────────────────────────────\n\n/**\n * Why a single event in a batch was dropped. These are permanent: re-sending\n * the same row produces the same rejection, so a forwarder should count it as\n * skipped and advance its cursor rather than retry.\n */\nexport const INGEST_REJECTION_REASONS = [\n /** Failed the zod schema (bad eventId, missing name, wrong types…). */\n \"validation_failed\",\n /** Used one of RESERVED_EVENT_NAMES. */\n \"reserved_name\",\n /** Another row earlier in the same batch already claimed this eventId. */\n \"duplicate_in_batch\",\n] as const;\nexport const zIngestRejectionReason = z.enum(INGEST_REJECTION_REASONS);\nexport type IngestRejectionReason = z.infer<typeof zIngestRejectionReason>;\n\nexport const zIngestRejection = z.object({\n /** May be absent or malformed on `validation_failed` — hence `string`, not `uuid`. */\n eventId: z.string(),\n /** Position in the submitted batch. The only reliable identifier when eventId itself is bad. */\n index: z.number().int().nonnegative(),\n reason: zIngestRejectionReason,\n message: z.string().optional(),\n});\nexport type IngestRejection = z.infer<typeof zIngestRejection>;\n\nconst ingestCounts = {\n /** Raw events newly persisted by this request. */\n accepted: z.number().int().nonnegative(),\n /**\n * Events the server already had. In `server` mode this is exactly the\n * eventId-idempotency count; in `browser` mode it also includes the\n * 5-second click dedup.\n */\n duplicates: z.number().int().nonnegative(),\n /** Always `[]` in `browser` mode, where a bad row fails the whole batch. */\n rejected: z.array(zIngestRejection),\n};\n\n/**\n * The session ingest filed this batch under, with the token that lets the\n * browser (or a server acting for it) join the same session later with\n * authority — see `signSessionToken` in `./identity`. Browser mode only;\n * absent when the batch carried no sessionable event.\n */\nexport const zSessionCredential = z.object({\n id: z.string().regex(IDENTITY_ID_PATTERN),\n token: z.string().regex(/^[A-Za-z0-9_-]{43}$/),\n});\nexport type SessionCredential = z.infer<typeof zSessionCredential>;\n\n/** 200 — accepted and handed to the materialize queue. */\nexport const zIngestOkResponse = z.object({\n status: z.literal(\"ok\"),\n requestId: z.string(),\n mode: zIngestMode,\n ...ingestCounts,\n queued: z.boolean(),\n session: zSessionCredential.optional(),\n});\n\n/**\n * 202 — raw events landed, but enqueueing the materialize task failed. No data\n * is lost: the `replay-unmaterialized` cron picks these up. A forwarder should\n * treat this as success and advance its cursor. Carries the same counts as 200\n * so the reconciliation below works here too.\n */\nexport const zIngestAcceptedResponse = z.object({\n status: z.literal(\"accepted\"),\n requestId: z.string(),\n mode: zIngestMode,\n ...ingestCounts,\n backgroundQueued: z.literal(false),\n replay: z.literal(\"unmaterialized-raw-events\"),\n session: zSessionCredential.optional(),\n});\n\nexport const zIngestResponse = z.discriminatedUnion(\"status\", [zIngestOkResponse, zIngestAcceptedResponse]);\n\nexport type IngestOkResponse = z.infer<typeof zIngestOkResponse>;\nexport type IngestAcceptedResponse = z.infer<typeof zIngestAcceptedResponse>;\nexport type IngestResponse = z.infer<typeof zIngestResponse>;\n\n/**\n * The reconciliation a forwarder runs on every 2xx:\n *\n * accepted + duplicates + rejected.length === events sent\n *\n * A mismatch means the server silently dropped something, which is exactly the\n * failure mode this contract exists to make impossible to miss.\n */\nexport function reconcileIngestResponse(response: IngestResponse, sentCount: number): boolean {\n return response.accepted + response.duplicates + response.rejected.length === sentCount;\n}\n\n// ─── Errors ─────────────────────────────────────────────────────────────────\n\n/**\n * Stable machine-readable codes. Branch on these, never on `error`/`message`,\n * which are prose and may be reworded.\n */\nexport const INGEST_ERROR_CODES = [\n /** 401 — unknown or mismatched credentials. Stop and alert; do not retry. */\n \"unauthorized\",\n /** 400 — body was not valid JSON. */\n \"invalid_json\",\n /** 400 — request exceeded MAX_TRACK_PAYLOAD_BYTES. Split the batch. */\n \"payload_too_large\",\n /** 400 — zero events submitted. */\n \"empty_batch\",\n /** 400 — batch contained a `type: \"alias\"` event, which is not supported. */\n \"alias_unsupported\",\n /** 400 — the project has no organization; it cannot be billed or quota-checked. */\n \"project_without_organization\",\n /** 400 — `browser` mode only: a row failed validation. `server` mode reports these in `rejected[]`. */\n \"validation_failed\",\n /** 429 — per-project request rate limit. `Retry-After` set. Pause this tick, keep the cursor. */\n \"rate_limited\",\n /** 429 — the organization's monthly event quota is exhausted. `Retry-After` set (capped at 1h). Alert: a human must raise the limit. */\n \"quota_exceeded\",\n /** 410 — the project is being deleted. Permanent; stop sending. */\n \"project_purging\",\n /** 500 — unexpected server failure. Back off and retry. */\n \"internal_error\",\n] as const;\nexport const zIngestErrorCode = z.enum(INGEST_ERROR_CODES);\nexport type IngestErrorCode = z.infer<typeof zIngestErrorCode>;\n\nexport const zIngestError = z.object({\n status: z.number().int(),\n code: zIngestErrorCode,\n error: z.string(),\n message: z.string().optional(),\n /** zod issues, when `code === \"validation_failed\"`. */\n errors: z.unknown().optional(),\n requestId: z.string().optional(),\n});\nexport type IngestError = z.infer<typeof zIngestError>;\n"]}
|
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
|
|
3
|
+
var _chunkZI6A3WQPcjs = require('./chunk-ZI6A3WQP.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
@@ -12,7 +12,7 @@ var _chunkBA52YA7Ncjs = require('./chunk-BA52YA7N.cjs');
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
var
|
|
15
|
+
var _chunkYCTGHWTPcjs = require('./chunk-YCTGHWTP.cjs');
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
|
|
@@ -20,18 +20,18 @@ var _chunkLA5F5KR6cjs = require('./chunk-LA5F5KR6.cjs');
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
var
|
|
23
|
+
var _chunkXDH5QQYFcjs = require('./chunk-XDH5QQYF.cjs');
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
var
|
|
27
|
-
require('./chunk-
|
|
26
|
+
var _chunkORNTN6AKcjs = require('./chunk-ORNTN6AK.cjs');
|
|
27
|
+
require('./chunk-L3JPDRVG.cjs');
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
var
|
|
34
|
+
var _chunkF2RNXJGOcjs = require('./chunk-F2RNXJGO.cjs');
|
|
35
35
|
require('./chunk-3EEANNYN.cjs');
|
|
36
36
|
|
|
37
37
|
// src/client.ts
|
|
@@ -80,7 +80,7 @@ function toApiError(status, rawBody, retryAfterMs, requestId) {
|
|
|
80
80
|
try {
|
|
81
81
|
parsed = JSON.parse(rawBody);
|
|
82
82
|
} catch (e) {
|
|
83
|
-
return new (0,
|
|
83
|
+
return new (0, _chunkORNTN6AKcjs.DataApiError)({
|
|
84
84
|
message: `reopt-data responded ${status} with a non-JSON body`,
|
|
85
85
|
status,
|
|
86
86
|
code: status >= 500 ? "internal_error" : "unknown_error",
|
|
@@ -92,7 +92,7 @@ function toApiError(status, rawBody, retryAfterMs, requestId) {
|
|
|
92
92
|
const body = _nullishCoalesce(parsed, () => ( {}));
|
|
93
93
|
const code = typeof body.code === "string" ? body.code : status >= 500 ? "internal_error" : "unknown_error";
|
|
94
94
|
const message = typeof body.message === "string" && body.message || typeof body.error === "string" && body.error || `reopt-data responded ${status}`;
|
|
95
|
-
return new (0,
|
|
95
|
+
return new (0, _chunkORNTN6AKcjs.DataApiError)({
|
|
96
96
|
message,
|
|
97
97
|
status,
|
|
98
98
|
code,
|
|
@@ -114,10 +114,10 @@ function createDataClient(options) {
|
|
|
114
114
|
maxDelayMs: _nullishCoalesce(_optionalChain([options, 'access', _11 => _11.retry, 'optionalAccess', _12 => _12.maxDelayMs]), () => ( DEFAULTS.maxDelayMs)),
|
|
115
115
|
respectRetryAfter: _nullishCoalesce(_optionalChain([options, 'access', _13 => _13.retry, 'optionalAccess', _14 => _14.respectRetryAfter]), () => ( true))
|
|
116
116
|
};
|
|
117
|
-
const userAgent = options.userAgent ? `reopt-data-contract/${
|
|
117
|
+
const userAgent = options.userAgent ? `reopt-data-contract/${_chunkF2RNXJGOcjs.CONTRACT_VERSION} ${options.userAgent}` : `reopt-data-contract/${_chunkF2RNXJGOcjs.CONTRACT_VERSION}`;
|
|
118
118
|
function requireClientCredentials() {
|
|
119
119
|
if (!options.clientId || !options.clientSecret) {
|
|
120
|
-
throw new (0,
|
|
120
|
+
throw new (0, _chunkORNTN6AKcjs.DataApiError)({
|
|
121
121
|
message: "createDataClient was given no client credentials \u2014 pass clientId and clientSecret to use the ingest or query planes",
|
|
122
122
|
status: 0,
|
|
123
123
|
code: "credentials_missing"
|
|
@@ -139,7 +139,7 @@ function createDataClient(options) {
|
|
|
139
139
|
headers: {
|
|
140
140
|
"content-type": "application/json",
|
|
141
141
|
"user-agent": userAgent,
|
|
142
|
-
...options.clientId && options.clientSecret ? { [
|
|
142
|
+
...options.clientId && options.clientSecret ? { [_chunkF2RNXJGOcjs.CLIENT_ID_HEADER]: options.clientId, [_chunkF2RNXJGOcjs.CLIENT_SECRET_HEADER]: options.clientSecret } : {},
|
|
143
143
|
...extraHeaders
|
|
144
144
|
},
|
|
145
145
|
body: JSON.stringify(body),
|
|
@@ -158,7 +158,7 @@ function createDataClient(options) {
|
|
|
158
158
|
response = await requestOnce(method, path, body, extraHeaders, signal);
|
|
159
159
|
} catch (cause) {
|
|
160
160
|
if (_optionalChain([signal, 'optionalAccess', _20 => _20.aborted])) throw cause;
|
|
161
|
-
lastError = new (0,
|
|
161
|
+
lastError = new (0, _chunkORNTN6AKcjs.DataApiError)({
|
|
162
162
|
message: cause instanceof Error ? cause.message : String(cause),
|
|
163
163
|
status: 0,
|
|
164
164
|
code: "network_error",
|
|
@@ -170,16 +170,16 @@ function createDataClient(options) {
|
|
|
170
170
|
}
|
|
171
171
|
throw lastError;
|
|
172
172
|
}
|
|
173
|
-
const requestId = _nullishCoalesce(response.headers.get(
|
|
174
|
-
const serverContractVersion = response.headers.get(
|
|
173
|
+
const requestId = _nullishCoalesce(response.headers.get(_chunkF2RNXJGOcjs.REQUEST_ID_HEADER), () => ( void 0));
|
|
174
|
+
const serverContractVersion = response.headers.get(_chunkF2RNXJGOcjs.CONTRACT_VERSION_HEADER);
|
|
175
175
|
const rawBody = await response.text();
|
|
176
|
-
if (serverContractVersion !==
|
|
177
|
-
throw new (0,
|
|
178
|
-
message: serverContractVersion ? `reopt-data contract ${serverContractVersion} does not match client contract ${
|
|
176
|
+
if (serverContractVersion !== _chunkF2RNXJGOcjs.CONTRACT_VERSION) {
|
|
177
|
+
throw new (0, _chunkORNTN6AKcjs.DataApiError)({
|
|
178
|
+
message: serverContractVersion ? `reopt-data contract ${serverContractVersion} does not match client contract ${_chunkF2RNXJGOcjs.CONTRACT_VERSION}` : "reopt-data response did not declare its contract version",
|
|
179
179
|
status: response.status,
|
|
180
180
|
code: "contract_mismatch",
|
|
181
181
|
requestId,
|
|
182
|
-
details: { expected:
|
|
182
|
+
details: { expected: _chunkF2RNXJGOcjs.CONTRACT_VERSION, received: serverContractVersion }
|
|
183
183
|
});
|
|
184
184
|
}
|
|
185
185
|
if (response.ok) {
|
|
@@ -187,7 +187,7 @@ function createDataClient(options) {
|
|
|
187
187
|
try {
|
|
188
188
|
json = JSON.parse(rawBody);
|
|
189
189
|
} catch (cause) {
|
|
190
|
-
throw new (0,
|
|
190
|
+
throw new (0, _chunkORNTN6AKcjs.DataApiError)({
|
|
191
191
|
message: "reopt-data returned a 2xx with an unparseable body",
|
|
192
192
|
status: response.status,
|
|
193
193
|
code: "contract_mismatch",
|
|
@@ -198,7 +198,7 @@ function createDataClient(options) {
|
|
|
198
198
|
try {
|
|
199
199
|
return parse(json);
|
|
200
200
|
} catch (cause) {
|
|
201
|
-
throw new (0,
|
|
201
|
+
throw new (0, _chunkORNTN6AKcjs.DataApiError)({
|
|
202
202
|
message: "reopt-data returned a 2xx that does not match the contract",
|
|
203
203
|
status: response.status,
|
|
204
204
|
code: "contract_mismatch",
|
|
@@ -212,7 +212,7 @@ function createDataClient(options) {
|
|
|
212
212
|
if (!lastError.retryable || attempt === retry.maxRetries) throw lastError;
|
|
213
213
|
await sleep(_nullishCoalesce(retryAfterMs, () => ( backoffDelay(attempt, retry))), signal);
|
|
214
214
|
}
|
|
215
|
-
throw _nullishCoalesce(lastError, () => ( new (0,
|
|
215
|
+
throw _nullishCoalesce(lastError, () => ( new (0, _chunkORNTN6AKcjs.DataApiError)({ message: "reopt-data request failed", status: 0, code: "network_error" })));
|
|
216
216
|
}
|
|
217
217
|
async function post(path, body, parse, signal) {
|
|
218
218
|
requireClientCredentials();
|
|
@@ -221,37 +221,37 @@ function createDataClient(options) {
|
|
|
221
221
|
return {
|
|
222
222
|
ingest: {
|
|
223
223
|
track(events, init) {
|
|
224
|
-
return post(TRACK_PATH, events, (value) =>
|
|
224
|
+
return post(TRACK_PATH, events, (value) => _chunkZI6A3WQPcjs.zIngestResponse.parse(value), _optionalChain([init, 'optionalAccess', _21 => _21.signal]));
|
|
225
225
|
}
|
|
226
226
|
},
|
|
227
227
|
query: {
|
|
228
228
|
eventsTimeseries(input, init) {
|
|
229
229
|
return post(
|
|
230
|
-
|
|
230
|
+
_chunkXDH5QQYFcjs.QUERY_API_PATHS.eventsTimeseries,
|
|
231
231
|
input,
|
|
232
|
-
(value) =>
|
|
232
|
+
(value) => _chunkXDH5QQYFcjs.zEventsTimeseriesResponse.parse(value),
|
|
233
233
|
_optionalChain([init, 'optionalAccess', _22 => _22.signal])
|
|
234
234
|
);
|
|
235
235
|
},
|
|
236
236
|
funnel(input, init) {
|
|
237
|
-
return post(
|
|
237
|
+
return post(_chunkXDH5QQYFcjs.QUERY_API_PATHS.funnel, input, (value) => _chunkXDH5QQYFcjs.zFunnelResponse.parse(value), _optionalChain([init, 'optionalAccess', _23 => _23.signal]));
|
|
238
238
|
},
|
|
239
239
|
retention(input, init) {
|
|
240
|
-
return post(
|
|
240
|
+
return post(_chunkXDH5QQYFcjs.QUERY_API_PATHS.retention, input, (value) => _chunkXDH5QQYFcjs.zRetentionResponse.parse(value), _optionalChain([init, 'optionalAccess', _24 => _24.signal]));
|
|
241
241
|
},
|
|
242
242
|
trafficOverview(input, init) {
|
|
243
243
|
return post(
|
|
244
|
-
|
|
244
|
+
_chunkXDH5QQYFcjs.QUERY_API_PATHS.trafficOverview,
|
|
245
245
|
input,
|
|
246
|
-
(value) =>
|
|
246
|
+
(value) => _chunkXDH5QQYFcjs.zTrafficOverviewResponse.parse(value),
|
|
247
247
|
_optionalChain([init, 'optionalAccess', _25 => _25.signal])
|
|
248
248
|
);
|
|
249
249
|
},
|
|
250
250
|
trafficSources(input, init) {
|
|
251
251
|
return post(
|
|
252
|
-
|
|
252
|
+
_chunkXDH5QQYFcjs.QUERY_API_PATHS.trafficSources,
|
|
253
253
|
input,
|
|
254
|
-
(value) =>
|
|
254
|
+
(value) => _chunkXDH5QQYFcjs.zTrafficSourcesResponse.parse(value),
|
|
255
255
|
_optionalChain([init, 'optionalAccess', _26 => _26.signal])
|
|
256
256
|
);
|
|
257
257
|
}
|
|
@@ -260,70 +260,70 @@ function createDataClient(options) {
|
|
|
260
260
|
createOrganization(input, auth, init) {
|
|
261
261
|
return send(
|
|
262
262
|
"POST",
|
|
263
|
-
|
|
263
|
+
_chunkYCTGHWTPcjs.CONTROL_API_PATHS.organizations,
|
|
264
264
|
input,
|
|
265
|
-
(value) =>
|
|
266
|
-
{ [
|
|
265
|
+
(value) => _chunkYCTGHWTPcjs.zCreateOrganizationResponse.parse(value),
|
|
266
|
+
{ [_chunkYCTGHWTPcjs.PLATFORM_KEY_HEADER]: auth.platformKey },
|
|
267
267
|
_optionalChain([init, 'optionalAccess', _27 => _27.signal])
|
|
268
268
|
);
|
|
269
269
|
},
|
|
270
270
|
rotateOrgKey(organizationId, auth, init) {
|
|
271
271
|
return send(
|
|
272
272
|
"POST",
|
|
273
|
-
|
|
273
|
+
_chunkYCTGHWTPcjs.CONTROL_API_PATHS.organizationKeys(organizationId),
|
|
274
274
|
{},
|
|
275
|
-
(value) =>
|
|
276
|
-
{ [
|
|
275
|
+
(value) => _chunkYCTGHWTPcjs.zRotateOrganizationKeyResponse.parse(value),
|
|
276
|
+
{ [_chunkYCTGHWTPcjs.PLATFORM_KEY_HEADER]: auth.platformKey },
|
|
277
277
|
_optionalChain([init, 'optionalAccess', _28 => _28.signal])
|
|
278
278
|
);
|
|
279
279
|
},
|
|
280
280
|
updateOrganizationQuota(organizationId, input, auth, init) {
|
|
281
281
|
return send(
|
|
282
282
|
"PATCH",
|
|
283
|
-
|
|
283
|
+
_chunkYCTGHWTPcjs.CONTROL_API_PATHS.organization(organizationId),
|
|
284
284
|
input,
|
|
285
|
-
(value) =>
|
|
286
|
-
{ [
|
|
285
|
+
(value) => _chunkYCTGHWTPcjs.zUpdateOrganizationQuotaResponse.parse(value),
|
|
286
|
+
{ [_chunkYCTGHWTPcjs.PLATFORM_KEY_HEADER]: auth.platformKey },
|
|
287
287
|
_optionalChain([init, 'optionalAccess', _29 => _29.signal])
|
|
288
288
|
);
|
|
289
289
|
},
|
|
290
290
|
createProject(input, auth, init) {
|
|
291
291
|
return send(
|
|
292
292
|
"POST",
|
|
293
|
-
|
|
293
|
+
_chunkYCTGHWTPcjs.CONTROL_API_PATHS.projects,
|
|
294
294
|
input,
|
|
295
|
-
(value) =>
|
|
296
|
-
{ [
|
|
295
|
+
(value) => _chunkYCTGHWTPcjs.zCreateProjectResponse.parse(value),
|
|
296
|
+
{ [_chunkYCTGHWTPcjs.ORG_KEY_HEADER]: auth.orgKey },
|
|
297
297
|
_optionalChain([init, 'optionalAccess', _30 => _30.signal])
|
|
298
298
|
);
|
|
299
299
|
},
|
|
300
300
|
rotateServerClientSecret(projectId, clientId, auth, init) {
|
|
301
301
|
return send(
|
|
302
302
|
"POST",
|
|
303
|
-
|
|
303
|
+
_chunkYCTGHWTPcjs.CONTROL_API_PATHS.clientRotate(projectId, clientId),
|
|
304
304
|
{},
|
|
305
|
-
(value) =>
|
|
306
|
-
{ [
|
|
305
|
+
(value) => _chunkYCTGHWTPcjs.zRotateClientSecretResponse.parse(value),
|
|
306
|
+
{ [_chunkYCTGHWTPcjs.ORG_KEY_HEADER]: auth.orgKey },
|
|
307
307
|
_optionalChain([init, 'optionalAccess', _31 => _31.signal])
|
|
308
308
|
);
|
|
309
309
|
},
|
|
310
310
|
deleteProject(projectId, input, auth, init) {
|
|
311
311
|
return send(
|
|
312
312
|
"DELETE",
|
|
313
|
-
|
|
313
|
+
_chunkYCTGHWTPcjs.CONTROL_API_PATHS.project(projectId),
|
|
314
314
|
input,
|
|
315
|
-
(value) =>
|
|
316
|
-
{ [
|
|
315
|
+
(value) => _chunkYCTGHWTPcjs.zDeleteProjectResponse.parse(value),
|
|
316
|
+
{ [_chunkYCTGHWTPcjs.ORG_KEY_HEADER]: auth.orgKey },
|
|
317
317
|
_optionalChain([init, 'optionalAccess', _32 => _32.signal])
|
|
318
318
|
);
|
|
319
319
|
},
|
|
320
320
|
upsertEventMeta(projectId, name, input, auth, init) {
|
|
321
321
|
return send(
|
|
322
322
|
"PUT",
|
|
323
|
-
|
|
323
|
+
_chunkYCTGHWTPcjs.CONTROL_API_PATHS.projectEvent(projectId, name),
|
|
324
324
|
input,
|
|
325
|
-
(value) =>
|
|
326
|
-
{ [
|
|
325
|
+
(value) => _chunkYCTGHWTPcjs.zEventMetaResponse.parse(value),
|
|
326
|
+
{ [_chunkYCTGHWTPcjs.ORG_KEY_HEADER]: auth.orgKey },
|
|
327
327
|
_optionalChain([init, 'optionalAccess', _33 => _33.signal])
|
|
328
328
|
);
|
|
329
329
|
}
|
package/dist/client.cjs.map
CHANGED
|
@@ -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 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"]}
|
|
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 | 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"]}
|