@reopt-ai/data-contract 0.2.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -4
- package/dist/{chunk-IKOEYZVT.js → chunk-2LZBZXBF.js} +9 -3
- package/dist/chunk-2LZBZXBF.js.map +1 -0
- package/dist/{chunk-LBSBZO7O.cjs → chunk-4B4AY44F.cjs} +33 -7
- package/dist/chunk-4B4AY44F.cjs.map +1 -0
- package/dist/{chunk-2SJPZP2D.js → chunk-AHXPQQKO.js} +30 -4
- package/dist/chunk-AHXPQQKO.js.map +1 -0
- package/dist/{chunk-SC7TFGTO.js → chunk-BCGR27G2.js} +130 -14
- package/dist/chunk-BCGR27G2.js.map +1 -0
- package/dist/{chunk-FRJK7OCQ.js → chunk-MFZEIH5Z.js} +7 -4
- package/dist/chunk-MFZEIH5Z.js.map +1 -0
- package/dist/{chunk-CSTC3ADG.cjs → chunk-OLSMH4RY.cjs} +9 -3
- package/dist/chunk-OLSMH4RY.cjs.map +1 -0
- package/dist/{chunk-GCLUMVPA.cjs → chunk-VQ2CD5MG.cjs} +138 -22
- package/dist/chunk-VQ2CD5MG.cjs.map +1 -0
- package/dist/{chunk-HRKELGGH.cjs → chunk-XI3VP5DN.cjs} +7 -4
- package/dist/chunk-XI3VP5DN.cjs.map +1 -0
- package/dist/client.cjs +94 -44
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +8 -4
- package/dist/client.d.ts +8 -4
- package/dist/client.js +58 -8
- package/dist/client.js.map +1 -1
- package/dist/control.cjs +14 -4
- package/dist/control.cjs.map +1 -1
- package/dist/control.d.cts +49 -7
- package/dist/control.d.ts +49 -7
- package/dist/control.js +15 -5
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +15 -4
- package/dist/index.d.ts +15 -4
- package/dist/index.js +1 -1
- package/dist/ingest.cjs +2 -2
- package/dist/ingest.d.cts +9 -7
- package/dist/ingest.d.ts +9 -7
- package/dist/ingest.js +1 -1
- package/dist/query.cjs +29 -3
- package/dist/query.cjs.map +1 -1
- package/dist/query.d.cts +317 -21
- package/dist/query.d.ts +317 -21
- package/dist/query.js +30 -4
- package/dist/report.cjs +85 -0
- package/dist/report.cjs.map +1 -0
- package/dist/report.d.cts +167 -0
- package/dist/report.d.ts +167 -0
- package/dist/report.js +85 -0
- package/dist/report.js.map +1 -0
- package/package.json +7 -2
- package/dist/chunk-2SJPZP2D.js.map +0 -1
- package/dist/chunk-CSTC3ADG.cjs.map +0 -1
- package/dist/chunk-FRJK7OCQ.js.map +0 -1
- package/dist/chunk-GCLUMVPA.cjs.map +0 -1
- package/dist/chunk-HRKELGGH.cjs.map +0 -1
- package/dist/chunk-IKOEYZVT.js.map +0 -1
- package/dist/chunk-LBSBZO7O.cjs.map +0 -1
- package/dist/chunk-SC7TFGTO.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/eric/reopt-ai/reopt-data/packages/data-contract/dist/chunk-LBSBZO7O.cjs","../src/control.ts"],"names":[],"mappings":"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","file":"/Users/eric/reopt-ai/reopt-data/packages/data-contract/dist/chunk-LBSBZO7O.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\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} as const;\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/query.ts"],"sourcesContent":["/**\n * `POST /api/v1/query/*` — the read contract.\n *\n * Server credentials, project-scoped: the authenticated client's projectId must\n * equal the `projectId` in the body, or the request is refused. Reads are POSTs\n * because the inputs nest (funnel steps, channel filters) and would not survive\n * a query string; consumers cache on their own side, so HTTP cache semantics\n * buy nothing here.\n *\n * Response shapes mirror the existing dashboard computations exactly — this\n * plane re-exposes them, it does not add new math.\n */\nimport { z } from \"zod\";\nimport { zDate, zInstant } from \"./index.js\";\n\nexport { zDate, zInstant };\n\n/** Bucket width for a time series. */\nexport const zGranularity = z.enum([\"hour\", \"day\", \"week\", \"month\"]);\nexport type Granularity = z.infer<typeof zGranularity>;\n\n/**\n * IANA time zone name, e.g. `Asia/Seoul`. Decides two things at once: where a\n * calendar day starts, and therefore which bucket an event falls in.\n *\n * A Korean brand reading \"23 Aug: 120 visits\" means 23 Aug in Seoul. Computed\n * in UTC, that headline silently covers 23 Aug 09:00 through 24 Aug 09:00 —\n * wrong by nine hours in a way nothing on the page reveals.\n *\n * Validated against the runtime's own zone database rather than a regex, so an\n * unknown name fails here with a clear message instead of deep inside a query.\n */\nexport const zTimezone = z.string().min(1).max(64).refine(isValidTimeZone, { message: \"unknown IANA time zone\" });\n\nexport function isValidTimeZone(value: string): boolean {\n try {\n new Intl.DateTimeFormat(\"en-US\", { timeZone: value });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Acquisition-channel filter. Every field is a set — an event matches when its\n * value is in the set; omitted fields do not constrain. Mirrors the dashboard's\n * `channelFilterSchema` field-for-field.\n */\nexport const zChannelFilter = z\n .object({\n referrerTypes: z.array(z.string()).optional(),\n channelTypes: z.array(z.string()).optional(),\n utmSources: z.array(z.string()).optional(),\n utmMediums: z.array(z.string()).optional(),\n utmCampaigns: z.array(z.string()).optional(),\n })\n .optional();\nexport type ChannelFilter = z.infer<typeof zChannelFilter>;\n\n// ─── Envelope ───────────────────────────────────────────────────────────────\n\n/**\n * Staleness is reported as two independent numbers, never as one sum, because\n * the two have different remedies: a stale cache resolves itself at the next\n * TTL, while ingest lag means the read model is genuinely behind and the right\n * response is an \"aggregating\" badge, not a refresh.\n */\nexport const zQueryMeta = z.object({\n projectId: z.string(),\n /** When the underlying computation actually ran. On a cache hit, when the cached value was computed. */\n computedAt: zInstant,\n /** Age of the returned computation, in seconds. `0` on a cache miss. */\n cacheAgeSeconds: z.number().int().nonnegative(),\n /**\n * How far behind materialization was when the computation ran, in seconds:\n * the age of the oldest raw event not yet materialized, or `0` when nothing\n * is pending.\n *\n * Deliberately not `now - max(events.created_at)` — that conflates \"the\n * pipeline is behind\" with \"this project is quiet\", and grows without bound\n * on an idle project.\n */\n ingestLagSeconds: z.number().int().nonnegative(),\n cached: z.boolean(),\n /**\n * The time zone actually used to place bucket and window boundaries — the\n * resolved value, not the requested one. Read it rather than assuming the\n * request was honoured: when no zone is given anywhere it is `\"UTC\"`, and\n * that is exactly the case a consumer needs to notice.\n */\n timezone: z.string(),\n requestId: z.string(),\n});\nexport type QueryMeta = z.infer<typeof zQueryMeta>;\n\n/** Every query response is `{ data, meta }`. */\nexport function zQueryEnvelope<T extends z.ZodTypeAny>(data: T) {\n return z.object({ data, meta: zQueryMeta });\n}\n\n// ─── events.timeseries ──────────────────────────────────────────────────────\n\n/**\n * v1 breaks down by `properties` JSON keys only. Built-in columns\n * (country / os / browser / utm_*) have a totals breakdown in the backend but\n * no *time series* variant, and this plane does not add new computations.\n */\nexport const zTimeseriesBreakdown = z.object({\n kind: z.literal(\"property\"),\n key: z.string().min(1).max(200),\n topN: z.number().int().min(1).max(10).default(5),\n});\nexport type TimeseriesBreakdown = z.infer<typeof zTimeseriesBreakdown>;\n\nexport const zEventsTimeseriesInput = z.object({\n projectId: z.string().min(1),\n startDate: zDate,\n endDate: zDate,\n granularity: zGranularity.default(\"day\"),\n /** Omit to count every event in the window. */\n eventName: z.string().min(1).max(200).optional(),\n breakdown: zTimeseriesBreakdown.optional(),\n /**\n * Cannot be combined with `breakdown` — the backend's breakdown time series\n * takes no segment. Sending both is refused with `unsupported_combination`\n * rather than silently ignoring one of them.\n */\n segmentId: z.string().min(1).optional(),\n /** Omit to fall back to the project's configured zone, then to UTC. */\n timezone: zTimezone.optional(),\n});\nexport type EventsTimeseriesInput = z.input<typeof zEventsTimeseriesInput>;\n\nexport const zTimeseriesPoint = z.object({\n /** Bucket start, formatted by the analytics backend for the requested granularity. */\n date: z.string(),\n count: z.number().int().nonnegative(),\n});\nexport type TimeseriesPoint = z.infer<typeof zTimeseriesPoint>;\n\nexport const zEventsTimeseriesData = z.object({\n granularity: zGranularity,\n /** Zone the buckets were cut in. Mirrors `meta.timezone`. */\n timezone: z.string(),\n /** Total per bucket. Always present, with or without a breakdown. */\n series: z.array(zTimeseriesPoint),\n /** Present only when `breakdown` was requested: the top-N values, each with its own series. */\n breakdown: z\n .array(\n z.object({\n value: z.string(),\n points: z.array(zTimeseriesPoint),\n })\n )\n .optional(),\n});\nexport type EventsTimeseriesData = z.infer<typeof zEventsTimeseriesData>;\n\nexport const zEventsTimeseriesResponse = zQueryEnvelope(zEventsTimeseriesData);\nexport type EventsTimeseriesResponse = z.infer<typeof zEventsTimeseriesResponse>;\n\n// ─── funnel ─────────────────────────────────────────────────────────────────\n\nexport const zFunnelInput = z.object({\n projectId: z.string().min(1),\n /** Ordered event names. A user counts at step k if they reached at least step k. */\n steps: z.array(z.string().min(1).max(200)).min(2).max(10),\n startDate: zDate,\n endDate: zDate,\n /** Max seconds between the first and last step for a conversion to count. Default 24h. */\n windowSeconds: z.number().int().min(60).max(2_592_000).default(86_400),\n segmentId: z.string().min(1).optional(),\n channelFilter: zChannelFilter,\n /**\n * Decides where `startDate` / `endDate` fall. A funnel has no buckets, so\n * this only moves the window — but a nine-hour window shift changes who is\n * in the funnel.\n */\n timezone: zTimezone.optional(),\n});\nexport type FunnelInput = z.input<typeof zFunnelInput>;\n\nexport const zFunnelStep = z.object({\n step: z.number().int().min(1),\n name: z.string(),\n users: z.number().int().nonnegative(),\n /** Percent of the previous step that reached this one. `100` for step 1. */\n conversionRate: z.number(),\n /** Percent of the previous step that did not. `0` for step 1. */\n dropoffRate: z.number(),\n dropoffUsers: z.number().int().nonnegative(),\n});\n\nexport const zFunnelData = z.object({\n steps: z.array(zFunnelStep),\n totalUsers: z.number().int().nonnegative(),\n /** Percent of step-1 users that reached the last step. */\n overallConversionRate: z.number(),\n});\nexport type FunnelData = z.infer<typeof zFunnelData>;\n\nexport const zFunnelResponse = zQueryEnvelope(zFunnelData);\nexport type FunnelResponse = z.infer<typeof zFunnelResponse>;\n\n// ─── retention ──────────────────────────────────────────────────────────────\n\nexport const zRetentionInterval = z.enum([\"day\", \"week\", \"month\"]);\n\nexport const zRetentionInput = z.object({\n projectId: z.string().min(1),\n startDate: zDate,\n endDate: zDate,\n interval: zRetentionInterval.default(\"day\"),\n periods: z.number().int().min(1).max(30).default(7),\n startEvent: z.string().min(1).max(200).optional(),\n returnEvent: z.string().min(1).max(200).optional(),\n /** `bounded`: returned in exactly period N. `unbounded`: returned in period N or later. */\n retentionType: z.enum([\"bounded\", \"unbounded\"]).default(\"bounded\"),\n /**\n * `first-ever` (default): the cohort is everyone whose true first activity\n * landed in the window, read from the first-seen aggregate. `startEvent`,\n * `segmentId` and `channelFilter` then constrain only the *returning* side.\n * `first-in-window`: the cohort is selected by scanning events in the window\n * with all filters applied. Slower, but filters apply to cohort selection.\n */\n cohortMode: z.enum([\"first-ever\", \"first-in-window\"]).default(\"first-ever\"),\n segmentId: z.string().min(1).optional(),\n channelFilter: zChannelFilter,\n /**\n * Decides where a cohort day starts, and so which period a return falls in.\n *\n * Honoured under both cohort modes. Note that a non-UTC zone makes\n * `first-ever` read raw events instead of its daily rollup — the rollup is\n * cut on UTC days and cannot be re-cut after the fact — so expect a slower\n * query in exchange for cohorts that match the reader's calendar.\n */\n timezone: zTimezone.optional(),\n});\nexport type RetentionInput = z.input<typeof zRetentionInput>;\n\nexport const zRetentionCell = z.object({\n /** `0` is the cohort's own period. */\n period: z.number().int().nonnegative(),\n users: z.number().int().nonnegative(),\n /** Percent of `cohortSize`. */\n rate: z.number(),\n});\n\nexport const zRetentionData = z.object({\n matrix: z.array(\n z.object({\n cohortDate: z.string(),\n cohortSize: z.number().int().nonnegative(),\n /** Length is `periods + 1`, index-aligned to `period`. */\n retention: z.array(zRetentionCell),\n })\n ),\n /** Unweighted mean rate per period across cohorts. */\n averageRetention: z.array(z.object({ period: z.number().int().nonnegative(), rate: z.number() })),\n interval: zRetentionInterval,\n periods: z.number().int(),\n retentionType: z.enum([\"bounded\", \"unbounded\"]),\n /** Zone the cohort days were cut in. Mirrors `meta.timezone`. */\n timezone: z.string(),\n});\nexport type RetentionData = z.infer<typeof zRetentionData>;\n\nexport const zRetentionResponse = zQueryEnvelope(zRetentionData);\nexport type RetentionResponse = z.infer<typeof zRetentionResponse>;\n\n// ─── Errors ─────────────────────────────────────────────────────────────────\n\nexport const QUERY_ERROR_CODES = [\n /** 401 — unknown or mismatched credentials. */\n \"unauthorized\",\n /** 403 — the credential's project is not the project asked about. */\n \"project_scope_mismatch\",\n /** 403 — the credential lacks the `query` scope. Provision a query-scoped client. */\n \"query_scope_missing\",\n /** 400 — input failed the schema. `errors` carries the zod issues. */\n \"validation_failed\",\n /** 400 — inputs are individually valid but cannot be served together (e.g. breakdown + segmentId). */\n \"unsupported_combination\",\n /** 429 — per-credential query rate limit. `Retry-After` set. */\n \"rate_limited\",\n /** 504 — the analytics backend exceeded its statement timeout. Narrow the window. */\n \"query_timeout\",\n /** 500 — unexpected server failure. */\n \"internal_error\",\n] as const;\nexport const zQueryErrorCode = z.enum(QUERY_ERROR_CODES);\nexport type QueryErrorCode = z.infer<typeof zQueryErrorCode>;\n\nexport const zQueryError = z.object({\n status: z.number().int(),\n code: zQueryErrorCode,\n error: z.string(),\n message: z.string().optional(),\n errors: z.unknown().optional(),\n requestId: z.string().optional(),\n});\nexport type QueryError = z.infer<typeof zQueryError>;\n\n/** Paths, so the client and the route handlers cannot drift apart. */\nexport const QUERY_API_PATHS = {\n eventsTimeseries: \"/api/v1/query/events/timeseries\",\n funnel: \"/api/v1/query/funnel\",\n retention: \"/api/v1/query/retention\",\n} as const;\n"],"mappings":"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","names":[]}
|