hotcodepush 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.
Files changed (62) hide show
  1. hotcodepush/__init__.py +183 -0
  2. hotcodepush/_http.py +314 -0
  3. hotcodepush/_types.py +15 -0
  4. hotcodepush/_upload.py +51 -0
  5. hotcodepush/_version.py +1 -0
  6. hotcodepush/client.py +81 -0
  7. hotcodepush/exceptions.py +45 -0
  8. hotcodepush/models.py +899 -0
  9. hotcodepush/py.typed +0 -0
  10. hotcodepush/resources/__init__.py +0 -0
  11. hotcodepush/resources/_base.py +10 -0
  12. hotcodepush/resources/apps.py +78 -0
  13. hotcodepush/resources/audit_logs.py +112 -0
  14. hotcodepush/resources/binaries.py +84 -0
  15. hotcodepush/resources/bundle_deltas.py +41 -0
  16. hotcodepush/resources/bundle_files.py +44 -0
  17. hotcodepush/resources/bundle_pack.py +54 -0
  18. hotcodepush/resources/bundle_pack_upload_parts.py +36 -0
  19. hotcodepush/resources/bundle_pack_uploads.py +65 -0
  20. hotcodepush/resources/bundles.py +147 -0
  21. hotcodepush/resources/channel_audience.py +43 -0
  22. hotcodepush/resources/channel_qr.py +27 -0
  23. hotcodepush/resources/channel_releases.py +119 -0
  24. hotcodepush/resources/channels.py +169 -0
  25. hotcodepush/resources/checkouts.py +26 -0
  26. hotcodepush/resources/customer_portal_sessions.py +25 -0
  27. hotcodepush/resources/device_events.py +44 -0
  28. hotcodepush/resources/devices.py +116 -0
  29. hotcodepush/resources/file_upload_parts.py +36 -0
  30. hotcodepush/resources/file_uploads.py +63 -0
  31. hotcodepush/resources/files.py +53 -0
  32. hotcodepush/resources/health.py +11 -0
  33. hotcodepush/resources/invitations.py +50 -0
  34. hotcodepush/resources/limits.py +20 -0
  35. hotcodepush/resources/members.py +121 -0
  36. hotcodepush/resources/notification_preferences.py +51 -0
  37. hotcodepush/resources/notifications.py +62 -0
  38. hotcodepush/resources/organization_apps.py +51 -0
  39. hotcodepush/resources/organization_invitations.py +112 -0
  40. hotcodepush/resources/organizations.py +110 -0
  41. hotcodepush/resources/release_audience.py +21 -0
  42. hotcodepush/resources/releases.py +162 -0
  43. hotcodepush/resources/rollbacks.py +31 -0
  44. hotcodepush/resources/signing_keys.py +53 -0
  45. hotcodepush/resources/sso_provider.py +61 -0
  46. hotcodepush/resources/sso_provider_verifications.py +27 -0
  47. hotcodepush/resources/statistics.py +15 -0
  48. hotcodepush/resources/statistics_fleet.py +17 -0
  49. hotcodepush/resources/statistics_updates.py +35 -0
  50. hotcodepush/resources/statistics_usage.py +25 -0
  51. hotcodepush/resources/subscription.py +53 -0
  52. hotcodepush/resources/usage.py +66 -0
  53. hotcodepush/resources/user_password.py +21 -0
  54. hotcodepush/resources/user_sessions.py +18 -0
  55. hotcodepush/resources/user_tokens.py +18 -0
  56. hotcodepush/resources/users.py +46 -0
  57. hotcodepush/resources/webhook_deliveries.py +91 -0
  58. hotcodepush/resources/webhooks.py +158 -0
  59. hotcodepush-0.1.0.dist-info/METADATA +98 -0
  60. hotcodepush-0.1.0.dist-info/RECORD +62 -0
  61. hotcodepush-0.1.0.dist-info/WHEEL +4 -0
  62. hotcodepush-0.1.0.dist-info/licenses/LICENSE +21 -0
hotcodepush/models.py ADDED
@@ -0,0 +1,899 @@
1
+ """The types every resource method takes or returns, derived from the OpenAPI snapshot.
2
+
3
+ Fields are snake_case and read the API's camelCase names; a field the API adds later is kept
4
+ in `model_extra`, so it never breaks a reader. `relations` embeds linked rows as the optional
5
+ fields named after them.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from datetime import date, datetime
11
+ from typing import Annotated, Literal
12
+
13
+ from pydantic import BaseModel, ConfigDict, Field
14
+ from pydantic.alias_generators import to_camel
15
+
16
+ AppUsageMonthRelation = Literal["app"]
17
+ AuditLogRelation = Literal["app", "user"]
18
+ BundleDeltaRelation = Literal["baseBundle"]
19
+ DeviceRelation = Literal["channel", "currentRelease"]
20
+ FailureAction = Literal["none", "notify", "pause", "revoke"]
21
+ Framework = Literal["capacitor", "cordova", "expo", "react-native"]
22
+ InvitationRelation = Literal["organization"]
23
+ InvitationRole = Literal["admin", "billing", "member"]
24
+ """A role an invitation grants: any but `owner`, which only a transfer hands over."""
25
+ MemberRelation = Literal["user", "user.accounts"]
26
+ NotificationCategory = Literal[
27
+ "account",
28
+ "billing",
29
+ "lifecycle",
30
+ "newsletter",
31
+ "product_alerts",
32
+ "service_notices",
33
+ "spending_alerts",
34
+ "team_activity",
35
+ ]
36
+ NotificationMedium = Literal["email", "in_app"]
37
+ NotificationRelation = Literal["app", "channel", "memberUser", "release"]
38
+ Platform = Literal["android", "ios"]
39
+ ReleaseRelation = Literal["bundle", "channel", "releaseCounters"]
40
+ Role = Literal["admin", "billing", "member", "owner"]
41
+ UserRelation = Literal["accounts", "members", "members.organization"]
42
+ WebhookEvent = Literal[
43
+ "app.created",
44
+ "app.deleted",
45
+ "app.restored",
46
+ "app.transferred",
47
+ "app.updated",
48
+ "binary.created",
49
+ "binary.expired",
50
+ "bundle.deleted",
51
+ "bundle.expired",
52
+ "bundle.uploaded",
53
+ "channel.created",
54
+ "channel.deleted",
55
+ "channel.expired",
56
+ "channel.paused",
57
+ "channel.resumed",
58
+ "channel.updated",
59
+ "device.deleted",
60
+ "invitation.accepted",
61
+ "invitation.created",
62
+ "invitation.revoked",
63
+ "member.joined",
64
+ "member.removed",
65
+ "member.role_changed",
66
+ "organization.deleted",
67
+ "organization.dormancy_noticed",
68
+ "organization.fair_use_warning",
69
+ "organization.restored",
70
+ "organization.spending_cap_changed",
71
+ "organization.spending_cap_reached",
72
+ "organization.spending_cap_warning",
73
+ "organization.storage_limit_reached",
74
+ "organization.storage_limit_warning",
75
+ "organization.updated",
76
+ "release.created",
77
+ "release.failure_rate_exceeded",
78
+ "release.paused",
79
+ "release.resumed",
80
+ "release.revoked",
81
+ "release.rollout_changed",
82
+ "release.updated",
83
+ "signing_key.created",
84
+ "signing_key.deleted",
85
+ "subscription.cancellation_scheduled",
86
+ "subscription.ended",
87
+ "subscription.uncanceled",
88
+ ]
89
+ """An audit type a webhook subscribes to."""
90
+
91
+
92
+ class HotCodePushModel(BaseModel):
93
+ model_config = ConfigDict(alias_generator=to_camel, extra="allow", populate_by_name=True)
94
+
95
+
96
+ class Account(HotCodePushModel):
97
+ """A sign-in identity of a user: `credential` for the password, otherwise its provider."""
98
+
99
+ created_at: datetime
100
+ id: str
101
+ provider_id: str
102
+ user_id: str
103
+
104
+
105
+ class AdoptionPoint(HotCodePushModel):
106
+ """A moment of a release's adoption curve and the updates confirmed by then."""
107
+
108
+ at: datetime
109
+ confirmed_update_count: int
110
+
111
+
112
+ class App(HotCodePushModel):
113
+ channel_link_template: str | None
114
+ created_at: datetime
115
+ default_channel_id: str | None
116
+ deleted_at: datetime | None
117
+ framework: Framework
118
+ id: str
119
+ name: str
120
+ next_bundle_number: int
121
+ organization_id: str
122
+ updated_at: datetime
123
+
124
+
125
+ class AppFile(HotCodePushModel):
126
+ """A content-addressed file of the app, shared between its bundles."""
127
+
128
+ app_id: str
129
+ created_at: datetime
130
+ sha256: str
131
+ size_bytes: int
132
+ updated_at: datetime
133
+
134
+
135
+ class AppUsageMonth(HotCodePushModel):
136
+ """One live app's usage in a month; `app` is set when `relations` names it."""
137
+
138
+ app: NamedEmbed | None = None
139
+ app_id: str
140
+ data_transfer_bytes: int
141
+ month: str
142
+ monthly_active_device_count: int
143
+
144
+
145
+ class AttributeCondition(HotCodePushModel):
146
+ """Devices whose attribute `key` holds the value of the SHA-256 `value_sha256`."""
147
+
148
+ key: str
149
+ type: Literal["attribute"] = "attribute"
150
+ value_sha256: str
151
+
152
+
153
+ class Audience(HotCodePushModel):
154
+ """The channel's active devices, the ones every condition reaches and the estimate at the
155
+ rollout percentage.
156
+ """
157
+
158
+ by_binary_version: list[DeviceCount]
159
+ by_platform: list[DeviceCount]
160
+ device_count: int
161
+ estimated_device_count: int
162
+ reached_device_count: int
163
+ warnings: list[AudienceWarning]
164
+
165
+
166
+ class AudienceWarning(HotCodePushModel):
167
+ """What the release would likely not do, read from the registry and the registered
168
+ binaries.
169
+ """
170
+
171
+ code: Literal["FINGERPRINT_UNKNOWN", "UNSUPPORTED_CONDITION_SHARE"]
172
+ details: dict[str, object] | None
173
+ message: str
174
+
175
+
176
+ class AuditLog(HotCodePushModel):
177
+ """A row of the audit log: who did what to which object, and when; `app` and `user` are set
178
+ when `relations` names them, while the app or the user is live.
179
+ """
180
+
181
+ actor_type: Literal["system", "user"]
182
+ address: str | None
183
+ api_key_id: str | None
184
+ app: NamedEmbed | None = None
185
+ app_id: str | None
186
+ country: str | None
187
+ created_at: datetime
188
+ dispatched_at: datetime | None
189
+ id: str
190
+ object_id: str | None
191
+ organization_id: str | None
192
+ session_id: str | None
193
+ snapshot: dict[str, object]
194
+ type: str
195
+ updated_at: datetime
196
+ user: EmbeddedUser | None = None
197
+ user_agent: str | None
198
+ user_id: str | None
199
+
200
+
201
+ class Binary(HotCodePushModel):
202
+ """A store build; the devices running it are the fleet statistics' `binary` buckets."""
203
+
204
+ app_id: str
205
+ build: str
206
+ bundle_id: str
207
+ created_at: datetime
208
+ fingerprint: str | None
209
+ id: str
210
+ platform: Platform
211
+ updated_at: datetime
212
+ version: str
213
+
214
+
215
+ class BinaryCondition(HotCodePushModel):
216
+ """Devices whose binary version lies in `range`, `>=2.0.0` say."""
217
+
218
+ range: str
219
+ type: Literal["binary"] = "binary"
220
+
221
+
222
+ class BinaryCount(HotCodePushModel):
223
+ """The devices of one binary, `value` its id, named by its platform and version, beside
224
+ their newest report; the value and the names are `None` for the builds no binary records.
225
+ """
226
+
227
+ device_count: int
228
+ last_seen_at: datetime
229
+ platform: Platform | None
230
+ value: str | None
231
+ version: str | None
232
+
233
+
234
+ class Bundle(HotCodePushModel):
235
+ app_id: str
236
+ created_at: datetime
237
+ expires_at: datetime | None
238
+ fingerprint: str | None
239
+ framework: Framework
240
+ git_message: str | None
241
+ git_ref: str | None
242
+ git_remote: str | None
243
+ git_sha: str | None
244
+ id: str
245
+ is_git_dirty: bool | None
246
+ manifest_sha256: str | None
247
+ number: int | None
248
+ platforms: list[Platform]
249
+ signature: str | None
250
+ signature_key_id: str | None
251
+ size_bytes: int
252
+ source: Literal["binary", "upload"]
253
+ status: Literal["ready", "uploading"]
254
+ unused_since: datetime | None
255
+ updated_at: datetime
256
+ version: str
257
+
258
+
259
+ class BundleDelta(HotCodePushModel):
260
+ """A delta pack of a bundle against one base, its size and patch count known once built;
261
+ `base_bundle` is set when `relations` names it.
262
+ """
263
+
264
+ base_bundle: Bundle | None = None
265
+ base_bundle_id: str
266
+ bundle_id: str
267
+ created_at: datetime
268
+ patch_count: int | None
269
+ requested_at: datetime
270
+ size_bytes: int | None
271
+ status: Literal["built", "failed", "requested"]
272
+ updated_at: datetime
273
+
274
+
275
+ class BundleFile(HotCodePushModel):
276
+ """A file a bundle lists; `stored_at` is when the app's store held its hash."""
277
+
278
+ bundle_id: str
279
+ created_at: datetime
280
+ path: str
281
+ sha256: str
282
+ size_bytes: int
283
+ stored_at: datetime | None
284
+ updated_at: datetime
285
+
286
+
287
+ class BundleSignature(HotCodePushModel):
288
+ """The signature of a bundle's manifest: the signing key's fingerprint and the value."""
289
+
290
+ key_id: str
291
+ value: str
292
+
293
+
294
+ class Channel(HotCodePushModel):
295
+ app_id: str
296
+ created_at: datetime
297
+ expires_at: datetime | None
298
+ failure_action: FailureAction | None
299
+ failure_minimum_update_count: int | None
300
+ failure_threshold_percent: int | None
301
+ id: str
302
+ is_discoverable: bool
303
+ is_protected: bool
304
+ name: str
305
+ next_release_number: int
306
+ paused_at: datetime | None
307
+ updated_at: datetime
308
+
309
+
310
+ class Checkout(HotCodePushModel):
311
+ """The URL of the Polar checkout to open."""
312
+
313
+ url: str
314
+
315
+
316
+ class Count(HotCodePushModel):
317
+ """What every list's `count` answers: the rows the list's filters match."""
318
+
319
+ count: int
320
+
321
+
322
+ class CustomerPortalSession(HotCodePushModel):
323
+ """The URL of the Polar customer portal to open."""
324
+
325
+ url: str
326
+
327
+
328
+ class DailyUpdateCounts(HotCodePushModel):
329
+ """A day's updates beside the channel's active devices of the day, the adoption rate's
330
+ denominator.
331
+ """
332
+
333
+ active_device_count: int | None
334
+ confirmed_update_count: int
335
+ day: date
336
+ failure_count: int
337
+ rolled_back_update_count: int
338
+
339
+
340
+ class Device(HotCodePushModel):
341
+ """A device of the registry, the facts of its last report; `channel` and `current_release`
342
+ are set when `relations` names them.
343
+ """
344
+
345
+ app_id: str
346
+ attributes: dict[str, str]
347
+ binary_build: str
348
+ binary_version: str
349
+ channel: Channel | None = None
350
+ channel_id: str | None
351
+ channel_source: Literal["config", "runtime"]
352
+ country: str | None
353
+ created_at: datetime
354
+ current_release: Release | None = None
355
+ current_release_id: str | None
356
+ device_id: str
357
+ embedded_bundle_id: str | None
358
+ fingerprint: str | None
359
+ last_seen_at: datetime
360
+ os_version: str
361
+ platform: Platform
362
+ sdk_version: str
363
+ updated_at: datetime
364
+
365
+
366
+ class DeviceCondition(HotCodePushModel):
367
+ """Devices whose hashed id is one of `hashed_ids`."""
368
+
369
+ hashed_ids: list[str]
370
+ type: Literal["device"] = "device"
371
+
372
+
373
+ class DeviceCount(HotCodePushModel):
374
+ """One value of a dimension and the number of devices that report it."""
375
+
376
+ device_count: int
377
+ value: str | None
378
+
379
+
380
+ class EmbeddedRelease(HotCodePushModel):
381
+ """The release a notification's `relations` embeds: the id and the number, since a release
382
+ has no name.
383
+ """
384
+
385
+ id: str
386
+ number: int
387
+
388
+
389
+ class EmbeddedUser(HotCodePushModel):
390
+ """A user embedded under another caller's member or audit row: what a colleague is shown;
391
+ `accounts` is set when `relations` names `user.accounts`.
392
+ """
393
+
394
+ accounts: list[Account] | None = None
395
+ created_at: datetime
396
+ email: str
397
+ email_verified: bool
398
+ id: str
399
+ image: str | None
400
+ name: str
401
+ two_factor_enabled: bool
402
+ updated_at: datetime
403
+
404
+
405
+ class FingerprintCondition(HotCodePushModel):
406
+ """Devices whose binary carries the native `fingerprint`."""
407
+
408
+ fingerprint: str
409
+ type: Literal["fingerprint"] = "fingerprint"
410
+
411
+
412
+ class FleetStatistics(HotCodePushModel):
413
+ """The devices seen in the last thirty days: `device_count`, `current_device_count` the ones
414
+ running their channel's newest active release, and their counts per dimension, each the most
415
+ common first.
416
+ """
417
+
418
+ binary: list[BinaryCount]
419
+ binary_version: list[DeviceCount]
420
+ channel: list[DeviceCount]
421
+ country: list[DeviceCount]
422
+ current_device_count: int
423
+ device_count: int
424
+ os_version: list[OsVersionCount]
425
+ platform: list[DeviceCount]
426
+ release: list[ReleaseCount]
427
+ sdk_version: list[DeviceCount]
428
+
429
+
430
+ class Invitation(HotCodePushModel):
431
+ """An invitation to an organization; `organization` is set on the caller's own invitations
432
+ when `relations` names it.
433
+ """
434
+
435
+ created_at: datetime
436
+ email: str
437
+ expires_at: datetime
438
+ id: str
439
+ inviter_id: str
440
+ organization: NamedEmbed | None = None
441
+ organization_id: str
442
+ role: InvitationRole
443
+ status: Literal["accepted", "canceled", "pending", "rejected"]
444
+ updated_at: datetime
445
+
446
+
447
+ class Limit(HotCodePushModel):
448
+ """A limit in effect: its value, the plan's default and whether the value overrides it."""
449
+
450
+ default: int
451
+ is_overridden: bool
452
+ value: int
453
+
454
+
455
+ class ManifestFile(HotCodePushModel):
456
+ """A file of a bundle's manifest: its path, the SHA-256 of its content and its size."""
457
+
458
+ path: str
459
+ sha256: str
460
+ size_bytes: int
461
+
462
+
463
+ class Member(HotCodePushModel):
464
+ """A member of an organization; `organization` and `user` are set when `relations` names
465
+ them.
466
+ """
467
+
468
+ created_at: datetime
469
+ id: str
470
+ last_seen_at: datetime | None
471
+ organization: Organization | None = None
472
+ organization_id: str
473
+ role: Role
474
+ updated_at: datetime
475
+ user: EmbeddedUser | None = None
476
+ user_id: str
477
+
478
+
479
+ class MultipartUpload(HotCodePushModel):
480
+ upload_id: str
481
+
482
+
483
+ class NamedEmbed(HotCodePushModel):
484
+ """A row another row embeds through `relations`, its id and its name alone: an app, an
485
+ organization, a channel or a member user.
486
+ """
487
+
488
+ id: str
489
+ name: str
490
+
491
+
492
+ class Notification(HotCodePushModel):
493
+ """An in-app notification of the caller, its `organization_id` `None` for one about the
494
+ account; `app`, `channel`, `member_user` and `release` are set when `relations` names them,
495
+ `None` once the row is deleted.
496
+ """
497
+
498
+ app: NamedEmbed | None = None
499
+ app_id: str | None
500
+ channel: NamedEmbed | None = None
501
+ channel_id: str | None
502
+ created_at: datetime
503
+ id: str
504
+ member_user: NamedEmbed | None = None
505
+ member_user_id: str | None
506
+ organization_id: str | None
507
+ read_at: datetime | None
508
+ release: EmbeddedRelease | None = None
509
+ release_id: str | None
510
+ type: str
511
+ updated_at: datetime
512
+ user_id: str
513
+
514
+
515
+ class NotificationPreference(HotCodePushModel):
516
+ """Whether the caller receives one category's notifications through one medium, for the
517
+ account or, with `organization_id`, for one membership.
518
+ """
519
+
520
+ category: NotificationCategory
521
+ is_enabled: bool
522
+ medium: NotificationMedium
523
+ organization_id: str | None
524
+
525
+
526
+ class OidcConfig(HotCodePushModel):
527
+ """The OpenID Connect provider of an organization's SSO; a field left `None` is not sent."""
528
+
529
+ client_id: str
530
+ client_secret: str
531
+ discovery_endpoint: str | None = None
532
+ issuer: str
533
+ scopes: list[str] | None = None
534
+
535
+
536
+ class Organization(HotCodePushModel):
537
+ app_count_limit: int | None
538
+ capped_at: datetime | None
539
+ channel_count_per_app_limit: int | None
540
+ country_allowlist: list[str] | None
541
+ created_at: datetime
542
+ current_period_ends_at: datetime | None
543
+ data_transfer_bytes_per_monthly_active_device_limit: int | None
544
+ deleted_at: datetime | None
545
+ enterprise_monthly_active_device_count_limit: int | None
546
+ file_count_per_bundle_limit: int | None
547
+ final_period_ends_at: datetime | None
548
+ id: str
549
+ ip_allowlist: list[str] | None
550
+ is_two_factor_required: bool
551
+ last_spending_cap_reached_sent_at: datetime | None
552
+ last_spending_cap_warning_sent_at: datetime | None
553
+ last_storage_limit_reached_sent_at: datetime | None
554
+ last_storage_warning_sent_at: datetime | None
555
+ member_count_limit: int | None
556
+ name: str
557
+ past_due_at: datetime | None
558
+ plan: Literal["enterprise", "free", "pay_as_you_go"]
559
+ region: str
560
+ release_count_per_app_per_day_limit: int | None
561
+ reported_billable_device_count: int
562
+ reported_billable_device_count_hour: datetime | None
563
+ reported_billable_device_count_month: date | None
564
+ retention_days: int | None
565
+ spending_cap_cents: int
566
+ storage_bytes: int
567
+ storage_bytes_limit: int | None
568
+ subscription_provider: Literal["polar"] | None
569
+ subscription_status: str | None
570
+ unsent_billable_device_count: int
571
+ updated_at: datetime
572
+
573
+
574
+ class OsCondition(HotCodePushModel):
575
+ """Devices whose operating system version lies in `range`, `>=17` say."""
576
+
577
+ range: str
578
+ type: Literal["os"] = "os"
579
+
580
+
581
+ class OsVersionCount(HotCodePushModel):
582
+ """The devices of one version of one platform's operating system."""
583
+
584
+ device_count: int
585
+ platform: Platform
586
+ value: str | None
587
+
588
+
589
+ class ReasonCount(HotCodePushModel):
590
+ """A reason the devices reported and the number of events that gave it."""
591
+
592
+ event_count: int
593
+ reason: str
594
+
595
+
596
+ class Release(HotCodePushModel):
597
+ """A release of a bundle in a channel; `bundle`, `channel` and `release_counters` are set
598
+ when `relations` names them.
599
+ """
600
+
601
+ auto_paused_at: datetime | None
602
+ bundle: Bundle | None = None
603
+ bundle_id: str
604
+ channel: Channel | None = None
605
+ channel_id: str
606
+ conditions: list[ReleaseCondition]
607
+ created_at: datetime
608
+ created_from_release_id: str | None
609
+ failure_action: FailureAction | None
610
+ failure_minimum_update_count: int | None
611
+ failure_notified_at: datetime | None
612
+ failure_threshold_percent: int | None
613
+ id: str
614
+ is_mandatory: bool
615
+ live_at: datetime | None
616
+ notes: str | None
617
+ number: int
618
+ paused_at: datetime | None
619
+ progression: ReleaseProgression | None
620
+ progression_step_started_at: datetime | None
621
+ purged_at: datetime | None
622
+ release_counters: ReleaseCounters | None = None
623
+ rolled_back_from_release_id: str | None
624
+ rollout_percentage: int
625
+ status: Literal["active", "paused", "revoked"]
626
+ step_start_applied_update_count: int
627
+ updated_at: datetime
628
+ window_start_applied_update_count: int
629
+ window_start_failure_count: int
630
+
631
+
632
+ class ReleaseAdoption(HotCodePushModel):
633
+ """A live release's adoption curve since it went live, with the moments it reached half and
634
+ nine tenths of the channel's active devices.
635
+ """
636
+
637
+ adoption: list[AdoptionPoint]
638
+ channel_id: str
639
+ live_at: datetime
640
+ number: int
641
+ release_id: str
642
+ time_to_adoption: TimeToAdoption
643
+
644
+
645
+ class ReleaseCount(HotCodePushModel):
646
+ """The devices of one release, `value` its id, named by its number and its channel; all
647
+ three are `None` for the embedded bundles.
648
+ """
649
+
650
+ channel_id: str | None
651
+ device_count: int
652
+ number: int | None
653
+ value: str | None
654
+
655
+
656
+ class ReleaseCounters(HotCodePushModel):
657
+ applied_update_count: int
658
+ confirmed_update_count: int
659
+ crash_failure_count: int
660
+ created_at: datetime
661
+ download_failure_count: int
662
+ readiness_timeout_failure_count: int
663
+ release_id: str
664
+ reported_failure_count: int
665
+ updated_at: datetime
666
+ verification_failure_count: int
667
+
668
+
669
+ class ReleaseDeviceEvent(HotCodePushModel):
670
+ """A device's first event of each type on a release, with the reason a failure gave."""
671
+
672
+ created_at: datetime
673
+ device_id: str
674
+ reason: str | None
675
+ release_id: str
676
+ type: Literal["applied", "checked", "confirmed", "failed"]
677
+ updated_at: datetime
678
+
679
+
680
+ class ReleaseProgression(HotCodePushModel):
681
+ """The schedule that raises a release's rollout through `percentages`, a step at a time."""
682
+
683
+ percentages: list[int]
684
+ step_minimum_seconds: int
685
+ step_minimum_update_count: int
686
+
687
+
688
+ class SamlConfig(HotCodePushModel):
689
+ """The SAML provider of an organization's SSO: its `metadata`, or its `cert` with its
690
+ `entity_id`; a field left `None` is not sent.
691
+ """
692
+
693
+ cert: str | None = None
694
+ entity_id: str | None = None
695
+ entry_point: str
696
+ issuer: str
697
+ metadata: str | None = None
698
+
699
+
700
+ class SigningKey(HotCodePushModel):
701
+ """A public key the app's bundles are verified against; its `fingerprint` is the `key_id` a
702
+ signature names.
703
+ """
704
+
705
+ app_id: str
706
+ created_at: datetime
707
+ fingerprint: str
708
+ id: str
709
+ public_key: str
710
+ updated_at: datetime
711
+
712
+
713
+ class SsoProvider(HotCodePushModel):
714
+ """An organization's SSO provider: the domain, and the token its TXT record
715
+ `_hotcodepush-sso-{providerId}.{domain}` carries until `domain_verified`; the configs are
716
+ write-only.
717
+ """
718
+
719
+ created_at: datetime
720
+ domain: str
721
+ domain_verification_token: str | None
722
+ domain_verified: bool
723
+ id: str
724
+ issuer: str
725
+ organization_id: str
726
+ provider_id: str
727
+ type: Literal["oidc", "saml"]
728
+ updated_at: datetime
729
+ user_id: str | None
730
+
731
+
732
+ class TimeToAdoption(HotCodePushModel):
733
+ """When a release reached half and nine tenths of the channel's active devices; `None` until
734
+ it does.
735
+ """
736
+
737
+ percent50_at: datetime | None
738
+ percent90_at: datetime | None
739
+
740
+
741
+ class UpdateStatistics(HotCodePushModel):
742
+ """The updates per day of the period, the adoption curves of the newest live releases and
743
+ the reasons the devices reported.
744
+ """
745
+
746
+ days: list[DailyUpdateCounts]
747
+ failure_reasons: list[ReasonCount]
748
+ releases: list[ReleaseAdoption]
749
+ skipped_reasons: list[ReasonCount]
750
+
751
+
752
+ class UploadedBundlePack(HotCodePushModel):
753
+ size_bytes: int
754
+
755
+
756
+ class UploadedPart(HotCodePushModel):
757
+ """A part of a multipart upload; its `etag` and `part_number` complete the upload."""
758
+
759
+ etag: str
760
+ part_number: int
761
+
762
+
763
+ class Usage(HotCodePushModel):
764
+ """An organization's monthly active devices and data transfer in `month`, `YYYY-MM`, summed
765
+ over its apps' rows.
766
+ """
767
+
768
+ data_transfer_bytes: int
769
+ month: str
770
+ monthly_active_device_count: int
771
+
772
+
773
+ class UsageDay(HotCodePushModel):
774
+ """A day's checks and data transfer, beside the bytes the devices reported downloading."""
775
+
776
+ check_count: int
777
+ data_transfer_bytes: int
778
+ day: date
779
+ device_download_bytes: int
780
+
781
+
782
+ class UsageMonth(HotCodePushModel):
783
+ """A month's monthly active devices and data transfer, the numbers the invoice shows."""
784
+
785
+ data_transfer_bytes: int
786
+ month: date
787
+ monthly_active_device_count: int
788
+
789
+
790
+ class UsageStatistics(HotCodePushModel):
791
+ """The monthly active devices and data transfer per month the period touches, and the
792
+ checks, data transfer and device downloads per day.
793
+ """
794
+
795
+ days: list[UsageDay]
796
+ months: list[UsageMonth]
797
+
798
+
799
+ class User(HotCodePushModel):
800
+ """The caller; `accounts` and `members` are set when `relations` names them."""
801
+
802
+ accounts: list[Account] | None = None
803
+ banned_at: datetime | None
804
+ created_at: datetime
805
+ deleted_at: datetime | None
806
+ discovery_source: (
807
+ Literal[
808
+ "ai_assistant",
809
+ "blog_or_article",
810
+ "friend_or_colleague",
811
+ "github",
812
+ "linkedin",
813
+ "other",
814
+ "reddit",
815
+ "search_engine",
816
+ "x_twitter",
817
+ "youtube",
818
+ ]
819
+ | None
820
+ )
821
+ email: str
822
+ email_verified: bool
823
+ id: str
824
+ image: str | None
825
+ intended_framework: Literal["capacitor", "cordova", "expo", "react_native", "unsure"] | None
826
+ job_role: (
827
+ Literal[
828
+ "cto_or_founder",
829
+ "developer",
830
+ "freelancer_or_agency",
831
+ "manager_or_lead",
832
+ "other",
833
+ "student_or_hobbyist",
834
+ ]
835
+ | None
836
+ )
837
+ last_seen_at: datetime
838
+ locale: str | None
839
+ members: list[Member] | None = None
840
+ name: str
841
+ time_format: Literal["12h", "24h"] | None
842
+ time_zone: str | None
843
+ two_factor_enabled: bool
844
+ updated_at: datetime
845
+
846
+
847
+ class Webhook(HotCodePushModel):
848
+ """An outbound webhook: the `format`, `raw` for the JSON payload or `slack`, `discord` or
849
+ `teams` for a chat message, the subscribed audit `events`, the app filter, `None` for every
850
+ app's events and the organization's, and `is_enabled`, off after fifty consecutive failed
851
+ deliveries.
852
+ """
853
+
854
+ app_id: str | None
855
+ consecutive_failure_count: int
856
+ created_at: datetime
857
+ events: list[str]
858
+ format: Literal["discord", "raw", "slack", "teams"]
859
+ id: str
860
+ is_enabled: bool
861
+ name: str
862
+ organization_id: str
863
+ updated_at: datetime
864
+ url: str
865
+
866
+
867
+ # Out of the alphabetical order: a subclass follows its base.
868
+ class CreatedWebhook(Webhook):
869
+ """A created webhook with its signing `secret`, answered this once; `None` for a chat
870
+ format, whose URL carries the token.
871
+ """
872
+
873
+ secret: str | None
874
+
875
+
876
+ class WebhookDelivery(HotCodePushModel):
877
+ """One event sent to a webhook with its attempts: the `type`, the audit type or
878
+ `webhook.test`, the receiver's last `response_code` and `response_body`, cut at 4,096
879
+ characters, and `next_attempt_at` while the queue retries it.
880
+ """
881
+
882
+ attempt_count: int
883
+ audit_row_id: str | None
884
+ created_at: datetime
885
+ id: str
886
+ next_attempt_at: datetime | None
887
+ response_body: str | None
888
+ response_code: int | None
889
+ status: Literal["failed", "pending", "succeeded"]
890
+ type: str
891
+ updated_at: datetime
892
+ webhook_id: str
893
+
894
+
895
+ ReleaseCondition = Annotated[
896
+ AttributeCondition | BinaryCondition | DeviceCondition | FingerprintCondition | OsCondition,
897
+ Field(discriminator="type"),
898
+ ]
899
+ """A condition a device meets to receive a release."""