superartifacts 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,3286 @@
1
+ # Generated from sdks/openapi.json, spec hash f1886b4302fd534ad9d18552806f52f6cee192f699da87d92a6b2d59e51a3288. Do not edit.
2
+ from __future__ import annotations
3
+
4
+ from typing import Any, AsyncIterator, Dict, Iterator, List, Literal, Optional
5
+
6
+ from .._helpers import OMIT, ArtifactHelper, AsyncArtifactHelper, AsyncUploadHelper, UploadHelper
7
+ from .._helpers import awalk_cursor, awalk_pages, walk_cursor, walk_pages
8
+
9
+
10
+ class _Resource:
11
+ def __init__(self, client: Any) -> None:
12
+ self._client = client
13
+
14
+
15
+ class Account(_Resource):
16
+
17
+ def whoami(
18
+ self,
19
+ *,
20
+ timeout: Optional[float] = None,
21
+ ) -> Dict[str, Any]:
22
+ """Who this key publishes as.
23
+
24
+ Who this key publishes as: the workspace `handle`, `email`, `agent` name and `scope`
25
+ (the artifacts it may change: its own, and those it is named Editor on), plus
26
+ `liveRooms` where live rooms run (the limit and who holds one). Useful to confirm where
27
+ a publish lands, or why an artifact answers `not_found`; no other tool needs it.
28
+ """
29
+ return self._client._call(
30
+ "GET",
31
+ "/v1/whoami",
32
+ timeout=timeout,
33
+ )
34
+
35
+ def help(
36
+ self,
37
+ *,
38
+ topic: Optional[Literal["tools", "data", "templates", "collections", "projects", "batch"]] = None,
39
+ timeout: Optional[float] = None,
40
+ ) -> Dict[str, Any]:
41
+ """How the operations fit together.
42
+
43
+ Plain-text notes for when it is unclear which tool, data store or argument shape does a
44
+ job. Topics: `tools` (a line per tool), `data` (which store a page needs and how the
45
+ page writes to it), `templates` (finding, building from, drafting, releasing),
46
+ `collections` (content models and field types), `projects` (creating, ordering, sharing,
47
+ rules), `batch` (what each tool takes in one call). Without `topic`: the full topic
48
+ list, which names two more reached from results. Answers `{topic, text}`; not needed
49
+ when a tool’s own description answers the question.
50
+ """
51
+ return self._client._call(
52
+ "GET",
53
+ "/v1/help",
54
+ query={"topic": topic},
55
+ timeout=timeout,
56
+ )
57
+
58
+
59
+ class Webhooks(_Resource):
60
+
61
+ def list(
62
+ self,
63
+ *,
64
+ agent: Optional[str] = None,
65
+ timeout: Optional[float] = None,
66
+ ) -> Dict[str, Any]:
67
+ """List account webhook endpoints.
68
+
69
+ Manage this account’s webhook endpoints. create and rotate return the signing secret
70
+ once; delete permanently removes an endpoint and its delivery history. Mutations require
71
+ write scope. agent: "me" selects the calling key’s agent (no_agent if absent); a handle
72
+ must be owned. messages returns the newest 100, optionally filtered by endpoint id and
73
+ sinceMinutes (1–43200). Declare artifact triggers through super_publish.
74
+ """
75
+ return self._client._call(
76
+ "GET",
77
+ "/v1/webhooks",
78
+ query={"agent": agent},
79
+ timeout=timeout,
80
+ )
81
+
82
+ def create(
83
+ self,
84
+ *,
85
+ url: Optional[str] = None,
86
+ description: Optional[str] = None,
87
+ event_types: Optional[List[str]] = None,
88
+ agent: Optional[str] = None,
89
+ idempotency_key: Optional[str] = None,
90
+ timeout: Optional[float] = None,
91
+ ) -> Dict[str, Any]:
92
+ """Create an endpoint; returns its signing secret once.
93
+
94
+ Manage this account’s webhook endpoints. create and rotate return the signing secret
95
+ once; delete permanently removes an endpoint and its delivery history. Mutations require
96
+ write scope. agent: "me" selects the calling key’s agent (no_agent if absent); a handle
97
+ must be owned. messages returns the newest 100, optionally filtered by endpoint id and
98
+ sinceMinutes (1–43200). Declare artifact triggers through super_publish.
99
+ """
100
+ return self._client._call(
101
+ "POST",
102
+ "/v1/webhooks",
103
+ body={"url": url, "description": description, "eventTypes": event_types, "agent": agent},
104
+ idempotency_key=idempotency_key,
105
+ timeout=timeout,
106
+ )
107
+
108
+ def get(
109
+ self,
110
+ *,
111
+ id: str,
112
+ timeout: Optional[float] = None,
113
+ ) -> Dict[str, Any]:
114
+ """Read an owned endpoint.
115
+
116
+ Manage this account’s webhook endpoints. create and rotate return the signing secret
117
+ once; delete permanently removes an endpoint and its delivery history. Mutations require
118
+ write scope. agent: "me" selects the calling key’s agent (no_agent if absent); a handle
119
+ must be owned. messages returns the newest 100, optionally filtered by endpoint id and
120
+ sinceMinutes (1–43200). Declare artifact triggers through super_publish.
121
+ """
122
+ return self._client._call(
123
+ "GET",
124
+ "/v1/webhooks/{id}",
125
+ path_params={"id": id},
126
+ timeout=timeout,
127
+ )
128
+
129
+ def delete(
130
+ self,
131
+ *,
132
+ id: str,
133
+ timeout: Optional[float] = None,
134
+ ) -> Dict[str, Any]:
135
+ """Delete an endpoint and its history.
136
+
137
+ Manage this account’s webhook endpoints. create and rotate return the signing secret
138
+ once; delete permanently removes an endpoint and its delivery history. Mutations require
139
+ write scope. agent: "me" selects the calling key’s agent (no_agent if absent); a handle
140
+ must be owned. messages returns the newest 100, optionally filtered by endpoint id and
141
+ sinceMinutes (1–43200). Declare artifact triggers through super_publish.
142
+ """
143
+ return self._client._call(
144
+ "DELETE",
145
+ "/v1/webhooks/{id}",
146
+ path_params={"id": id},
147
+ timeout=timeout,
148
+ )
149
+
150
+ def test(
151
+ self,
152
+ *,
153
+ id: str,
154
+ idempotency_key: Optional[str] = None,
155
+ timeout: Optional[float] = None,
156
+ ) -> Dict[str, Any]:
157
+ """Send a signed webhook.test.
158
+
159
+ Manage this account’s webhook endpoints. create and rotate return the signing secret
160
+ once; delete permanently removes an endpoint and its delivery history. Mutations require
161
+ write scope. agent: "me" selects the calling key’s agent (no_agent if absent); a handle
162
+ must be owned. messages returns the newest 100, optionally filtered by endpoint id and
163
+ sinceMinutes (1–43200). Declare artifact triggers through super_publish.
164
+ """
165
+ return self._client._call(
166
+ "POST",
167
+ "/v1/webhooks/{id}/test",
168
+ path_params={"id": id},
169
+ idempotency_key=idempotency_key,
170
+ timeout=timeout,
171
+ )
172
+
173
+ def rotate_secret(
174
+ self,
175
+ *,
176
+ id: str,
177
+ idempotency_key: Optional[str] = None,
178
+ timeout: Optional[float] = None,
179
+ ) -> Dict[str, Any]:
180
+ """Rotate the signing secret; returns it once.
181
+
182
+ Manage this account’s webhook endpoints. create and rotate return the signing secret
183
+ once; delete permanently removes an endpoint and its delivery history. Mutations require
184
+ write scope. agent: "me" selects the calling key’s agent (no_agent if absent); a handle
185
+ must be owned. messages returns the newest 100, optionally filtered by endpoint id and
186
+ sinceMinutes (1–43200). Declare artifact triggers through super_publish.
187
+ """
188
+ return self._client._call(
189
+ "POST",
190
+ "/v1/webhooks/{id}/rotate",
191
+ path_params={"id": id},
192
+ idempotency_key=idempotency_key,
193
+ timeout=timeout,
194
+ )
195
+
196
+ def messages(
197
+ self,
198
+ *,
199
+ id: Optional[str] = None,
200
+ since_minutes: Optional[int] = None,
201
+ timeout: Optional[float] = None,
202
+ ) -> Dict[str, Any]:
203
+ """Read the newest 100 webhook messages.
204
+
205
+ Manage this account’s webhook endpoints. create and rotate return the signing secret
206
+ once; delete permanently removes an endpoint and its delivery history. Mutations require
207
+ write scope. agent: "me" selects the calling key’s agent (no_agent if absent); a handle
208
+ must be owned. messages returns the newest 100, optionally filtered by endpoint id and
209
+ sinceMinutes (1–43200). Declare artifact triggers through super_publish.
210
+ """
211
+ return self._client._call(
212
+ "GET",
213
+ "/v1/webhook-messages",
214
+ query={"id": id, "sinceMinutes": since_minutes},
215
+ timeout=timeout,
216
+ )
217
+
218
+
219
+ class Artifacts(ArtifactHelper, _Resource):
220
+
221
+ def list(
222
+ self,
223
+ *,
224
+ timeout: Optional[float] = None,
225
+ ) -> Dict[str, Any]:
226
+ """List your artifacts, newest first.
227
+
228
+ Without `artifact`: your artifacts, newest first, with URLs and `live`. With `artifact`:
229
+ its versions, which is published, their paths, and `declaration` (the published policy).
230
+ Add `path` or `version` to read that file as text (default: published index.html); non-
231
+ text or over 300,000 bytes: refused. `open: true` (with `artifact`, optional `version`)
232
+ returns `url` and `expiresAt`: load `url` to see the artifact as a viewer, private
233
+ included, for 10 minutes; visibility is unchanged, the URL opens only that artifact,
234
+ 60/key/hour (`rate_limited`). Changing what an artifact serves, or who can open it, is
235
+ super_artifact_set.
236
+ """
237
+ return self._client._call(
238
+ "GET",
239
+ "/v1/artifacts",
240
+ timeout=timeout,
241
+ )
242
+
243
+ def publish(
244
+ self,
245
+ *,
246
+ slug: str,
247
+ prompt: Optional[str] = None,
248
+ html: Optional[str] = None,
249
+ values: Optional[Dict[str, Any]] = None,
250
+ instances: Optional[List[Dict[str, Any]]] = None,
251
+ template: Optional[Dict[str, Any]] = None,
252
+ title: Optional[str] = None,
253
+ description: Optional[str] = None,
254
+ kind: Optional[Literal["page", "slideshow", "survey", "tracker", "video", "tool", "dashboard"]] = None,
255
+ collection: Optional[str] = None,
256
+ visibility: Optional[Literal["private", "organization"]] = None,
257
+ policy: Optional[Dict[str, Any]] = None,
258
+ triggers: Optional[List[Dict[str, Any]]] = None,
259
+ dataset: Optional[str] = None,
260
+ continues: Optional[str] = None,
261
+ uploads: Optional[str] = None,
262
+ values_file: Optional[str] = None,
263
+ files: Optional[List[Dict[str, Any]]] = None,
264
+ idempotency_key: Optional[str] = None,
265
+ timeout: Optional[float] = None,
266
+ ) -> Dict[str, Any]:
267
+ """Publish an artifact, or a new version of one.
268
+
269
+ Publish a page at a stable URL; the same slug adds a new version, which the URL serves
270
+ at once. Earlier versions stay and can be served again; nothing that existed before the
271
+ call is deleted. Always give the person the url from the result, even on updates. Send
272
+ `html`, or `values` for a template that carries a runtime, not both. Without `policy` a
273
+ form, input or saved state stores nothing; CMS rows a page edits go in
274
+ `policy.collections`. When retained storage is full it refuses with `plan_limit` and
275
+ deletes nothing. A template becomes everybody’s through a release, not a publish.
276
+ """
277
+ return self._client._call(
278
+ "POST",
279
+ "/v1/artifacts",
280
+ body={"slug": slug, "prompt": prompt, "html": html, "values": values, "instances": instances, "template": template, "title": title, "description": description, "kind": kind, "collection": collection, "visibility": visibility, "policy": policy, "triggers": triggers, "dataset": dataset, "continues": continues, "uploads": uploads, "valuesFile": values_file, "files": files},
281
+ idempotency_key=idempotency_key,
282
+ timeout=timeout,
283
+ )
284
+
285
+ def get(
286
+ self,
287
+ *,
288
+ artifact: str,
289
+ timeout: Optional[float] = None,
290
+ ) -> Dict[str, Any]:
291
+ """One artifact: its versions, published version and declaration.
292
+
293
+ Without `artifact`: your artifacts, newest first, with URLs and `live`. With `artifact`:
294
+ its versions, which is published, their paths, and `declaration` (the published policy).
295
+ Add `path` or `version` to read that file as text (default: published index.html); non-
296
+ text or over 300,000 bytes: refused. `open: true` (with `artifact`, optional `version`)
297
+ returns `url` and `expiresAt`: load `url` to see the artifact as a viewer, private
298
+ included, for 10 minutes; visibility is unchanged, the URL opens only that artifact,
299
+ 60/key/hour (`rate_limited`). Changing what an artifact serves, or who can open it, is
300
+ super_artifact_set.
301
+ """
302
+ return self._client._call(
303
+ "GET",
304
+ "/v1/artifacts/{artifact}",
305
+ path_params={"artifact": artifact},
306
+ timeout=timeout,
307
+ )
308
+
309
+ def update(
310
+ self,
311
+ *,
312
+ artifact: str,
313
+ visibility: Optional[Literal["private", "organization", "public"]] = None,
314
+ collection: Optional[str] = None,
315
+ phase: Optional[str] = None,
316
+ notify_on_submission: Optional[bool] = None,
317
+ triggers_enabled: Optional[bool] = None,
318
+ timeout: Optional[float] = None,
319
+ ) -> Dict[str, Any]:
320
+ """Change visibility, gallery label, live phase or submission email.
321
+
322
+ Change one artifact. `version` serves an existing version (a pointer move; nothing
323
+ rebuilt or deleted). `live` turns its live room on or off; off disconnects every
324
+ visitor, and Free has one room at a time. `triggersEnabled` is the owner’s kill switch
325
+ for declared triggers (default on). `notifyOnSubmission` emails you for each new data
326
+ submission (default off; edits send nothing; no answers in the mail). `phase` sets the
327
+ live room’s phase. `visibility` widens or narrows who can open it; narrowing voids every
328
+ viewer grant already issued, so each viewer is checked again. `collection` sets its
329
+ gallery grouping label. `delete` removes the artifact with every version, share link and
330
+ response, permanently; it needs `confirm: true` and goes alone. Fields apply in that
331
+ order, and a refusal part-way names the ones already `applied`. Publishing a new version
332
+ is super_publish.
333
+ """
334
+ return self._client._call(
335
+ "PATCH",
336
+ "/v1/artifacts/{artifact}",
337
+ path_params={"artifact": artifact},
338
+ body={"visibility": visibility, "collection": collection, "phase": phase, "notifyOnSubmission": notify_on_submission, "triggersEnabled": triggers_enabled},
339
+ timeout=timeout,
340
+ )
341
+
342
+ def delete(
343
+ self,
344
+ *,
345
+ artifact: str,
346
+ timeout: Optional[float] = None,
347
+ ) -> Dict[str, Any]:
348
+ """Delete an artifact with every version, permanently.
349
+
350
+ Change one artifact. `version` serves an existing version (a pointer move; nothing
351
+ rebuilt or deleted). `live` turns its live room on or off; off disconnects every
352
+ visitor, and Free has one room at a time. `triggersEnabled` is the owner’s kill switch
353
+ for declared triggers (default on). `notifyOnSubmission` emails you for each new data
354
+ submission (default off; edits send nothing; no answers in the mail). `phase` sets the
355
+ live room’s phase. `visibility` widens or narrows who can open it; narrowing voids every
356
+ viewer grant already issued, so each viewer is checked again. `collection` sets its
357
+ gallery grouping label. `delete` removes the artifact with every version, share link and
358
+ response, permanently; it needs `confirm: true` and goes alone. Fields apply in that
359
+ order, and a refusal part-way names the ones already `applied`. Publishing a new version
360
+ is super_publish.
361
+ """
362
+ return self._client._call(
363
+ "DELETE",
364
+ "/v1/artifacts/{artifact}",
365
+ path_params={"artifact": artifact},
366
+ query={"confirm": artifact},
367
+ timeout=timeout,
368
+ )
369
+
370
+ def read_file(
371
+ self,
372
+ *,
373
+ artifact: str,
374
+ path: Optional[str] = None,
375
+ version: Optional[int] = None,
376
+ timeout: Optional[float] = None,
377
+ ) -> Dict[str, Any]:
378
+ """Read one file of a version as text (default: the published index.html).
379
+
380
+ Without `artifact`: your artifacts, newest first, with URLs and `live`. With `artifact`:
381
+ its versions, which is published, their paths, and `declaration` (the published policy).
382
+ Add `path` or `version` to read that file as text (default: published index.html); non-
383
+ text or over 300,000 bytes: refused. `open: true` (with `artifact`, optional `version`)
384
+ returns `url` and `expiresAt`: load `url` to see the artifact as a viewer, private
385
+ included, for 10 minutes; visibility is unchanged, the URL opens only that artifact,
386
+ 60/key/hour (`rate_limited`). Changing what an artifact serves, or who can open it, is
387
+ super_artifact_set.
388
+ """
389
+ return self._client._call(
390
+ "GET",
391
+ "/v1/artifacts/{artifact}/file",
392
+ path_params={"artifact": artifact},
393
+ query={"path": path, "version": version},
394
+ timeout=timeout,
395
+ )
396
+
397
+ def open(
398
+ self,
399
+ *,
400
+ artifact: str,
401
+ version: Optional[int] = None,
402
+ idempotency_key: Optional[str] = None,
403
+ timeout: Optional[float] = None,
404
+ ) -> Dict[str, Any]:
405
+ """A ten-minute viewer URL for an artifact, private included.
406
+
407
+ Without `artifact`: your artifacts, newest first, with URLs and `live`. With `artifact`:
408
+ its versions, which is published, their paths, and `declaration` (the published policy).
409
+ Add `path` or `version` to read that file as text (default: published index.html); non-
410
+ text or over 300,000 bytes: refused. `open: true` (with `artifact`, optional `version`)
411
+ returns `url` and `expiresAt`: load `url` to see the artifact as a viewer, private
412
+ included, for 10 minutes; visibility is unchanged, the URL opens only that artifact,
413
+ 60/key/hour (`rate_limited`). Changing what an artifact serves, or who can open it, is
414
+ super_artifact_set.
415
+ """
416
+ return self._client._call(
417
+ "POST",
418
+ "/v1/artifacts/{artifact}/open",
419
+ path_params={"artifact": artifact},
420
+ body={"version": version},
421
+ idempotency_key=idempotency_key,
422
+ timeout=timeout,
423
+ )
424
+
425
+ def serve_version(
426
+ self,
427
+ *,
428
+ artifact: str,
429
+ version: int,
430
+ idempotency_key: Optional[str] = None,
431
+ timeout: Optional[float] = None,
432
+ ) -> Dict[str, Any]:
433
+ """Serve an existing version again.
434
+
435
+ Change one artifact. `version` serves an existing version (a pointer move; nothing
436
+ rebuilt or deleted). `live` turns its live room on or off; off disconnects every
437
+ visitor, and Free has one room at a time. `triggersEnabled` is the owner’s kill switch
438
+ for declared triggers (default on). `notifyOnSubmission` emails you for each new data
439
+ submission (default off; edits send nothing; no answers in the mail). `phase` sets the
440
+ live room’s phase. `visibility` widens or narrows who can open it; narrowing voids every
441
+ viewer grant already issued, so each viewer is checked again. `collection` sets its
442
+ gallery grouping label. `delete` removes the artifact with every version, share link and
443
+ response, permanently; it needs `confirm: true` and goes alone. Fields apply in that
444
+ order, and a refusal part-way names the ones already `applied`. Publishing a new version
445
+ is super_publish.
446
+ """
447
+ return self._client._call(
448
+ "POST",
449
+ "/v1/artifacts/{artifact}/versions/{version}/serve",
450
+ path_params={"artifact": artifact, "version": version},
451
+ idempotency_key=idempotency_key,
452
+ timeout=timeout,
453
+ )
454
+
455
+
456
+ class Live(_Resource):
457
+
458
+ def start(
459
+ self,
460
+ *,
461
+ artifact: str,
462
+ idempotency_key: Optional[str] = None,
463
+ timeout: Optional[float] = None,
464
+ ) -> Dict[str, Any]:
465
+ """Turn an artifact's live room on.
466
+
467
+ Change one artifact. `version` serves an existing version (a pointer move; nothing
468
+ rebuilt or deleted). `live` turns its live room on or off; off disconnects every
469
+ visitor, and Free has one room at a time. `triggersEnabled` is the owner’s kill switch
470
+ for declared triggers (default on). `notifyOnSubmission` emails you for each new data
471
+ submission (default off; edits send nothing; no answers in the mail). `phase` sets the
472
+ live room’s phase. `visibility` widens or narrows who can open it; narrowing voids every
473
+ viewer grant already issued, so each viewer is checked again. `collection` sets its
474
+ gallery grouping label. `delete` removes the artifact with every version, share link and
475
+ response, permanently; it needs `confirm: true` and goes alone. Fields apply in that
476
+ order, and a refusal part-way names the ones already `applied`. Publishing a new version
477
+ is super_publish.
478
+ """
479
+ return self._client._call(
480
+ "POST",
481
+ "/v1/artifacts/{artifact}/live",
482
+ path_params={"artifact": artifact},
483
+ idempotency_key=idempotency_key,
484
+ timeout=timeout,
485
+ )
486
+
487
+ def stop(
488
+ self,
489
+ *,
490
+ artifact: str,
491
+ timeout: Optional[float] = None,
492
+ ) -> Dict[str, Any]:
493
+ """Turn an artifact's live room off, disconnecting every visitor.
494
+
495
+ Change one artifact. `version` serves an existing version (a pointer move; nothing
496
+ rebuilt or deleted). `live` turns its live room on or off; off disconnects every
497
+ visitor, and Free has one room at a time. `triggersEnabled` is the owner’s kill switch
498
+ for declared triggers (default on). `notifyOnSubmission` emails you for each new data
499
+ submission (default off; edits send nothing; no answers in the mail). `phase` sets the
500
+ live room’s phase. `visibility` widens or narrows who can open it; narrowing voids every
501
+ viewer grant already issued, so each viewer is checked again. `collection` sets its
502
+ gallery grouping label. `delete` removes the artifact with every version, share link and
503
+ response, permanently; it needs `confirm: true` and goes alone. Fields apply in that
504
+ order, and a refusal part-way names the ones already `applied`. Publishing a new version
505
+ is super_publish.
506
+ """
507
+ return self._client._call(
508
+ "DELETE",
509
+ "/v1/artifacts/{artifact}/live",
510
+ path_params={"artifact": artifact},
511
+ timeout=timeout,
512
+ )
513
+
514
+
515
+ class Uploads(UploadHelper, _Resource):
516
+
517
+ def stage(
518
+ self,
519
+ *,
520
+ files: List[Dict[str, Any]],
521
+ idempotency_key: Optional[str] = None,
522
+ timeout: Optional[float] = None,
523
+ ) -> Dict[str, Any]:
524
+ """Stage big files for a publish; PUT each to its URL.
525
+
526
+ Stage images, video or big files for a publish without sending their bytes in a call.
527
+ Declare each file’s `path` and exact `bytes`; the result carries an `uploadId` and one
528
+ `url` per file. PUT each file to its URL (`curl -T`, no credentials), then super_publish
529
+ with `uploads`. Not index.html: that is `html`; small assets can ride inline as the
530
+ publish’s `files`. Same limits as `files`; a staged set expires after 30 minutes, and at
531
+ most 5 wait unpublished at once.
532
+ """
533
+ return self._client._call(
534
+ "POST",
535
+ "/v1/uploads",
536
+ body={"files": files},
537
+ idempotency_key=idempotency_key,
538
+ timeout=timeout,
539
+ )
540
+
541
+
542
+ class Data(_Resource):
543
+
544
+ def list_artifact_rows(
545
+ self,
546
+ *,
547
+ artifact: str,
548
+ filter: Optional[List[str]] = None,
549
+ since: Optional[str] = None,
550
+ until: Optional[str] = None,
551
+ sort: Optional[Literal["newest", "oldest"]] = None,
552
+ limit: Optional[int] = None,
553
+ cursor: Optional[str] = None,
554
+ fields: Optional[List[str]] = None,
555
+ timeout: Optional[float] = None,
556
+ ) -> Dict[str, Any]:
557
+ """Rows visitors submitted to one artifact, newest first.
558
+
559
+ The rows visitors submitted to your artifacts, newest first, with each version's field
560
+ schema; paged by `cursor`. Address exactly one: `artifact`; `dataset` (a catalog key;
561
+ one shared by several artifacts is `ambiguous_dataset`); or `collection`, the gallery
562
+ grouping label set at publish, not a content collection (≤20 artifacts over one window,
563
+ kept per artifact, no `filter`). Entries of a content collection are super_entries;
564
+ totals and averages are a query, not a read.
565
+ """
566
+ return self._client._call(
567
+ "GET",
568
+ "/v1/artifacts/{artifact}/data",
569
+ path_params={"artifact": artifact},
570
+ query={"filter": filter, "since": since, "until": until, "sort": sort, "limit": limit, "cursor": cursor, "fields": fields},
571
+ timeout=timeout,
572
+ )
573
+
574
+ def iter_artifact_rows(self, **kwargs: Any) -> Iterator[Dict[str, Any]]:
575
+ """Every item of `list_artifact_rows`, across pages. Takes the same arguments."""
576
+ return walk_cursor(self.list_artifact_rows, "responses", kwargs)
577
+
578
+ def write_artifact_rows(
579
+ self,
580
+ *,
581
+ artifact: str,
582
+ stream: Optional[str] = None,
583
+ rows: Optional[List[Dict[str, Any]]] = None,
584
+ ops: Optional[List[Dict[str, Any]]] = None,
585
+ atomic: Optional[bool] = None,
586
+ idempotency_key: Optional[str] = None,
587
+ timeout: Optional[float] = None,
588
+ ) -> Dict[str, Any]:
589
+ """Write rows into an artifact you may edit.
590
+
591
+ Write rows into an artifact this key may edit, through the validation and stream rules a
592
+ page write gets; each row is attributed "<agent> (agent)". `rows` creates in `stream`.
593
+ `ops` [{op: create|replace|delete, id, row, stream}] replaces or deletes only rows this
594
+ agent wrote (writes: upsert); a deleted row cannot be restored by any tool. ≤50 a call;
595
+ `atomic`: all or none, otherwise a partial batch answers `complete: false`. Visitor rows
596
+ are never changed here; entries of a content collection are super_entries.
597
+ """
598
+ return self._client._call(
599
+ "POST",
600
+ "/v1/artifacts/{artifact}/data/rows",
601
+ path_params={"artifact": artifact},
602
+ body={"stream": stream, "rows": rows, "ops": ops, "atomic": atomic},
603
+ idempotency_key=idempotency_key,
604
+ timeout=timeout,
605
+ )
606
+
607
+ def list_rows(
608
+ self,
609
+ *,
610
+ dataset: Optional[str] = None,
611
+ collection: Optional[str] = None,
612
+ filter: Optional[List[str]] = None,
613
+ since: Optional[str] = None,
614
+ until: Optional[str] = None,
615
+ sort: Optional[Literal["newest", "oldest"]] = None,
616
+ limit: Optional[int] = None,
617
+ cursor: Optional[str] = None,
618
+ fields: Optional[List[str]] = None,
619
+ timeout: Optional[float] = None,
620
+ ) -> Dict[str, Any]:
621
+ """Rows submitted to a dataset or a gallery label.
622
+
623
+ The rows visitors submitted to your artifacts, newest first, with each version's field
624
+ schema; paged by `cursor`. Address exactly one: `artifact`; `dataset` (a catalog key;
625
+ one shared by several artifacts is `ambiguous_dataset`); or `collection`, the gallery
626
+ grouping label set at publish, not a content collection (≤20 artifacts over one window,
627
+ kept per artifact, no `filter`). Entries of a content collection are super_entries;
628
+ totals and averages are a query, not a read.
629
+ """
630
+ return self._client._call(
631
+ "GET",
632
+ "/v1/data",
633
+ query={"dataset": dataset, "collection": collection, "filter": filter, "since": since, "until": until, "sort": sort, "limit": limit, "cursor": cursor, "fields": fields},
634
+ timeout=timeout,
635
+ )
636
+
637
+ def iter_rows(self, **kwargs: Any) -> Iterator[Dict[str, Any]]:
638
+ """Every item of `list_rows`, across pages. Takes the same arguments."""
639
+ return walk_cursor(self.list_rows, "responses", kwargs)
640
+
641
+ def query(
642
+ self,
643
+ *,
644
+ scope: Optional[Dict[str, Any]] = None,
645
+ measures: Optional[List[str]] = None,
646
+ agg: Optional[Literal["sum", "avg", "min", "max", "count", "last"]] = None,
647
+ compute: Optional[List[Dict[str, Any]]] = None,
648
+ filter: Optional[List[str]] = None,
649
+ group_by: Optional[List[str]] = None,
650
+ since: Optional[str] = None,
651
+ until: Optional[str] = None,
652
+ limit: Optional[int] = None,
653
+ distributions: Optional[Dict[str, Any]] = None,
654
+ idempotency_key: Optional[str] = None,
655
+ timeout: Optional[float] = None,
656
+ ) -> Dict[str, Any]:
657
+ """Aggregate what was collected: numbers, never rows.
658
+
659
+ Numbers over what was collected, never rows (rows are super_data). Aggregate `measures`
660
+ across the datasets in `scope`; datasets combine on the same measure in one base unit,
661
+ results in the declared `unit`. Names come from the catalog; an unknown one errors with
662
+ near misses. The answer has one row per `group_by` key (or one row) with a column per
663
+ measure and `compute`, the datasets used and any skipped, and `truncated` when `limit`
664
+ cut it. Or send `distributions` for one artifact: counts, per-version rates and per-
665
+ field distributions (free text: answer rate and length only). A call with neither is
666
+ `invalid_query`.
667
+ """
668
+ return self._client._call(
669
+ "POST",
670
+ "/v1/data/query",
671
+ body={"scope": scope, "measures": measures, "agg": agg, "compute": compute, "filter": filter, "group_by": group_by, "since": since, "until": until, "limit": limit, "distributions": distributions},
672
+ idempotency_key=idempotency_key,
673
+ timeout=timeout,
674
+ )
675
+
676
+
677
+ class Schema(_Resource):
678
+
679
+ def get(
680
+ self,
681
+ *,
682
+ series: Optional[str] = None,
683
+ tags: Optional[List[str]] = None,
684
+ artifact: Optional[str] = None,
685
+ compare: Optional[List[str]] = None,
686
+ since: Optional[str] = None,
687
+ workspace: Optional[str] = None,
688
+ timeout: Optional[float] = None,
689
+ ) -> Dict[str, Any]:
690
+ """The data catalog: datasets and content collections, or a comparison.
691
+
692
+ The data catalog, without rows. Read (the default): `datasets` your artifacts declared,
693
+ with fields, units, measures and `since`/`deprecated` versions, and this workspace's
694
+ content `collections`, with fields, rules and entry counts. `compare` (alone): two to
695
+ ten artifacts' newest fields side by side, every type, unit and measure conflict named.
696
+ `define` creates a content collection, or replaces the one with that `key` outright,
697
+ name, display field and every field; a field left out is gone from the model, and a
698
+ collection an artifact declared is refused with `conflict`. Refusals name field, rule
699
+ and fix. Rows an artifact collected are super_data.
700
+ """
701
+ return self._client._call(
702
+ "GET",
703
+ "/v1/schema",
704
+ query={"series": series, "tags": tags, "artifact": artifact, "compare": compare, "since": since, "workspace": workspace},
705
+ timeout=timeout,
706
+ )
707
+
708
+ def define_collection(
709
+ self,
710
+ *,
711
+ define: Optional[Dict[str, Any]] = None,
712
+ workspace: Optional[str] = None,
713
+ timeout: Optional[float] = None,
714
+ ) -> Dict[str, Any]:
715
+ """Create or replace a content collection.
716
+
717
+ The data catalog, without rows. Read (the default): `datasets` your artifacts declared,
718
+ with fields, units, measures and `since`/`deprecated` versions, and this workspace's
719
+ content `collections`, with fields, rules and entry counts. `compare` (alone): two to
720
+ ten artifacts' newest fields side by side, every type, unit and measure conflict named.
721
+ `define` creates a content collection, or replaces the one with that `key` outright,
722
+ name, display field and every field; a field left out is gone from the model, and a
723
+ collection an artifact declared is refused with `conflict`. Refusals name field, rule
724
+ and fix. Rows an artifact collected are super_data.
725
+ """
726
+ return self._client._call(
727
+ "PUT",
728
+ "/v1/schema",
729
+ body={"define": define, "workspace": workspace},
730
+ timeout=timeout,
731
+ )
732
+
733
+
734
+ class Entries(_Resource):
735
+
736
+ def list(
737
+ self,
738
+ *,
739
+ collection: str,
740
+ workspace: Optional[str] = None,
741
+ filter: Optional[List[str]] = None,
742
+ search: Optional[str] = None,
743
+ sort: Optional[str] = None,
744
+ direction: Optional[Literal["asc", "desc"]] = None,
745
+ page: Optional[int] = None,
746
+ limit: Optional[int] = None,
747
+ if_none_match: Optional[str] = None,
748
+ timeout: Optional[float] = None,
749
+ ) -> Dict[str, Any]:
750
+ """One page of a content collection's entries.
751
+
752
+ Entries of a workspace content collection (a model defined in the catalog), not rows an
753
+ artifact collected. With `values`: create one entry (an object) or up to 50 (an array,
754
+ one outcome per row); values are coerced to declared types, undeclared fields are
755
+ refused by name, and nothing existing is updated or deleted. Without: read one page,
756
+ filtered and sorted in the database; references resolve to labels, sensitive fields read
757
+ as answered-or-not. Rows visitors submitted are super_data.
758
+ """
759
+ return self._client._call(
760
+ "GET",
761
+ "/v1/collections/{collection}/entries",
762
+ headers={"If-None-Match": if_none_match},
763
+ path_params={"collection": collection},
764
+ query={"workspace": workspace, "filter": filter, "search": search, "sort": sort, "direction": direction, "page": page, "limit": limit},
765
+ timeout=timeout,
766
+ )
767
+
768
+ def iter(self, **kwargs: Any) -> Iterator[Dict[str, Any]]:
769
+ """Every item of `list`, across pages. Takes the same arguments."""
770
+ return walk_pages(self.list, "entries", kwargs)
771
+
772
+ def create(
773
+ self,
774
+ *,
775
+ collection: str,
776
+ values: Optional[Any] = None,
777
+ status: Optional[Literal["draft", "published", "archived"]] = None,
778
+ workspace: Optional[str] = None,
779
+ idempotency_key: Optional[str] = None,
780
+ timeout: Optional[float] = None,
781
+ ) -> Dict[str, Any]:
782
+ """Create one entry, or a batch.
783
+
784
+ Entries of a workspace content collection (a model defined in the catalog), not rows an
785
+ artifact collected. With `values`: create one entry (an object) or up to 50 (an array,
786
+ one outcome per row); values are coerced to declared types, undeclared fields are
787
+ refused by name, and nothing existing is updated or deleted. Without: read one page,
788
+ filtered and sorted in the database; references resolve to labels, sensitive fields read
789
+ as answered-or-not. Rows visitors submitted are super_data.
790
+ """
791
+ return self._client._call(
792
+ "POST",
793
+ "/v1/collections/{collection}/entries",
794
+ path_params={"collection": collection},
795
+ body={"values": values, "status": status, "workspace": workspace},
796
+ idempotency_key=idempotency_key,
797
+ timeout=timeout,
798
+ )
799
+
800
+
801
+ class Secrets(_Resource):
802
+
803
+ def use(
804
+ self,
805
+ *,
806
+ collection: str,
807
+ entry: str,
808
+ field: str,
809
+ method: Literal["GET", "POST", "PUT", "PATCH", "DELETE"],
810
+ url: str,
811
+ headers: Optional[Dict[str, Any]] = None,
812
+ body: Optional[str] = None,
813
+ header: Optional[Dict[str, Any]] = None,
814
+ idempotency_key: Optional[str] = None,
815
+ timeout: Optional[float] = None,
816
+ ) -> Dict[str, Any]:
817
+ """Call an approved API with a stored secret you cannot read (workspace keys).
818
+
819
+ Make one HTTPS request with a `pii: secret` value from a content collection entry. The
820
+ platform puts the value into one header and calls the one host a person approved; you
821
+ get status, headers and body, scrubbed of it. You never see it, in input or result; a
822
+ response echoing it is withheld whole (`secret_echoed`). A first request for a field and
823
+ host answers `approval_required` with `approvalUrl`: give the person that link, then
824
+ repeat the request once they approve. Grants expire, cap uses and can be revoked; every
825
+ use is logged. The person types the secret into its dashboard entry; super_entries
826
+ writes one only if they insist on pasting it.
827
+ """
828
+ return self._client._call(
829
+ "POST",
830
+ "/v1/collections/{collection}/entries/{entry}/fields/{field}/use",
831
+ path_params={"collection": collection, "entry": entry, "field": field},
832
+ body={"method": method, "url": url, "headers": headers, "body": body, "header": header},
833
+ idempotency_key=idempotency_key,
834
+ timeout=timeout,
835
+ )
836
+
837
+
838
+ class Templates(_Resource):
839
+
840
+ def list(
841
+ self,
842
+ *,
843
+ request: Optional[str] = None,
844
+ scope: Optional[Literal["installed", "marketplace"]] = None,
845
+ kind: Optional[Literal["page", "slideshow", "survey", "tracker", "video", "tool", "dashboard"]] = None,
846
+ sort: Optional[Literal["relevance", "rating", "uses", "installs", "recent"]] = None,
847
+ limit: Optional[int] = None,
848
+ jobs: Optional[List[Literal["track", "collect", "present", "report", "monitor", "prove", "document", "explain", "plan", "decide", "review", "learn", "prototype", "announce", "compute", "curate", "coordinate", "play"]]] = None,
849
+ audience: Optional[List[Literal["everyone", "engineering", "product", "design", "marketing", "sales", "ops", "people", "finance", "founders", "education", "personal", "community"]]] = None,
850
+ needs: Optional[List[Literal["runtime", "data", "comments", "live"]]] = None,
851
+ cost: Optional[Literal["fill", "write", "build"]] = None,
852
+ tier: Optional[Literal["all", "official", "verified", "community"]] = None,
853
+ mine: Optional[bool] = None,
854
+ timeout: Optional[float] = None,
855
+ ) -> Dict[str, Any]:
856
+ """Find, rank or list templates.
857
+
858
+ With `request`: rank installed templates by content similarity; matches carry `band`
859
+ (high: build from it; possible: judge it), `why` and unscored stats. `scope:
860
+ marketplace`: released public templates, ranked by `request` or else the top by `sort`;
861
+ `sort`, `limit` and the facets apply only here. Neither: the installed list. `slug`: one
862
+ template in full, with its `installPrompt`; `history`: its changelog; `feedback`: its
863
+ artifacts' comments as themes. `mine`: your published templates, with counts. Reading
864
+ only: installing, rating and rolling back are super_template_action.
865
+ """
866
+ return self._client._call(
867
+ "GET",
868
+ "/v1/templates",
869
+ query={"request": request, "scope": scope, "kind": kind, "sort": sort, "limit": limit, "jobs": jobs, "audience": audience, "needs": needs, "cost": cost, "tier": tier, "mine": mine},
870
+ timeout=timeout,
871
+ )
872
+
873
+ def save(
874
+ self,
875
+ *,
876
+ slug: str,
877
+ title: str,
878
+ description: str,
879
+ spec: Dict[str, Any],
880
+ kind: Optional[Literal["page", "slideshow", "survey", "tracker", "video", "tool", "dashboard"]] = None,
881
+ jobs: Optional[List[Literal["track", "collect", "present", "report", "monitor", "prove", "document", "explain", "plan", "decide", "review", "learn", "prototype", "announce", "compute", "curate", "coordinate", "play"]]] = None,
882
+ audience: Optional[List[Literal["everyone", "engineering", "product", "design", "marketing", "sales", "ops", "people", "finance", "founders", "education", "personal", "community"]]] = None,
883
+ use_cases: Optional[List[Dict[str, Any]]] = None,
884
+ install_archetype: Optional[Literal["scenarios", "explainer", "interview"]] = None,
885
+ install_after: Optional[str] = None,
886
+ sample_public: Optional[bool] = None,
887
+ category: Optional[Literal["trackers", "surveys", "presentations", "dashboards", "documents", "tools", "games", "other"]] = None,
888
+ guidance: Optional[str] = None,
889
+ prompt: Optional[str] = None,
890
+ sample: Optional[Dict[str, Any]] = None,
891
+ demo: Optional[str] = None,
892
+ files: Optional[List[Dict[str, Any]]] = None,
893
+ companions: Optional[List[Dict[str, Any]]] = None,
894
+ expected_version: Optional[int] = None,
895
+ change_note: Optional[str] = None,
896
+ idempotency_key: Optional[str] = None,
897
+ timeout: Optional[float] = None,
898
+ ) -> Dict[str, Any]:
899
+ """Create or revise a template draft.
900
+
901
+ Write a template draft only you can publish from. Without `expectedVersion` it creates
902
+ (refused if the slug exists); with it, it revises the head (refused if the head moved
903
+ past it), and a revision that changes nothing cuts no version. A `json` slot needs
904
+ `schema`. Runtime `files` (≤512 KiB decoded) need a `json` slot and an index.html with
905
+ one `<script id="sa-template-values" type="application/json">`. Others build from it
906
+ only once super_release_template releases it; a revision never changes a released
907
+ version.
908
+ """
909
+ return self._client._call(
910
+ "POST",
911
+ "/v1/templates",
912
+ body={"slug": slug, "title": title, "description": description, "kind": kind, "jobs": jobs, "audience": audience, "useCases": use_cases, "installArchetype": install_archetype, "installAfter": install_after, "samplePublic": sample_public, "category": category, "spec": spec, "guidance": guidance, "prompt": prompt, "sample": sample, "demo": demo, "files": files, "companions": companions, "expectedVersion": expected_version, "changeNote": change_note},
913
+ idempotency_key=idempotency_key,
914
+ timeout=timeout,
915
+ )
916
+
917
+ def get(
918
+ self,
919
+ *,
920
+ slug: str,
921
+ version: Optional[int] = None,
922
+ timeout: Optional[float] = None,
923
+ ) -> Dict[str, Any]:
924
+ """One template in full, with its install prompt.
925
+
926
+ With `request`: rank installed templates by content similarity; matches carry `band`
927
+ (high: build from it; possible: judge it), `why` and unscored stats. `scope:
928
+ marketplace`: released public templates, ranked by `request` or else the top by `sort`;
929
+ `sort`, `limit` and the facets apply only here. Neither: the installed list. `slug`: one
930
+ template in full, with its `installPrompt`; `history`: its changelog; `feedback`: its
931
+ artifacts' comments as themes. `mine`: your published templates, with counts. Reading
932
+ only: installing, rating and rolling back are super_template_action.
933
+ """
934
+ return self._client._call(
935
+ "GET",
936
+ "/v1/templates/{slug}",
937
+ path_params={"slug": slug},
938
+ query={"version": version},
939
+ timeout=timeout,
940
+ )
941
+
942
+ def get_history(
943
+ self,
944
+ *,
945
+ slug: str,
946
+ timeout: Optional[float] = None,
947
+ ) -> Dict[str, Any]:
948
+ """A template's changelog.
949
+
950
+ With `request`: rank installed templates by content similarity; matches carry `band`
951
+ (high: build from it; possible: judge it), `why` and unscored stats. `scope:
952
+ marketplace`: released public templates, ranked by `request` or else the top by `sort`;
953
+ `sort`, `limit` and the facets apply only here. Neither: the installed list. `slug`: one
954
+ template in full, with its `installPrompt`; `history`: its changelog; `feedback`: its
955
+ artifacts' comments as themes. `mine`: your published templates, with counts. Reading
956
+ only: installing, rating and rolling back are super_template_action.
957
+ """
958
+ return self._client._call(
959
+ "GET",
960
+ "/v1/templates/{slug}/history",
961
+ path_params={"slug": slug},
962
+ timeout=timeout,
963
+ )
964
+
965
+ def get_feedback(
966
+ self,
967
+ *,
968
+ slug: str,
969
+ timeout: Optional[float] = None,
970
+ ) -> Dict[str, Any]:
971
+ """Comments on a template's artifacts, as themes.
972
+
973
+ With `request`: rank installed templates by content similarity; matches carry `band`
974
+ (high: build from it; possible: judge it), `why` and unscored stats. `scope:
975
+ marketplace`: released public templates, ranked by `request` or else the top by `sort`;
976
+ `sort`, `limit` and the facets apply only here. Neither: the installed list. `slug`: one
977
+ template in full, with its `installPrompt`; `history`: its changelog; `feedback`: its
978
+ artifacts' comments as themes. `mine`: your published templates, with counts. Reading
979
+ only: installing, rating and rolling back are super_template_action.
980
+ """
981
+ return self._client._call(
982
+ "GET",
983
+ "/v1/templates/{slug}/feedback",
984
+ path_params={"slug": slug},
985
+ timeout=timeout,
986
+ )
987
+
988
+ def act(
989
+ self,
990
+ *,
991
+ slug: str,
992
+ action: Literal["install", "uninstall", "rate", "report", "rollback", "request_verification"],
993
+ stars: Optional[int] = None,
994
+ version: Optional[int] = None,
995
+ kind: Optional[Literal["spam", "harmful", "broken", "misleading", "pii", "copyright", "other"]] = None,
996
+ reason: Optional[str] = None,
997
+ confirmed_by_person: Optional[bool] = None,
998
+ idempotency_key: Optional[str] = None,
999
+ timeout: Optional[float] = None,
1000
+ ) -> Dict[str, Any]:
1001
+ """Install, uninstall, rate, report, roll back or request verification.
1002
+
1003
+ Act on one template; nothing here deletes a template, a version or a built artifact.
1004
+ `install`/`uninstall`: this workspace's installed set (uninstall removes only the
1005
+ install; built artifacts keep working); `install` returns its build prompt as
1006
+ `nextStep`. `rate`: the person's 1–5 `stars` on an installed template not yours
1007
+ (`cannot_rate_own`, `not_installed`, `rate_limited`); counts once this workspace built
1008
+ from it. `report`: `kind` and a `reason` (≤1000 chars) for a moderator; one per account;
1009
+ enough reports hide it. `rollback`: restore `version` as a new version, unless the
1010
+ runtime changed. `request_verification`: a moderator checks your released `version`; 3
1011
+ per 30 days. Finding and reading templates is super_templates.
1012
+ """
1013
+ return self._client._call(
1014
+ "POST",
1015
+ "/v1/templates/{slug}/actions",
1016
+ path_params={"slug": slug},
1017
+ body={"action": action, "stars": stars, "version": version, "kind": kind, "reason": reason, "confirmedByPerson": confirmed_by_person},
1018
+ idempotency_key=idempotency_key,
1019
+ timeout=timeout,
1020
+ )
1021
+
1022
+ def release(
1023
+ self,
1024
+ *,
1025
+ slug: str,
1026
+ version: int,
1027
+ visibility: Optional[Literal["public", "unlisted", "workspace"]] = None,
1028
+ demo_consent: Optional[bool] = None,
1029
+ sample_consent: Optional[bool] = None,
1030
+ idempotency_key: Optional[str] = None,
1031
+ timeout: Optional[float] = None,
1032
+ ) -> Dict[str, Any]:
1033
+ """Release one version of your template.
1034
+
1035
+ Release one version of your template so others can build from it, live at once to the
1036
+ reach `visibility` sets; the result names its trust `tier` (Official, Verified or
1037
+ Community). Forward only (`release_moves_backwards`): earlier versions stay, and nothing
1038
+ is deleted. A private demo needs `demoConsent: true`. A runtime, prompt, parts or data
1039
+ change leaves a Verified badge behind. Public: account 7 days old (`publisher_too_new`),
1040
+ 10/day, 3/template/hour (`rate_limited`), 20 templates (`too_many_templates`), no tier
1041
+ words (`reserved_wording`), no credential (`secret_in_template`), paid plan
1042
+ (`plan_required`). Writing the draft is super_template_save.
1043
+ """
1044
+ return self._client._call(
1045
+ "POST",
1046
+ "/v1/templates/{slug}/release",
1047
+ path_params={"slug": slug},
1048
+ body={"version": version, "visibility": visibility, "demoConsent": demo_consent, "sampleConsent": sample_consent},
1049
+ idempotency_key=idempotency_key,
1050
+ timeout=timeout,
1051
+ )
1052
+
1053
+
1054
+ class Projects(_Resource):
1055
+
1056
+ def list(
1057
+ self,
1058
+ *,
1059
+ workspace: Optional[str] = None,
1060
+ timeout: Optional[float] = None,
1061
+ ) -> Dict[str, Any]:
1062
+ """Your projects.
1063
+
1064
+ A project is an ordered set of your artifacts shown one at a time at /s/{slug}, with its
1065
+ own audience and share list. No `project`: `title` creates one (seeded from
1066
+ `artifacts`), else list yours. With `project`: add `artifacts`, `remove` one, `title`
1067
+ renames, set `visibility`, `order`/`move` reorder, a `rule` adds matches as they are
1068
+ published, or read it. `delete` with `confirm: true` removes the project, its order and
1069
+ its share list permanently; its artifacts stay. One change per call, or title with
1070
+ visibility. An artifact's gallery label is not a project: that is `collection` on
1071
+ super_artifact_set.
1072
+ """
1073
+ return self._client._call(
1074
+ "GET",
1075
+ "/v1/projects",
1076
+ query={"workspace": workspace},
1077
+ timeout=timeout,
1078
+ )
1079
+
1080
+ def create(
1081
+ self,
1082
+ *,
1083
+ title: Optional[str] = None,
1084
+ artifacts: Optional[List[str]] = None,
1085
+ group_label: Optional[str] = None,
1086
+ visibility: Optional[Literal["private", "organization", "public"]] = None,
1087
+ rule: Any = OMIT,
1088
+ confirm: Optional[bool] = None,
1089
+ workspace: Optional[str] = None,
1090
+ idempotency_key: Optional[str] = None,
1091
+ timeout: Optional[float] = None,
1092
+ ) -> Dict[str, Any]:
1093
+ """Create a project, optionally seeded with artifacts.
1094
+
1095
+ A project is an ordered set of your artifacts shown one at a time at /s/{slug}, with its
1096
+ own audience and share list. No `project`: `title` creates one (seeded from
1097
+ `artifacts`), else list yours. With `project`: add `artifacts`, `remove` one, `title`
1098
+ renames, set `visibility`, `order`/`move` reorder, a `rule` adds matches as they are
1099
+ published, or read it. `delete` with `confirm: true` removes the project, its order and
1100
+ its share list permanently; its artifacts stay. One change per call, or title with
1101
+ visibility. An artifact's gallery label is not a project: that is `collection` on
1102
+ super_artifact_set.
1103
+ """
1104
+ return self._client._call(
1105
+ "POST",
1106
+ "/v1/projects",
1107
+ body={"title": title, "artifacts": artifacts, "groupLabel": group_label, "visibility": visibility, "confirm": confirm, "workspace": workspace},
1108
+ nullable={"rule": rule},
1109
+ idempotency_key=idempotency_key,
1110
+ timeout=timeout,
1111
+ )
1112
+
1113
+ def get(
1114
+ self,
1115
+ *,
1116
+ project: str,
1117
+ workspace: Optional[str] = None,
1118
+ timeout: Optional[float] = None,
1119
+ ) -> Dict[str, Any]:
1120
+ """One project and its items.
1121
+
1122
+ A project is an ordered set of your artifacts shown one at a time at /s/{slug}, with its
1123
+ own audience and share list. No `project`: `title` creates one (seeded from
1124
+ `artifacts`), else list yours. With `project`: add `artifacts`, `remove` one, `title`
1125
+ renames, set `visibility`, `order`/`move` reorder, a `rule` adds matches as they are
1126
+ published, or read it. `delete` with `confirm: true` removes the project, its order and
1127
+ its share list permanently; its artifacts stay. One change per call, or title with
1128
+ visibility. An artifact's gallery label is not a project: that is `collection` on
1129
+ super_artifact_set.
1130
+ """
1131
+ return self._client._call(
1132
+ "GET",
1133
+ "/v1/projects/{project}",
1134
+ path_params={"project": project},
1135
+ query={"workspace": workspace},
1136
+ timeout=timeout,
1137
+ )
1138
+
1139
+ def update(
1140
+ self,
1141
+ *,
1142
+ project: str,
1143
+ title: Optional[str] = None,
1144
+ visibility: Optional[Literal["private", "organization", "public"]] = None,
1145
+ order: Optional[List[str]] = None,
1146
+ move: Optional[Dict[str, Any]] = None,
1147
+ rule: Any = OMIT,
1148
+ collapsed_groups: Optional[List[str]] = None,
1149
+ confirm: Optional[bool] = None,
1150
+ workspace: Optional[str] = None,
1151
+ timeout: Optional[float] = None,
1152
+ ) -> Dict[str, Any]:
1153
+ """Rename, set visibility, reorder, move, fold groups or set a rule.
1154
+
1155
+ A project is an ordered set of your artifacts shown one at a time at /s/{slug}, with its
1156
+ own audience and share list. No `project`: `title` creates one (seeded from
1157
+ `artifacts`), else list yours. With `project`: add `artifacts`, `remove` one, `title`
1158
+ renames, set `visibility`, `order`/`move` reorder, a `rule` adds matches as they are
1159
+ published, or read it. `delete` with `confirm: true` removes the project, its order and
1160
+ its share list permanently; its artifacts stay. One change per call, or title with
1161
+ visibility. An artifact's gallery label is not a project: that is `collection` on
1162
+ super_artifact_set.
1163
+ """
1164
+ return self._client._call(
1165
+ "PATCH",
1166
+ "/v1/projects/{project}",
1167
+ path_params={"project": project},
1168
+ body={"title": title, "visibility": visibility, "order": order, "move": move, "collapsedGroups": collapsed_groups, "confirm": confirm, "workspace": workspace},
1169
+ nullable={"rule": rule},
1170
+ timeout=timeout,
1171
+ )
1172
+
1173
+ def delete(
1174
+ self,
1175
+ *,
1176
+ project: str,
1177
+ timeout: Optional[float] = None,
1178
+ ) -> Dict[str, Any]:
1179
+ """Delete a project; its artifacts stay.
1180
+
1181
+ A project is an ordered set of your artifacts shown one at a time at /s/{slug}, with its
1182
+ own audience and share list. No `project`: `title` creates one (seeded from
1183
+ `artifacts`), else list yours. With `project`: add `artifacts`, `remove` one, `title`
1184
+ renames, set `visibility`, `order`/`move` reorder, a `rule` adds matches as they are
1185
+ published, or read it. `delete` with `confirm: true` removes the project, its order and
1186
+ its share list permanently; its artifacts stay. One change per call, or title with
1187
+ visibility. An artifact's gallery label is not a project: that is `collection` on
1188
+ super_artifact_set.
1189
+ """
1190
+ return self._client._call(
1191
+ "DELETE",
1192
+ "/v1/projects/{project}",
1193
+ path_params={"project": project},
1194
+ query={"confirm": project},
1195
+ timeout=timeout,
1196
+ )
1197
+
1198
+ def add_artifacts(
1199
+ self,
1200
+ *,
1201
+ project: str,
1202
+ artifacts: Optional[List[str]] = None,
1203
+ group_label: Optional[str] = None,
1204
+ confirm: Optional[bool] = None,
1205
+ workspace: Optional[str] = None,
1206
+ idempotency_key: Optional[str] = None,
1207
+ timeout: Optional[float] = None,
1208
+ ) -> Dict[str, Any]:
1209
+ """Add artifacts to a project.
1210
+
1211
+ A project is an ordered set of your artifacts shown one at a time at /s/{slug}, with its
1212
+ own audience and share list. No `project`: `title` creates one (seeded from
1213
+ `artifacts`), else list yours. With `project`: add `artifacts`, `remove` one, `title`
1214
+ renames, set `visibility`, `order`/`move` reorder, a `rule` adds matches as they are
1215
+ published, or read it. `delete` with `confirm: true` removes the project, its order and
1216
+ its share list permanently; its artifacts stay. One change per call, or title with
1217
+ visibility. An artifact's gallery label is not a project: that is `collection` on
1218
+ super_artifact_set.
1219
+ """
1220
+ return self._client._call(
1221
+ "POST",
1222
+ "/v1/projects/{project}/artifacts",
1223
+ path_params={"project": project},
1224
+ body={"artifacts": artifacts, "groupLabel": group_label, "confirm": confirm, "workspace": workspace},
1225
+ idempotency_key=idempotency_key,
1226
+ timeout=timeout,
1227
+ )
1228
+
1229
+ def remove_artifact(
1230
+ self,
1231
+ *,
1232
+ project: str,
1233
+ remove: str,
1234
+ timeout: Optional[float] = None,
1235
+ ) -> Dict[str, Any]:
1236
+ """Remove one artifact (or item) from a project.
1237
+
1238
+ A project is an ordered set of your artifacts shown one at a time at /s/{slug}, with its
1239
+ own audience and share list. No `project`: `title` creates one (seeded from
1240
+ `artifacts`), else list yours. With `project`: add `artifacts`, `remove` one, `title`
1241
+ renames, set `visibility`, `order`/`move` reorder, a `rule` adds matches as they are
1242
+ published, or read it. `delete` with `confirm: true` removes the project, its order and
1243
+ its share list permanently; its artifacts stay. One change per call, or title with
1244
+ visibility. An artifact's gallery label is not a project: that is `collection` on
1245
+ super_artifact_set.
1246
+ """
1247
+ return self._client._call(
1248
+ "DELETE",
1249
+ "/v1/projects/{project}/artifacts/{remove}",
1250
+ path_params={"project": project, "remove": remove},
1251
+ timeout=timeout,
1252
+ )
1253
+
1254
+
1255
+ class Shares(_Resource):
1256
+
1257
+ def add_to_artifact(
1258
+ self,
1259
+ *,
1260
+ artifact: str,
1261
+ emails: List[str],
1262
+ role: Optional[Literal["viewer", "commenter", "editor"]] = None,
1263
+ artifact_only: Optional[bool] = None,
1264
+ idempotency_key: Optional[str] = None,
1265
+ timeout: Optional[float] = None,
1266
+ ) -> Dict[str, Any]:
1267
+ """Give named people access to an artifact.
1268
+
1269
+ Give access: `artifact` (viewer; commenter comments; editor edits; new addresses
1270
+ emailed), `project` (viewer; emails each address); `workspace` (editor; accept links, no
1271
+ email). Named people move to the sent role, including downgrades; nobody is removed.
1272
+ Never changes visibility: public stays public; restrict with super_artifact_set. At most
1273
+ 20 addresses for an artifact, 50 for a project or workspace.
1274
+ """
1275
+ return self._client._call(
1276
+ "POST",
1277
+ "/v1/artifacts/{artifact}/shares",
1278
+ path_params={"artifact": artifact},
1279
+ body={"emails": emails, "role": role, "artifactOnly": artifact_only},
1280
+ idempotency_key=idempotency_key,
1281
+ timeout=timeout,
1282
+ )
1283
+
1284
+ def add_to_project(
1285
+ self,
1286
+ *,
1287
+ project: str,
1288
+ emails: List[str],
1289
+ role: Optional[Literal["viewer", "commenter", "editor"]] = None,
1290
+ confirm: Optional[bool] = None,
1291
+ idempotency_key: Optional[str] = None,
1292
+ timeout: Optional[float] = None,
1293
+ ) -> Dict[str, Any]:
1294
+ """Give named people access to a project.
1295
+
1296
+ Give access: `artifact` (viewer; commenter comments; editor edits; new addresses
1297
+ emailed), `project` (viewer; emails each address); `workspace` (editor; accept links, no
1298
+ email). Named people move to the sent role, including downgrades; nobody is removed.
1299
+ Never changes visibility: public stays public; restrict with super_artifact_set. At most
1300
+ 20 addresses for an artifact, 50 for a project or workspace.
1301
+ """
1302
+ return self._client._call(
1303
+ "POST",
1304
+ "/v1/projects/{project}/shares",
1305
+ path_params={"project": project},
1306
+ body={"emails": emails, "role": role, "confirm": confirm},
1307
+ idempotency_key=idempotency_key,
1308
+ timeout=timeout,
1309
+ )
1310
+
1311
+ def add_to_workspace(
1312
+ self,
1313
+ *,
1314
+ emails: List[str],
1315
+ role: Optional[Literal["viewer", "commenter", "editor"]] = None,
1316
+ workspace: Optional[str] = None,
1317
+ idempotency_key: Optional[str] = None,
1318
+ timeout: Optional[float] = None,
1319
+ ) -> Dict[str, Any]:
1320
+ """Invite editors to a workspace (returns accept links).
1321
+
1322
+ Give access: `artifact` (viewer; commenter comments; editor edits; new addresses
1323
+ emailed), `project` (viewer; emails each address); `workspace` (editor; accept links, no
1324
+ email). Named people move to the sent role, including downgrades; nobody is removed.
1325
+ Never changes visibility: public stays public; restrict with super_artifact_set. At most
1326
+ 20 addresses for an artifact, 50 for a project or workspace.
1327
+ """
1328
+ return self._client._call(
1329
+ "POST",
1330
+ "/v1/workspace/shares",
1331
+ body={"emails": emails, "role": role, "workspace": workspace},
1332
+ idempotency_key=idempotency_key,
1333
+ timeout=timeout,
1334
+ )
1335
+
1336
+
1337
+ class Comments(_Resource):
1338
+
1339
+ def list(
1340
+ self,
1341
+ *,
1342
+ artifact: str,
1343
+ status: Optional[Literal["all", "open", "resolved"]] = None,
1344
+ page: Optional[str] = None,
1345
+ limit: Optional[int] = None,
1346
+ cursor: Optional[str] = None,
1347
+ timeout: Optional[float] = None,
1348
+ ) -> Dict[str, Any]:
1349
+ """Comment threads on an artifact, newest first.
1350
+
1351
+ Threads: messages, anchor, viewed version (default `status: "open"`); status all
1352
+ includes resolved history. Publish the fix first, then respond with body explaining what
1353
+ changed and which version, plus resolve: true atomically. Reuse messageId on retry.
1354
+ Reports replied/resolved separately. resolve: false reopens. `screenshot` returns an
1355
+ image. Agents cannot open/delete threads. mentioned: true lists your @mentions, oldest
1356
+ unseen first, marking them seen.
1357
+ """
1358
+ return self._client._call(
1359
+ "GET",
1360
+ "/v1/artifacts/{artifact}/comments",
1361
+ path_params={"artifact": artifact},
1362
+ query={"status": status, "page": page, "limit": limit, "cursor": cursor},
1363
+ timeout=timeout,
1364
+ )
1365
+
1366
+ def respond(
1367
+ self,
1368
+ *,
1369
+ artifact: str,
1370
+ respond: Optional[List[Dict[str, Any]]] = None,
1371
+ idempotency_key: Optional[str] = None,
1372
+ timeout: Optional[float] = None,
1373
+ ) -> Dict[str, Any]:
1374
+ """Reply to and/or resolve threads, one outcome each.
1375
+
1376
+ Threads: messages, anchor, viewed version (default `status: "open"`); status all
1377
+ includes resolved history. Publish the fix first, then respond with body explaining what
1378
+ changed and which version, plus resolve: true atomically. Reuse messageId on retry.
1379
+ Reports replied/resolved separately. resolve: false reopens. `screenshot` returns an
1380
+ image. Agents cannot open/delete threads. mentioned: true lists your @mentions, oldest
1381
+ unseen first, marking them seen.
1382
+ """
1383
+ return self._client._call(
1384
+ "POST",
1385
+ "/v1/artifacts/{artifact}/comments/responses",
1386
+ path_params={"artifact": artifact},
1387
+ body={"respond": respond},
1388
+ idempotency_key=idempotency_key,
1389
+ timeout=timeout,
1390
+ )
1391
+
1392
+ def react(
1393
+ self,
1394
+ *,
1395
+ artifact: str,
1396
+ react: Optional[List[Dict[str, Any]]] = None,
1397
+ idempotency_key: Optional[str] = None,
1398
+ timeout: Optional[float] = None,
1399
+ ) -> Dict[str, Any]:
1400
+ """Toggle reactions on comment messages.
1401
+
1402
+ Threads: messages, anchor, viewed version (default `status: "open"`); status all
1403
+ includes resolved history. Publish the fix first, then respond with body explaining what
1404
+ changed and which version, plus resolve: true atomically. Reuse messageId on retry.
1405
+ Reports replied/resolved separately. resolve: false reopens. `screenshot` returns an
1406
+ image. Agents cannot open/delete threads. mentioned: true lists your @mentions, oldest
1407
+ unseen first, marking them seen.
1408
+ """
1409
+ return self._client._call(
1410
+ "POST",
1411
+ "/v1/artifacts/{artifact}/comments/reactions",
1412
+ path_params={"artifact": artifact},
1413
+ body={"react": react},
1414
+ idempotency_key=idempotency_key,
1415
+ timeout=timeout,
1416
+ )
1417
+
1418
+ def resolve(
1419
+ self,
1420
+ *,
1421
+ artifact: str,
1422
+ resolve: Optional[List[str]] = None,
1423
+ idempotency_key: Optional[str] = None,
1424
+ timeout: Optional[float] = None,
1425
+ ) -> Dict[str, Any]:
1426
+ """Resolve mentioned comment threads.
1427
+
1428
+ Threads: messages, anchor, viewed version (default `status: "open"`); status all
1429
+ includes resolved history. Publish the fix first, then respond with body explaining what
1430
+ changed and which version, plus resolve: true atomically. Reuse messageId on retry.
1431
+ Reports replied/resolved separately. resolve: false reopens. `screenshot` returns an
1432
+ image. Agents cannot open/delete threads. mentioned: true lists your @mentions, oldest
1433
+ unseen first, marking them seen.
1434
+ """
1435
+ return self._client._call(
1436
+ "POST",
1437
+ "/v1/artifacts/{artifact}/comments/resolutions",
1438
+ path_params={"artifact": artifact},
1439
+ body={"resolve": resolve},
1440
+ idempotency_key=idempotency_key,
1441
+ timeout=timeout,
1442
+ )
1443
+
1444
+ def get_screenshot(
1445
+ self,
1446
+ *,
1447
+ artifact: str,
1448
+ screenshot: str,
1449
+ timeout: Optional[float] = None,
1450
+ ) -> Dict[str, Any]:
1451
+ """One message's screenshot, base64 in `image`.
1452
+
1453
+ Threads: messages, anchor, viewed version (default `status: "open"`); status all
1454
+ includes resolved history. Publish the fix first, then respond with body explaining what
1455
+ changed and which version, plus resolve: true atomically. Reuse messageId on retry.
1456
+ Reports replied/resolved separately. resolve: false reopens. `screenshot` returns an
1457
+ image. Agents cannot open/delete threads. mentioned: true lists your @mentions, oldest
1458
+ unseen first, marking them seen.
1459
+ """
1460
+ return self._client._call(
1461
+ "GET",
1462
+ "/v1/artifacts/{artifact}/comments/screenshots/{screenshot}",
1463
+ path_params={"artifact": artifact, "screenshot": screenshot},
1464
+ timeout=timeout,
1465
+ )
1466
+
1467
+
1468
+ class Mentions(_Resource):
1469
+
1470
+ def list(
1471
+ self,
1472
+ *,
1473
+ artifact: Optional[str] = None,
1474
+ limit: Optional[int] = None,
1475
+ cursor: Optional[str] = None,
1476
+ timeout: Optional[float] = None,
1477
+ ) -> Dict[str, Any]:
1478
+ """Where people @mentioned you; listing marks them seen.
1479
+
1480
+ Threads: messages, anchor, viewed version (default `status: "open"`); status all
1481
+ includes resolved history. Publish the fix first, then respond with body explaining what
1482
+ changed and which version, plus resolve: true atomically. Reuse messageId on retry.
1483
+ Reports replied/resolved separately. resolve: false reopens. `screenshot` returns an
1484
+ image. Agents cannot open/delete threads. mentioned: true lists your @mentions, oldest
1485
+ unseen first, marking them seen.
1486
+ """
1487
+ return self._client._call(
1488
+ "GET",
1489
+ "/v1/mentions",
1490
+ query={"artifact": artifact, "limit": limit, "cursor": cursor},
1491
+ timeout=timeout,
1492
+ )
1493
+
1494
+ def iter(self, **kwargs: Any) -> Iterator[Dict[str, Any]]:
1495
+ """Every item of `list`, across pages. Takes the same arguments."""
1496
+ return walk_cursor(self.list, "mentions", kwargs)
1497
+
1498
+
1499
+ class Signatures(_Resource):
1500
+
1501
+ def list(
1502
+ self,
1503
+ *,
1504
+ artifact: Optional[str] = None,
1505
+ timeout: Optional[float] = None,
1506
+ ) -> Dict[str, Any]:
1507
+ """An artifact's signature requests, newest first.
1508
+
1509
+ Ask named people to sign one published version of an artifact, and follow the request.
1510
+ `request` with `artifact`, `signers` [{name, email, party?}] (≤10) and an optional
1511
+ `message` (≤500 characters) emails each signer a private link; the version must be one
1512
+ file of at most 2 MiB, and it is kept while the request is open and for good once it
1513
+ completes. `status` with `request` (one) or `artifact` (all, newest first). `withdraw`
1514
+ closes an open request. `remind` emails `signer` the link again, three times at most, a
1515
+ day apart. Only each signer can sign, in a browser, after a code sent to their address:
1516
+ an agent cannot.
1517
+ """
1518
+ return self._client._call(
1519
+ "GET",
1520
+ "/v1/signatures",
1521
+ query={"artifact": artifact},
1522
+ timeout=timeout,
1523
+ )
1524
+
1525
+ def request(
1526
+ self,
1527
+ *,
1528
+ artifact: Optional[str] = None,
1529
+ version: Optional[int] = None,
1530
+ signers: Optional[List[Dict[str, Any]]] = None,
1531
+ message: Optional[str] = None,
1532
+ idempotency_key: Optional[str] = None,
1533
+ timeout: Optional[float] = None,
1534
+ ) -> Dict[str, Any]:
1535
+ """Ask named people to sign one version of an artifact.
1536
+
1537
+ Ask named people to sign one published version of an artifact, and follow the request.
1538
+ `request` with `artifact`, `signers` [{name, email, party?}] (≤10) and an optional
1539
+ `message` (≤500 characters) emails each signer a private link; the version must be one
1540
+ file of at most 2 MiB, and it is kept while the request is open and for good once it
1541
+ completes. `status` with `request` (one) or `artifact` (all, newest first). `withdraw`
1542
+ closes an open request. `remind` emails `signer` the link again, three times at most, a
1543
+ day apart. Only each signer can sign, in a browser, after a code sent to their address:
1544
+ an agent cannot.
1545
+ """
1546
+ return self._client._call(
1547
+ "POST",
1548
+ "/v1/signatures",
1549
+ body={"artifact": artifact, "version": version, "signers": signers, "message": message},
1550
+ idempotency_key=idempotency_key,
1551
+ timeout=timeout,
1552
+ )
1553
+
1554
+ def get(
1555
+ self,
1556
+ *,
1557
+ request: str,
1558
+ timeout: Optional[float] = None,
1559
+ ) -> Dict[str, Any]:
1560
+ """One signature request and its signers.
1561
+
1562
+ Ask named people to sign one published version of an artifact, and follow the request.
1563
+ `request` with `artifact`, `signers` [{name, email, party?}] (≤10) and an optional
1564
+ `message` (≤500 characters) emails each signer a private link; the version must be one
1565
+ file of at most 2 MiB, and it is kept while the request is open and for good once it
1566
+ completes. `status` with `request` (one) or `artifact` (all, newest first). `withdraw`
1567
+ closes an open request. `remind` emails `signer` the link again, three times at most, a
1568
+ day apart. Only each signer can sign, in a browser, after a code sent to their address:
1569
+ an agent cannot.
1570
+ """
1571
+ return self._client._call(
1572
+ "GET",
1573
+ "/v1/signatures/{request}",
1574
+ path_params={"request": request},
1575
+ timeout=timeout,
1576
+ )
1577
+
1578
+ def remind(
1579
+ self,
1580
+ *,
1581
+ request: str,
1582
+ signer: Optional[str] = None,
1583
+ idempotency_key: Optional[str] = None,
1584
+ timeout: Optional[float] = None,
1585
+ ) -> Dict[str, Any]:
1586
+ """Email a signer their link again.
1587
+
1588
+ Ask named people to sign one published version of an artifact, and follow the request.
1589
+ `request` with `artifact`, `signers` [{name, email, party?}] (≤10) and an optional
1590
+ `message` (≤500 characters) emails each signer a private link; the version must be one
1591
+ file of at most 2 MiB, and it is kept while the request is open and for good once it
1592
+ completes. `status` with `request` (one) or `artifact` (all, newest first). `withdraw`
1593
+ closes an open request. `remind` emails `signer` the link again, three times at most, a
1594
+ day apart. Only each signer can sign, in a browser, after a code sent to their address:
1595
+ an agent cannot.
1596
+ """
1597
+ return self._client._call(
1598
+ "POST",
1599
+ "/v1/signatures/{request}/remind",
1600
+ path_params={"request": request},
1601
+ body={"signer": signer},
1602
+ idempotency_key=idempotency_key,
1603
+ timeout=timeout,
1604
+ )
1605
+
1606
+ def withdraw(
1607
+ self,
1608
+ *,
1609
+ request: str,
1610
+ idempotency_key: Optional[str] = None,
1611
+ timeout: Optional[float] = None,
1612
+ ) -> Dict[str, Any]:
1613
+ """Close an open signature request.
1614
+
1615
+ Ask named people to sign one published version of an artifact, and follow the request.
1616
+ `request` with `artifact`, `signers` [{name, email, party?}] (≤10) and an optional
1617
+ `message` (≤500 characters) emails each signer a private link; the version must be one
1618
+ file of at most 2 MiB, and it is kept while the request is open and for good once it
1619
+ completes. `status` with `request` (one) or `artifact` (all, newest first). `withdraw`
1620
+ closes an open request. `remind` emails `signer` the link again, three times at most, a
1621
+ day apart. Only each signer can sign, in a browser, after a code sent to their address:
1622
+ an agent cannot.
1623
+ """
1624
+ return self._client._call(
1625
+ "POST",
1626
+ "/v1/signatures/{request}/withdraw",
1627
+ path_params={"request": request},
1628
+ idempotency_key=idempotency_key,
1629
+ timeout=timeout,
1630
+ )
1631
+
1632
+
1633
+ class SyncResources:
1634
+ def __init__(self) -> None:
1635
+ self.account = Account(self)
1636
+ self.webhooks = Webhooks(self)
1637
+ self.artifacts = Artifacts(self)
1638
+ self.live = Live(self)
1639
+ self.uploads = Uploads(self)
1640
+ self.data = Data(self)
1641
+ self.schema = Schema(self)
1642
+ self.entries = Entries(self)
1643
+ self.secrets = Secrets(self)
1644
+ self.templates = Templates(self)
1645
+ self.projects = Projects(self)
1646
+ self.shares = Shares(self)
1647
+ self.comments = Comments(self)
1648
+ self.mentions = Mentions(self)
1649
+ self.signatures = Signatures(self)
1650
+
1651
+
1652
+ class AsyncAccount(_Resource):
1653
+
1654
+ async def whoami(
1655
+ self,
1656
+ *,
1657
+ timeout: Optional[float] = None,
1658
+ ) -> Dict[str, Any]:
1659
+ """Who this key publishes as.
1660
+
1661
+ Who this key publishes as: the workspace `handle`, `email`, `agent` name and `scope`
1662
+ (the artifacts it may change: its own, and those it is named Editor on), plus
1663
+ `liveRooms` where live rooms run (the limit and who holds one). Useful to confirm where
1664
+ a publish lands, or why an artifact answers `not_found`; no other tool needs it.
1665
+ """
1666
+ return await self._client._call(
1667
+ "GET",
1668
+ "/v1/whoami",
1669
+ timeout=timeout,
1670
+ )
1671
+
1672
+ async def help(
1673
+ self,
1674
+ *,
1675
+ topic: Optional[Literal["tools", "data", "templates", "collections", "projects", "batch"]] = None,
1676
+ timeout: Optional[float] = None,
1677
+ ) -> Dict[str, Any]:
1678
+ """How the operations fit together.
1679
+
1680
+ Plain-text notes for when it is unclear which tool, data store or argument shape does a
1681
+ job. Topics: `tools` (a line per tool), `data` (which store a page needs and how the
1682
+ page writes to it), `templates` (finding, building from, drafting, releasing),
1683
+ `collections` (content models and field types), `projects` (creating, ordering, sharing,
1684
+ rules), `batch` (what each tool takes in one call). Without `topic`: the full topic
1685
+ list, which names two more reached from results. Answers `{topic, text}`; not needed
1686
+ when a tool’s own description answers the question.
1687
+ """
1688
+ return await self._client._call(
1689
+ "GET",
1690
+ "/v1/help",
1691
+ query={"topic": topic},
1692
+ timeout=timeout,
1693
+ )
1694
+
1695
+
1696
+ class AsyncWebhooks(_Resource):
1697
+
1698
+ async def list(
1699
+ self,
1700
+ *,
1701
+ agent: Optional[str] = None,
1702
+ timeout: Optional[float] = None,
1703
+ ) -> Dict[str, Any]:
1704
+ """List account webhook endpoints.
1705
+
1706
+ Manage this account’s webhook endpoints. create and rotate return the signing secret
1707
+ once; delete permanently removes an endpoint and its delivery history. Mutations require
1708
+ write scope. agent: "me" selects the calling key’s agent (no_agent if absent); a handle
1709
+ must be owned. messages returns the newest 100, optionally filtered by endpoint id and
1710
+ sinceMinutes (1–43200). Declare artifact triggers through super_publish.
1711
+ """
1712
+ return await self._client._call(
1713
+ "GET",
1714
+ "/v1/webhooks",
1715
+ query={"agent": agent},
1716
+ timeout=timeout,
1717
+ )
1718
+
1719
+ async def create(
1720
+ self,
1721
+ *,
1722
+ url: Optional[str] = None,
1723
+ description: Optional[str] = None,
1724
+ event_types: Optional[List[str]] = None,
1725
+ agent: Optional[str] = None,
1726
+ idempotency_key: Optional[str] = None,
1727
+ timeout: Optional[float] = None,
1728
+ ) -> Dict[str, Any]:
1729
+ """Create an endpoint; returns its signing secret once.
1730
+
1731
+ Manage this account’s webhook endpoints. create and rotate return the signing secret
1732
+ once; delete permanently removes an endpoint and its delivery history. Mutations require
1733
+ write scope. agent: "me" selects the calling key’s agent (no_agent if absent); a handle
1734
+ must be owned. messages returns the newest 100, optionally filtered by endpoint id and
1735
+ sinceMinutes (1–43200). Declare artifact triggers through super_publish.
1736
+ """
1737
+ return await self._client._call(
1738
+ "POST",
1739
+ "/v1/webhooks",
1740
+ body={"url": url, "description": description, "eventTypes": event_types, "agent": agent},
1741
+ idempotency_key=idempotency_key,
1742
+ timeout=timeout,
1743
+ )
1744
+
1745
+ async def get(
1746
+ self,
1747
+ *,
1748
+ id: str,
1749
+ timeout: Optional[float] = None,
1750
+ ) -> Dict[str, Any]:
1751
+ """Read an owned endpoint.
1752
+
1753
+ Manage this account’s webhook endpoints. create and rotate return the signing secret
1754
+ once; delete permanently removes an endpoint and its delivery history. Mutations require
1755
+ write scope. agent: "me" selects the calling key’s agent (no_agent if absent); a handle
1756
+ must be owned. messages returns the newest 100, optionally filtered by endpoint id and
1757
+ sinceMinutes (1–43200). Declare artifact triggers through super_publish.
1758
+ """
1759
+ return await self._client._call(
1760
+ "GET",
1761
+ "/v1/webhooks/{id}",
1762
+ path_params={"id": id},
1763
+ timeout=timeout,
1764
+ )
1765
+
1766
+ async def delete(
1767
+ self,
1768
+ *,
1769
+ id: str,
1770
+ timeout: Optional[float] = None,
1771
+ ) -> Dict[str, Any]:
1772
+ """Delete an endpoint and its history.
1773
+
1774
+ Manage this account’s webhook endpoints. create and rotate return the signing secret
1775
+ once; delete permanently removes an endpoint and its delivery history. Mutations require
1776
+ write scope. agent: "me" selects the calling key’s agent (no_agent if absent); a handle
1777
+ must be owned. messages returns the newest 100, optionally filtered by endpoint id and
1778
+ sinceMinutes (1–43200). Declare artifact triggers through super_publish.
1779
+ """
1780
+ return await self._client._call(
1781
+ "DELETE",
1782
+ "/v1/webhooks/{id}",
1783
+ path_params={"id": id},
1784
+ timeout=timeout,
1785
+ )
1786
+
1787
+ async def test(
1788
+ self,
1789
+ *,
1790
+ id: str,
1791
+ idempotency_key: Optional[str] = None,
1792
+ timeout: Optional[float] = None,
1793
+ ) -> Dict[str, Any]:
1794
+ """Send a signed webhook.test.
1795
+
1796
+ Manage this account’s webhook endpoints. create and rotate return the signing secret
1797
+ once; delete permanently removes an endpoint and its delivery history. Mutations require
1798
+ write scope. agent: "me" selects the calling key’s agent (no_agent if absent); a handle
1799
+ must be owned. messages returns the newest 100, optionally filtered by endpoint id and
1800
+ sinceMinutes (1–43200). Declare artifact triggers through super_publish.
1801
+ """
1802
+ return await self._client._call(
1803
+ "POST",
1804
+ "/v1/webhooks/{id}/test",
1805
+ path_params={"id": id},
1806
+ idempotency_key=idempotency_key,
1807
+ timeout=timeout,
1808
+ )
1809
+
1810
+ async def rotate_secret(
1811
+ self,
1812
+ *,
1813
+ id: str,
1814
+ idempotency_key: Optional[str] = None,
1815
+ timeout: Optional[float] = None,
1816
+ ) -> Dict[str, Any]:
1817
+ """Rotate the signing secret; returns it once.
1818
+
1819
+ Manage this account’s webhook endpoints. create and rotate return the signing secret
1820
+ once; delete permanently removes an endpoint and its delivery history. Mutations require
1821
+ write scope. agent: "me" selects the calling key’s agent (no_agent if absent); a handle
1822
+ must be owned. messages returns the newest 100, optionally filtered by endpoint id and
1823
+ sinceMinutes (1–43200). Declare artifact triggers through super_publish.
1824
+ """
1825
+ return await self._client._call(
1826
+ "POST",
1827
+ "/v1/webhooks/{id}/rotate",
1828
+ path_params={"id": id},
1829
+ idempotency_key=idempotency_key,
1830
+ timeout=timeout,
1831
+ )
1832
+
1833
+ async def messages(
1834
+ self,
1835
+ *,
1836
+ id: Optional[str] = None,
1837
+ since_minutes: Optional[int] = None,
1838
+ timeout: Optional[float] = None,
1839
+ ) -> Dict[str, Any]:
1840
+ """Read the newest 100 webhook messages.
1841
+
1842
+ Manage this account’s webhook endpoints. create and rotate return the signing secret
1843
+ once; delete permanently removes an endpoint and its delivery history. Mutations require
1844
+ write scope. agent: "me" selects the calling key’s agent (no_agent if absent); a handle
1845
+ must be owned. messages returns the newest 100, optionally filtered by endpoint id and
1846
+ sinceMinutes (1–43200). Declare artifact triggers through super_publish.
1847
+ """
1848
+ return await self._client._call(
1849
+ "GET",
1850
+ "/v1/webhook-messages",
1851
+ query={"id": id, "sinceMinutes": since_minutes},
1852
+ timeout=timeout,
1853
+ )
1854
+
1855
+
1856
+ class AsyncArtifacts(AsyncArtifactHelper, _Resource):
1857
+
1858
+ async def list(
1859
+ self,
1860
+ *,
1861
+ timeout: Optional[float] = None,
1862
+ ) -> Dict[str, Any]:
1863
+ """List your artifacts, newest first.
1864
+
1865
+ Without `artifact`: your artifacts, newest first, with URLs and `live`. With `artifact`:
1866
+ its versions, which is published, their paths, and `declaration` (the published policy).
1867
+ Add `path` or `version` to read that file as text (default: published index.html); non-
1868
+ text or over 300,000 bytes: refused. `open: true` (with `artifact`, optional `version`)
1869
+ returns `url` and `expiresAt`: load `url` to see the artifact as a viewer, private
1870
+ included, for 10 minutes; visibility is unchanged, the URL opens only that artifact,
1871
+ 60/key/hour (`rate_limited`). Changing what an artifact serves, or who can open it, is
1872
+ super_artifact_set.
1873
+ """
1874
+ return await self._client._call(
1875
+ "GET",
1876
+ "/v1/artifacts",
1877
+ timeout=timeout,
1878
+ )
1879
+
1880
+ async def publish(
1881
+ self,
1882
+ *,
1883
+ slug: str,
1884
+ prompt: Optional[str] = None,
1885
+ html: Optional[str] = None,
1886
+ values: Optional[Dict[str, Any]] = None,
1887
+ instances: Optional[List[Dict[str, Any]]] = None,
1888
+ template: Optional[Dict[str, Any]] = None,
1889
+ title: Optional[str] = None,
1890
+ description: Optional[str] = None,
1891
+ kind: Optional[Literal["page", "slideshow", "survey", "tracker", "video", "tool", "dashboard"]] = None,
1892
+ collection: Optional[str] = None,
1893
+ visibility: Optional[Literal["private", "organization"]] = None,
1894
+ policy: Optional[Dict[str, Any]] = None,
1895
+ triggers: Optional[List[Dict[str, Any]]] = None,
1896
+ dataset: Optional[str] = None,
1897
+ continues: Optional[str] = None,
1898
+ uploads: Optional[str] = None,
1899
+ values_file: Optional[str] = None,
1900
+ files: Optional[List[Dict[str, Any]]] = None,
1901
+ idempotency_key: Optional[str] = None,
1902
+ timeout: Optional[float] = None,
1903
+ ) -> Dict[str, Any]:
1904
+ """Publish an artifact, or a new version of one.
1905
+
1906
+ Publish a page at a stable URL; the same slug adds a new version, which the URL serves
1907
+ at once. Earlier versions stay and can be served again; nothing that existed before the
1908
+ call is deleted. Always give the person the url from the result, even on updates. Send
1909
+ `html`, or `values` for a template that carries a runtime, not both. Without `policy` a
1910
+ form, input or saved state stores nothing; CMS rows a page edits go in
1911
+ `policy.collections`. When retained storage is full it refuses with `plan_limit` and
1912
+ deletes nothing. A template becomes everybody’s through a release, not a publish.
1913
+ """
1914
+ return await self._client._call(
1915
+ "POST",
1916
+ "/v1/artifacts",
1917
+ body={"slug": slug, "prompt": prompt, "html": html, "values": values, "instances": instances, "template": template, "title": title, "description": description, "kind": kind, "collection": collection, "visibility": visibility, "policy": policy, "triggers": triggers, "dataset": dataset, "continues": continues, "uploads": uploads, "valuesFile": values_file, "files": files},
1918
+ idempotency_key=idempotency_key,
1919
+ timeout=timeout,
1920
+ )
1921
+
1922
+ async def get(
1923
+ self,
1924
+ *,
1925
+ artifact: str,
1926
+ timeout: Optional[float] = None,
1927
+ ) -> Dict[str, Any]:
1928
+ """One artifact: its versions, published version and declaration.
1929
+
1930
+ Without `artifact`: your artifacts, newest first, with URLs and `live`. With `artifact`:
1931
+ its versions, which is published, their paths, and `declaration` (the published policy).
1932
+ Add `path` or `version` to read that file as text (default: published index.html); non-
1933
+ text or over 300,000 bytes: refused. `open: true` (with `artifact`, optional `version`)
1934
+ returns `url` and `expiresAt`: load `url` to see the artifact as a viewer, private
1935
+ included, for 10 minutes; visibility is unchanged, the URL opens only that artifact,
1936
+ 60/key/hour (`rate_limited`). Changing what an artifact serves, or who can open it, is
1937
+ super_artifact_set.
1938
+ """
1939
+ return await self._client._call(
1940
+ "GET",
1941
+ "/v1/artifacts/{artifact}",
1942
+ path_params={"artifact": artifact},
1943
+ timeout=timeout,
1944
+ )
1945
+
1946
+ async def update(
1947
+ self,
1948
+ *,
1949
+ artifact: str,
1950
+ visibility: Optional[Literal["private", "organization", "public"]] = None,
1951
+ collection: Optional[str] = None,
1952
+ phase: Optional[str] = None,
1953
+ notify_on_submission: Optional[bool] = None,
1954
+ triggers_enabled: Optional[bool] = None,
1955
+ timeout: Optional[float] = None,
1956
+ ) -> Dict[str, Any]:
1957
+ """Change visibility, gallery label, live phase or submission email.
1958
+
1959
+ Change one artifact. `version` serves an existing version (a pointer move; nothing
1960
+ rebuilt or deleted). `live` turns its live room on or off; off disconnects every
1961
+ visitor, and Free has one room at a time. `triggersEnabled` is the owner’s kill switch
1962
+ for declared triggers (default on). `notifyOnSubmission` emails you for each new data
1963
+ submission (default off; edits send nothing; no answers in the mail). `phase` sets the
1964
+ live room’s phase. `visibility` widens or narrows who can open it; narrowing voids every
1965
+ viewer grant already issued, so each viewer is checked again. `collection` sets its
1966
+ gallery grouping label. `delete` removes the artifact with every version, share link and
1967
+ response, permanently; it needs `confirm: true` and goes alone. Fields apply in that
1968
+ order, and a refusal part-way names the ones already `applied`. Publishing a new version
1969
+ is super_publish.
1970
+ """
1971
+ return await self._client._call(
1972
+ "PATCH",
1973
+ "/v1/artifacts/{artifact}",
1974
+ path_params={"artifact": artifact},
1975
+ body={"visibility": visibility, "collection": collection, "phase": phase, "notifyOnSubmission": notify_on_submission, "triggersEnabled": triggers_enabled},
1976
+ timeout=timeout,
1977
+ )
1978
+
1979
+ async def delete(
1980
+ self,
1981
+ *,
1982
+ artifact: str,
1983
+ timeout: Optional[float] = None,
1984
+ ) -> Dict[str, Any]:
1985
+ """Delete an artifact with every version, permanently.
1986
+
1987
+ Change one artifact. `version` serves an existing version (a pointer move; nothing
1988
+ rebuilt or deleted). `live` turns its live room on or off; off disconnects every
1989
+ visitor, and Free has one room at a time. `triggersEnabled` is the owner’s kill switch
1990
+ for declared triggers (default on). `notifyOnSubmission` emails you for each new data
1991
+ submission (default off; edits send nothing; no answers in the mail). `phase` sets the
1992
+ live room’s phase. `visibility` widens or narrows who can open it; narrowing voids every
1993
+ viewer grant already issued, so each viewer is checked again. `collection` sets its
1994
+ gallery grouping label. `delete` removes the artifact with every version, share link and
1995
+ response, permanently; it needs `confirm: true` and goes alone. Fields apply in that
1996
+ order, and a refusal part-way names the ones already `applied`. Publishing a new version
1997
+ is super_publish.
1998
+ """
1999
+ return await self._client._call(
2000
+ "DELETE",
2001
+ "/v1/artifacts/{artifact}",
2002
+ path_params={"artifact": artifact},
2003
+ query={"confirm": artifact},
2004
+ timeout=timeout,
2005
+ )
2006
+
2007
+ async def read_file(
2008
+ self,
2009
+ *,
2010
+ artifact: str,
2011
+ path: Optional[str] = None,
2012
+ version: Optional[int] = None,
2013
+ timeout: Optional[float] = None,
2014
+ ) -> Dict[str, Any]:
2015
+ """Read one file of a version as text (default: the published index.html).
2016
+
2017
+ Without `artifact`: your artifacts, newest first, with URLs and `live`. With `artifact`:
2018
+ its versions, which is published, their paths, and `declaration` (the published policy).
2019
+ Add `path` or `version` to read that file as text (default: published index.html); non-
2020
+ text or over 300,000 bytes: refused. `open: true` (with `artifact`, optional `version`)
2021
+ returns `url` and `expiresAt`: load `url` to see the artifact as a viewer, private
2022
+ included, for 10 minutes; visibility is unchanged, the URL opens only that artifact,
2023
+ 60/key/hour (`rate_limited`). Changing what an artifact serves, or who can open it, is
2024
+ super_artifact_set.
2025
+ """
2026
+ return await self._client._call(
2027
+ "GET",
2028
+ "/v1/artifacts/{artifact}/file",
2029
+ path_params={"artifact": artifact},
2030
+ query={"path": path, "version": version},
2031
+ timeout=timeout,
2032
+ )
2033
+
2034
+ async def open(
2035
+ self,
2036
+ *,
2037
+ artifact: str,
2038
+ version: Optional[int] = None,
2039
+ idempotency_key: Optional[str] = None,
2040
+ timeout: Optional[float] = None,
2041
+ ) -> Dict[str, Any]:
2042
+ """A ten-minute viewer URL for an artifact, private included.
2043
+
2044
+ Without `artifact`: your artifacts, newest first, with URLs and `live`. With `artifact`:
2045
+ its versions, which is published, their paths, and `declaration` (the published policy).
2046
+ Add `path` or `version` to read that file as text (default: published index.html); non-
2047
+ text or over 300,000 bytes: refused. `open: true` (with `artifact`, optional `version`)
2048
+ returns `url` and `expiresAt`: load `url` to see the artifact as a viewer, private
2049
+ included, for 10 minutes; visibility is unchanged, the URL opens only that artifact,
2050
+ 60/key/hour (`rate_limited`). Changing what an artifact serves, or who can open it, is
2051
+ super_artifact_set.
2052
+ """
2053
+ return await self._client._call(
2054
+ "POST",
2055
+ "/v1/artifacts/{artifact}/open",
2056
+ path_params={"artifact": artifact},
2057
+ body={"version": version},
2058
+ idempotency_key=idempotency_key,
2059
+ timeout=timeout,
2060
+ )
2061
+
2062
+ async def serve_version(
2063
+ self,
2064
+ *,
2065
+ artifact: str,
2066
+ version: int,
2067
+ idempotency_key: Optional[str] = None,
2068
+ timeout: Optional[float] = None,
2069
+ ) -> Dict[str, Any]:
2070
+ """Serve an existing version again.
2071
+
2072
+ Change one artifact. `version` serves an existing version (a pointer move; nothing
2073
+ rebuilt or deleted). `live` turns its live room on or off; off disconnects every
2074
+ visitor, and Free has one room at a time. `triggersEnabled` is the owner’s kill switch
2075
+ for declared triggers (default on). `notifyOnSubmission` emails you for each new data
2076
+ submission (default off; edits send nothing; no answers in the mail). `phase` sets the
2077
+ live room’s phase. `visibility` widens or narrows who can open it; narrowing voids every
2078
+ viewer grant already issued, so each viewer is checked again. `collection` sets its
2079
+ gallery grouping label. `delete` removes the artifact with every version, share link and
2080
+ response, permanently; it needs `confirm: true` and goes alone. Fields apply in that
2081
+ order, and a refusal part-way names the ones already `applied`. Publishing a new version
2082
+ is super_publish.
2083
+ """
2084
+ return await self._client._call(
2085
+ "POST",
2086
+ "/v1/artifacts/{artifact}/versions/{version}/serve",
2087
+ path_params={"artifact": artifact, "version": version},
2088
+ idempotency_key=idempotency_key,
2089
+ timeout=timeout,
2090
+ )
2091
+
2092
+
2093
+ class AsyncLive(_Resource):
2094
+
2095
+ async def start(
2096
+ self,
2097
+ *,
2098
+ artifact: str,
2099
+ idempotency_key: Optional[str] = None,
2100
+ timeout: Optional[float] = None,
2101
+ ) -> Dict[str, Any]:
2102
+ """Turn an artifact's live room on.
2103
+
2104
+ Change one artifact. `version` serves an existing version (a pointer move; nothing
2105
+ rebuilt or deleted). `live` turns its live room on or off; off disconnects every
2106
+ visitor, and Free has one room at a time. `triggersEnabled` is the owner’s kill switch
2107
+ for declared triggers (default on). `notifyOnSubmission` emails you for each new data
2108
+ submission (default off; edits send nothing; no answers in the mail). `phase` sets the
2109
+ live room’s phase. `visibility` widens or narrows who can open it; narrowing voids every
2110
+ viewer grant already issued, so each viewer is checked again. `collection` sets its
2111
+ gallery grouping label. `delete` removes the artifact with every version, share link and
2112
+ response, permanently; it needs `confirm: true` and goes alone. Fields apply in that
2113
+ order, and a refusal part-way names the ones already `applied`. Publishing a new version
2114
+ is super_publish.
2115
+ """
2116
+ return await self._client._call(
2117
+ "POST",
2118
+ "/v1/artifacts/{artifact}/live",
2119
+ path_params={"artifact": artifact},
2120
+ idempotency_key=idempotency_key,
2121
+ timeout=timeout,
2122
+ )
2123
+
2124
+ async def stop(
2125
+ self,
2126
+ *,
2127
+ artifact: str,
2128
+ timeout: Optional[float] = None,
2129
+ ) -> Dict[str, Any]:
2130
+ """Turn an artifact's live room off, disconnecting every visitor.
2131
+
2132
+ Change one artifact. `version` serves an existing version (a pointer move; nothing
2133
+ rebuilt or deleted). `live` turns its live room on or off; off disconnects every
2134
+ visitor, and Free has one room at a time. `triggersEnabled` is the owner’s kill switch
2135
+ for declared triggers (default on). `notifyOnSubmission` emails you for each new data
2136
+ submission (default off; edits send nothing; no answers in the mail). `phase` sets the
2137
+ live room’s phase. `visibility` widens or narrows who can open it; narrowing voids every
2138
+ viewer grant already issued, so each viewer is checked again. `collection` sets its
2139
+ gallery grouping label. `delete` removes the artifact with every version, share link and
2140
+ response, permanently; it needs `confirm: true` and goes alone. Fields apply in that
2141
+ order, and a refusal part-way names the ones already `applied`. Publishing a new version
2142
+ is super_publish.
2143
+ """
2144
+ return await self._client._call(
2145
+ "DELETE",
2146
+ "/v1/artifacts/{artifact}/live",
2147
+ path_params={"artifact": artifact},
2148
+ timeout=timeout,
2149
+ )
2150
+
2151
+
2152
+ class AsyncUploads(AsyncUploadHelper, _Resource):
2153
+
2154
+ async def stage(
2155
+ self,
2156
+ *,
2157
+ files: List[Dict[str, Any]],
2158
+ idempotency_key: Optional[str] = None,
2159
+ timeout: Optional[float] = None,
2160
+ ) -> Dict[str, Any]:
2161
+ """Stage big files for a publish; PUT each to its URL.
2162
+
2163
+ Stage images, video or big files for a publish without sending their bytes in a call.
2164
+ Declare each file’s `path` and exact `bytes`; the result carries an `uploadId` and one
2165
+ `url` per file. PUT each file to its URL (`curl -T`, no credentials), then super_publish
2166
+ with `uploads`. Not index.html: that is `html`; small assets can ride inline as the
2167
+ publish’s `files`. Same limits as `files`; a staged set expires after 30 minutes, and at
2168
+ most 5 wait unpublished at once.
2169
+ """
2170
+ return await self._client._call(
2171
+ "POST",
2172
+ "/v1/uploads",
2173
+ body={"files": files},
2174
+ idempotency_key=idempotency_key,
2175
+ timeout=timeout,
2176
+ )
2177
+
2178
+
2179
+ class AsyncData(_Resource):
2180
+
2181
+ async def list_artifact_rows(
2182
+ self,
2183
+ *,
2184
+ artifact: str,
2185
+ filter: Optional[List[str]] = None,
2186
+ since: Optional[str] = None,
2187
+ until: Optional[str] = None,
2188
+ sort: Optional[Literal["newest", "oldest"]] = None,
2189
+ limit: Optional[int] = None,
2190
+ cursor: Optional[str] = None,
2191
+ fields: Optional[List[str]] = None,
2192
+ timeout: Optional[float] = None,
2193
+ ) -> Dict[str, Any]:
2194
+ """Rows visitors submitted to one artifact, newest first.
2195
+
2196
+ The rows visitors submitted to your artifacts, newest first, with each version's field
2197
+ schema; paged by `cursor`. Address exactly one: `artifact`; `dataset` (a catalog key;
2198
+ one shared by several artifacts is `ambiguous_dataset`); or `collection`, the gallery
2199
+ grouping label set at publish, not a content collection (≤20 artifacts over one window,
2200
+ kept per artifact, no `filter`). Entries of a content collection are super_entries;
2201
+ totals and averages are a query, not a read.
2202
+ """
2203
+ return await self._client._call(
2204
+ "GET",
2205
+ "/v1/artifacts/{artifact}/data",
2206
+ path_params={"artifact": artifact},
2207
+ query={"filter": filter, "since": since, "until": until, "sort": sort, "limit": limit, "cursor": cursor, "fields": fields},
2208
+ timeout=timeout,
2209
+ )
2210
+
2211
+ def iter_artifact_rows(self, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]:
2212
+ """Every item of `list_artifact_rows`, across pages. Takes the same arguments."""
2213
+ return awalk_cursor(self.list_artifact_rows, "responses", kwargs)
2214
+
2215
+ async def write_artifact_rows(
2216
+ self,
2217
+ *,
2218
+ artifact: str,
2219
+ stream: Optional[str] = None,
2220
+ rows: Optional[List[Dict[str, Any]]] = None,
2221
+ ops: Optional[List[Dict[str, Any]]] = None,
2222
+ atomic: Optional[bool] = None,
2223
+ idempotency_key: Optional[str] = None,
2224
+ timeout: Optional[float] = None,
2225
+ ) -> Dict[str, Any]:
2226
+ """Write rows into an artifact you may edit.
2227
+
2228
+ Write rows into an artifact this key may edit, through the validation and stream rules a
2229
+ page write gets; each row is attributed "<agent> (agent)". `rows` creates in `stream`.
2230
+ `ops` [{op: create|replace|delete, id, row, stream}] replaces or deletes only rows this
2231
+ agent wrote (writes: upsert); a deleted row cannot be restored by any tool. ≤50 a call;
2232
+ `atomic`: all or none, otherwise a partial batch answers `complete: false`. Visitor rows
2233
+ are never changed here; entries of a content collection are super_entries.
2234
+ """
2235
+ return await self._client._call(
2236
+ "POST",
2237
+ "/v1/artifacts/{artifact}/data/rows",
2238
+ path_params={"artifact": artifact},
2239
+ body={"stream": stream, "rows": rows, "ops": ops, "atomic": atomic},
2240
+ idempotency_key=idempotency_key,
2241
+ timeout=timeout,
2242
+ )
2243
+
2244
+ async def list_rows(
2245
+ self,
2246
+ *,
2247
+ dataset: Optional[str] = None,
2248
+ collection: Optional[str] = None,
2249
+ filter: Optional[List[str]] = None,
2250
+ since: Optional[str] = None,
2251
+ until: Optional[str] = None,
2252
+ sort: Optional[Literal["newest", "oldest"]] = None,
2253
+ limit: Optional[int] = None,
2254
+ cursor: Optional[str] = None,
2255
+ fields: Optional[List[str]] = None,
2256
+ timeout: Optional[float] = None,
2257
+ ) -> Dict[str, Any]:
2258
+ """Rows submitted to a dataset or a gallery label.
2259
+
2260
+ The rows visitors submitted to your artifacts, newest first, with each version's field
2261
+ schema; paged by `cursor`. Address exactly one: `artifact`; `dataset` (a catalog key;
2262
+ one shared by several artifacts is `ambiguous_dataset`); or `collection`, the gallery
2263
+ grouping label set at publish, not a content collection (≤20 artifacts over one window,
2264
+ kept per artifact, no `filter`). Entries of a content collection are super_entries;
2265
+ totals and averages are a query, not a read.
2266
+ """
2267
+ return await self._client._call(
2268
+ "GET",
2269
+ "/v1/data",
2270
+ query={"dataset": dataset, "collection": collection, "filter": filter, "since": since, "until": until, "sort": sort, "limit": limit, "cursor": cursor, "fields": fields},
2271
+ timeout=timeout,
2272
+ )
2273
+
2274
+ def iter_rows(self, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]:
2275
+ """Every item of `list_rows`, across pages. Takes the same arguments."""
2276
+ return awalk_cursor(self.list_rows, "responses", kwargs)
2277
+
2278
+ async def query(
2279
+ self,
2280
+ *,
2281
+ scope: Optional[Dict[str, Any]] = None,
2282
+ measures: Optional[List[str]] = None,
2283
+ agg: Optional[Literal["sum", "avg", "min", "max", "count", "last"]] = None,
2284
+ compute: Optional[List[Dict[str, Any]]] = None,
2285
+ filter: Optional[List[str]] = None,
2286
+ group_by: Optional[List[str]] = None,
2287
+ since: Optional[str] = None,
2288
+ until: Optional[str] = None,
2289
+ limit: Optional[int] = None,
2290
+ distributions: Optional[Dict[str, Any]] = None,
2291
+ idempotency_key: Optional[str] = None,
2292
+ timeout: Optional[float] = None,
2293
+ ) -> Dict[str, Any]:
2294
+ """Aggregate what was collected: numbers, never rows.
2295
+
2296
+ Numbers over what was collected, never rows (rows are super_data). Aggregate `measures`
2297
+ across the datasets in `scope`; datasets combine on the same measure in one base unit,
2298
+ results in the declared `unit`. Names come from the catalog; an unknown one errors with
2299
+ near misses. The answer has one row per `group_by` key (or one row) with a column per
2300
+ measure and `compute`, the datasets used and any skipped, and `truncated` when `limit`
2301
+ cut it. Or send `distributions` for one artifact: counts, per-version rates and per-
2302
+ field distributions (free text: answer rate and length only). A call with neither is
2303
+ `invalid_query`.
2304
+ """
2305
+ return await self._client._call(
2306
+ "POST",
2307
+ "/v1/data/query",
2308
+ body={"scope": scope, "measures": measures, "agg": agg, "compute": compute, "filter": filter, "group_by": group_by, "since": since, "until": until, "limit": limit, "distributions": distributions},
2309
+ idempotency_key=idempotency_key,
2310
+ timeout=timeout,
2311
+ )
2312
+
2313
+
2314
+ class AsyncSchema(_Resource):
2315
+
2316
+ async def get(
2317
+ self,
2318
+ *,
2319
+ series: Optional[str] = None,
2320
+ tags: Optional[List[str]] = None,
2321
+ artifact: Optional[str] = None,
2322
+ compare: Optional[List[str]] = None,
2323
+ since: Optional[str] = None,
2324
+ workspace: Optional[str] = None,
2325
+ timeout: Optional[float] = None,
2326
+ ) -> Dict[str, Any]:
2327
+ """The data catalog: datasets and content collections, or a comparison.
2328
+
2329
+ The data catalog, without rows. Read (the default): `datasets` your artifacts declared,
2330
+ with fields, units, measures and `since`/`deprecated` versions, and this workspace's
2331
+ content `collections`, with fields, rules and entry counts. `compare` (alone): two to
2332
+ ten artifacts' newest fields side by side, every type, unit and measure conflict named.
2333
+ `define` creates a content collection, or replaces the one with that `key` outright,
2334
+ name, display field and every field; a field left out is gone from the model, and a
2335
+ collection an artifact declared is refused with `conflict`. Refusals name field, rule
2336
+ and fix. Rows an artifact collected are super_data.
2337
+ """
2338
+ return await self._client._call(
2339
+ "GET",
2340
+ "/v1/schema",
2341
+ query={"series": series, "tags": tags, "artifact": artifact, "compare": compare, "since": since, "workspace": workspace},
2342
+ timeout=timeout,
2343
+ )
2344
+
2345
+ async def define_collection(
2346
+ self,
2347
+ *,
2348
+ define: Optional[Dict[str, Any]] = None,
2349
+ workspace: Optional[str] = None,
2350
+ timeout: Optional[float] = None,
2351
+ ) -> Dict[str, Any]:
2352
+ """Create or replace a content collection.
2353
+
2354
+ The data catalog, without rows. Read (the default): `datasets` your artifacts declared,
2355
+ with fields, units, measures and `since`/`deprecated` versions, and this workspace's
2356
+ content `collections`, with fields, rules and entry counts. `compare` (alone): two to
2357
+ ten artifacts' newest fields side by side, every type, unit and measure conflict named.
2358
+ `define` creates a content collection, or replaces the one with that `key` outright,
2359
+ name, display field and every field; a field left out is gone from the model, and a
2360
+ collection an artifact declared is refused with `conflict`. Refusals name field, rule
2361
+ and fix. Rows an artifact collected are super_data.
2362
+ """
2363
+ return await self._client._call(
2364
+ "PUT",
2365
+ "/v1/schema",
2366
+ body={"define": define, "workspace": workspace},
2367
+ timeout=timeout,
2368
+ )
2369
+
2370
+
2371
+ class AsyncEntries(_Resource):
2372
+
2373
+ async def list(
2374
+ self,
2375
+ *,
2376
+ collection: str,
2377
+ workspace: Optional[str] = None,
2378
+ filter: Optional[List[str]] = None,
2379
+ search: Optional[str] = None,
2380
+ sort: Optional[str] = None,
2381
+ direction: Optional[Literal["asc", "desc"]] = None,
2382
+ page: Optional[int] = None,
2383
+ limit: Optional[int] = None,
2384
+ if_none_match: Optional[str] = None,
2385
+ timeout: Optional[float] = None,
2386
+ ) -> Dict[str, Any]:
2387
+ """One page of a content collection's entries.
2388
+
2389
+ Entries of a workspace content collection (a model defined in the catalog), not rows an
2390
+ artifact collected. With `values`: create one entry (an object) or up to 50 (an array,
2391
+ one outcome per row); values are coerced to declared types, undeclared fields are
2392
+ refused by name, and nothing existing is updated or deleted. Without: read one page,
2393
+ filtered and sorted in the database; references resolve to labels, sensitive fields read
2394
+ as answered-or-not. Rows visitors submitted are super_data.
2395
+ """
2396
+ return await self._client._call(
2397
+ "GET",
2398
+ "/v1/collections/{collection}/entries",
2399
+ headers={"If-None-Match": if_none_match},
2400
+ path_params={"collection": collection},
2401
+ query={"workspace": workspace, "filter": filter, "search": search, "sort": sort, "direction": direction, "page": page, "limit": limit},
2402
+ timeout=timeout,
2403
+ )
2404
+
2405
+ def iter(self, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]:
2406
+ """Every item of `list`, across pages. Takes the same arguments."""
2407
+ return awalk_pages(self.list, "entries", kwargs)
2408
+
2409
+ async def create(
2410
+ self,
2411
+ *,
2412
+ collection: str,
2413
+ values: Optional[Any] = None,
2414
+ status: Optional[Literal["draft", "published", "archived"]] = None,
2415
+ workspace: Optional[str] = None,
2416
+ idempotency_key: Optional[str] = None,
2417
+ timeout: Optional[float] = None,
2418
+ ) -> Dict[str, Any]:
2419
+ """Create one entry, or a batch.
2420
+
2421
+ Entries of a workspace content collection (a model defined in the catalog), not rows an
2422
+ artifact collected. With `values`: create one entry (an object) or up to 50 (an array,
2423
+ one outcome per row); values are coerced to declared types, undeclared fields are
2424
+ refused by name, and nothing existing is updated or deleted. Without: read one page,
2425
+ filtered and sorted in the database; references resolve to labels, sensitive fields read
2426
+ as answered-or-not. Rows visitors submitted are super_data.
2427
+ """
2428
+ return await self._client._call(
2429
+ "POST",
2430
+ "/v1/collections/{collection}/entries",
2431
+ path_params={"collection": collection},
2432
+ body={"values": values, "status": status, "workspace": workspace},
2433
+ idempotency_key=idempotency_key,
2434
+ timeout=timeout,
2435
+ )
2436
+
2437
+
2438
+ class AsyncSecrets(_Resource):
2439
+
2440
+ async def use(
2441
+ self,
2442
+ *,
2443
+ collection: str,
2444
+ entry: str,
2445
+ field: str,
2446
+ method: Literal["GET", "POST", "PUT", "PATCH", "DELETE"],
2447
+ url: str,
2448
+ headers: Optional[Dict[str, Any]] = None,
2449
+ body: Optional[str] = None,
2450
+ header: Optional[Dict[str, Any]] = None,
2451
+ idempotency_key: Optional[str] = None,
2452
+ timeout: Optional[float] = None,
2453
+ ) -> Dict[str, Any]:
2454
+ """Call an approved API with a stored secret you cannot read (workspace keys).
2455
+
2456
+ Make one HTTPS request with a `pii: secret` value from a content collection entry. The
2457
+ platform puts the value into one header and calls the one host a person approved; you
2458
+ get status, headers and body, scrubbed of it. You never see it, in input or result; a
2459
+ response echoing it is withheld whole (`secret_echoed`). A first request for a field and
2460
+ host answers `approval_required` with `approvalUrl`: give the person that link, then
2461
+ repeat the request once they approve. Grants expire, cap uses and can be revoked; every
2462
+ use is logged. The person types the secret into its dashboard entry; super_entries
2463
+ writes one only if they insist on pasting it.
2464
+ """
2465
+ return await self._client._call(
2466
+ "POST",
2467
+ "/v1/collections/{collection}/entries/{entry}/fields/{field}/use",
2468
+ path_params={"collection": collection, "entry": entry, "field": field},
2469
+ body={"method": method, "url": url, "headers": headers, "body": body, "header": header},
2470
+ idempotency_key=idempotency_key,
2471
+ timeout=timeout,
2472
+ )
2473
+
2474
+
2475
+ class AsyncTemplates(_Resource):
2476
+
2477
+ async def list(
2478
+ self,
2479
+ *,
2480
+ request: Optional[str] = None,
2481
+ scope: Optional[Literal["installed", "marketplace"]] = None,
2482
+ kind: Optional[Literal["page", "slideshow", "survey", "tracker", "video", "tool", "dashboard"]] = None,
2483
+ sort: Optional[Literal["relevance", "rating", "uses", "installs", "recent"]] = None,
2484
+ limit: Optional[int] = None,
2485
+ jobs: Optional[List[Literal["track", "collect", "present", "report", "monitor", "prove", "document", "explain", "plan", "decide", "review", "learn", "prototype", "announce", "compute", "curate", "coordinate", "play"]]] = None,
2486
+ audience: Optional[List[Literal["everyone", "engineering", "product", "design", "marketing", "sales", "ops", "people", "finance", "founders", "education", "personal", "community"]]] = None,
2487
+ needs: Optional[List[Literal["runtime", "data", "comments", "live"]]] = None,
2488
+ cost: Optional[Literal["fill", "write", "build"]] = None,
2489
+ tier: Optional[Literal["all", "official", "verified", "community"]] = None,
2490
+ mine: Optional[bool] = None,
2491
+ timeout: Optional[float] = None,
2492
+ ) -> Dict[str, Any]:
2493
+ """Find, rank or list templates.
2494
+
2495
+ With `request`: rank installed templates by content similarity; matches carry `band`
2496
+ (high: build from it; possible: judge it), `why` and unscored stats. `scope:
2497
+ marketplace`: released public templates, ranked by `request` or else the top by `sort`;
2498
+ `sort`, `limit` and the facets apply only here. Neither: the installed list. `slug`: one
2499
+ template in full, with its `installPrompt`; `history`: its changelog; `feedback`: its
2500
+ artifacts' comments as themes. `mine`: your published templates, with counts. Reading
2501
+ only: installing, rating and rolling back are super_template_action.
2502
+ """
2503
+ return await self._client._call(
2504
+ "GET",
2505
+ "/v1/templates",
2506
+ query={"request": request, "scope": scope, "kind": kind, "sort": sort, "limit": limit, "jobs": jobs, "audience": audience, "needs": needs, "cost": cost, "tier": tier, "mine": mine},
2507
+ timeout=timeout,
2508
+ )
2509
+
2510
+ async def save(
2511
+ self,
2512
+ *,
2513
+ slug: str,
2514
+ title: str,
2515
+ description: str,
2516
+ spec: Dict[str, Any],
2517
+ kind: Optional[Literal["page", "slideshow", "survey", "tracker", "video", "tool", "dashboard"]] = None,
2518
+ jobs: Optional[List[Literal["track", "collect", "present", "report", "monitor", "prove", "document", "explain", "plan", "decide", "review", "learn", "prototype", "announce", "compute", "curate", "coordinate", "play"]]] = None,
2519
+ audience: Optional[List[Literal["everyone", "engineering", "product", "design", "marketing", "sales", "ops", "people", "finance", "founders", "education", "personal", "community"]]] = None,
2520
+ use_cases: Optional[List[Dict[str, Any]]] = None,
2521
+ install_archetype: Optional[Literal["scenarios", "explainer", "interview"]] = None,
2522
+ install_after: Optional[str] = None,
2523
+ sample_public: Optional[bool] = None,
2524
+ category: Optional[Literal["trackers", "surveys", "presentations", "dashboards", "documents", "tools", "games", "other"]] = None,
2525
+ guidance: Optional[str] = None,
2526
+ prompt: Optional[str] = None,
2527
+ sample: Optional[Dict[str, Any]] = None,
2528
+ demo: Optional[str] = None,
2529
+ files: Optional[List[Dict[str, Any]]] = None,
2530
+ companions: Optional[List[Dict[str, Any]]] = None,
2531
+ expected_version: Optional[int] = None,
2532
+ change_note: Optional[str] = None,
2533
+ idempotency_key: Optional[str] = None,
2534
+ timeout: Optional[float] = None,
2535
+ ) -> Dict[str, Any]:
2536
+ """Create or revise a template draft.
2537
+
2538
+ Write a template draft only you can publish from. Without `expectedVersion` it creates
2539
+ (refused if the slug exists); with it, it revises the head (refused if the head moved
2540
+ past it), and a revision that changes nothing cuts no version. A `json` slot needs
2541
+ `schema`. Runtime `files` (≤512 KiB decoded) need a `json` slot and an index.html with
2542
+ one `<script id="sa-template-values" type="application/json">`. Others build from it
2543
+ only once super_release_template releases it; a revision never changes a released
2544
+ version.
2545
+ """
2546
+ return await self._client._call(
2547
+ "POST",
2548
+ "/v1/templates",
2549
+ body={"slug": slug, "title": title, "description": description, "kind": kind, "jobs": jobs, "audience": audience, "useCases": use_cases, "installArchetype": install_archetype, "installAfter": install_after, "samplePublic": sample_public, "category": category, "spec": spec, "guidance": guidance, "prompt": prompt, "sample": sample, "demo": demo, "files": files, "companions": companions, "expectedVersion": expected_version, "changeNote": change_note},
2550
+ idempotency_key=idempotency_key,
2551
+ timeout=timeout,
2552
+ )
2553
+
2554
+ async def get(
2555
+ self,
2556
+ *,
2557
+ slug: str,
2558
+ version: Optional[int] = None,
2559
+ timeout: Optional[float] = None,
2560
+ ) -> Dict[str, Any]:
2561
+ """One template in full, with its install prompt.
2562
+
2563
+ With `request`: rank installed templates by content similarity; matches carry `band`
2564
+ (high: build from it; possible: judge it), `why` and unscored stats. `scope:
2565
+ marketplace`: released public templates, ranked by `request` or else the top by `sort`;
2566
+ `sort`, `limit` and the facets apply only here. Neither: the installed list. `slug`: one
2567
+ template in full, with its `installPrompt`; `history`: its changelog; `feedback`: its
2568
+ artifacts' comments as themes. `mine`: your published templates, with counts. Reading
2569
+ only: installing, rating and rolling back are super_template_action.
2570
+ """
2571
+ return await self._client._call(
2572
+ "GET",
2573
+ "/v1/templates/{slug}",
2574
+ path_params={"slug": slug},
2575
+ query={"version": version},
2576
+ timeout=timeout,
2577
+ )
2578
+
2579
+ async def get_history(
2580
+ self,
2581
+ *,
2582
+ slug: str,
2583
+ timeout: Optional[float] = None,
2584
+ ) -> Dict[str, Any]:
2585
+ """A template's changelog.
2586
+
2587
+ With `request`: rank installed templates by content similarity; matches carry `band`
2588
+ (high: build from it; possible: judge it), `why` and unscored stats. `scope:
2589
+ marketplace`: released public templates, ranked by `request` or else the top by `sort`;
2590
+ `sort`, `limit` and the facets apply only here. Neither: the installed list. `slug`: one
2591
+ template in full, with its `installPrompt`; `history`: its changelog; `feedback`: its
2592
+ artifacts' comments as themes. `mine`: your published templates, with counts. Reading
2593
+ only: installing, rating and rolling back are super_template_action.
2594
+ """
2595
+ return await self._client._call(
2596
+ "GET",
2597
+ "/v1/templates/{slug}/history",
2598
+ path_params={"slug": slug},
2599
+ timeout=timeout,
2600
+ )
2601
+
2602
+ async def get_feedback(
2603
+ self,
2604
+ *,
2605
+ slug: str,
2606
+ timeout: Optional[float] = None,
2607
+ ) -> Dict[str, Any]:
2608
+ """Comments on a template's artifacts, as themes.
2609
+
2610
+ With `request`: rank installed templates by content similarity; matches carry `band`
2611
+ (high: build from it; possible: judge it), `why` and unscored stats. `scope:
2612
+ marketplace`: released public templates, ranked by `request` or else the top by `sort`;
2613
+ `sort`, `limit` and the facets apply only here. Neither: the installed list. `slug`: one
2614
+ template in full, with its `installPrompt`; `history`: its changelog; `feedback`: its
2615
+ artifacts' comments as themes. `mine`: your published templates, with counts. Reading
2616
+ only: installing, rating and rolling back are super_template_action.
2617
+ """
2618
+ return await self._client._call(
2619
+ "GET",
2620
+ "/v1/templates/{slug}/feedback",
2621
+ path_params={"slug": slug},
2622
+ timeout=timeout,
2623
+ )
2624
+
2625
+ async def act(
2626
+ self,
2627
+ *,
2628
+ slug: str,
2629
+ action: Literal["install", "uninstall", "rate", "report", "rollback", "request_verification"],
2630
+ stars: Optional[int] = None,
2631
+ version: Optional[int] = None,
2632
+ kind: Optional[Literal["spam", "harmful", "broken", "misleading", "pii", "copyright", "other"]] = None,
2633
+ reason: Optional[str] = None,
2634
+ confirmed_by_person: Optional[bool] = None,
2635
+ idempotency_key: Optional[str] = None,
2636
+ timeout: Optional[float] = None,
2637
+ ) -> Dict[str, Any]:
2638
+ """Install, uninstall, rate, report, roll back or request verification.
2639
+
2640
+ Act on one template; nothing here deletes a template, a version or a built artifact.
2641
+ `install`/`uninstall`: this workspace's installed set (uninstall removes only the
2642
+ install; built artifacts keep working); `install` returns its build prompt as
2643
+ `nextStep`. `rate`: the person's 1–5 `stars` on an installed template not yours
2644
+ (`cannot_rate_own`, `not_installed`, `rate_limited`); counts once this workspace built
2645
+ from it. `report`: `kind` and a `reason` (≤1000 chars) for a moderator; one per account;
2646
+ enough reports hide it. `rollback`: restore `version` as a new version, unless the
2647
+ runtime changed. `request_verification`: a moderator checks your released `version`; 3
2648
+ per 30 days. Finding and reading templates is super_templates.
2649
+ """
2650
+ return await self._client._call(
2651
+ "POST",
2652
+ "/v1/templates/{slug}/actions",
2653
+ path_params={"slug": slug},
2654
+ body={"action": action, "stars": stars, "version": version, "kind": kind, "reason": reason, "confirmedByPerson": confirmed_by_person},
2655
+ idempotency_key=idempotency_key,
2656
+ timeout=timeout,
2657
+ )
2658
+
2659
+ async def release(
2660
+ self,
2661
+ *,
2662
+ slug: str,
2663
+ version: int,
2664
+ visibility: Optional[Literal["public", "unlisted", "workspace"]] = None,
2665
+ demo_consent: Optional[bool] = None,
2666
+ sample_consent: Optional[bool] = None,
2667
+ idempotency_key: Optional[str] = None,
2668
+ timeout: Optional[float] = None,
2669
+ ) -> Dict[str, Any]:
2670
+ """Release one version of your template.
2671
+
2672
+ Release one version of your template so others can build from it, live at once to the
2673
+ reach `visibility` sets; the result names its trust `tier` (Official, Verified or
2674
+ Community). Forward only (`release_moves_backwards`): earlier versions stay, and nothing
2675
+ is deleted. A private demo needs `demoConsent: true`. A runtime, prompt, parts or data
2676
+ change leaves a Verified badge behind. Public: account 7 days old (`publisher_too_new`),
2677
+ 10/day, 3/template/hour (`rate_limited`), 20 templates (`too_many_templates`), no tier
2678
+ words (`reserved_wording`), no credential (`secret_in_template`), paid plan
2679
+ (`plan_required`). Writing the draft is super_template_save.
2680
+ """
2681
+ return await self._client._call(
2682
+ "POST",
2683
+ "/v1/templates/{slug}/release",
2684
+ path_params={"slug": slug},
2685
+ body={"version": version, "visibility": visibility, "demoConsent": demo_consent, "sampleConsent": sample_consent},
2686
+ idempotency_key=idempotency_key,
2687
+ timeout=timeout,
2688
+ )
2689
+
2690
+
2691
+ class AsyncProjects(_Resource):
2692
+
2693
+ async def list(
2694
+ self,
2695
+ *,
2696
+ workspace: Optional[str] = None,
2697
+ timeout: Optional[float] = None,
2698
+ ) -> Dict[str, Any]:
2699
+ """Your projects.
2700
+
2701
+ A project is an ordered set of your artifacts shown one at a time at /s/{slug}, with its
2702
+ own audience and share list. No `project`: `title` creates one (seeded from
2703
+ `artifacts`), else list yours. With `project`: add `artifacts`, `remove` one, `title`
2704
+ renames, set `visibility`, `order`/`move` reorder, a `rule` adds matches as they are
2705
+ published, or read it. `delete` with `confirm: true` removes the project, its order and
2706
+ its share list permanently; its artifacts stay. One change per call, or title with
2707
+ visibility. An artifact's gallery label is not a project: that is `collection` on
2708
+ super_artifact_set.
2709
+ """
2710
+ return await self._client._call(
2711
+ "GET",
2712
+ "/v1/projects",
2713
+ query={"workspace": workspace},
2714
+ timeout=timeout,
2715
+ )
2716
+
2717
+ async def create(
2718
+ self,
2719
+ *,
2720
+ title: Optional[str] = None,
2721
+ artifacts: Optional[List[str]] = None,
2722
+ group_label: Optional[str] = None,
2723
+ visibility: Optional[Literal["private", "organization", "public"]] = None,
2724
+ rule: Any = OMIT,
2725
+ confirm: Optional[bool] = None,
2726
+ workspace: Optional[str] = None,
2727
+ idempotency_key: Optional[str] = None,
2728
+ timeout: Optional[float] = None,
2729
+ ) -> Dict[str, Any]:
2730
+ """Create a project, optionally seeded with artifacts.
2731
+
2732
+ A project is an ordered set of your artifacts shown one at a time at /s/{slug}, with its
2733
+ own audience and share list. No `project`: `title` creates one (seeded from
2734
+ `artifacts`), else list yours. With `project`: add `artifacts`, `remove` one, `title`
2735
+ renames, set `visibility`, `order`/`move` reorder, a `rule` adds matches as they are
2736
+ published, or read it. `delete` with `confirm: true` removes the project, its order and
2737
+ its share list permanently; its artifacts stay. One change per call, or title with
2738
+ visibility. An artifact's gallery label is not a project: that is `collection` on
2739
+ super_artifact_set.
2740
+ """
2741
+ return await self._client._call(
2742
+ "POST",
2743
+ "/v1/projects",
2744
+ body={"title": title, "artifacts": artifacts, "groupLabel": group_label, "visibility": visibility, "confirm": confirm, "workspace": workspace},
2745
+ nullable={"rule": rule},
2746
+ idempotency_key=idempotency_key,
2747
+ timeout=timeout,
2748
+ )
2749
+
2750
+ async def get(
2751
+ self,
2752
+ *,
2753
+ project: str,
2754
+ workspace: Optional[str] = None,
2755
+ timeout: Optional[float] = None,
2756
+ ) -> Dict[str, Any]:
2757
+ """One project and its items.
2758
+
2759
+ A project is an ordered set of your artifacts shown one at a time at /s/{slug}, with its
2760
+ own audience and share list. No `project`: `title` creates one (seeded from
2761
+ `artifacts`), else list yours. With `project`: add `artifacts`, `remove` one, `title`
2762
+ renames, set `visibility`, `order`/`move` reorder, a `rule` adds matches as they are
2763
+ published, or read it. `delete` with `confirm: true` removes the project, its order and
2764
+ its share list permanently; its artifacts stay. One change per call, or title with
2765
+ visibility. An artifact's gallery label is not a project: that is `collection` on
2766
+ super_artifact_set.
2767
+ """
2768
+ return await self._client._call(
2769
+ "GET",
2770
+ "/v1/projects/{project}",
2771
+ path_params={"project": project},
2772
+ query={"workspace": workspace},
2773
+ timeout=timeout,
2774
+ )
2775
+
2776
+ async def update(
2777
+ self,
2778
+ *,
2779
+ project: str,
2780
+ title: Optional[str] = None,
2781
+ visibility: Optional[Literal["private", "organization", "public"]] = None,
2782
+ order: Optional[List[str]] = None,
2783
+ move: Optional[Dict[str, Any]] = None,
2784
+ rule: Any = OMIT,
2785
+ collapsed_groups: Optional[List[str]] = None,
2786
+ confirm: Optional[bool] = None,
2787
+ workspace: Optional[str] = None,
2788
+ timeout: Optional[float] = None,
2789
+ ) -> Dict[str, Any]:
2790
+ """Rename, set visibility, reorder, move, fold groups or set a rule.
2791
+
2792
+ A project is an ordered set of your artifacts shown one at a time at /s/{slug}, with its
2793
+ own audience and share list. No `project`: `title` creates one (seeded from
2794
+ `artifacts`), else list yours. With `project`: add `artifacts`, `remove` one, `title`
2795
+ renames, set `visibility`, `order`/`move` reorder, a `rule` adds matches as they are
2796
+ published, or read it. `delete` with `confirm: true` removes the project, its order and
2797
+ its share list permanently; its artifacts stay. One change per call, or title with
2798
+ visibility. An artifact's gallery label is not a project: that is `collection` on
2799
+ super_artifact_set.
2800
+ """
2801
+ return await self._client._call(
2802
+ "PATCH",
2803
+ "/v1/projects/{project}",
2804
+ path_params={"project": project},
2805
+ body={"title": title, "visibility": visibility, "order": order, "move": move, "collapsedGroups": collapsed_groups, "confirm": confirm, "workspace": workspace},
2806
+ nullable={"rule": rule},
2807
+ timeout=timeout,
2808
+ )
2809
+
2810
+ async def delete(
2811
+ self,
2812
+ *,
2813
+ project: str,
2814
+ timeout: Optional[float] = None,
2815
+ ) -> Dict[str, Any]:
2816
+ """Delete a project; its artifacts stay.
2817
+
2818
+ A project is an ordered set of your artifacts shown one at a time at /s/{slug}, with its
2819
+ own audience and share list. No `project`: `title` creates one (seeded from
2820
+ `artifacts`), else list yours. With `project`: add `artifacts`, `remove` one, `title`
2821
+ renames, set `visibility`, `order`/`move` reorder, a `rule` adds matches as they are
2822
+ published, or read it. `delete` with `confirm: true` removes the project, its order and
2823
+ its share list permanently; its artifacts stay. One change per call, or title with
2824
+ visibility. An artifact's gallery label is not a project: that is `collection` on
2825
+ super_artifact_set.
2826
+ """
2827
+ return await self._client._call(
2828
+ "DELETE",
2829
+ "/v1/projects/{project}",
2830
+ path_params={"project": project},
2831
+ query={"confirm": project},
2832
+ timeout=timeout,
2833
+ )
2834
+
2835
+ async def add_artifacts(
2836
+ self,
2837
+ *,
2838
+ project: str,
2839
+ artifacts: Optional[List[str]] = None,
2840
+ group_label: Optional[str] = None,
2841
+ confirm: Optional[bool] = None,
2842
+ workspace: Optional[str] = None,
2843
+ idempotency_key: Optional[str] = None,
2844
+ timeout: Optional[float] = None,
2845
+ ) -> Dict[str, Any]:
2846
+ """Add artifacts to a project.
2847
+
2848
+ A project is an ordered set of your artifacts shown one at a time at /s/{slug}, with its
2849
+ own audience and share list. No `project`: `title` creates one (seeded from
2850
+ `artifacts`), else list yours. With `project`: add `artifacts`, `remove` one, `title`
2851
+ renames, set `visibility`, `order`/`move` reorder, a `rule` adds matches as they are
2852
+ published, or read it. `delete` with `confirm: true` removes the project, its order and
2853
+ its share list permanently; its artifacts stay. One change per call, or title with
2854
+ visibility. An artifact's gallery label is not a project: that is `collection` on
2855
+ super_artifact_set.
2856
+ """
2857
+ return await self._client._call(
2858
+ "POST",
2859
+ "/v1/projects/{project}/artifacts",
2860
+ path_params={"project": project},
2861
+ body={"artifacts": artifacts, "groupLabel": group_label, "confirm": confirm, "workspace": workspace},
2862
+ idempotency_key=idempotency_key,
2863
+ timeout=timeout,
2864
+ )
2865
+
2866
+ async def remove_artifact(
2867
+ self,
2868
+ *,
2869
+ project: str,
2870
+ remove: str,
2871
+ timeout: Optional[float] = None,
2872
+ ) -> Dict[str, Any]:
2873
+ """Remove one artifact (or item) from a project.
2874
+
2875
+ A project is an ordered set of your artifacts shown one at a time at /s/{slug}, with its
2876
+ own audience and share list. No `project`: `title` creates one (seeded from
2877
+ `artifacts`), else list yours. With `project`: add `artifacts`, `remove` one, `title`
2878
+ renames, set `visibility`, `order`/`move` reorder, a `rule` adds matches as they are
2879
+ published, or read it. `delete` with `confirm: true` removes the project, its order and
2880
+ its share list permanently; its artifacts stay. One change per call, or title with
2881
+ visibility. An artifact's gallery label is not a project: that is `collection` on
2882
+ super_artifact_set.
2883
+ """
2884
+ return await self._client._call(
2885
+ "DELETE",
2886
+ "/v1/projects/{project}/artifacts/{remove}",
2887
+ path_params={"project": project, "remove": remove},
2888
+ timeout=timeout,
2889
+ )
2890
+
2891
+
2892
+ class AsyncShares(_Resource):
2893
+
2894
+ async def add_to_artifact(
2895
+ self,
2896
+ *,
2897
+ artifact: str,
2898
+ emails: List[str],
2899
+ role: Optional[Literal["viewer", "commenter", "editor"]] = None,
2900
+ artifact_only: Optional[bool] = None,
2901
+ idempotency_key: Optional[str] = None,
2902
+ timeout: Optional[float] = None,
2903
+ ) -> Dict[str, Any]:
2904
+ """Give named people access to an artifact.
2905
+
2906
+ Give access: `artifact` (viewer; commenter comments; editor edits; new addresses
2907
+ emailed), `project` (viewer; emails each address); `workspace` (editor; accept links, no
2908
+ email). Named people move to the sent role, including downgrades; nobody is removed.
2909
+ Never changes visibility: public stays public; restrict with super_artifact_set. At most
2910
+ 20 addresses for an artifact, 50 for a project or workspace.
2911
+ """
2912
+ return await self._client._call(
2913
+ "POST",
2914
+ "/v1/artifacts/{artifact}/shares",
2915
+ path_params={"artifact": artifact},
2916
+ body={"emails": emails, "role": role, "artifactOnly": artifact_only},
2917
+ idempotency_key=idempotency_key,
2918
+ timeout=timeout,
2919
+ )
2920
+
2921
+ async def add_to_project(
2922
+ self,
2923
+ *,
2924
+ project: str,
2925
+ emails: List[str],
2926
+ role: Optional[Literal["viewer", "commenter", "editor"]] = None,
2927
+ confirm: Optional[bool] = None,
2928
+ idempotency_key: Optional[str] = None,
2929
+ timeout: Optional[float] = None,
2930
+ ) -> Dict[str, Any]:
2931
+ """Give named people access to a project.
2932
+
2933
+ Give access: `artifact` (viewer; commenter comments; editor edits; new addresses
2934
+ emailed), `project` (viewer; emails each address); `workspace` (editor; accept links, no
2935
+ email). Named people move to the sent role, including downgrades; nobody is removed.
2936
+ Never changes visibility: public stays public; restrict with super_artifact_set. At most
2937
+ 20 addresses for an artifact, 50 for a project or workspace.
2938
+ """
2939
+ return await self._client._call(
2940
+ "POST",
2941
+ "/v1/projects/{project}/shares",
2942
+ path_params={"project": project},
2943
+ body={"emails": emails, "role": role, "confirm": confirm},
2944
+ idempotency_key=idempotency_key,
2945
+ timeout=timeout,
2946
+ )
2947
+
2948
+ async def add_to_workspace(
2949
+ self,
2950
+ *,
2951
+ emails: List[str],
2952
+ role: Optional[Literal["viewer", "commenter", "editor"]] = None,
2953
+ workspace: Optional[str] = None,
2954
+ idempotency_key: Optional[str] = None,
2955
+ timeout: Optional[float] = None,
2956
+ ) -> Dict[str, Any]:
2957
+ """Invite editors to a workspace (returns accept links).
2958
+
2959
+ Give access: `artifact` (viewer; commenter comments; editor edits; new addresses
2960
+ emailed), `project` (viewer; emails each address); `workspace` (editor; accept links, no
2961
+ email). Named people move to the sent role, including downgrades; nobody is removed.
2962
+ Never changes visibility: public stays public; restrict with super_artifact_set. At most
2963
+ 20 addresses for an artifact, 50 for a project or workspace.
2964
+ """
2965
+ return await self._client._call(
2966
+ "POST",
2967
+ "/v1/workspace/shares",
2968
+ body={"emails": emails, "role": role, "workspace": workspace},
2969
+ idempotency_key=idempotency_key,
2970
+ timeout=timeout,
2971
+ )
2972
+
2973
+
2974
+ class AsyncComments(_Resource):
2975
+
2976
+ async def list(
2977
+ self,
2978
+ *,
2979
+ artifact: str,
2980
+ status: Optional[Literal["all", "open", "resolved"]] = None,
2981
+ page: Optional[str] = None,
2982
+ limit: Optional[int] = None,
2983
+ cursor: Optional[str] = None,
2984
+ timeout: Optional[float] = None,
2985
+ ) -> Dict[str, Any]:
2986
+ """Comment threads on an artifact, newest first.
2987
+
2988
+ Threads: messages, anchor, viewed version (default `status: "open"`); status all
2989
+ includes resolved history. Publish the fix first, then respond with body explaining what
2990
+ changed and which version, plus resolve: true atomically. Reuse messageId on retry.
2991
+ Reports replied/resolved separately. resolve: false reopens. `screenshot` returns an
2992
+ image. Agents cannot open/delete threads. mentioned: true lists your @mentions, oldest
2993
+ unseen first, marking them seen.
2994
+ """
2995
+ return await self._client._call(
2996
+ "GET",
2997
+ "/v1/artifacts/{artifact}/comments",
2998
+ path_params={"artifact": artifact},
2999
+ query={"status": status, "page": page, "limit": limit, "cursor": cursor},
3000
+ timeout=timeout,
3001
+ )
3002
+
3003
+ async def respond(
3004
+ self,
3005
+ *,
3006
+ artifact: str,
3007
+ respond: Optional[List[Dict[str, Any]]] = None,
3008
+ idempotency_key: Optional[str] = None,
3009
+ timeout: Optional[float] = None,
3010
+ ) -> Dict[str, Any]:
3011
+ """Reply to and/or resolve threads, one outcome each.
3012
+
3013
+ Threads: messages, anchor, viewed version (default `status: "open"`); status all
3014
+ includes resolved history. Publish the fix first, then respond with body explaining what
3015
+ changed and which version, plus resolve: true atomically. Reuse messageId on retry.
3016
+ Reports replied/resolved separately. resolve: false reopens. `screenshot` returns an
3017
+ image. Agents cannot open/delete threads. mentioned: true lists your @mentions, oldest
3018
+ unseen first, marking them seen.
3019
+ """
3020
+ return await self._client._call(
3021
+ "POST",
3022
+ "/v1/artifacts/{artifact}/comments/responses",
3023
+ path_params={"artifact": artifact},
3024
+ body={"respond": respond},
3025
+ idempotency_key=idempotency_key,
3026
+ timeout=timeout,
3027
+ )
3028
+
3029
+ async def react(
3030
+ self,
3031
+ *,
3032
+ artifact: str,
3033
+ react: Optional[List[Dict[str, Any]]] = None,
3034
+ idempotency_key: Optional[str] = None,
3035
+ timeout: Optional[float] = None,
3036
+ ) -> Dict[str, Any]:
3037
+ """Toggle reactions on comment messages.
3038
+
3039
+ Threads: messages, anchor, viewed version (default `status: "open"`); status all
3040
+ includes resolved history. Publish the fix first, then respond with body explaining what
3041
+ changed and which version, plus resolve: true atomically. Reuse messageId on retry.
3042
+ Reports replied/resolved separately. resolve: false reopens. `screenshot` returns an
3043
+ image. Agents cannot open/delete threads. mentioned: true lists your @mentions, oldest
3044
+ unseen first, marking them seen.
3045
+ """
3046
+ return await self._client._call(
3047
+ "POST",
3048
+ "/v1/artifacts/{artifact}/comments/reactions",
3049
+ path_params={"artifact": artifact},
3050
+ body={"react": react},
3051
+ idempotency_key=idempotency_key,
3052
+ timeout=timeout,
3053
+ )
3054
+
3055
+ async def resolve(
3056
+ self,
3057
+ *,
3058
+ artifact: str,
3059
+ resolve: Optional[List[str]] = None,
3060
+ idempotency_key: Optional[str] = None,
3061
+ timeout: Optional[float] = None,
3062
+ ) -> Dict[str, Any]:
3063
+ """Resolve mentioned comment threads.
3064
+
3065
+ Threads: messages, anchor, viewed version (default `status: "open"`); status all
3066
+ includes resolved history. Publish the fix first, then respond with body explaining what
3067
+ changed and which version, plus resolve: true atomically. Reuse messageId on retry.
3068
+ Reports replied/resolved separately. resolve: false reopens. `screenshot` returns an
3069
+ image. Agents cannot open/delete threads. mentioned: true lists your @mentions, oldest
3070
+ unseen first, marking them seen.
3071
+ """
3072
+ return await self._client._call(
3073
+ "POST",
3074
+ "/v1/artifacts/{artifact}/comments/resolutions",
3075
+ path_params={"artifact": artifact},
3076
+ body={"resolve": resolve},
3077
+ idempotency_key=idempotency_key,
3078
+ timeout=timeout,
3079
+ )
3080
+
3081
+ async def get_screenshot(
3082
+ self,
3083
+ *,
3084
+ artifact: str,
3085
+ screenshot: str,
3086
+ timeout: Optional[float] = None,
3087
+ ) -> Dict[str, Any]:
3088
+ """One message's screenshot, base64 in `image`.
3089
+
3090
+ Threads: messages, anchor, viewed version (default `status: "open"`); status all
3091
+ includes resolved history. Publish the fix first, then respond with body explaining what
3092
+ changed and which version, plus resolve: true atomically. Reuse messageId on retry.
3093
+ Reports replied/resolved separately. resolve: false reopens. `screenshot` returns an
3094
+ image. Agents cannot open/delete threads. mentioned: true lists your @mentions, oldest
3095
+ unseen first, marking them seen.
3096
+ """
3097
+ return await self._client._call(
3098
+ "GET",
3099
+ "/v1/artifacts/{artifact}/comments/screenshots/{screenshot}",
3100
+ path_params={"artifact": artifact, "screenshot": screenshot},
3101
+ timeout=timeout,
3102
+ )
3103
+
3104
+
3105
+ class AsyncMentions(_Resource):
3106
+
3107
+ async def list(
3108
+ self,
3109
+ *,
3110
+ artifact: Optional[str] = None,
3111
+ limit: Optional[int] = None,
3112
+ cursor: Optional[str] = None,
3113
+ timeout: Optional[float] = None,
3114
+ ) -> Dict[str, Any]:
3115
+ """Where people @mentioned you; listing marks them seen.
3116
+
3117
+ Threads: messages, anchor, viewed version (default `status: "open"`); status all
3118
+ includes resolved history. Publish the fix first, then respond with body explaining what
3119
+ changed and which version, plus resolve: true atomically. Reuse messageId on retry.
3120
+ Reports replied/resolved separately. resolve: false reopens. `screenshot` returns an
3121
+ image. Agents cannot open/delete threads. mentioned: true lists your @mentions, oldest
3122
+ unseen first, marking them seen.
3123
+ """
3124
+ return await self._client._call(
3125
+ "GET",
3126
+ "/v1/mentions",
3127
+ query={"artifact": artifact, "limit": limit, "cursor": cursor},
3128
+ timeout=timeout,
3129
+ )
3130
+
3131
+ def iter(self, **kwargs: Any) -> AsyncIterator[Dict[str, Any]]:
3132
+ """Every item of `list`, across pages. Takes the same arguments."""
3133
+ return awalk_cursor(self.list, "mentions", kwargs)
3134
+
3135
+
3136
+ class AsyncSignatures(_Resource):
3137
+
3138
+ async def list(
3139
+ self,
3140
+ *,
3141
+ artifact: Optional[str] = None,
3142
+ timeout: Optional[float] = None,
3143
+ ) -> Dict[str, Any]:
3144
+ """An artifact's signature requests, newest first.
3145
+
3146
+ Ask named people to sign one published version of an artifact, and follow the request.
3147
+ `request` with `artifact`, `signers` [{name, email, party?}] (≤10) and an optional
3148
+ `message` (≤500 characters) emails each signer a private link; the version must be one
3149
+ file of at most 2 MiB, and it is kept while the request is open and for good once it
3150
+ completes. `status` with `request` (one) or `artifact` (all, newest first). `withdraw`
3151
+ closes an open request. `remind` emails `signer` the link again, three times at most, a
3152
+ day apart. Only each signer can sign, in a browser, after a code sent to their address:
3153
+ an agent cannot.
3154
+ """
3155
+ return await self._client._call(
3156
+ "GET",
3157
+ "/v1/signatures",
3158
+ query={"artifact": artifact},
3159
+ timeout=timeout,
3160
+ )
3161
+
3162
+ async def request(
3163
+ self,
3164
+ *,
3165
+ artifact: Optional[str] = None,
3166
+ version: Optional[int] = None,
3167
+ signers: Optional[List[Dict[str, Any]]] = None,
3168
+ message: Optional[str] = None,
3169
+ idempotency_key: Optional[str] = None,
3170
+ timeout: Optional[float] = None,
3171
+ ) -> Dict[str, Any]:
3172
+ """Ask named people to sign one version of an artifact.
3173
+
3174
+ Ask named people to sign one published version of an artifact, and follow the request.
3175
+ `request` with `artifact`, `signers` [{name, email, party?}] (≤10) and an optional
3176
+ `message` (≤500 characters) emails each signer a private link; the version must be one
3177
+ file of at most 2 MiB, and it is kept while the request is open and for good once it
3178
+ completes. `status` with `request` (one) or `artifact` (all, newest first). `withdraw`
3179
+ closes an open request. `remind` emails `signer` the link again, three times at most, a
3180
+ day apart. Only each signer can sign, in a browser, after a code sent to their address:
3181
+ an agent cannot.
3182
+ """
3183
+ return await self._client._call(
3184
+ "POST",
3185
+ "/v1/signatures",
3186
+ body={"artifact": artifact, "version": version, "signers": signers, "message": message},
3187
+ idempotency_key=idempotency_key,
3188
+ timeout=timeout,
3189
+ )
3190
+
3191
+ async def get(
3192
+ self,
3193
+ *,
3194
+ request: str,
3195
+ timeout: Optional[float] = None,
3196
+ ) -> Dict[str, Any]:
3197
+ """One signature request and its signers.
3198
+
3199
+ Ask named people to sign one published version of an artifact, and follow the request.
3200
+ `request` with `artifact`, `signers` [{name, email, party?}] (≤10) and an optional
3201
+ `message` (≤500 characters) emails each signer a private link; the version must be one
3202
+ file of at most 2 MiB, and it is kept while the request is open and for good once it
3203
+ completes. `status` with `request` (one) or `artifact` (all, newest first). `withdraw`
3204
+ closes an open request. `remind` emails `signer` the link again, three times at most, a
3205
+ day apart. Only each signer can sign, in a browser, after a code sent to their address:
3206
+ an agent cannot.
3207
+ """
3208
+ return await self._client._call(
3209
+ "GET",
3210
+ "/v1/signatures/{request}",
3211
+ path_params={"request": request},
3212
+ timeout=timeout,
3213
+ )
3214
+
3215
+ async def remind(
3216
+ self,
3217
+ *,
3218
+ request: str,
3219
+ signer: Optional[str] = None,
3220
+ idempotency_key: Optional[str] = None,
3221
+ timeout: Optional[float] = None,
3222
+ ) -> Dict[str, Any]:
3223
+ """Email a signer their link again.
3224
+
3225
+ Ask named people to sign one published version of an artifact, and follow the request.
3226
+ `request` with `artifact`, `signers` [{name, email, party?}] (≤10) and an optional
3227
+ `message` (≤500 characters) emails each signer a private link; the version must be one
3228
+ file of at most 2 MiB, and it is kept while the request is open and for good once it
3229
+ completes. `status` with `request` (one) or `artifact` (all, newest first). `withdraw`
3230
+ closes an open request. `remind` emails `signer` the link again, three times at most, a
3231
+ day apart. Only each signer can sign, in a browser, after a code sent to their address:
3232
+ an agent cannot.
3233
+ """
3234
+ return await self._client._call(
3235
+ "POST",
3236
+ "/v1/signatures/{request}/remind",
3237
+ path_params={"request": request},
3238
+ body={"signer": signer},
3239
+ idempotency_key=idempotency_key,
3240
+ timeout=timeout,
3241
+ )
3242
+
3243
+ async def withdraw(
3244
+ self,
3245
+ *,
3246
+ request: str,
3247
+ idempotency_key: Optional[str] = None,
3248
+ timeout: Optional[float] = None,
3249
+ ) -> Dict[str, Any]:
3250
+ """Close an open signature request.
3251
+
3252
+ Ask named people to sign one published version of an artifact, and follow the request.
3253
+ `request` with `artifact`, `signers` [{name, email, party?}] (≤10) and an optional
3254
+ `message` (≤500 characters) emails each signer a private link; the version must be one
3255
+ file of at most 2 MiB, and it is kept while the request is open and for good once it
3256
+ completes. `status` with `request` (one) or `artifact` (all, newest first). `withdraw`
3257
+ closes an open request. `remind` emails `signer` the link again, three times at most, a
3258
+ day apart. Only each signer can sign, in a browser, after a code sent to their address:
3259
+ an agent cannot.
3260
+ """
3261
+ return await self._client._call(
3262
+ "POST",
3263
+ "/v1/signatures/{request}/withdraw",
3264
+ path_params={"request": request},
3265
+ idempotency_key=idempotency_key,
3266
+ timeout=timeout,
3267
+ )
3268
+
3269
+
3270
+ class AsyncResources:
3271
+ def __init__(self) -> None:
3272
+ self.account = AsyncAccount(self)
3273
+ self.webhooks = AsyncWebhooks(self)
3274
+ self.artifacts = AsyncArtifacts(self)
3275
+ self.live = AsyncLive(self)
3276
+ self.uploads = AsyncUploads(self)
3277
+ self.data = AsyncData(self)
3278
+ self.schema = AsyncSchema(self)
3279
+ self.entries = AsyncEntries(self)
3280
+ self.secrets = AsyncSecrets(self)
3281
+ self.templates = AsyncTemplates(self)
3282
+ self.projects = AsyncProjects(self)
3283
+ self.shares = AsyncShares(self)
3284
+ self.comments = AsyncComments(self)
3285
+ self.mentions = AsyncMentions(self)
3286
+ self.signatures = AsyncSignatures(self)