@labelbox/rl-sdk 0.0.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 +90 -0
- package/dist/client-options.d.ts +39 -0
- package/dist/client-options.js +29 -0
- package/dist/generated/client/client.gen.d.ts +2 -0
- package/dist/generated/client/client.gen.js +216 -0
- package/dist/generated/client/index.d.ts +8 -0
- package/dist/generated/client/index.js +6 -0
- package/dist/generated/client/types.gen.d.ts +120 -0
- package/dist/generated/client/types.gen.js +2 -0
- package/dist/generated/client/utils.gen.d.ts +37 -0
- package/dist/generated/client/utils.gen.js +228 -0
- package/dist/generated/client.gen.d.ts +12 -0
- package/dist/generated/client.gen.js +3 -0
- package/dist/generated/core/auth.gen.d.ts +18 -0
- package/dist/generated/core/auth.gen.js +14 -0
- package/dist/generated/core/bodySerializer.gen.d.ts +25 -0
- package/dist/generated/core/bodySerializer.gen.js +57 -0
- package/dist/generated/core/params.gen.d.ts +43 -0
- package/dist/generated/core/params.gen.js +100 -0
- package/dist/generated/core/pathSerializer.gen.d.ts +33 -0
- package/dist/generated/core/pathSerializer.gen.js +106 -0
- package/dist/generated/core/queryKeySerializer.gen.d.ts +18 -0
- package/dist/generated/core/queryKeySerializer.gen.js +92 -0
- package/dist/generated/core/serverSentEvents.gen.d.ts +71 -0
- package/dist/generated/core/serverSentEvents.gen.js +132 -0
- package/dist/generated/core/types.gen.d.ts +78 -0
- package/dist/generated/core/types.gen.js +2 -0
- package/dist/generated/core/utils.gen.d.ts +19 -0
- package/dist/generated/core/utils.gen.js +87 -0
- package/dist/generated/index.d.ts +2 -0
- package/dist/generated/index.js +2 -0
- package/dist/generated/sdk.gen.d.ts +3054 -0
- package/dist/generated/sdk.gen.js +5962 -0
- package/dist/generated/types.gen.d.ts +39711 -0
- package/dist/generated/types.gen.js +2 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +39 -0
- package/dist/nesting.d.ts +18 -0
- package/dist/nesting.js +75 -0
- package/dist/reference/concepts-reference.generated.d.ts +9 -0
- package/dist/reference/concepts-reference.generated.js +356 -0
- package/dist/reference/concepts-schema.d.ts +16 -0
- package/dist/reference/concepts-schema.js +39 -0
- package/dist/reference/concepts.d.ts +15 -0
- package/dist/reference/concepts.js +354 -0
- package/dist/reference/domains.d.ts +65 -0
- package/dist/reference/domains.js +32 -0
- package/dist/reference/recipes-reference.generated.d.ts +11 -0
- package/dist/reference/recipes-reference.generated.js +11415 -0
- package/dist/reference/recipes-schema.d.ts +676 -0
- package/dist/reference/recipes-schema.js +406 -0
- package/dist/reference/resources-reference.generated.d.ts +11 -0
- package/dist/reference/resources-reference.generated.js +7174 -0
- package/dist/reference/resources-schema.d.ts +78 -0
- package/dist/reference/resources-schema.js +71 -0
- package/dist/reference/schema.d.ts +153 -0
- package/dist/reference/schema.js +151 -0
- package/dist/reference/sdk-reference.generated.d.ts +10 -0
- package/dist/reference/sdk-reference.generated.js +65703 -0
- package/dist/reference/tutorials.d.ts +76 -0
- package/dist/reference/tutorials.js +65 -0
- package/dist/session-events.d.ts +92 -0
- package/dist/session-events.js +213 -0
- package/package.json +126 -0
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
// Types for declarative **recipes** — medium-grained user goals composed of an
|
|
3
|
+
// ordered sequence of SDK operations, with values threaded from one step's
|
|
4
|
+
// response into the next step's inputs. Authored under
|
|
5
|
+
// `tests/smoke/recipes/<category>/<id>/` (a `manifest.ts` + an `api.ts`),
|
|
6
|
+
// statically validated and composed into SDK/CLI/cURL examples by
|
|
7
|
+
// `yarn dx recipes:generate`, and rendered in the in-app "Recipes" docs.
|
|
8
|
+
//
|
|
9
|
+
// Two layers live here:
|
|
10
|
+
// 1. Authoring types (`RecipeManifest`, `RecipeApi`) — what an author writes.
|
|
11
|
+
// 2. The generated reference entry (`RecipeReferenceEntry`) — what the
|
|
12
|
+
// generator emits and the frontend renders.
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Authoring types — `manifest.ts` + `api.ts`
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Kebab-case (lowercase words joined by single hyphens). Shared by recipe ids
|
|
17
|
+
// and category slugs: the docs nav groups by category and renders it via a
|
|
18
|
+
// kebab→sentence-case transform, so a free-form category (trailing space,
|
|
19
|
+
// spaces vs hyphens) could collapse two distinct categories into one nav group.
|
|
20
|
+
const KEBAB_CASE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
21
|
+
/**
|
|
22
|
+
* How often a recipe is validated — an **internal CI cadence**, never surfaced
|
|
23
|
+
* in the docs (deliberately not on `RecipeReferenceEntry`):
|
|
24
|
+
* - `'per-merge'` — rides the post-deploy smoke on every merge.
|
|
25
|
+
* - `{ everyDays: N }` — pulled out of the per-merge smoke; validated by the
|
|
26
|
+
* daily workflow only on the days it's "due" (date-modulo schedule).
|
|
27
|
+
* A future weekly tier is just `{ everyDays: 7 }` — no schema change.
|
|
28
|
+
*/
|
|
29
|
+
export const RecipeCadenceSchema = z.union([
|
|
30
|
+
z.literal('per-merge'),
|
|
31
|
+
z.object({ everyDays: z.number().int().positive() }).strict(),
|
|
32
|
+
]);
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Related links — the relationship graph between recipes and doc elements
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
//
|
|
37
|
+
// A recipe is no longer a floating island: its optional `related` block names
|
|
38
|
+
// what it **requires** (a prerequisite recipe or a precondition state), the
|
|
39
|
+
// **canonical** recipe it's a `variationOf` (one knob changed), and the concept
|
|
40
|
+
// / tutorial / resource pages worth reading to **learn more**. These are pure
|
|
41
|
+
// *metadata*, never execution — no recipe runs another; each still provisions
|
|
42
|
+
// and tears down its own world. They are a map read by the CLI (`rl recipes
|
|
43
|
+
// <id>`), the in-app recipe page, the agent (the recursion skill traverses
|
|
44
|
+
// them), and — later — the course generator. `recipes:check` validates that
|
|
45
|
+
// every target resolves and that the `requires` graph is acyclic.
|
|
46
|
+
/** A link to another **recipe** (traversable — the agent can follow it). */
|
|
47
|
+
export const RecipeRecipeTargetSchema = z
|
|
48
|
+
.object({ type: z.literal('recipe'), id: z.string().regex(KEBAB_CASE, 'id must be kebab-case') })
|
|
49
|
+
.strict();
|
|
50
|
+
/** A link to a **concept** (Explanation) page declared in `CONCEPT_REFERENCE`. */
|
|
51
|
+
export const RecipeConceptTargetSchema = z
|
|
52
|
+
.object({ type: z.literal('concept'), id: z.string().min(1) })
|
|
53
|
+
.strict();
|
|
54
|
+
/** A link to a **tutorial** page. */
|
|
55
|
+
export const RecipeTutorialTargetSchema = z
|
|
56
|
+
.object({ type: z.literal('tutorial'), id: z.string().min(1) })
|
|
57
|
+
.strict();
|
|
58
|
+
/** A link to a **resource** page. */
|
|
59
|
+
export const RecipeResourceTargetSchema = z
|
|
60
|
+
.object({ type: z.literal('resource'), id: z.string().min(1) })
|
|
61
|
+
.strict();
|
|
62
|
+
/**
|
|
63
|
+
* Any typed link target (`recipe | concept | tutorial | resource`). One typed
|
|
64
|
+
* model lets a recipe reference *any* doc element — relationships aren't only
|
|
65
|
+
* between recipes — instead of a separate field per kind.
|
|
66
|
+
*/
|
|
67
|
+
export const RecipeLinkTargetSchema = z.discriminatedUnion('type', [
|
|
68
|
+
RecipeRecipeTargetSchema,
|
|
69
|
+
RecipeConceptTargetSchema,
|
|
70
|
+
RecipeTutorialTargetSchema,
|
|
71
|
+
RecipeResourceTargetSchema,
|
|
72
|
+
]);
|
|
73
|
+
/**
|
|
74
|
+
* A `learnMore` target — the "why" behind the how-to: a concept / tutorial /
|
|
75
|
+
* resource. NOT a recipe (a recipe demonstrates; a concept explains — pairing
|
|
76
|
+
* them is what teaches the reader). The concept page lists its recipes via the
|
|
77
|
+
* inverse, so there's no second "taught by" field.
|
|
78
|
+
*/
|
|
79
|
+
export const RecipeLearnMoreTargetSchema = z.discriminatedUnion('type', [
|
|
80
|
+
RecipeConceptTargetSchema,
|
|
81
|
+
RecipeTutorialTargetSchema,
|
|
82
|
+
RecipeResourceTargetSchema,
|
|
83
|
+
]);
|
|
84
|
+
/**
|
|
85
|
+
* A `requires` entry that is a **state precondition** rather than a recipe — the
|
|
86
|
+
* common "the version must be locked" case that has no recipe of its own. It
|
|
87
|
+
* carries a human `explanation`, an optional machine-checkable `predicate`
|
|
88
|
+
* (e.g. `version.locked === true` — in L0 only *stored* and required to be a
|
|
89
|
+
* non-empty string; *evaluated* in a later layer), and an optional `via` link to
|
|
90
|
+
* whatever reaches the state (a recipe / concept / tutorial / resource).
|
|
91
|
+
*/
|
|
92
|
+
export const RecipeStateRequirementSchema = z
|
|
93
|
+
.object({
|
|
94
|
+
type: z.literal('state'),
|
|
95
|
+
explanation: z.string().min(1),
|
|
96
|
+
predicate: z.string().min(1).optional(),
|
|
97
|
+
via: RecipeLinkTargetSchema.optional(),
|
|
98
|
+
})
|
|
99
|
+
.strict();
|
|
100
|
+
/**
|
|
101
|
+
* A typed prerequisite: another **recipe** (a real, followable edge — "author a
|
|
102
|
+
* problem before grading it") or a **state** precondition (the explanation +
|
|
103
|
+
* optional predicate above). The backbone an agent traverses off the `now what?`
|
|
104
|
+
* cliff.
|
|
105
|
+
*/
|
|
106
|
+
export const RecipeRequiresEntrySchema = z.discriminatedUnion('type', [
|
|
107
|
+
RecipeRecipeTargetSchema,
|
|
108
|
+
RecipeStateRequirementSchema,
|
|
109
|
+
]);
|
|
110
|
+
/**
|
|
111
|
+
* The optional `related` block on a recipe — its place in the graph. All fields
|
|
112
|
+
* optional; an absent block means "no declared relationships" (an island, which
|
|
113
|
+
* `recipes:check` permits but the docs nudge away from).
|
|
114
|
+
*/
|
|
115
|
+
export const RecipeRelatedSchema = z
|
|
116
|
+
.object({
|
|
117
|
+
// Typed prerequisites (recipes and/or states) to satisfy before this recipe.
|
|
118
|
+
requires: z.array(RecipeRequiresEntrySchema).min(1).optional(),
|
|
119
|
+
// The canonical recipe this is a one-knob variation of (its id).
|
|
120
|
+
variationOf: z
|
|
121
|
+
.string()
|
|
122
|
+
.regex(KEBAB_CASE, 'variationOf must be a kebab-case recipe id')
|
|
123
|
+
.optional(),
|
|
124
|
+
// Related reading — the "why" behind the how-to.
|
|
125
|
+
learnMore: z.array(RecipeLearnMoreTargetSchema).min(1).optional(),
|
|
126
|
+
})
|
|
127
|
+
.strict();
|
|
128
|
+
/** A recipe's identity + docs metadata (`manifest.ts`). */
|
|
129
|
+
export const RecipeManifestSchema = z
|
|
130
|
+
.object({
|
|
131
|
+
// Stable kebab-case id; must match the recipe's folder name.
|
|
132
|
+
id: z.string().regex(KEBAB_CASE, 'id must be kebab-case'),
|
|
133
|
+
title: z.string().min(1),
|
|
134
|
+
// One-sentence statement of the user goal this recipe accomplishes.
|
|
135
|
+
goal: z.string().min(1),
|
|
136
|
+
// The canonical product domain this recipe lives under in the docs How-to nav
|
|
137
|
+
// (one of the eight `DOMAINS`). Kebab here; membership in `DOMAINS` is enforced
|
|
138
|
+
// fail-fast by `recipes:generate` (it can't import the domains module — schema
|
|
139
|
+
// files are loaded as source at codegen time, so they may only import npm deps).
|
|
140
|
+
category: z.string().regex(KEBAB_CASE, 'category must be kebab-case'),
|
|
141
|
+
// Internal CI validation cadence (required, no default — every recipe makes
|
|
142
|
+
// a deliberate tier choice). Read only by dx for smoke selection; NOT
|
|
143
|
+
// projected into the generated reference, so it never reaches the frontend.
|
|
144
|
+
cadence: RecipeCadenceSchema,
|
|
145
|
+
// Optional editorial one-liners for the walkthrough steps, keyed by the
|
|
146
|
+
// step's caption. Authored here (not captured), so editing copy is a fast
|
|
147
|
+
// `recipes:generate` — never a staging re-capture. Merged into the
|
|
148
|
+
// reference's walkthrough by `recipes:generate`.
|
|
149
|
+
stepDescriptions: z.record(z.string(), z.string()).optional(),
|
|
150
|
+
// The documented opt-out from the terminal GET-or-poll gate (`recipes:check`):
|
|
151
|
+
// every recipe must end its `main` phase by observing the user-meaningful
|
|
152
|
+
// outcome (a read or a `poll`). The ONLY exception is a last-mile step that
|
|
153
|
+
// genuinely has no API — e.g. the Intelligence reviewer's approval in
|
|
154
|
+
// `submit-and-review` — whose outcome is instead proven in `ui.spec`. Set this
|
|
155
|
+
// (with a non-empty reason naming the step) to satisfy the gate in that case.
|
|
156
|
+
outcomeInUiOnly: z
|
|
157
|
+
.object({ reason: z.string().min(1) })
|
|
158
|
+
.strict()
|
|
159
|
+
.optional(),
|
|
160
|
+
// The recipe's place in the relationship graph (prerequisites / canonical /
|
|
161
|
+
// related reading). Optional + additive; projected verbatim into the
|
|
162
|
+
// generated reference and validated by `recipes:check`.
|
|
163
|
+
related: RecipeRelatedSchema.optional(),
|
|
164
|
+
})
|
|
165
|
+
.strict();
|
|
166
|
+
/** A reference to a value captured by an earlier step (threading). */
|
|
167
|
+
export const RecipeRefSchema = z.object({ $ref: z.string().min(1) }).strict();
|
|
168
|
+
/**
|
|
169
|
+
* An input supplied to one of a step's params:
|
|
170
|
+
* - `{ $ref: '<captureName>' }` — threaded from an earlier step's capture.
|
|
171
|
+
* - `{ value: <json> }` — a literal rendered verbatim in the examples.
|
|
172
|
+
* Params not listed in a step's `inputs` render as placeholders (user-supplied).
|
|
173
|
+
*/
|
|
174
|
+
export const RecipeInputSchema = z.union([
|
|
175
|
+
RecipeRefSchema,
|
|
176
|
+
z.object({ value: z.unknown() }).strict(),
|
|
177
|
+
]);
|
|
178
|
+
/**
|
|
179
|
+
* A response-field condition: the value at `path` is one of `in`, OR (with
|
|
180
|
+
* `present: true`) is simply non-null. `present` gates on a field that only
|
|
181
|
+
* appears once the real outcome lands — e.g. `gradedAt`/`finalScore`, where the
|
|
182
|
+
* `status` string alone is ambiguous (a graded run passes through `completed`
|
|
183
|
+
* transiently before grading finalizes). Exactly one of `in` / `present`.
|
|
184
|
+
*/
|
|
185
|
+
// A union of two CLOSED variants rather than one flat object with an `.refine`
|
|
186
|
+
// exclusivity check, so every consumer reads `cond.in` / `cond.present` with no
|
|
187
|
+
// `?? []` defence. Note the static guarantee is partial: authoring NEITHER field
|
|
188
|
+
// (`{ path }`) is a `satisfies RecipeApiInput` compile error (both variants
|
|
189
|
+
// require their discriminating field), but authoring BOTH (`{ path, in, present }`)
|
|
190
|
+
// still compiles — TypeScript's excess-property check treats a property as
|
|
191
|
+
// "known" if it appears in ANY union constituent — and is only rejected at
|
|
192
|
+
// runtime by the `.strict()` variants inside `recipes:generate`/`recipes:check`.
|
|
193
|
+
// (Root CLAUDE.md: "Leverage discriminated unions" / "Encode as much invariant
|
|
194
|
+
// information in the type system as possible".)
|
|
195
|
+
const RecipePollConditionSchema = z.union([
|
|
196
|
+
z
|
|
197
|
+
.object({
|
|
198
|
+
// A field path on the operation's response, in the same grammar `captures`
|
|
199
|
+
// uses (e.g. `status`, `result.grade`). Read each poll iteration.
|
|
200
|
+
path: z.string().min(1),
|
|
201
|
+
// The values that satisfy the condition (≥1). For `until`, these are the
|
|
202
|
+
// terminal-success states; for `failOn`, the terminal-failure states.
|
|
203
|
+
in: z.array(z.string()).min(1),
|
|
204
|
+
})
|
|
205
|
+
.strict(),
|
|
206
|
+
z
|
|
207
|
+
.object({
|
|
208
|
+
path: z.string().min(1),
|
|
209
|
+
// Satisfied as soon as the field is present (non-null) — e.g. a numeric
|
|
210
|
+
// `finalScore` (including `0`), where a `status` string alone is ambiguous.
|
|
211
|
+
present: z.literal(true),
|
|
212
|
+
})
|
|
213
|
+
.strict(),
|
|
214
|
+
]);
|
|
215
|
+
/**
|
|
216
|
+
* A **poll** modifier on an SDK step: re-invoke this operation on an interval
|
|
217
|
+
* until it reaches a terminal state, *then* read its captures off that terminal
|
|
218
|
+
* response. This makes "wait for the result, then read it" a first-class,
|
|
219
|
+
* **documented** part of the recipe (rendered as a real loop in the SDK/CLI/cURL
|
|
220
|
+
* examples) rather than hidden test scaffolding — a recipe teaches the reader how
|
|
221
|
+
* to wait, exactly as the UI walkthrough does. The executor (`executeApiPlan`):
|
|
222
|
+
* - fails RED when `failOn` is set and its condition holds — `failOn.path`'s
|
|
223
|
+
* value is in `failOn.in` (or, with `present`, is non-null). Checked FIRST,
|
|
224
|
+
* so a terminal failure is surfaced, never masked by a coincident `until`.
|
|
225
|
+
* - stops successfully when `until` holds — `until.path`'s value is in
|
|
226
|
+
* `until.in`, or (with `present`) is non-null (e.g. `finalScore` landing).
|
|
227
|
+
* - fails RED when `timeoutMs` elapses first.
|
|
228
|
+
* Poll is SDK-only (an Intelligence step has no `operationId` to re-invoke).
|
|
229
|
+
*/
|
|
230
|
+
export const RecipePollSchema = z
|
|
231
|
+
.object({
|
|
232
|
+
until: RecipePollConditionSchema,
|
|
233
|
+
failOn: RecipePollConditionSchema.optional(),
|
|
234
|
+
timeoutMs: z.number().int().positive(),
|
|
235
|
+
intervalMs: z.number().int().positive(),
|
|
236
|
+
})
|
|
237
|
+
.strict();
|
|
238
|
+
/**
|
|
239
|
+
* An SDK step — today's `operationId`-based call. `setup` steps render as a
|
|
240
|
+
* marked preamble (each recipe provisions its own setup); `main` steps are the
|
|
241
|
+
* goal proper. `kind` defaults to `'sdk'` so existing (kind-less) recipes stay
|
|
242
|
+
* valid and the common case needs no `kind:` line.
|
|
243
|
+
*/
|
|
244
|
+
export const RecipeSdkStepSchema = z
|
|
245
|
+
.object({
|
|
246
|
+
kind: z.literal('sdk').default('sdk'),
|
|
247
|
+
operationId: z.string().min(1),
|
|
248
|
+
// Human caption — mirrors the matching `ui.spec` `test.step()` caption and
|
|
249
|
+
// doubles as the step heading in docs.
|
|
250
|
+
caption: z.string().optional(),
|
|
251
|
+
phase: z.enum(['setup', 'main']).default('main'),
|
|
252
|
+
// Param name → input value (threaded ref or literal).
|
|
253
|
+
inputs: z.record(z.string(), RecipeInputSchema).default({}),
|
|
254
|
+
// Optional poll: when set, this step waits for a terminal state (see
|
|
255
|
+
// RecipePollSchema) before reading its captures — the documented "wait for
|
|
256
|
+
// the result" step that lets a recipe prove its outcome.
|
|
257
|
+
poll: RecipePollSchema.optional(),
|
|
258
|
+
// Capture name → a field path on this operation's response shape.
|
|
259
|
+
captures: z.record(z.string(), z.string()).default({}),
|
|
260
|
+
})
|
|
261
|
+
.strict();
|
|
262
|
+
/**
|
|
263
|
+
* An Intelligence (Labelbox) step — a raw GraphQL command POSTed to
|
|
264
|
+
* `${LBX_URL}/api/_gql` with the SAME `Authorization: Bearer <LABELBOX_API_KEY>`
|
|
265
|
+
* the rl SDK/CLI already use. This surfaces the parts of a real flow that have
|
|
266
|
+
* no rl-gym SDK route (create a project, add a labeler, submit/review) so an
|
|
267
|
+
* agent reading the recipe gets the *complete* journey, not just the SDK slice.
|
|
268
|
+
* `caption` is REQUIRED — it is the user-facing instruction ("Create a project
|
|
269
|
+
* in Intelligence") that the whole feature exists to surface. `{ $ref }` markers
|
|
270
|
+
* embedded in `gql.variables` thread in earlier captures; `captures` reads
|
|
271
|
+
* fields off the GraphQL response's `data` object (e.g. `createProject.id`).
|
|
272
|
+
*/
|
|
273
|
+
export const RecipeIntelligenceStepSchema = z
|
|
274
|
+
.object({
|
|
275
|
+
kind: z.literal('intelligence'),
|
|
276
|
+
caption: z.string().min(1),
|
|
277
|
+
phase: z.enum(['setup', 'main']).default('main'),
|
|
278
|
+
gql: z
|
|
279
|
+
.object({
|
|
280
|
+
query: z.string().min(1),
|
|
281
|
+
// GraphQL variables; values may embed `{ $ref: '<capture>' }` markers,
|
|
282
|
+
// resolved against earlier captures at execution + render time.
|
|
283
|
+
variables: z.record(z.string(), z.unknown()).default({}),
|
|
284
|
+
})
|
|
285
|
+
.strict(),
|
|
286
|
+
// Capture name → a dot/`[]` path on the GraphQL `data` response.
|
|
287
|
+
captures: z.record(z.string(), z.string()).default({}),
|
|
288
|
+
})
|
|
289
|
+
.strict();
|
|
290
|
+
/**
|
|
291
|
+
* One step of a recipe's `api.ts`: an SDK call or an Intelligence GraphQL
|
|
292
|
+
* command. A plain `z.union` (not `discriminatedUnion`) is deliberate — Zod 4's
|
|
293
|
+
* `discriminatedUnion` reads the discriminator BEFORE applying defaults, so a
|
|
294
|
+
* `kind`-less step would fail to match; `z.union` tries the SDK variant first,
|
|
295
|
+
* whose defaulted `kind` absorbs the omitted discriminator. TypeScript still
|
|
296
|
+
* narrows on the `kind` literal at the consumer.
|
|
297
|
+
*/
|
|
298
|
+
export const RecipeApiStepSchema = z.union([RecipeSdkStepSchema, RecipeIntelligenceStepSchema]);
|
|
299
|
+
/** The ordered API plan for a recipe (`api.ts`). */
|
|
300
|
+
export const RecipeApiSchema = z
|
|
301
|
+
.object({
|
|
302
|
+
steps: z.array(RecipeApiStepSchema).min(1),
|
|
303
|
+
})
|
|
304
|
+
.strict();
|
|
305
|
+
// ---------------------------------------------------------------------------
|
|
306
|
+
// Generated reference entry — `recipes-reference.generated.ts`
|
|
307
|
+
// ---------------------------------------------------------------------------
|
|
308
|
+
/** A validated SDK step in the generated reference (phase/inputs/captures normalized). */
|
|
309
|
+
export const RecipeSdkReferenceStepSchema = z
|
|
310
|
+
.object({
|
|
311
|
+
kind: z.literal('sdk'),
|
|
312
|
+
operationId: z.string(),
|
|
313
|
+
caption: z.string().optional(),
|
|
314
|
+
phase: z.enum(['setup', 'main']),
|
|
315
|
+
inputs: z.record(z.string(), RecipeInputSchema),
|
|
316
|
+
// Mirrors the authoring step's `poll` (carried verbatim into the reference so
|
|
317
|
+
// the renderer can emit the wait-loop in the SDK/CLI/cURL examples).
|
|
318
|
+
poll: RecipePollSchema.optional(),
|
|
319
|
+
captures: z.record(z.string(), z.string()),
|
|
320
|
+
})
|
|
321
|
+
.strict();
|
|
322
|
+
/** A validated Intelligence step in the generated reference (normalized). */
|
|
323
|
+
export const RecipeIntelligenceReferenceStepSchema = z
|
|
324
|
+
.object({
|
|
325
|
+
kind: z.literal('intelligence'),
|
|
326
|
+
caption: z.string().min(1),
|
|
327
|
+
phase: z.enum(['setup', 'main']),
|
|
328
|
+
gql: z
|
|
329
|
+
.object({
|
|
330
|
+
query: z.string().min(1),
|
|
331
|
+
variables: z.record(z.string(), z.unknown()),
|
|
332
|
+
})
|
|
333
|
+
.strict(),
|
|
334
|
+
captures: z.record(z.string(), z.string()),
|
|
335
|
+
})
|
|
336
|
+
.strict();
|
|
337
|
+
/**
|
|
338
|
+
* A validated step in the generated reference. The reference is the *normalized*
|
|
339
|
+
* form (defaults already applied, so `kind` is always present) — a
|
|
340
|
+
* `discriminatedUnion` is safe here and gives precise per-variant errors.
|
|
341
|
+
*/
|
|
342
|
+
export const RecipeReferenceStepSchema = z.discriminatedUnion('kind', [
|
|
343
|
+
RecipeSdkReferenceStepSchema,
|
|
344
|
+
RecipeIntelligenceReferenceStepSchema,
|
|
345
|
+
]);
|
|
346
|
+
/**
|
|
347
|
+
* One step of the UI **walkthrough** — a user-facing caption next to its
|
|
348
|
+
* screenshot. Captured from the `ui.spec` run by `recipes:capture-media`
|
|
349
|
+
* (`image` is a filename under `apps/recursion/web/public/docs/recipes/<id>/`) and
|
|
350
|
+
* rendered as the docs Walkthrough filmstrip. The caption is page text beside
|
|
351
|
+
* the image, never burned into it.
|
|
352
|
+
*/
|
|
353
|
+
export const RecipeWalkthroughStepSchema = z
|
|
354
|
+
.object({
|
|
355
|
+
caption: z.string().min(1),
|
|
356
|
+
image: z.string().min(1),
|
|
357
|
+
// Optional editorial one-liner (from the manifest's `stepDescriptions`),
|
|
358
|
+
// rendered under the caption. Absent in the captured manifest.
|
|
359
|
+
description: z.string().optional(),
|
|
360
|
+
})
|
|
361
|
+
.strict();
|
|
362
|
+
/** The committed walkthrough manifest (`walkthrough.json`): an ordered step list. */
|
|
363
|
+
export const RecipeWalkthroughSchema = z.array(RecipeWalkthroughStepSchema);
|
|
364
|
+
/**
|
|
365
|
+
* A composed example for one surface, split by phase: the `setup` preamble
|
|
366
|
+
* (provisioning steps — `phase: 'setup'`) and the `main` goal steps. The docs
|
|
367
|
+
* render `setup` as a collapsed disclosure so the recipe's actual point leads;
|
|
368
|
+
* concatenating `setup` + `main` is the full runnable script. Either may be the
|
|
369
|
+
* empty string (a recipe with no setup steps, or none in main).
|
|
370
|
+
*/
|
|
371
|
+
export const RecipeSnippetSchema = z.object({ setup: z.string(), main: z.string() }).strict();
|
|
372
|
+
/**
|
|
373
|
+
* One recipe in the generated reference, keyed by id. Carries the docs
|
|
374
|
+
* metadata, the validated step plan, and the composed SDK/CLI/cURL examples
|
|
375
|
+
* (full runnable snippets with captured values threaded between steps), each
|
|
376
|
+
* split into a folded `setup` preamble + the `main` goal steps.
|
|
377
|
+
*/
|
|
378
|
+
export const RecipeReferenceEntrySchema = z
|
|
379
|
+
.object({
|
|
380
|
+
id: z.string(),
|
|
381
|
+
title: z.string(),
|
|
382
|
+
goal: z.string(),
|
|
383
|
+
// The canonical domain (carried verbatim from the manifest) — keeps the docs
|
|
384
|
+
// How-to nav grouping 1:1 with the domain taxonomy. Membership validated by
|
|
385
|
+
// `recipes:generate`.
|
|
386
|
+
category: z.string().regex(KEBAB_CASE, 'category must be kebab-case'),
|
|
387
|
+
// Docs video path, derived as `<id>.mp4` by the generator (never authored).
|
|
388
|
+
// Always present: the generator sets it unconditionally from `id` (it is a
|
|
389
|
+
// derived path string, not captured content), so every generated entry has
|
|
390
|
+
// one. The file's existence — and a non-empty walkthrough — are separately
|
|
391
|
+
// presence-checked by `recipes:check` before a recipe can land.
|
|
392
|
+
video: z.string().min(1),
|
|
393
|
+
// Ordered UI walkthrough (caption + screenshot per step), captured from the
|
|
394
|
+
// ui.spec run. Empty until `recipes:capture-media` has been run.
|
|
395
|
+
walkthrough: z.array(RecipeWalkthroughStepSchema).default([]),
|
|
396
|
+
steps: z.array(RecipeReferenceStepSchema).min(1),
|
|
397
|
+
// Composed, ready-to-render examples per representation (setup + main split).
|
|
398
|
+
sdk: RecipeSnippetSchema,
|
|
399
|
+
cli: RecipeSnippetSchema,
|
|
400
|
+
curl: RecipeSnippetSchema,
|
|
401
|
+
// The recipe's place in the graph, carried verbatim from the manifest so
|
|
402
|
+
// every surface (CLI / frontend / agent) reads one source. Absent when the
|
|
403
|
+
// recipe declares no relationships.
|
|
404
|
+
related: RecipeRelatedSchema.optional(),
|
|
405
|
+
})
|
|
406
|
+
.strict();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AUTO-GENERATED by 'yarn dx resources:generate'.
|
|
3
|
+
* Do not edit manually — changes will be overwritten.
|
|
4
|
+
*
|
|
5
|
+
* Explanation-layer resource hubs, keyed by resource id (= the OpenAPI tag
|
|
6
|
+
* name). One hub per domain-resource tag; the resource tree (`parent`),
|
|
7
|
+
* object shape, operations, and relationships are all derived from the
|
|
8
|
+
* backend OpenAPI spec.
|
|
9
|
+
*/
|
|
10
|
+
import type { ResourceReferenceEntry } from './resources-schema.js';
|
|
11
|
+
export declare const RESOURCE_REFERENCE: Record<string, ResourceReferenceEntry>;
|