@to11ai/sdk 2.0.0-rc.3 → 2.0.0-rc.4

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.
@@ -1,9 +1,10 @@
1
- import { z } from "zod";
2
- import { EnvNotFoundError, To11aiNetworkError } from "../errors";
1
+ import {
2
+ MissingLabelError,
3
+ To11aiApiError,
4
+ To11aiNetworkError,
5
+ } from "../errors";
3
6
  import { zResolvedPrompt } from "../generated/zod.gen";
4
7
  import type { ApiEnvelope, Transport } from "../transport";
5
- import type { CacheConfig } from "./cache";
6
- import { buildRenderCacheKey, PromptCache } from "./cache";
7
8
  import type {
8
9
  AnthropicRenderedPrompt,
9
10
  OpenAiRenderedPrompt,
@@ -56,13 +57,12 @@ import type {
56
57
  } from "./types";
57
58
  import { ENV_SLUG_REGEX } from "./types";
58
59
 
59
- // Re-export CacheConfig so callers can import from this module
60
- export type { CacheConfig } from "./cache";
61
60
  export type {
62
61
  ArchivePromptInput,
63
62
  ArchivePromptResult,
64
63
  BlockRenderRecord,
65
64
  ChatMessage,
65
+ ChatRole,
66
66
  CreateProjectPromptLabelInput,
67
67
  CreateProjectPromptLabelResult,
68
68
  CreatePromptInput,
@@ -111,8 +111,6 @@ export type {
111
111
  ResolvedToolCall,
112
112
  ResolvedToolDefinition,
113
113
  RowError,
114
- TextChatMessage,
115
- TextChatRole,
116
114
  UnknownRoleMode,
117
115
  UpdateProjectPromptLabelInput,
118
116
  UpdateProjectPromptLabelResult,
@@ -120,9 +118,7 @@ export type {
120
118
  UpdatePromptResult,
121
119
  } from "./types";
122
120
 
123
- const zResolvedPromptEnvelope = zResolvedPrompt
124
- .partial({ releaseId: true })
125
- .extend({ strategy: z.enum(["single", "weighted"]).optional() });
121
+ const zResolvedPromptEnvelope = zResolvedPrompt.partial({ releaseId: true });
126
122
 
127
123
  function unwrap<T>(envelope: ApiEnvelope<T>): T {
128
124
  if (envelope.data === null || envelope.data === undefined) {
@@ -293,7 +289,6 @@ export interface PromptResourceConfig {
293
289
 
294
290
  export class PromptResource<F extends RenderFormat | undefined = undefined> {
295
291
  private readonly transport: Transport;
296
- private readonly cache: PromptCache;
297
292
  private readonly projectId: string | undefined;
298
293
  private readonly env: string | undefined;
299
294
  private readonly format: RenderFormat | undefined;
@@ -301,14 +296,12 @@ export class PromptResource<F extends RenderFormat | undefined = undefined> {
301
296
 
302
297
  constructor(
303
298
  transport: Transport,
304
- cacheConfig?: CacheConfig,
305
299
  // `format` is bound to the class generic `F` (not the wider `RenderFormat`)
306
300
  // so the constructed default shape cannot disagree with what `render()`'s
307
301
  // return type (`RenderResult<F>`) promises.
308
302
  config?: Omit<PromptResourceConfig, "format"> & { format?: F },
309
303
  ) {
310
304
  this.transport = transport;
311
- this.cache = new PromptCache(cacheConfig);
312
305
  this.projectId = config?.projectId;
313
306
  this.env = config?.env;
314
307
  this.format = config?.format;
@@ -527,17 +520,14 @@ export class PromptResource<F extends RenderFormat | undefined = undefined> {
527
520
 
528
521
  /**
529
522
  * Env-aware resolution → neutral `RenderedPrompt`. Carries the resolve /
530
- * cache / offline-fallback logic; `render()` is the public shaping surface.
523
+ * offline-fallback logic; `render()` is the public shaping surface.
531
524
  *
532
- * - **env→label wire mapping:** the resolve route is label-based
525
+ * - **label wire mapping:** the resolve route is label-based
533
526
  * (`/v1/projects/:projectId/prompts:resolve`, body `labels[]`); the
534
- * resolved env slug is sent as the single resolution label.
535
- * - **No silent fallback (R4):** if no env is resolvable (none at init AND
536
- * none per call) this throws `EnvNotFoundError` CLIENT-side, eagerly,
537
- * before any transport call.
538
- * - **Cache (D8):** caches `single`-strategy releases and weighted releases
539
- * WITH a `subject`; BYPASSES the cache for weighted releases with NO
540
- * `subject` (a uniform-random assignment must not be pinned for the TTL).
527
+ * resolved label is sent as the single resolution label.
528
+ * - **No silent fallback (R4):** if no label is resolvable (none per call
529
+ * AND no client `env` fallback) this throws `MissingLabelError`
530
+ * CLIENT-side, eagerly, before any transport call.
541
531
  */
542
532
  private async resolveToRendered(
543
533
  slug: string,
@@ -549,41 +539,28 @@ export class PromptResource<F extends RenderFormat | undefined = undefined> {
549
539
  );
550
540
  }
551
541
 
552
- // R2 precedence: per-call env > init-time env. No third source.
553
- const env = options.env ?? this.env;
542
+ // R2 precedence: per-call label > client `env` fallback. No third source.
543
+ const label = options.label ?? this.env;
554
544
 
555
- // R4 / AC4: no env resolvable → throw eagerly, ZERO transport calls.
556
- if (env === undefined) {
557
- throw EnvNotFoundError.missing();
545
+ // R4 / AC4: no label resolvable → throw eagerly, ZERO transport calls.
546
+ if (label === undefined) {
547
+ throw new MissingLabelError();
558
548
  }
559
549
 
560
- // Validate the RESOLVED env (per-call OR init). createClient validates the
561
- // init-time env, but PromptResource has a public constructor that can
562
- // bypass createClient, so re-validate here so a malformed env (e.g.
563
- // "Prod") never reaches the wire as a resolution label (CodeRabbit).
564
- if (!ENV_SLUG_REGEX.test(env)) {
550
+ // Validate the RESOLVED label (per-call OR the client `env` fallback).
551
+ // createClient validates the init-time env, but PromptResource has a
552
+ // public constructor that can bypass createClient, so re-validate here so
553
+ // a malformed label (e.g. "Prod") never reaches the wire (CodeRabbit).
554
+ if (!ENV_SLUG_REGEX.test(label)) {
565
555
  throw new Error(
566
- `[to11ai/sdk] \`env\` must match ${ENV_SLUG_REGEX} (lowercase-kebab, 1-63 chars). Received: ${JSON.stringify(env)}`,
556
+ `[to11ai/sdk] \`label\` must match ${ENV_SLUG_REGEX} (lowercase-kebab, 1-63 chars). Received: ${JSON.stringify(label)}`,
567
557
  );
568
558
  }
569
559
 
570
- const { subject, variables, cache: useCache = true, fallback } = options;
560
+ const { subject, variables, fallback } = options;
571
561
 
572
- const cacheKey = buildRenderCacheKey(
573
- this.projectId,
574
- slug,
575
- env,
576
- subject,
577
- variables,
578
- );
579
-
580
- if (useCache) {
581
- const cached = this.cache.get(cacheKey);
582
- if (cached) return structuredClone(cached);
583
- }
584
-
585
- // env→label mapping: the env slug is the single resolution label.
586
- const body: Record<string, unknown> = { slug, labels: [env] };
562
+ // The resolved label is sent as the single resolution label.
563
+ const body: Record<string, unknown> = { slug, labels: [label] };
587
564
  if (subject !== undefined) body.subject = subject;
588
565
  if (variables !== undefined) body.variables = variables;
589
566
 
@@ -598,31 +575,16 @@ export class PromptResource<F extends RenderFormat | undefined = undefined> {
598
575
  },
599
576
  );
600
577
  const raw = unwrap(envelope);
601
- const result = normalizeResolvedEnvelope(raw, slug);
602
-
603
- // D8: bypass the cache for a weighted release with NO subject —
604
- // caching a uniform-random assignment would pin one variant for the
605
- // whole TTL. Cache `single` releases and `subject`-keyed weighted
606
- // releases (deterministic, safe to cache). Weighted-ness is inferred
607
- // from `strategy === "weighted"` OR the presence of `variantName`
608
- // (which the server stamps iff weighted) — so a result that carries a
609
- // variant but omits `strategy` is still correctly bypassed rather than
610
- // pinning one random variant for the TTL (Cursor / Greptile).
611
- const isWeighted =
612
- raw.strategy === "weighted" || result.variantName !== undefined;
613
- const cacheable = !(isWeighted && subject === undefined);
614
- if (useCache && cacheable) {
615
- this.cache.set(cacheKey, structuredClone(result));
616
- }
617
-
618
- return result;
578
+ return normalizeResolvedEnvelope(raw, slug);
619
579
  } catch (err) {
620
- // D7: offline fallback is consulted ONLY on a network outage with an
621
- // empty cache. A server `ENV_NOT_FOUND` is a typed application error
622
- // (not a To11aiNetworkError), so it bypasses this branch. R4's
623
- // client-eager throw already happened above the try, so there is no
624
- // network error to trigger it on the env-missing path.
625
- if (err instanceof To11aiNetworkError && fallback !== undefined) {
580
+ // Serve the offline fallback on a TRANSIENT outage — a network error
581
+ // or a 5xx from the control plane. A typed 4xx (not-found / policy /
582
+ // validation) is a real application error and is NOT masked. The
583
+ // client-eager MissingLabelError already threw above the try.
584
+ const transient =
585
+ err instanceof To11aiNetworkError ||
586
+ (err instanceof To11aiApiError && err.statusCode >= 500);
587
+ if (transient && fallback !== undefined) {
626
588
  return liftFallbackToRendered(fallback, slug);
627
589
  }
628
590
  throw err;
@@ -135,7 +135,7 @@ export function shapeAnthropic(
135
135
  return result;
136
136
  }
137
137
 
138
- /** Shape a fetched prompt for `format`, or return it neutral when unset. */
138
+ /** Shape a rendered prompt for `format`, or return it neutral when unset. */
139
139
  export function shapePrompt(
140
140
  prompt: RenderedPrompt,
141
141
  format: RenderFormat | undefined,
@@ -23,16 +23,14 @@ export type PromptVersion = GenPromptVersion;
23
23
  export type PromptFormat = PromptVersion["format"];
24
24
  export type PromptLabelPointer = GenPromptLabelPointer;
25
25
 
26
- export type TextChatRole = "system" | "user" | "assistant" | "developer";
26
+ export type ChatRole = "system" | "user" | "assistant" | "developer";
27
27
 
28
- export interface TextChatMessage {
29
- role: TextChatRole;
28
+ export interface ChatMessage {
29
+ role: ChatRole;
30
30
  content: string;
31
31
  disabled?: boolean;
32
32
  }
33
33
 
34
- export type ChatMessage = TextChatMessage;
35
-
36
34
  export type RenderedChatMessage = GenRenderedChatPrompt["messages"][number];
37
35
 
38
36
  /** Provider shape for `prompts.render()` output. Omit for the neutral result. */
@@ -174,6 +172,13 @@ export interface ListPromptLabelsInput {
174
172
 
175
173
  export type ListPromptLabelsResult = PromptLabelPointer[];
176
174
 
175
+ /**
176
+ * Slug rule for a `render()` label — lowercase-kebab, 1-63 chars. Env slugs are
177
+ * a special case of a label value, so labels are held to the same strict rule
178
+ * (no uppercase, no underscores): a label is a routing key, and case-insensitive
179
+ * routing keys invite silent "production" vs "Production" mismatches. Intentionally
180
+ * strict — do not loosen.
181
+ */
177
182
  export const ENV_SLUG_REGEX = /^[a-z0-9-]{1,63}$/;
178
183
 
179
184
  export type BlockRenderRecord = Record<string, "rendered" | "dimmed">;
@@ -223,20 +228,18 @@ export interface RenderedPrompt {
223
228
  toolChoice?: NonNullable<ResolvedPrompt["toolChoice"]>;
224
229
  }
225
230
 
226
- export type ResolvedPromptEnvelope = GenResolvedPrompt & {
227
- /** Active release strategy. Used to decide weighted-no-subject cache bypass (D8). */
228
- strategy?: "single" | "weighted";
229
- };
231
+ export type ResolvedPromptEnvelope = GenResolvedPrompt;
230
232
 
231
233
  export interface RenderOptions {
232
- /** Serving environment for this call; overrides the client default. */
233
- env?: string;
234
+ /**
235
+ * Label to resolve this call's prompt version; overrides the client default.
236
+ * When omitted, falls back to the client's `env` (env is a label value).
237
+ */
238
+ label?: string;
234
239
  /** Stable id so a weighted release sends the same caller to the same variant. */
235
240
  subject?: string;
236
241
  variables?: Record<string, unknown>;
237
- /** Set false to bypass the LRU cache for this call. Default: true */
238
- cache?: boolean;
239
- /** Prompt served if the API is unreachable on a network error and cache is empty. */
242
+ /** Prompt served if the API is unreachable on a network error. */
240
243
  fallback?: RenderedPrompt;
241
244
  /** Provider shape for this call's output; overrides the client default. */
242
245
  format?: RenderFormat;
package/src/transport.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import type { BehaviorStore } from "./behaviors/store";
2
2
  import {
3
- AmbiguousEnvLabelsError,
4
3
  EnvNotEnabledForProviderError,
5
- EnvNotFoundError,
4
+ LabelNotFoundError,
6
5
  NoActiveReleaseError,
7
6
  NoApplicableRouteError,
8
7
  PromptLabelNotRegisteredError,
@@ -108,14 +107,11 @@ function mapPromptResolveError(
108
107
  );
109
108
  }
110
109
  if (detailsCode === "ENV_NOT_FOUND") {
111
- // Server-side unknown-env. (The client-eager "missing" variant is
112
- // raised in resource.ts before any request — never here.)
113
- return new EnvNotFoundError(
114
- message,
115
- { env, source: "unknown" },
116
- details,
117
- status,
118
- );
110
+ // Server-side unknown-label. (The client-side MissingLabelError — no
111
+ // label supplied at all — is raised in resource.ts before any request.)
112
+ // Prefer `details.label`, falling back to `details.env`.
113
+ const label = typeof d.label === "string" ? d.label : env;
114
+ return new LabelNotFoundError(message, label, details, status);
119
115
  }
120
116
  if (detailsCode === "NO_ACTIVE_RELEASE") {
121
117
  return new NoActiveReleaseError(
@@ -125,9 +121,6 @@ function mapPromptResolveError(
125
121
  status,
126
122
  );
127
123
  }
128
- if (detailsCode === "AMBIGUOUS_ENV_LABELS") {
129
- return new AmbiguousEnvLabelsError(message, { env, slug }, details, status);
130
- }
131
124
  if (PROMPT_POLICY_VIOLATION_DETAILS_CODES.has(detailsCode)) {
132
125
  const policy = typeof d.policy === "string" ? d.policy : undefined;
133
126
  return new PromptPolicyViolationError(
@@ -140,9 +133,9 @@ function mapPromptResolveError(
140
133
  return undefined;
141
134
  }
142
135
 
143
- export type AuthConfig =
144
- | { readonly apiKey: string; readonly getAccessToken?: never }
145
- | { readonly getAccessToken: () => Promise<string>; readonly apiKey?: never };
136
+ export interface AuthConfig {
137
+ readonly apiKey: string;
138
+ }
146
139
 
147
140
  export interface TransportConfig {
148
141
  readonly baseUrl: string;
@@ -248,12 +241,25 @@ function mapHttpError(
248
241
  }
249
242
  if (status === 429) {
250
243
  const retryAfterHeader = headers?.get("retry-after");
251
- const retryAfterSeconds = retryAfterHeader
252
- ? Number(retryAfterHeader)
253
- : undefined;
244
+ let retryAfterSeconds: number | undefined;
245
+ if (retryAfterHeader) {
246
+ const numeric = Number(retryAfterHeader);
247
+ if (Number.isFinite(numeric)) {
248
+ retryAfterSeconds = Math.max(0, numeric);
249
+ } else {
250
+ // RFC 9110 HTTP-date form → seconds until that instant.
251
+ const when = Date.parse(retryAfterHeader);
252
+ if (!Number.isNaN(when)) {
253
+ retryAfterSeconds = Math.max(
254
+ 0,
255
+ Math.round((when - Date.now()) / 1000),
256
+ );
257
+ }
258
+ }
259
+ }
254
260
  return new To11aiRateLimitError(
255
261
  message,
256
- Number.isFinite(retryAfterSeconds) ? retryAfterSeconds : undefined,
262
+ retryAfterSeconds,
257
263
  errorCode,
258
264
  details,
259
265
  );
@@ -395,25 +401,20 @@ export class Transport {
395
401
  private readonly behaviorStore: BehaviorStore | undefined;
396
402
 
397
403
  constructor(config: TransportConfig) {
398
- this.baseUrl = config.baseUrl.replace(/\/$/, "");
404
+ this.baseUrl = config.baseUrl.replace(/\/+$/, "");
399
405
  this.auth = config.auth;
400
406
  this.timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
401
407
  this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
402
408
  this.behaviorStore = config.behaviorStore;
403
409
  }
404
410
 
405
- private async buildHeaders(): Promise<Record<string, string>> {
411
+ private buildHeaders(): Record<string, string> {
406
412
  const headers: Record<string, string> = {
407
413
  "content-type": "application/json",
408
414
  accept: "application/json",
409
415
  };
410
416
 
411
- if (this.auth.apiKey !== undefined) {
412
- headers.authorization = `Bearer ${this.auth.apiKey}`;
413
- } else if (this.auth.getAccessToken) {
414
- const token = await this.auth.getAccessToken();
415
- headers.authorization = `Bearer ${token}`;
416
- }
417
+ headers.authorization = `Bearer ${this.auth.apiKey}`;
417
418
 
418
419
  const tp = activeTraceContext();
419
420
  if (tp) {
@@ -452,7 +453,7 @@ export class Transport {
452
453
  let attempt = 0;
453
454
 
454
455
  while (true) {
455
- const headers = await this.buildHeaders();
456
+ const headers = this.buildHeaders();
456
457
  const controller = new AbortController();
457
458
  const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);
458
459
 
@@ -495,16 +496,28 @@ export class Transport {
495
496
  let json: ApiEnvelope<T> | undefined;
496
497
  const text = await response.text();
497
498
 
498
- try {
499
- json = JSON.parse(text) as ApiEnvelope<T>;
500
- } catch {
501
- // Not a JSON body — treat as generic API error
502
- throw mapHttpError(
503
- response.status,
504
- null,
505
- text || response.statusText,
506
- response.headers,
507
- );
499
+ if (text === "" && response.ok) {
500
+ // A successful empty body (e.g. 204): synthesize an empty-data
501
+ // envelope rather than mis-mapping it to an API error.
502
+ json = {
503
+ success: true,
504
+ code: response.status,
505
+ data: null,
506
+ error: null,
507
+ pagination: null,
508
+ } as ApiEnvelope<T>;
509
+ } else {
510
+ try {
511
+ json = JSON.parse(text) as ApiEnvelope<T>;
512
+ } catch {
513
+ // Not a JSON body — treat as generic API error
514
+ throw mapHttpError(
515
+ response.status,
516
+ null,
517
+ text || response.statusText,
518
+ response.headers,
519
+ );
520
+ }
508
521
  }
509
522
 
510
523
  if (!response.ok) {
@@ -554,7 +567,7 @@ export class Transport {
554
567
  const isTimeout =
555
568
  err instanceof DOMException && err.name === "AbortError";
556
569
  // Only retry on genuine network failures (fetch throws TypeError) or timeouts.
557
- // Unexpected errors (e.g. getAccessToken rejections) propagate immediately.
570
+ // Other unexpected errors propagate immediately.
558
571
  const isNetworkError = err instanceof TypeError;
559
572
 
560
573
  if (
@@ -1,58 +0,0 @@
1
- import type { RenderedPrompt } from "./types";
2
- export interface CacheConfig {
3
- /** Time-to-live in seconds. Default: 300 (5 minutes) */
4
- ttlSeconds?: number;
5
- /** Maximum number of entries. Default: 100 */
6
- maxEntries?: number;
7
- }
8
- /**
9
- * The cache stores enriched `render()` results, which are JSON-cloneable.
10
- */
11
- export type CacheableRendered = RenderedPrompt;
12
- /**
13
- * Build a canonical base cache key from project/slug/labels/variables.
14
- *
15
- * - projectId is included to prevent cross-project cache collisions: a single
16
- * PromptResource can serve multiple projects, so the same slug+labels must
17
- * not share a cache entry across different projects.
18
- * - Labels are sorted alphabetically so ["production", "en"] and ["en", "production"]
19
- * map to the same key.
20
- * - Variables are canonicalized with deterministic sorted-keys JSON before hashing.
21
- * - Each segment is JSON-encoded so that separator characters in slug or label
22
- * values cannot cause key collisions (e.g. a slug containing "|" or ",").
23
- */
24
- export declare function buildCacheKey(projectId: string, slug: string, labels: string[], variables?: Record<string, unknown>): string;
25
- /**
26
- * Build a cache key for an env-aware `render()` call.
27
- *
28
- * Folds in `env` and `subject` ON TOP of the base
29
- * project/slug/labels/variables key so two calls that differ only by
30
- * env/subject do not return a stale cross-env / cross-cohort hit
31
- * (spec §3 "Caching key changes"). The env slug is also forwarded as the
32
- * single resolution label (env→label mapping, correction #3), so it appears
33
- * in the `labels` segment too; including it explicitly here keeps the key
34
- * unambiguous and self-documenting.
35
- *
36
- * `subject` participates in the key so a `subject`-keyed weighted assignment
37
- * caches as the same deterministic variant on repeat (D8); the
38
- * weighted-no-subject bypass is handled in the resource, not here.
39
- */
40
- export declare function buildRenderCacheKey(projectId: string, slug: string, env: string, subject?: string, variables?: Record<string, unknown>): string;
41
- /**
42
- * In-memory LRU cache for RenderedPrompt objects.
43
- *
44
- * Uses a Map (insertion-ordered) as the backing store. On every access, the
45
- * entry is deleted and re-inserted to maintain LRU order — oldest entries sit
46
- * at the front of the Map.
47
- */
48
- export declare class PromptCache {
49
- private readonly ttlMs;
50
- private readonly maxEntries;
51
- private readonly store;
52
- constructor(config?: CacheConfig);
53
- get(key: string): CacheableRendered | undefined;
54
- set(key: string, value: CacheableRendered): void;
55
- delete(key: string): void;
56
- clear(): void;
57
- get size(): number;
58
- }
@@ -1,138 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropNames = Object.getOwnPropertyNames;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- function __accessProp(key) {
6
- return this[key];
7
- }
8
- var __toCommonJS = (from) => {
9
- var entry = (__moduleCache ??= new WeakMap).get(from), desc;
10
- if (entry)
11
- return entry;
12
- entry = __defProp({}, "__esModule", { value: true });
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (var key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(entry, key))
16
- __defProp(entry, key, {
17
- get: __accessProp.bind(from, key),
18
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
- });
20
- }
21
- __moduleCache.set(from, entry);
22
- return entry;
23
- };
24
- var __moduleCache;
25
- var __returnValue = (v) => v;
26
- function __exportSetter(name, newValue) {
27
- this[name] = __returnValue.bind(null, newValue);
28
- }
29
- var __export = (target, all) => {
30
- for (var name in all)
31
- __defProp(target, name, {
32
- get: all[name],
33
- enumerable: true,
34
- configurable: true,
35
- set: __exportSetter.bind(all, name)
36
- });
37
- };
38
-
39
- // src/routingRules/resource.ts
40
- var exports_resource = {};
41
- __export(exports_resource, {
42
- RoutingRulesResource: () => RoutingRulesResource,
43
- RoutingRuleVersionResource: () => RoutingRuleVersionResource,
44
- RoutingRuleReleaseResource: () => RoutingRuleReleaseResource
45
- });
46
- module.exports = __toCommonJS(exports_resource);
47
- var import_zod = require("zod");
48
- var import_zod2 = require("../generated/zod.gen");
49
- function unwrap(envelope) {
50
- if (envelope.data === null || envelope.data === undefined) {
51
- throw new Error("API returned success but data is null");
52
- }
53
- return envelope.data;
54
- }
55
- function rulePath(projectId, ruleId) {
56
- return `/v1/projects/${encodeURIComponent(projectId)}/routing/rules/${encodeURIComponent(ruleId)}`;
57
- }
58
- function versionsPath(projectId, ruleId) {
59
- return `${rulePath(projectId, ruleId)}/versions`;
60
- }
61
- function versionPath(projectId, ruleId, versionId) {
62
- return `${versionsPath(projectId, ruleId)}/${encodeURIComponent(versionId)}`;
63
- }
64
- function releasesPath(projectId, ruleId) {
65
- return `${rulePath(projectId, ruleId)}/releases`;
66
- }
67
- function releasePath(projectId, ruleId, envSlug) {
68
- return `${releasesPath(projectId, ruleId)}/${encodeURIComponent(envSlug)}`;
69
- }
70
- function releaseRollbackPath(projectId, ruleId, envSlug) {
71
- return `${releasePath(projectId, ruleId, envSlug)}/rollback`;
72
- }
73
-
74
- class RoutingRuleVersionResource {
75
- transport;
76
- constructor(transport) {
77
- this.transport = transport;
78
- }
79
- async create(input) {
80
- const { projectId, ruleId, ...body } = input;
81
- const envelope = await this.transport.request("POST", versionsPath(projectId, ruleId), { body });
82
- return unwrap(envelope);
83
- }
84
- async list(input) {
85
- const query = {};
86
- if (input.cursor !== undefined)
87
- query.cursor = input.cursor;
88
- if (input.limit !== undefined)
89
- query.limit = input.limit;
90
- const envelope = await this.transport.request("GET", versionsPath(input.projectId, input.ruleId), { query });
91
- return unwrap(envelope);
92
- }
93
- async get(input) {
94
- const envelope = await this.transport.request("GET", versionPath(input.projectId, input.ruleId, input.versionId), {
95
- decode: (data) => import_zod2.zRuleVersion.parse(data)
96
- });
97
- return unwrap(envelope);
98
- }
99
- }
100
-
101
- class RoutingRuleReleaseResource {
102
- transport;
103
- constructor(transport) {
104
- this.transport = transport;
105
- }
106
- async set(input) {
107
- const { projectId, ruleId, envSlug, ...body } = input;
108
- const envelope = await this.transport.request("PUT", releasePath(projectId, ruleId, envSlug), { body });
109
- return unwrap(envelope);
110
- }
111
- async rollback(input) {
112
- const { projectId, ruleId, envSlug, ...body } = input;
113
- const envelope = await this.transport.request("POST", releaseRollbackPath(projectId, ruleId, envSlug), { body });
114
- return unwrap(envelope);
115
- }
116
- async list(input) {
117
- const query = {};
118
- if (input.cursor !== undefined)
119
- query.cursor = input.cursor;
120
- if (input.limit !== undefined)
121
- query.limit = input.limit;
122
- const path = input.envSlug !== undefined ? releasePath(input.projectId, input.ruleId, input.envSlug) : releasesPath(input.projectId, input.ruleId);
123
- const envelope = await this.transport.request("GET", path, {
124
- query,
125
- decode: (data) => import_zod.z.array(import_zod2.zRuleRelease).parse(data)
126
- });
127
- return unwrap(envelope);
128
- }
129
- }
130
-
131
- class RoutingRulesResource {
132
- versions;
133
- releases;
134
- constructor(transport) {
135
- this.versions = new RoutingRuleVersionResource(transport);
136
- this.releases = new RoutingRuleReleaseResource(transport);
137
- }
138
- }