@pipelex/sdk 0.60.0 → 0.62.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 CHANGED
@@ -178,6 +178,18 @@ const copy = await client.copyMethod(
178
178
  );
179
179
  if (copy.outcome === "copied") console.log(copy.method.copied_from); // the original it names
180
180
 
181
+ // The template catalog: the public methods every organization reads, in the platform's order, with
182
+ // the categories that have a template and each card's thumbnails behind short-lived links.
183
+ const templates = await client.listMethodTemplates({ category: "human-resources", limit: 8 });
184
+ for (const tab of templates.categories) console.log(tab.slug, tab.label);
185
+ // Another organization's public method reads in a narrower shape, its latest published version
186
+ // and no draft: `updated_at` is what tells it from one of your own.
187
+ const first = templates.items[0];
188
+ const template = first === undefined ? undefined : await client.getMethod(first.method_id);
189
+ if (template !== undefined && !("updated_at" in template)) {
190
+ console.log(template.latest_published.categories);
191
+ }
192
+
181
193
  // The organization's files, newest first: uploads, test files and the files runs made. Each row's
182
194
  // `uri` goes into a run's inputs as any address does. A filtered page can be empty and still carry
183
195
  // a nextCursor; iterateFiles follows it.
@@ -285,7 +297,8 @@ These pages ship inside the published package, so a reader who has only installe
285
297
  | [`docs/files.md`](./docs/files.md) | An organization's files: `listFiles` and `iterateFiles`, the row, the whole record and its provenance, the query and its repeated filters, paging through filtered pages, one file and its uses, the records of an address, the rename rule, links that name the file, a zip of files and its caps, a run's files, the copy into a method's draft, and an upload recorded as a method's test file with the refusals that come with it |
286
298
  | [`docs/method-examples.md`](./docs/method-examples.md) | A method's saved examples: the create, the paged list and its iterator, the edit that raises the input revision, the latest-run write and its `recorded` or `stale` verdict, the build assistant's save and its `kept` or `created` verdict, how an integer past `Number.MAX_SAFE_INTEGER` in the inputs stays exact, and what is refused before sending |
287
299
  | [`docs/method-copy.md`](./docs/method-copy.md) | Copying a method into another organization or duplicating it: what a copy holds and the stored files it copies, the `copied` or `refused` verdict, every refusal, the copy's idempotency key, and `copied_from` |
288
- | [`docs/organization-branding.md`](./docs/organization-branding.md) | An organization's logos and colours: `getBranding`, which every member and API key reads, `updateOrganizationBranding`, an admin's write that sets, clears or keeps each key, and how a refused logo or colour names its slot in `errors` so a settings screen shows the sentence under it |
300
+ | [`docs/public-methods.md`](./docs/public-methods.md) | Public methods and the template catalog: `listMethodTemplates` and its iterator, the ordering, the categories and the thumbnails' links, another organization's public method read in its narrower shape, the copy of a public method, `visibility` and `categories` on a method, and the refusals a public method's publish adds |
301
+ | [`docs/organization-branding.md`](./docs/organization-branding.md) | An organization's logos, colours, app style and typeface, and its white-label entitlement: `getBranding`, which every member and API key reads, `updateOrganizationBranding`, a write by the `admin` or the `member` role that sets, clears or keeps each key, and how a refused logo, colour, style or typeface names its field so a settings screen shows the sentence under it |
289
302
  | [`docs/exact-integers.md`](./docs/exact-integers.md) | Which reads keep an integer past `Number.MAX_SAFE_INTEGER` exact, as a `bigint` (a run's inputs and outputs, an example's inputs), how a request body writes it back with its digits, and `parseExactJson` and `stringifyExactJson` for code showing such data as JSON text |
290
303
  | [`docs/crate-routes.md`](./docs/crate-routes.md) | `resolve`, `codegen` and `pipeIo` — the method's tree as the protocol's `files` map, with its dependencies, the normalized crate, the stamped types, and a method's I/O artifacts without a validation — and the offline `runCodegenCheck` that guards a committed tree |
291
304
  | [`docs/client-identification.md`](./docs/client-identification.md) | The `User-Agent` every API request carries, and `appInfo`, the option that puts your program's name in front of it |
@@ -15,7 +15,7 @@ import type { CommandIO } from "./io.js";
15
15
  * update notice and npm 12's run notices off the script's stderr, which carries the command's
16
16
  * own lines, while npm's warnings and errors still print.
17
17
  */
18
- export declare const SCRIPT_RUNNER = "npx --yes --no-update-notifier --loglevel=warn @pipelex/sdk@0.60.0";
18
+ export declare const SCRIPT_RUNNER = "npx --yes --no-update-notifier --loglevel=warn @pipelex/sdk@0.62.0";
19
19
  export declare const SCRIPT_WRITER = "@pipelex/sdk";
20
20
  export declare const SCRIPT_NEEDS = "Node 22.12 or later";
21
21
  /** Run `pipelex-sdk script` and return its exit code. */
package/dist/client.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { MTHDSProtocol, ModelCategory, ModelDeck, RunOptions, StartOptions, VersionInfo } from "mthds/protocol";
2
2
  import type { CodegenRequest, CodegenResponse, CrateRouteOptions, DictPipeOutput, FormatResponse, LintResponse, ModelCheckCategory, ModelReferenceVerdict, PipeIORequest, PipeIOResponse, PipelexRunResultStart, PipelexValidateSource, PipelexValidationResult, ResolveRequest, ResolveResponse, ValidateMethodSelector } from "./models.js";
3
3
  import { type GetRunResultOptions, type RunProgress, type RunRead, type RunResults, type RunResultState, type StartAndWaitForResultOptions, type WaitForResultOptions } from "./runs.js";
4
- import type { BillingPortalResponse, ChangePlanResponse, CheckoutResponse, DraftFileFromFileInput, DraftFileFromFileResult, FileArchive, FileArchiveRequest, FileDetail, FileLinkTarget, FileLinksResult, FilePage, FileRecord, FileRecordList, FileRenameInput, FileSummary, GetFileQuery, GetFilesByUriOptions, InvoiceView, Membership, MembershipsResponse, OrganizationBranding, OrganizationBrandingUpdate, ListFilesQuery, ListMethodExamplesQuery, ListMethodsQuery, ListMethodVersionsQuery, ListRunFilesQuery, MethodCopyInput, MethodCopyResult, MethodData, MethodDeletionAccepted, MethodDetail, MethodDraftInput, MethodExample, MethodExampleAssistantSaveInput, MethodExampleAssistantSaveResult, MethodExampleCreateInput, MethodExampleLatestRunInput, MethodExampleLatestRunResult, MethodExamplePage, MethodExampleUpdateInput, MethodPage, MethodPublishInput, MethodPublishResult, MethodRenameInput, MethodSummary, MethodVersion, MethodVersionPage, MethodWriteInput, OnboardingSubmission, PipelexApiKeyCreated, PipelexApiKeyList, ListRunsQuery, RunHistoryItem, RunDetail, RunFilesPage, RunPage, PlanView, ResolvedStorageUrl, SavedMethodFile, SubscriptionResponse, UpdateRunInput, UploadGrant, UploadGrantInput, UploadInput, UploadedFile, UserProfile } from "./product-models.js";
4
+ import type { BillingPortalResponse, ChangePlanResponse, CheckoutResponse, DraftFileFromFileInput, DraftFileFromFileResult, FileArchive, FileArchiveRequest, FileDetail, FileLinkTarget, FileLinksResult, FilePage, FileRecord, FileRecordList, FileRenameInput, FileSummary, GetFileQuery, GetFilesByUriOptions, InvoiceView, Membership, MembershipsResponse, OrganizationBranding, OrganizationBrandingUpdate, ListFilesQuery, ListMethodExamplesQuery, ListMethodsQuery, ListMethodTemplatesQuery, ListMethodVersionsQuery, ListRunFilesQuery, MethodCopyInput, MethodCopyResult, MethodData, MethodDeletionAccepted, MethodDetail, MethodDraftInput, MethodExample, MethodExampleAssistantSaveInput, MethodExampleAssistantSaveResult, MethodExampleCreateInput, MethodExampleLatestRunInput, MethodExampleLatestRunResult, MethodExamplePage, MethodExampleUpdateInput, MethodPage, MethodPublishInput, MethodPublishResult, MethodRenameInput, MethodSummary, MethodTemplate, MethodTemplatePage, MethodVersion, MethodVersionPage, MethodWriteInput, OnboardingSubmission, PublicMethodDetail, PipelexApiKeyCreated, PipelexApiKeyList, ListRunsQuery, RunHistoryItem, RunDetail, RunFilesPage, RunPage, PlanView, ResolvedStorageUrl, SavedMethodFile, SubscriptionResponse, UpdateRunInput, UploadGrant, UploadGrantInput, UploadInput, UploadedFile, UserProfile } from "./product-models.js";
5
5
  import type { MethodTreeForms, MethodTreeLimits } from "./method-trees.js";
6
6
  import type { AppInfo } from "./user-agent.js";
7
7
  import type { WebhookDeliveryDetail, WebhookDeliveryList, WebhookReplayAccepted, WebhookReplayOptions, WebhookSecret, WebhookSecretRotateOptions } from "./webhooks.js";
@@ -988,7 +988,49 @@ export declare class PipelexApiClient implements HostedProtocolSurface {
988
988
  */
989
989
  iterateMethods(query?: Omit<ListMethodsQuery, "cursor">): AsyncGenerator<MethodSummary, void, undefined>;
990
990
  /**
991
- * Read one method with its draft's files — `GET /v1/methods/{id}`: its identity, its draft
991
+ * One page of the template catalog — `GET /v1/method-templates`: the public methods of the
992
+ * organization the deployment names as its templates organization, the same for every caller.
993
+ *
994
+ * The templates the ordering lists lead, in its order, and every other template follows by name.
995
+ * `ordering` names the ordering to serve, such as `default` or an arm of a test; an absent,
996
+ * unknown or malformed name serves `default`, and the page's `ordering` names the one served,
997
+ * `null` when there is none. `category` keeps one category's templates, by slug, in the same
998
+ * order; an unknown slug keeps none. Whatever the filter, the page's `categories` names, with its
999
+ * label, every category at least one template shows, in the catalog's order, so no tab drawn
1000
+ * from it is ever empty.
1001
+ *
1002
+ * Each `MethodTemplate` carries the method's id and name, its latest published version's number,
1003
+ * description and categories, its organization's display name and each thumbnail with its size
1004
+ * and a link to its bytes valid for about fifteen minutes. A template reads, runs and copies by
1005
+ * its `method_id`, as another organization's public method does (`getMethod`, `copyMethod`).
1006
+ *
1007
+ * Pass the page's `nextCursor` back as `cursor` with the same `ordering` and `category`, which the
1008
+ * cursor does not hold; `null` is the last page. `iterateMethodTemplates` follows it for you.
1009
+ *
1010
+ * Throws `ApiResponseError`: `422` `request.invalid` for a `limit` outside 1 to 200 or a cursor of
1011
+ * another listing, `422` `request.malformed` for a cursor that does not decode, `500`
1012
+ * `runtime.misconfigured` when the templates organization the deployment names has no record or
1013
+ * a link cannot be signed, and `503` `runtime.unavailable`, safe to retry. A page whose `items`
1014
+ * or `categories` is not an array, whose `next_cursor` or `ordering` is neither a string nor
1015
+ * `null`, a template lacking a member a card is drawn from (a string `method_id`, `name` and
1016
+ * `organization_name`, a `description` that is a string or `null`, a positive integer
1017
+ * `latest_version`, an array of string `categories`, and `thumbnails` each with a string `path`,
1018
+ * `media_type`, `sha256`, `url` and `expires_at` and a positive integer `width` and `height`), and a
1019
+ * category without a string `slug` and `label` are an answer the SDK cannot read, thrown as an
1020
+ * `ApiResponseError` too, its links redacted.
1021
+ */
1022
+ listMethodTemplates(query?: ListMethodTemplatesQuery): Promise<MethodTemplatePage>;
1023
+ /**
1024
+ * Every template of the catalog, in the order served — follows `listMethodTemplates`'s cursor
1025
+ * for you, with the same `ordering` and `category` on every page. It stops on a `null` cursor or
1026
+ * on a cursor the server failed to advance, and throws `PagingNotTerminatingError` past a page
1027
+ * ceiling no real catalog reaches. The ordering served and the categories are on each page, so
1028
+ * read one page with `listMethodTemplates` when you need them.
1029
+ */
1030
+ iterateMethodTemplates(query?: Omit<ListMethodTemplatesQuery, "cursor">): AsyncGenerator<MethodTemplate, void, undefined>;
1031
+ /**
1032
+ * Read one method with its files — `GET /v1/methods/{id}`. One of the caller's organization's
1033
+ * methods answers a `MethodDetail`: its identity, its draft
992
1034
  * (`files`, `input_data`) with the draft's token (`updated_at`) and digest (`draft_digest`),
993
1035
  * and its latest published version's summary (`latest_version`, `latest_published`), whatever
994
1036
  * the publish state. A method never published reads with both `null`, never as an error.
@@ -996,6 +1038,11 @@ export declare class PipelexApiClient implements HostedProtocolSurface {
996
1038
  * link to its bytes valid for about fifteen minutes, and is empty for an empty draft;
997
1039
  * `writeMethodTree` brings the tree to disk.
998
1040
  *
1041
+ * **Another organization's public method reads too, in a narrower shape**, a
1042
+ * `PublicMethodDetail`: its latest published version, that version's description, categories
1043
+ * and files, and nothing of its draft or of the owner's people, so no `updated_at` to write or
1044
+ * publish with. Narrow the answer with `"updated_at" in method` before reading the draft.
1045
+ *
999
1046
  * Takes a bare catalog id: the method routes address the method itself, never a version of
1000
1047
  * it. A caller holding `mt_…@3` strips the suffix with `parseMethodSelector` and reads that
1001
1048
  * version with `getMethodVersion`. Every method route throws `RequestArgumentError` for a
@@ -1003,13 +1050,18 @@ export declare class PipelexApiClient implements HostedProtocolSurface {
1003
1050
  * and for an id that is empty, `.` or `..`, which the URL would resolve into another route's
1004
1051
  * path.
1005
1052
  *
1006
- * Throws `ApiResponseError`: `404` `pipelex.catalog.not_found` for an unknown or foreign-org
1007
- * method, `409` `pipelex.catalog.being_deleted` while its erasure runs, and a `500`
1008
- * `runtime.unexpected` for a method whose draft names a tree the platform holds no record of. An
1009
- * answer whose `files` is not a listing is an answer the SDK cannot read, thrown as an
1010
- * `ApiResponseError` too.
1053
+ * Throws `ApiResponseError`: `404` `pipelex.catalog.not_found` for an unknown method, for
1054
+ * another organization's internal one, and for a public one made internal again or being
1055
+ * erased; `409` `pipelex.catalog.being_deleted` while the erasure of the caller's own method
1056
+ * runs; and a `500` `runtime.unexpected` for a method whose tree the platform holds no record
1057
+ * of. An answer whose `files` is not a listing is an answer the SDK cannot read, thrown as an
1058
+ * `ApiResponseError` too, its links redacted, and so is one that lacks `updated_at` while it
1059
+ * carries a member only the owner's read has (`draft_digest`, `created_by_user_id`,
1060
+ * `input_data`, `pipe_output`, `copied_from`, `deletion_state`), which would otherwise pass for
1061
+ * another organization's public method, and a public read without an integer `latest_version`
1062
+ * and a `latest_published` object.
1011
1063
  */
1012
- getMethod(methodId: string): Promise<MethodDetail>;
1064
+ getMethod(methodId: string): Promise<MethodDetail | PublicMethodDetail>;
1013
1065
  /**
1014
1066
  * Create a method — `POST /v1/methods`. The new method holds its tree as its draft and has no
1015
1067
  * published version, so its bare id answers `409` `pipelex.catalog.not_published` on the run and
@@ -1239,9 +1291,12 @@ export declare class PipelexApiClient implements HostedProtocolSurface {
1239
1291
  *
1240
1292
  * The answer is a `MethodPublishResult` discriminated on `outcome` — branch on it:
1241
1293
  * `published` with the new `version`; `unchanged` with the existing latest `version`;
1242
- * `refused` with a `reason` (`invalid`, or `not_runnable` for a draft that validates with
1243
- * pending signatures), a `message` and the runner's `validation` verdict, whose problem items
1244
- * are read member by member as `validate` reads them. Every arm carries the `method`. A publish
1294
+ * `refused` with a `reason`, a `message` and the runner's `validation` verdict, whose problem
1295
+ * items are read member by member as `validate` reads them. The reason is `invalid`, or
1296
+ * `not_runnable` for a draft that validates with pending signatures, and for a public method
1297
+ * also `thumbnail_missing`, `thumbnail_invalid` or `storage_reference` (see
1298
+ * `MethodPublishRefusalReason`); a reason this SDK does not know is passed through as its raw
1299
+ * string, still a verdict, so show its `message`. Every arm carries the `method`. A publish
1245
1300
  * moves no token.
1246
1301
  *
1247
1302
  * Takes a bare catalog id, as `getMethod` does. Throws `RequestArgumentError` when
@@ -1256,11 +1311,14 @@ export declare class PipelexApiClient implements HostedProtocolSurface {
1256
1311
  * cannot be reached, answers unusably or does not finish within the platform's deadline is a
1257
1312
  * `502` or a `503` with nothing written, so a retry is safe; a runner that refuses the request
1258
1313
  * itself is relayed under its own status. A retry of a publish that landed while its answer was
1259
- * lost, as on a client timeout, answers `unchanged` with the version it wrote.
1314
+ * lost, as on a client timeout, answers `unchanged` with the version it wrote. A method made
1315
+ * public while its publish ran is a `503` with nothing written, safe to retry, which a retry
1316
+ * judges as a public method's publish.
1260
1317
  *
1261
1318
  * An answer whose `outcome` is not one of the outcomes above, that carries no `method` object,
1262
- * or a refusal whose `validation` is not a verdict object with a boolean `is_valid`, is an answer
1263
- * the SDK cannot read, thrown as an `ApiResponseError` too.
1319
+ * or a refusal whose `reason` or `message` is not a string or whose `validation` is not a verdict
1320
+ * object with a boolean `is_valid`, is an answer the SDK cannot read, thrown as an
1321
+ * `ApiResponseError` too.
1264
1322
  */
1265
1323
  publishMethod(methodId: string, input: MethodPublishInput): Promise<MethodPublishResult>;
1266
1324
  /**
@@ -1269,11 +1327,13 @@ export declare class PipelexApiClient implements HostedProtocolSurface {
1269
1327
  *
1270
1328
  * Pass the page's `nextCursor` back as `cursor` to continue; `null` is the last page. A page
1271
1329
  * may be short while `nextCursor` is set, because the platform reads versions whole. A method
1272
- * never published answers an empty page.
1330
+ * never published answers an empty page. Another organization's public method lists its
1331
+ * versions too, each without its `published_by`.
1273
1332
  *
1274
1333
  * Takes a bare catalog id, as `getMethod` does. Throws `ApiResponseError`: `404`
1275
- * `pipelex.catalog.not_found` for an unknown method, `409` `pipelex.catalog.being_deleted`, and
1276
- * `422` `request.invalid` for a cursor the listing did not issue for this method or a `limit`
1334
+ * `pipelex.catalog.not_found` for an unknown method and for another organization's internal
1335
+ * one, `409` `pipelex.catalog.being_deleted` while the erasure of the caller's own method runs,
1336
+ * and `422` `request.invalid` for a cursor the listing did not issue for this method or a `limit`
1277
1337
  * outside 1 to 100. A page whose `items` is not an array or whose `next_cursor` is neither a
1278
1338
  * string nor `null` is an answer the SDK cannot read, thrown as an `ApiResponseError` too.
1279
1339
  */
@@ -1281,12 +1341,15 @@ export declare class PipelexApiClient implements HostedProtocolSurface {
1281
1341
  /**
1282
1342
  * One published version of a method, with its files — `GET /v1/methods/{id}/versions/{n}`.
1283
1343
  * `files` lists the version's tree as `getMethod` lists the draft's, each file with a link to
1284
- * its bytes valid for about fifteen minutes, which `writeMethodTree` writes to disk.
1344
+ * its bytes valid for about fifteen minutes, which `writeMethodTree` writes to disk. Another
1345
+ * organization's public method reads its versions too, without their `published_by`, the files
1346
+ * linked in the organization that holds it.
1285
1347
  *
1286
1348
  * Takes a bare catalog id, as `getMethod` does, and the version number. Throws
1287
1349
  * `RequestArgumentError` for a `version` that is not a positive integer, before any request.
1288
1350
  * Throws `ApiResponseError`: `404` `pipelex.catalog.not_found` for a version the method never
1289
- * published and for an unknown method, `409` `pipelex.catalog.being_deleted`, and `500`
1351
+ * published, for an unknown method and for another organization's internal one, `409`
1352
+ * `pipelex.catalog.being_deleted` while the erasure of the caller's own method runs, and `500`
1290
1353
  * `runtime.unexpected` for a version stored before methods were trees and never rewritten as
1291
1354
  * one, which names no tree to serve.
1292
1355
  */
@@ -1303,10 +1366,16 @@ export declare class PipelexApiClient implements HostedProtocolSurface {
1303
1366
  * original stays as it was. The copy takes the draft, never the latest published version; with
1304
1367
  * `expected_draft_updated_at`, it takes exactly the draft the caller last saw.
1305
1368
  *
1369
+ * **Another organization's public method copies too**, a template of the catalog among them,
1370
+ * from its latest published version rather than its draft: that version's tree, description and
1371
+ * categories, and the method's examples, never the owner's form inputs, with `copied_from`
1372
+ * naming the `version`. Leave `expected_draft_updated_at` out then: sent with such a method, it
1373
+ * is refused with a `422` `request.invalid` naming it.
1374
+ *
1306
1375
  * The answer is a `MethodCopyResult` discriminated on `outcome` — branch on it: `copied` with
1307
1376
  * the copy as `method`, `examples_copied` and `stored_files_copied`; `refused` with the
1308
1377
  * `reason` `bundle_names_other_storage`, a `message` and every `references` entry (`{ path, uri
1309
- * }`) a `.mthds` file of the draft holds that the destination cannot read and, in a duplicate,
1378
+ * }`) a `.mthds` file of the tree holds that the destination cannot read and, in a duplicate,
1310
1379
  * that names a file under the original's run files, which erasing the original would remove,
1311
1380
  * nothing written.
1312
1381
  *
@@ -1325,7 +1394,8 @@ export declare class PipelexApiClient implements HostedProtocolSurface {
1325
1394
  * that is not from a web session, or for a role that may not change methods, in the method's
1326
1395
  * organization or in the destination; `404` `pipelex.org.not_found` for a destination the
1327
1396
  * caller does not belong to, still being set up or unknown, alike; `404`
1328
- * `pipelex.catalog.not_found` for an unknown method; `409` `pipelex.catalog.being_deleted`;
1397
+ * `pipelex.catalog.not_found` for an unknown method and for another organization's internal
1398
+ * one; `409` `pipelex.catalog.being_deleted` while the erasure of the caller's own method runs;
1329
1399
  * `409` `pipelex.catalog.update_conflict` for a draft that moved since
1330
1400
  * `expected_draft_updated_at`; a `409` whose `domain` is `runtime` and `retry` `no`, for a
1331
1401
  * draft whose tree the method's organization holds no record of or no longer holds every file
@@ -1527,32 +1597,41 @@ export declare class PipelexApiClient implements HostedProtocolSurface {
1527
1597
  }): Promise<Membership>;
1528
1598
  /**
1529
1599
  * The branding of the caller's active organization — `GET /v1/branding`: its name, its light
1530
- * and dark colour sets and its two logos. Any role reads it, `runner` included, by web session
1531
- * or API key, so an app scaffolded from the method-app template reads its organization's
1532
- * branding with its own key. A personal workspace, or a team that set nothing, answers every
1533
- * colour and logo `null`. A logo's `uri` is a `pipelex-storage://` reference, which
1534
- * `resolveStorageUrl` turns into a short-lived link to its bytes.
1535
- *
1536
- * Throws `ApiResponseError`: `400` when the caller has no active organization, `404` when its
1537
- * row is missing, and an answer that is not a JSON object, an empty one included.
1600
+ * and dark colour sets, its two logos, its app style and typeface, and whether it holds the
1601
+ * white-label entitlement. Any role reads it, `runner` included, by web session or API key, so
1602
+ * an app scaffolded from the method-app template reads its organization's branding with its own
1603
+ * key. A personal workspace, or a team that set nothing, answers every colour and logo `null`
1604
+ * and no style or typeface. A logo's `uri` is a `pipelex-storage://` reference, which
1605
+ * `resolveStorageUrl` turns into a short-lived link to its bytes. An answer without `style`,
1606
+ * `typeface` or `white_label`, as a platform that predates them sends, reads as `null`, `null`
1607
+ * and `false`.
1608
+ *
1609
+ * Throws `ApiResponseError`: `403` `pipelex.org.required` when the caller has no active
1610
+ * organization, `404` when its row is missing, and an answer that is not a JSON object, an
1611
+ * empty one included.
1538
1612
  */
1539
1613
  getBranding(): Promise<OrganizationBranding>;
1540
1614
  /**
1541
- * Set or clear an organization's branding — `PATCH /v1/organizations/{org_id}/branding`, an
1542
- * admin's write to the active organization. Every key of `input` is optional: a value sets it,
1543
- * `null` clears it, and a key left out keeps its value (`OrganizationBrandingUpdate`), so `{}`
1544
- * writes nothing. A new logo is the `pipelex-storage://` URI of a file the organization uploaded
1545
- * on its own, which the platform reads and measures, then copies under `branding/`: the answer's
1546
- * `uri` is that copy, and sending it back unchanged keeps the logo. The logo a write replaces or
1547
- * clears is erased. Answers the branding as the write left it.
1615
+ * Set or clear an organization's branding — `PATCH /v1/organizations/{org_id}/branding`, a
1616
+ * write to the active organization by the `admin` or the `member` role, never a `runner`. Every
1617
+ * key of `input` is optional: a value sets it, `null` clears it, and a key left out keeps its
1618
+ * value (`OrganizationBrandingUpdate`), so `{}` writes nothing. A new logo is the
1619
+ * `pipelex-storage://` URI of a file the organization uploaded on its own, which the platform
1620
+ * reads and measures, then copies under `branding/`: the answer's `uri` is that copy, and sending
1621
+ * it back unchanged keeps the logo. The logo a write replaces or clears is erased. A style or a
1622
+ * typeface is an id of the shape `^[a-z0-9-]{1,32}$`, stored whether or not it names one that
1623
+ * exists. Answers the branding as the write left it, read as `getBranding` reads it.
1548
1624
  *
1549
1625
  * Throws `RequestArgumentError` for an organization id that is empty, `.` or `..`, before any
1550
1626
  * request. Throws `ApiResponseError`, refusing every change of the request when it refuses one:
1551
1627
  * `403` `pipelex.org.mismatch` when `orgId` is not the active organization, `403`
1552
- * `auth.forbidden` for a caller who is not its admin, `404` `pipelex.org.not_found` for a missing
1553
- * organization, `409` `pipelex.org.not_manageable` for a personal workspace, which has no
1554
- * branding, and `422` `request.invalid` for a colour that is not `#rrggbb` or a key the body does
1555
- * not know. A logo's refusal names its slot in its problem's `errors`, each item's
1628
+ * `auth.forbidden` for a runner or a caller with no recognised role, `404`
1629
+ * `pipelex.org.not_found` for a missing organization, `409` `pipelex.org.not_manageable` for a
1630
+ * personal workspace, which has no branding, and `422` `request.invalid` for a colour that is
1631
+ * not `#rrggbb`, a style or a typeface of another shape, or a key the body does not know, which
1632
+ * names the field in `location.field`: the problem's own when it refuses one field alone, each
1633
+ * item's of its `errors` when it refuses several. `white_label` is such a key, since only
1634
+ * Pipelex staff grant it. A logo's refusal names its slot in its problem's `errors`, each item's
1556
1635
  * `location.field` being `square_logo` or `wide_logo` and its `detail` the sentence to show under
1557
1636
  * that slot: `422` `pipelex.storage.uri_invalid` for a URI that is not a storage URI, `403`
1558
1637
  * `pipelex.org.mismatch` for another organization's file, and `422` `request.invalid` with an