durable-actors 0.7.14

Standalone regional durable-actors control plane, host, and durability runtime
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
openapi: 3.1.0
info:
    title: durable-actors HTTP API
    version: "1"
    description: |
        Manage durable-actors deployments, invoke actors, find actor hosts, and inspect activity.
        When DURABLE_ACTORS_SECRET is set on the server, authenticate backend requests
        with that bearer API key; never expose it to browsers. When unset, no API key is required.
        Project-scoped actor routes work in development and production. Run `durable-actors dev`
        and copy the printed connection settings into your backend's environment. The default
        local project ID is `local`; use it as `project_id` in requests.
        Servers listening beyond localhost warn when the secret is unset but still start.
servers:
    - url: http://127.0.0.1:7100
      description: Local server.
security:
    - ApiKey: []
    - {}
tags:
    - name: Discovery
    - name: Deployments
    - name: Actors
    - name: Observability
    - name: WebSockets
    - name: Sessions
paths:
    /openapi.yaml:
        get:
            operationId: getOpenApi
            tags: [Discovery]
            summary: Get the API specification
            security: []
            responses:
                "200":
                    description: OpenAPI 3.1 document.
                    content:
                        application/yaml:
                            schema: { type: string }
    /healthz:
        get:
            operationId: getHealth
            tags: [Discovery]
            summary: Check server health
            security: []
            responses:
                "200":
                    description: Server is running.
                    content:
                        text/plain:
                            schema: { type: string, const: ok }
    /v1/projects/{project_id}/deployment:
        parameters:
            - { $ref: "#/components/parameters/ProjectId" }
        put:
            operationId: registerDeployment
            tags: [Deployments]
            summary: Deploy actors
            description: Registers a compiled GCS bundle and its actor contract. Build and upload with any compatible toolchain before calling this endpoint. Replaces the deployment and restarts actors while preserving saved state. The bundle must use the configured artifact bucket and durable-actors/v3/artifacts/{UUID}/ paths. A new bundle requires contract; resubmitting the current bundle may omit it to retain the current contract. Local development registers localSource with its project directory and entrypoint.
            requestBody:
                required: true
                content:
                    application/json:
                        schema: { $ref: "#/components/schemas/Deployment" }
                        examples:
                            compiled:
                                value:
                                    bundle:
                                        bucket: actor-code
                                        files:
                                            - path: actors.mjs
                                              object: durable-actors/v3/artifacts/00000000-0000-4000-8000-000000000001/actors.mjs
                                              generation: 123456789
                                              sha256: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                                    contract: { version: 1, actors: [], typescript: { declarations: "export interface ActorTypes {}", dependencies: {} } }
                            local:
                                value:
                                    localSource: { workingDirectory: /project, actorEntrypoint: src/actors.ts }
            responses:
                "200": { $ref: "#/components/responses/Changed" }
                "400": { $ref: "#/components/responses/InvalidRequest" }
                "401": { $ref: "#/components/responses/Unauthenticated" }
                "413": { $ref: "#/components/responses/PayloadTooLarge" }
        get:
            operationId: getDeployment
            tags: [Deployments]
            summary: Get current deployment
            responses:
                "200":
                    description: Active deployment, without the contract.
                    content:
                        application/json:
                            schema: { $ref: "#/components/schemas/CurrentDeployment" }
                "400": { $ref: "#/components/responses/InvalidRequest" }
                "401": { $ref: "#/components/responses/Unauthenticated" }
                "404": { $ref: "#/components/responses/NotFound" }
                "500": { $ref: "#/components/responses/Internal" }
        delete:
            operationId: deleteDeployment
            tags: [Deployments]
            summary: Delete deployment
            description: Stops deployed actors and keeps their saved state.
            responses:
                "200": { $ref: "#/components/responses/Changed" }
                "400": { $ref: "#/components/responses/InvalidRequest" }
                "401": { $ref: "#/components/responses/Unauthenticated" }
                "500": { $ref: "#/components/responses/Internal" }
    /v1/projects/{project_id}/deployment/contract:
        parameters:
            - { $ref: "#/components/parameters/ProjectId" }
        get:
            operationId: getContract
            tags: [Deployments]
            summary: Get actor contracts
            responses:
                "200":
                    description: Active actor contract.
                    headers:
                        Cache-Control: { $ref: "#/components/headers/NoStore" }
                    content:
                        application/json:
                            schema:
                                type: object
                                required: [contractHash, contract]
                                properties:
                                    contractHash:
                                        type: string
                                        pattern: "^sha256:[a-f0-9]{64}$"
                                        description: Contract fingerprint.
                                    contract: { $ref: "#/components/schemas/PublicActorContract" }
                "400": { $ref: "#/components/responses/InvalidRequest" }
                "401": { $ref: "#/components/responses/Unauthenticated" }
                "404": { $ref: "#/components/responses/NotFound" }
                "500": { $ref: "#/components/responses/Internal" }
    /v1/projects/{project_id}/sessions:
        parameters:
            - { $ref: "#/components/parameters/ProjectId" }
        post:
            operationId: issueActorSession
            tags: [Sessions]
            summary: Issue a scoped RPC session
            security: [{ ApiKey: [] }]
            description: Requires the configured administrative secret and an active deployment. The trusted backend must authenticate its caller and check project ACLs first. Sessions authorize all actor types, actor IDs, and published RPC methods in exactly one project. Expiry is capped by the requested absolute deadline, 60 seconds, and the runtime maximum JWT lifetime. Session credentials cannot issue sessions or access administrative APIs or WebSockets.
            requestBody:
                required: true
                content:
                    application/json:
                        schema: { $ref: "#/components/schemas/IssueActorSession" }
            responses:
                "200":
                    description: Runtime-signed session and its absolute expiration.
                    headers:
                        Cache-Control: { $ref: "#/components/headers/NoStore" }
                    content:
                        application/json:
                            schema:
                                type: object
                                required: [token, expiresAtMs]
                                properties:
                                    token: { type: string }
                                    expiresAtMs: { type: integer, format: int64 }
                "400": { $ref: "#/components/responses/InvalidRequest" }
                "401": { $ref: "#/components/responses/Unauthenticated" }
                "404": { $ref: "#/components/responses/NotFound" }
                "413": { $ref: "#/components/responses/PayloadTooLarge" }
                "500": { $ref: "#/components/responses/Internal" }
    /v1/projects/{project_id}/actors/{actor_name}/{actor_id}/find-actor:
        parameters:
            - { $ref: "#/components/parameters/ProjectId" }
            - { $ref: "#/components/parameters/ActorName" }
            - { $ref: "#/components/parameters/ActorId" }
        post:
            operationId: findActor
            tags: [Actors]
            summary: Find an actor host
            security: [{ ApiKey: [] }, { ActorSession: [] }, {}]
            description: Resolves placement, starts a host if needed, and issues credentials for direct HTTP calls. Requires an active deployment. Accepts the administrative secret or a runtime-issued actor:session credential for this project. Sessions produce actor-specific tickets containing all of the actor's published RPC methods. These tickets cannot outlive the session.
            requestBody: { $ref: "#/components/requestBodies/FindActor" }
            responses:
                "200": { $ref: "#/components/responses/ActorTarget" }
                "400": { $ref: "#/components/responses/InvalidRequest" }
                "401": { $ref: "#/components/responses/Unauthenticated" }
                "403": { description: Actor has no published RPC methods. }
                "404": { $ref: "#/components/responses/NotFound" }
                "409": { $ref: "#/components/responses/Conflict" }
                "413": { $ref: "#/components/responses/PayloadTooLarge" }
                "500": { $ref: "#/components/responses/Internal" }
                "503": { $ref: "#/components/responses/Unavailable" }
    /v1/projects/{project_id}/actors/{actor_name}/{actor_id}/invoke:
        servers:
            - url: "{actorHost}"
              description: Use the cached route returned by invokeActor or findActor.
              variables:
                  actorHost: { default: "http://127.0.0.1:7101" }
        parameters:
            - { $ref: "#/components/parameters/ProjectId" }
            - { $ref: "#/components/parameters/ActorName" }
            - { $ref: "#/components/parameters/ActorId" }
        post:
            operationId: invokeActor
            tags: [Actors]
            summary: Resolve and invoke an actor method
            servers:
                - url: "{controlPlane}"
                  description: Resolve and invoke with an API key or project session.
                  variables:
                      controlPlane: { default: "http://127.0.0.1:7100" }
                - url: "{actorHost}"
                  description: Cached invocation through the gateway (or local host) with a signed ticket and ownership epoch.
                  variables:
                      actorHost: { default: "http://127.0.0.1:7101" }
            security: [{ ApiKey: [] }, { ActorSession: [] }, { ActorTicket: [] }, {}]
            description: |
                Without a valid cached target, the SDK sends requestId, method, args and an optional homeRegion to the control plane.
                The control plane resolves placement, forwards one call and returns its outcome together with a scoped host target.
                The SDK caches that target for subsequent invocations and broadcasts. Warm invocations use the cached route with its ticket and ownerEpoch. On Kubernetes this is the shared gateway, which verifies the signed route and forwards to the private host.
                The host validates the actor, host session and ownership epoch before dispatch.
                Socket effects are delivered by the host before a completed response.
                The SDK retries once across both paths only for explicit pre-execution rejection or a refused host connection.
                When the gateway cannot connect to a cached host, it returns not_executed with reason upstream_not_reached; the SDK clears the target and retries once through control-plane resolution with the same requestId.
                A control-plane outcome of unauthenticated means the host rejected its ticket before execution; HTTP 401 means the caller credential was rejected.
                Actor failures and ambiguous errors are never automatically replayed. An outcome_unknown error means execution may have occurred.
                requestId identifies an attempt; it does not deduplicate execution.
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            oneOf:
                                - { $ref: "#/components/schemas/ActorInvocation" }
                                - { $ref: "#/components/schemas/ControlPlaneInvocation" }
                        examples:
                            resolveAndIncrement:
                                value: { requestId: request-1, method: increment, args: [2], homeRegion: north-america-west }
                            increment:
                                value: { requestId: request-1, ownerEpoch: 3, method: increment, args: [2] }
            responses:
                "200":
                    description: Explicit execution outcome, including actor failures. A completed result includes null for void methods.
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - { $ref: "#/components/schemas/ControlPlaneInvocationReply" }
                                    - { $ref: "#/components/schemas/ActorInvocationReply" }
                            examples:
                                resolved:
                                    value:
                                        target: { homeRegion: north-america-west, route: "https://actors.example.com", token: host-ticket, ownerEpoch: 3, expiresAtMs: 1900000000000 }
                                        outcome: { type: completed, result: 7 }
                                completed: { value: { type: completed, result: 7 } }
                                failed: { value: { type: failed, code: actor_error, message: Method failed } }
                                notExecuted: { value: { type: not_executed, reason: host_unavailable } }
                "400": { $ref: "#/components/responses/InvalidRequest" }
                "401": { description: "API key, project session or host ticket rejected before dispatch." }
                "403": { description: "Host ticket belongs to another actor, host session or ownership epoch." }
                "404": { $ref: "#/components/responses/NotFound" }
                "409": { $ref: "#/components/responses/Conflict" }
                "502": { description: The invocation outcome is unknown. Do not replay automatically. }
                "503": { $ref: "#/components/responses/Unavailable" }
                "413": { $ref: "#/components/responses/PayloadTooLarge" }
                "415": { description: Expected application/json. }
                "422": { description: Invalid invocation document. }
    /v1/projects/{project_id}/actors/{actor_name}/{actor_id}/socket-effects:
        servers:
            - url: "{actorHost}"
              description: Use the route returned by findActor.
              variables:
                  actorHost: { default: "http://127.0.0.1:7101" }
        parameters:
            - { $ref: "#/components/parameters/ProjectId" }
            - { $ref: "#/components/parameters/ActorName" }
            - { $ref: "#/components/parameters/ActorId" }
        post:
            operationId: publishActorSocketEffects
            tags: [WebSockets]
            summary: Deliver socket effects to the owning host
            security: [{ ActorTicket: [] }]
            description: Used by backend broadcasts. Actor method effects are already delivered by invokeActor. Do not retry an uncertain delivery.
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            additionalProperties: false
                            required: [ownerEpoch, effects]
                            properties:
                                ownerEpoch: { type: integer, minimum: 1, maximum: 9007199254740991 }
                                effects:
                                    type: array
                                    items: { $ref: "#/components/schemas/ActorSocketEffect" }
                        examples:
                            broadcast:
                                value:
                                    ownerEpoch: 3
                                    effects:
                                        - type: broadcast
                                          message: { type: text, data: '"hello"' }
                                          except_connection_ids: []
                                          tags: []
            responses:
                "204": { description: Effects delivered. }
                "400": { $ref: "#/components/responses/InvalidRequest" }
                "401": { description: Ticket rejected. }
                "403": { description: "Ticket belongs to another actor, host session or ownership epoch." }
                "413": { $ref: "#/components/responses/PayloadTooLarge" }
                "415": { description: Expected application/json. }
                "422": { description: Invalid effects document. }
                "503": { description: Delivery unavailable; some effects may already have been applied. }
    /v1/projects/{project_id}/actors/{actor_name}/{actor_id}/find-websocket:
        parameters:
            - { $ref: "#/components/parameters/ProjectId" }
            - { $ref: "#/components/parameters/ActorName" }
            - { $ref: "#/components/parameters/ActorId" }
        post:
            operationId: findWebSocket
            tags: [Actors]
            summary: Find an authorized WebSocket URL
            description: Issues a fresh connection URL. Authorize the application user before requesting it. Requires an active deployment.
            requestBody: { $ref: "#/components/requestBodies/FindWebSocket" }
            responses:
                "200": { $ref: "#/components/responses/WebSocketGrant" }
                "400": { $ref: "#/components/responses/InvalidRequest" }
                "401": { $ref: "#/components/responses/Unauthenticated" }
                "409": { $ref: "#/components/responses/Conflict" }
                "413": { $ref: "#/components/responses/PayloadTooLarge" }
                "500": { $ref: "#/components/responses/Internal" }
                "503": { $ref: "#/components/responses/Unavailable" }
    /v1/projects/{project_id}/observe/actors:
        parameters:
            - { $ref: "#/components/parameters/ProjectId" }
        get:
            operationId: getActorInventory
            tags: [Observability]
            summary: Get actor activity
            responses:
                "200":
                    description: Actor counts and connections.
                    headers:
                        Cache-Control: { $ref: "#/components/headers/NoStore" }
                    content:
                        application/json:
                            schema: { $ref: "#/components/schemas/Inventory" }
                "401": { $ref: "#/components/responses/Unauthenticated" }
                "500": { $ref: "#/components/responses/Internal" }
                "503": { $ref: "#/components/responses/Unavailable" }
    /v1/projects/{project_id}/observe/events:
        parameters:
            - { $ref: "#/components/parameters/ProjectId" }
        get:
            operationId: streamActorInventory
            tags: [Observability]
            summary: Stream actor activity
            description: "SSE: inventory events contain Inventory JSON; error events contain text and close the stream."
            responses:
                "200": { $ref: "#/components/responses/EventStream" }
                "401": { $ref: "#/components/responses/Unauthenticated" }
    /v1/projects/{project_id}/observe/state:
        parameters:
            - { $ref: "#/components/parameters/ProjectId" }
        get:
            operationId: getActorState
            tags: [Observability]
            summary: Read an actor snapshot from storage
            description: Reads existing persisted snapshots without activating the actor. Uploads may lag completed requests. History is limited by the bucket lifecycle.
            parameters:
                - name: actorName
                  in: query
                  required: true
                  schema: { type: string, pattern: "^[A-Za-z0-9._-]{1,48}$" }
                - name: actorId
                  in: query
                  required: true
                  schema: { type: string, pattern: "^[A-Za-z0-9._-]{1,128}$" }
                - name: version
                  in: query
                  schema: { type: integer, minimum: 1 }
            responses:
                "200":
                    description: Persisted state inspection result.
                    headers:
                        Cache-Control: { $ref: "#/components/headers/NoStore" }
                    content:
                        application/json:
                            schema: { $ref: "#/components/schemas/ActorStateResponse" }
                "400": { $ref: "#/components/responses/InvalidRequest" }
                "401": { $ref: "#/components/responses/Unauthenticated" }
                "500": { $ref: "#/components/responses/Internal" }
    /v1/projects/{project_id}/observe/state/history:
        parameters:
            - { $ref: "#/components/parameters/ProjectId" }
        get:
            operationId: listActorStateHistory
            tags: [Observability]
            summary: List actor snapshot metadata from storage
            description: Reads existing persisted snapshots without activating the actor. Uploads may lag completed requests. History is limited by the bucket lifecycle.
            parameters:
                - name: actorName
                  in: query
                  required: true
                  schema: { type: string, pattern: "^[A-Za-z0-9._-]{1,48}$" }
                - name: actorId
                  in: query
                  required: true
                  schema: { type: string, pattern: "^[A-Za-z0-9._-]{1,128}$" }
                - name: before
                  in: query
                  schema: { type: integer, minimum: 1 }
                - name: limit
                  in: query
                  schema: { type: integer, minimum: 1, maximum: 100, default: 25 }
            responses:
                "200":
                    description: Persisted state inspection result.
                    headers:
                        Cache-Control: { $ref: "#/components/headers/NoStore" }
                    content:
                        application/json:
                            schema: { $ref: "#/components/schemas/ActorStateHistory" }
                "400": { $ref: "#/components/responses/InvalidRequest" }
                "401": { $ref: "#/components/responses/Unauthenticated" }
                "500": { $ref: "#/components/responses/Internal" }
    /v1/projects/{project_id}/observe/requests:
        parameters:
            - { $ref: "#/components/parameters/ProjectId" }
        get:
            operationId: listRequestHistory
            tags: [Observability]
            summary: Get request history
            description: Newest first. Use nextCursor with the same filters for older records; replace previous records when reset=true.
            parameters:
                - name: actorName
                  in: query
                  schema: { type: string, pattern: "^[A-Za-z0-9._-]{1,48}$" }
                - name: actorId
                  in: query
                  schema: { type: string, pattern: "^[A-Za-z0-9._-]{1,128}$" }
                - name: requestId
                  in: query
                  schema: { type: string, minLength: 1, maxLength: 256 }
                - name: connectionId
                  in: query
                  schema: { type: string, minLength: 1, maxLength: 256 }
                - name: outcome
                  in: query
                  schema: { type: string, enum: [completed, failed, rejected, rerouted, interrupted] }
                - { $ref: "#/components/parameters/FromMs" }
                - { $ref: "#/components/parameters/ToMs" }
                - name: limit
                  in: query
                  schema: { type: integer, minimum: 1, maximum: 500, default: 100 }
                - name: cursor
                  in: query
                  description: nextCursor from the previous page.
                  schema: { type: string, minLength: 1, maxLength: 4096 }
            responses:
                "200":
                    description: Request records; nextCursor is null on the last page.
                    headers:
                        Cache-Control: { $ref: "#/components/headers/NoStore" }
                    content:
                        application/json:
                            schema: { $ref: "#/components/schemas/TracePage" }
                            examples:
                                empty:
                                    value:
                                        {
                                            epoch: "history-1",
                                            cursor: 0,
                                            capacity: 100,
                                            evicted: 0,
                                            dropped: 0,
                                            persistenceFailed: false,
                                            records: [],
                                            nextCursor: null,
                                            resumeCursor: "opaque-cursor",
                                            reset: false
                                        }
                "400": { $ref: "#/components/responses/InvalidRequest" }
                "401": { $ref: "#/components/responses/Unauthenticated" }
                "500": { $ref: "#/components/responses/Internal" }
    /v1/projects/{project_id}/observe/metrics:
        parameters:
            - { $ref: "#/components/parameters/ProjectId" }
        get:
            operationId: getObserverMetrics
            tags: [Observability]
            summary: Get retained request metrics
            description: Counts include reroutes; success and p95 use non-rerouted attempts. Returns deployment totals and up to 499 actor classes from retained history.
            parameters:
                - { $ref: "#/components/parameters/FromMs" }
                - { $ref: "#/components/parameters/ToMs" }
            responses:
                "200":
                    description: Retained history for the selected range.
                    headers:
                        Cache-Control: { $ref: "#/components/headers/NoStore" }
                    content:
                        application/json:
                            schema: { $ref: "#/components/schemas/OverviewMetrics" }
                "400": { $ref: "#/components/responses/InvalidRequest" }
                "401": { $ref: "#/components/responses/Unauthenticated" }
                "500": { $ref: "#/components/responses/Internal" }
    /v1/projects/{project_id}/observe/queue-waits:
        parameters:
            - { $ref: "#/components/parameters/ProjectId" }
        get:
            operationId: listQueueWaits
            tags: [Observability]
            summary: Get queue wait statistics
            description: Up to 500 actor instances ordered by admitted request count, then actor name and ID. Includes non-rerouted attempts with a queue wait.
            parameters:
                - { $ref: "#/components/parameters/FromMs" }
                - { $ref: "#/components/parameters/ToMs" }
                - name: actorName
                  in: query
                  schema: { type: string, minLength: 1, maxLength: 48, pattern: "^[A-Za-z0-9._-]+$" }
            responses:
                "200":
                    description: Retained history for the selected range.
                    headers:
                        Cache-Control: { $ref: "#/components/headers/NoStore" }
                    content:
                        application/json:
                            schema:
                                type: array
                                maxItems: 500
                                items: { $ref: "#/components/schemas/QueueWaitRow" }
                "400": { $ref: "#/components/responses/InvalidRequest" }
                "401": { $ref: "#/components/responses/Unauthenticated" }
                "500": { $ref: "#/components/responses/Internal" }
    /v1/projects/{project_id}/observe/websockets:
        parameters:
            - { $ref: "#/components/parameters/ProjectId" }
        get:
            operationId: listWebSocketSessions
            tags: [Observability]
            summary: Get WebSocket session history
            description: Up to 500 sessions ordered by latest start. Selects sessions whose retained activity span overlaps the inclusive range, keeping their full retained events and connect metadata.
            parameters:
                - { $ref: "#/components/parameters/FromMs" }
                - { $ref: "#/components/parameters/ToMs" }
            responses:
                "200":
                    description: Retained history for the selected range.
                    headers:
                        Cache-Control: { $ref: "#/components/headers/NoStore" }
                    content:
                        application/json:
                            schema:
                                type: array
                                maxItems: 500
                                items: { $ref: "#/components/schemas/SocketSession" }
                "400": { $ref: "#/components/responses/InvalidRequest" }
                "401": { $ref: "#/components/responses/Unauthenticated" }
                "500": { $ref: "#/components/responses/Internal" }
    /v1/projects/{project_id}/observe/requests/events:
        parameters:
            - { $ref: "#/components/parameters/ProjectId" }
        get:
            operationId: streamRequestHistory
            tags: [Observability]
            summary: Stream request history
            description: |
                SSE requests events contain TracePage JSON. Resume with resumeCursor;
                when reset=true, replace previous records. Error events contain text and close the stream.
            parameters:
                - name: after
                  in: query
                  description: resumeCursor; overrides Last-Event-ID.
                  schema: { type: string, maxLength: 4096 }
                - name: Last-Event-ID
                  in: header
                  description: Previous SSE event ID.
                  schema: { type: string, maxLength: 4096 }
            responses:
                "200": { $ref: "#/components/responses/EventStream" }
                "400": { $ref: "#/components/responses/InvalidRequest" }
                "401": { $ref: "#/components/responses/Unauthenticated" }
                "500": { $ref: "#/components/responses/Internal" }
    /v1/socket:
        get:
            operationId: openWebSocket
            tags: [WebSockets]
            summary: Open a WebSocket
            description: Pass websocketUrl from the find-websocket response directly to new WebSocket().
            servers:
                - url: https://{actorHost}
                  variables:
                      actorHost: { default: actor-host.example.com }
            security:
                - SocketTicket: []
            responses:
                "101": { description: WebSocket upgrade accepted. }
                "400": { $ref: "#/components/responses/UpgradeError" }
                "401": { description: Socket authorization rejected. Request a fresh URL. No response body. }
                "426":
                    description: Connection cannot be upgraded to a WebSocket.
                    content:
                        text/plain:
                            schema: { type: string }
                "503": { description: Actor host is stopping. No response body. }
webhooks:
    socketMessage:
        post:
            operationId: receiveSocketMessageEvent
            tags: [WebSockets]
            summary: Receive handled socket messages
            description: Set DURABLE_ACTORS_SOCKET_EVENT_URL to enable. When DURABLE_ACTORS_SECRET is configured, callbacks send it as a bearer API key; otherwise the authorization header is omitted. Delivery is best effort, without retries.
            requestBody:
                required: true
                content:
                    application/json:
                        schema: { $ref: "#/components/schemas/SocketMessageEvent" }
                        examples:
                            message:
                                value:
                                    eventId: 04c842c9-4532-467a-9831-f58f183b110e
                                    actorName: ChatRoom
                                    actorId: lobby
                                    triggerId: null
                                    connectionId: connection-1
                                    message: { type: text, data: '{"type":"post","text":"Hello"}' }
            responses:
                "2XX": { description: Accepted; no response body required. }
components:
    securitySchemes:
        ApiKey:
            type: http
            scheme: bearer
            description: Required when DURABLE_ACTORS_SECRET is set on the server. Never send it to browsers.
        ActorTicket:
            type: http
            scheme: bearer
            description: Short-lived actor capability returned by findActor. Never use the application API key at the actor host.
        ActorSession:
            type: http
            scheme: bearer
            description: Runtime-issued project-scoped session, accepted only for actor RPC discovery.
        SocketTicket:
            type: apiKey
            in: query
            name: key
            description: Included in websocketUrl. Keep the URL private.
    headers:
        NoStore:
            schema: { type: string, const: no-store }
    parameters:
        FromMs:
            name: fromMs
            in: query
            description: Inclusive lower bound in Unix milliseconds; must not exceed toMs.
            schema: { type: integer, minimum: 0, maximum: 9007199254740991 }
        ToMs:
            name: toMs
            in: query
            description: Inclusive upper bound in Unix milliseconds.
            schema: { type: integer, minimum: 0, maximum: 9007199254740991 }
        ProjectId:
            name: project_id
            in: path
            required: true
            schema: { type: string, pattern: "^[A-Za-z0-9._-]{1,64}$" }
        ActorName:
            name: actor_name
            in: path
            required: true
            schema: { type: string, pattern: "^[A-Za-z0-9._-]{1,48}$" }
        ActorId:
            name: actor_id
            in: path
            required: true
            schema: { type: string, pattern: "^[A-Za-z0-9._-]{1,128}$" }
    requestBodies:
        FindActor:
            required: true
            content:
                application/json:
                    schema: { $ref: "#/components/schemas/FindActorRequest" }
                    examples:
                        default: { value: {} }
                        regional: { value: { homeRegion: north-america-west } }
        FindWebSocket:
            required: true
            content:
                application/json:
                    schema: { $ref: "#/components/schemas/FindWebSocketRequest" }
                    examples:
                        socket: { value: { metadata: { userId: alice }, authorizationLifetimeMs: 900000 } }
    responses:
        Changed:
            description: Whether the deployment changed.
            content:
                application/json:
                    schema:
                        type: object
                        required: [changed]
                        properties:
                            changed: { type: boolean }
        ActorTarget:
            description: Owning host and RPC credentials. Timestamps use Unix milliseconds.
            headers:
                Cache-Control: { $ref: "#/components/headers/NoStore" }
            content:
                application/json:
                    schema: { $ref: "#/components/schemas/ActorTarget" }
        WebSocketGrant:
            description: Authorized WebSocket URL and deadlines. Timestamps use Unix milliseconds.
            headers:
                Cache-Control: { $ref: "#/components/headers/NoStore" }
            content:
                application/json:
                    schema: { $ref: "#/components/schemas/WebSocketGrant" }
        EventStream:
            description: Server-sent events.
            headers:
                Cache-Control: { $ref: "#/components/headers/NoStore" }
            content:
                text/event-stream:
                    schema: { type: string }
        InvalidRequest:
            description: Invalid request (invalid_request).
            content:
                application/json:
                    schema: { $ref: "#/components/schemas/Error" }
        Unauthenticated:
            description: Invalid or missing API key (unauthenticated).
            content:
                application/json:
                    schema: { $ref: "#/components/schemas/Error" }
        NotFound:
            description: Not found (not_found).
            content:
                application/json:
                    schema: { $ref: "#/components/schemas/Error" }
        Conflict:
            description: Deployment or region conflict (conflict).
            content:
                application/json:
                    schema: { $ref: "#/components/schemas/Error" }
        PayloadTooLarge:
            description: Request rejected by an upstream transport limit (payload_too_large).
            content:
                application/json:
                    schema: { $ref: "#/components/schemas/Error" }
        Internal:
            description: Server failure (internal).
            content:
                application/json:
                    schema: { $ref: "#/components/schemas/Error" }
        Unavailable:
            description: Temporarily unavailable (unavailable).
            content:
                application/json:
                    schema: { $ref: "#/components/schemas/Error" }
        UpgradeError:
            description: Invalid WebSocket upgrade request.
            content:
                text/plain:
                    schema: { type: string }
    schemas:
        OverviewMetrics:
            type: object
            required: [total, classes]
            properties:
                total: { $ref: "#/components/schemas/ClassMetrics" }
                classes:
                    type: array
                    maxItems: 499
                    items: { $ref: "#/components/schemas/ClassMetrics" }
        ClassMetrics:
            type: object
            required: [actorName, count, success, p95, queueP95]
            properties:
                actorName: { type: string, description: Empty for the deployment total. }
                count: { type: integer, minimum: 0 }
                success: { type: [number, "null"], minimum: 0, maximum: 100, description: Completed attempts as a percentage of non-rerouted attempts. }
                p95: { type: [number, "null"], minimum: 0, description: 95th percentile duration in milliseconds. }
                queueP95: { type: [number, "null"], minimum: 0, description: 95th percentile queue wait in milliseconds. }
        QueueWaitRow:
            type: object
            required: [actorName, actorId, admitted, averageMs, maxMs]
            properties:
                actorName: { type: string }
                actorId: { type: string }
                admitted: { type: integer, minimum: 1 }
                averageMs: { type: number, minimum: 0 }
                maxMs: { type: number, minimum: 0 }
        SocketSession:
            type: object
            required: [connectionId, actorName, actorId, hostId, openedAtMs, closedAtMs, lastSeenMs, messages, failures]
            properties:
                connectionId: { type: string }
                actorName: { type: string }
                actorId: { type: string }
                hostId: { type: [string, "null"] }
                openedAtMs: { type: [integer, "null"], minimum: 0 }
                closedAtMs: { type: [integer, "null"], minimum: 0 }
                lastSeenMs: { type: [integer, "null"], minimum: 0 }
                messages: { type: integer, minimum: 0 }
                failures: { type: integer, minimum: 0 }
                metadata: { description: Metadata saved with a retained onConnect event. }
        ActorBundle:
            type: object
            additionalProperties: false
            required: [bucket, files]
            properties:
                bucket: { type: string, minLength: 3 }
                files:
                    type: array
                    minItems: 1
                    description: Unique relative paths including exactly one actors.mjs or actors.pyz entrypoint. Objects must belong to one immutable artifact deployment.
                    items:
                        type: object
                        additionalProperties: false
                        required: [path, object, generation, sha256]
                        properties:
                            path: { type: string, minLength: 1 }
                            object: { type: string, minLength: 1 }
                            generation: { type: integer, minimum: 1 }
                            sha256: { type: string, pattern: "^[A-Za-z0-9_-]{43}$", description: Base64url-encoded SHA256 without padding. }
        LocalSource:
            type: object
            additionalProperties: false
            required: [workingDirectory]
            properties:
                workingDirectory:
                    type: string
                    pattern: "^/"
                    maxLength: 1024
                    description: Absolute project directory in the local development server.
                actorEntrypoint:
                    type: [string, "null"]
                    minLength: 1
                    maxLength: 1024
                    default: null
                    description: TypeScript or Python source path; null uses src/actors.ts.
        Deployment:
            type: object
            additionalProperties: false
            oneOf:
                - required: [bundle]
                - required: [localSource]
            properties:
                bundle: { $ref: "#/components/schemas/ActorBundle" }
                localSource: { $ref: "#/components/schemas/LocalSource" }
                secretRefs:
                    type: array
                    maxItems: 16
                    default: []
                    items: { type: string, pattern: "^[A-Za-z0-9._-]{1,255}$" }
                    description: Secret names for deployed actors.
                contract:
                    oneOf:
                        - { $ref: "#/components/schemas/PublicActorContract" }
                        - { type: "null" }
                    default: null
                    description: Optional; generated for hosted deployments.
        CurrentDeployment:
            type: object
            additionalProperties: false
            required: [secretRefs]
            oneOf:
                - required: [bundle]
                - required: [localSource]
            properties:
                bundle: { $ref: "#/components/schemas/ActorBundle" }
                localSource: { $ref: "#/components/schemas/LocalSource" }
                secretRefs: { $ref: "#/components/schemas/Deployment/properties/secretRefs" }
        PublicActorContract:
            type: object
            additionalProperties: false
            required: [version, actors]
            properties:
                typescript:
                    type: object
                    additionalProperties: false
                    required: [declarations, dependencies]
                    properties:
                        declarations: { type: string, minLength: 1 }
                        dependencies:
                            type: object
                            additionalProperties: { type: string, minLength: 1 }
                version: { type: integer, const: 1 }
                actors:
                    type: array
                    items:
                        type: object
                        additionalProperties: false
                        required: [actorName, socket, rpc]
                        properties:
                            actorName: { type: string }
                            description: { type: string, description: Actor documentation for generated clients. }
                            sandbox: { $ref: "#/components/schemas/SandboxOptions" }
                            socket:
                                type: object
                                additionalProperties: false
                                required: [version, actorName, schema, emittable]
                                properties:
                                    version: { type: integer, const: 1 }
                                    actorName: { type: string }
                                    schema: { type: object, description: JSON Schema for socket types. }
                                    emittable: { type: array, uniqueItems: true, items: { type: string } }
                            rpc:
                                type: object
                                additionalProperties: false
                                required: [schema, methods]
                                properties:
                                    schema: { type: object, description: JSON Schema for RPC types. }
                                    methods: { type: array, items: { $ref: "#/components/schemas/RpcMethod" } }
        SandboxOptions:
            type: object
            additionalProperties: false
            description: Optional actor sandbox overrides compiled from the class decorator. Omitted fields inherit deployment defaults.
            properties:
                cpu: { type: number, minimum: 0.1, maximum: 64, multipleOf: 0.001 }
                memoryMiB: { type: integer, minimum: 128, maximum: 262144 }
                idleTimeoutMs: { type: integer, minimum: 1, maximum: 86400000 }
                regions:
                    type: array
                    minItems: 1
                    maxItems: 7
                    uniqueItems: true
                    description: Allowed compute regions. Order is not a preference; existing actors retain their saved home.
                    items:
                        type: string
                        enum: [canada, north-america-east, north-america-central, north-america-south, north-america-west, europe-west, asia-southeast]
        RpcMethod:
            type: object
            additionalProperties: false
            required: [name, parameters, result]
            properties:
                name: { type: string }
                description: { type: string, description: Method documentation for generated clients. }
                parameters:
                    type: array
                    items:
                        type: object
                        additionalProperties: false
                        required: [name, type, optional, rest]
                        properties:
                            name: { type: string }
                            type: { $ref: "#/components/schemas/RpcType" }
                            optional: { type: boolean }
                            rest: { type: boolean }
                result:
                    oneOf:
                        - type: object
                          additionalProperties: false
                          required: [kind]
                          properties:
                              kind: { type: string, const: void }
                        - type: object
                          additionalProperties: false
                          required: [kind, type]
                          properties:
                              kind: { type: string, const: value }
                              type: { $ref: "#/components/schemas/RpcType" }
        RpcType:
            type: object
            additionalProperties: false
            required: ["$ref"]
            properties:
                $ref: { type: string, description: Reference into rpc.schema. }
        ActorInvocation:
            type: object
            additionalProperties: false
            required: [requestId, ownerEpoch, method, args]
            properties:
                requestId: { type: string, minLength: 1, maxLength: 255 }
                ownerEpoch: { type: integer, minimum: 1, maximum: 9007199254740991 }
                method: { type: string, minLength: 1, maxLength: 128 }
                args: { type: array, items: {} }
        ControlPlaneInvocation:
            type: object
            additionalProperties: false
            required: [requestId, method, args]
            properties:
                requestId: { type: string, minLength: 1, maxLength: 255 }
                method: { type: string, minLength: 1, maxLength: 128 }
                args: { type: array, items: {} }
                homeRegion: { type: [string, "null"], minLength: 1, maxLength: 64, pattern: "^[a-z0-9-]+$" }
        ControlPlaneInvocationReply:
            type: object
            required: [target, outcome]
            properties:
                target: { $ref: "#/components/schemas/ActorTarget" }
                outcome:
                    oneOf:
                        - { $ref: "#/components/schemas/ActorInvocationReply" }
                        - type: object
                          required: [type]
                          properties:
                              type: { const: unauthenticated }
        ActorInvocationMetadata:
            type: object
            description: Timing and host-start context finalized once by the host request tracker and shared with the response, observability and diagnostic log. Omitted for requests denied before host dispatch.
            required: [durationMs, queueWaitMs, hostState, routingMs]
            properties:
                routingMs:
                    type: number
                    minimum: 0
                    description: Gateway time before the final host dispatch, including host discovery, provisioning and routing retries. Separate from durationMs.
                durationMs:
                    type: number
                    minimum: 0
                    description: Total traced host duration in milliseconds, including queue wait, state loading, actor execution and persistence. Ends before the result handoff to the HTTP handler; excludes network transit and subsequent HTTP-handler socket delivery.
                queueWaitMs:
                    type: [number, "null"]
                    minimum: 0
                    description: Milliseconds from host submission until the actor worker begins processing, before state loading. Null when processing never begins; otherwise no greater than durationMs.
                hostState:
                    type: string
                    enum: [cold, warm]
                    description: Cold when this invocation required actor-host provisioning or activation during routing; warm when routed to an existing host. This is independent of the host's actor-state cache. Host duration excludes provisioning time.
        ActorInvocationReply:
            oneOf:
                - type: object
                  required: [type, result]
                  properties:
                      metadata: { $ref: "#/components/schemas/ActorInvocationMetadata" }
                      type: { const: completed }
                      result: {}
                - type: object
                  required: [type, code, message]
                  properties:
                      metadata: { $ref: "#/components/schemas/ActorInvocationMetadata" }
                      type: { const: failed }
                      code: { type: string, minLength: 1, description: "Includes actor_error, unavailable and outcome_unknown." }
                      message: { type: string }
                - type: object
                  required: [type, reason]
                  properties:
                      metadata: { $ref: "#/components/schemas/ActorInvocationMetadata" }
                      type: { const: not_executed }
                      reason:
                          type: string
                          enum: [stale_owner, host_unavailable, upstream_not_reached]
        ActorSocketEffect:
            type: object
            description: Host-validated socket effect. Broadcasts require message, except_connection_ids and tags; connection-specific effects require connection_id.
            required: [type]
            properties:
                type: { enum: [state_snapshot, state_update, send, broadcast, close, reject, set_metadata, set_tags] }
                connection_id: { type: string }
                message:
                    type: object
                    required: [type, data]
                    properties:
                        type: { enum: [text, binary] }
                        data: { type: string, description: UTF-8 text or base64-encoded binary. }
                except_connection_ids: { type: array, items: { type: string }, maxItems: 128 }
                tags: { type: array, items: { type: string }, maxItems: 128 }
                tag_match: { enum: [all, any] }
                metadata: {}
                state: { type: object }
                changes: { type: object }
                removed: { type: array, items: { type: string } }
                version: { type: integer, minimum: 0 }
                code: { type: integer, description: "1000 or 3000–4999." }
                reason: { type: string }
        IssueActorSession:
            type: object
            additionalProperties: false
            required: [subject, expiresAtMs]
            properties:
                subject: { type: string, minLength: 1, maxLength: 128, description: "Stable opaque credential fingerprint, not a secret." }
                expiresAtMs:
                    {
                        type: integer,
                        format: int64,
                        description: "Absolute authorization deadline in Unix milliseconds. Set this from the start of application authentication, not after it completes."
                    }
        FindActorRequest:
            type: object
            additionalProperties: false
            properties:
                homeRegion: { $ref: "#/components/schemas/HomeRegion" }
        FindWebSocketRequest:
            type: object
            additionalProperties: false
            required: [metadata]
            properties:
                homeRegion: { $ref: "#/components/schemas/HomeRegion" }
                metadata: { description: Required connection metadata; may be null. Maximum 64 KiB of JSON. }
                authorizationLifetimeMs: { type: integer, minimum: 1000, maximum: 86400000, default: 900000 }
        HomeRegion:
            type: [string, "null"]
            pattern: "^[a-z0-9._-]{1,64}$"
            description: Region for new actors; cannot change an existing actor's region. Omit or use null for automatic placement.
        ActorTarget:
            type: object
            required: [homeRegion, route, token, ownerEpoch, expiresAtMs]
            properties:
                homeRegion: { type: string }
                route: { type: string, format: uri, description: HTTP(S) origin of the actor HTTP host. }
                token: { type: string, description: Bearer token for actor RPCs. }
                ownerEpoch: { type: integer, minimum: 0 }
                expiresAtMs:
                    type: integer
                    format: int64
                    description: Route cache deadline in Unix milliseconds, bounded by the host idle timeout, host lease, and credential expiry. May precede the token's expiry.
        WebSocketGrant:
            type: object
            required: [homeRegion, websocketUrl, connectByMs, authorizedUntilMs]
            properties:
                homeRegion: { type: string }
                websocketUrl: { type: string, format: uri }
                connectByMs: { type: integer, format: int64, description: Connect before this time. }
                authorizedUntilMs: { type: integer, format: int64, description: Connection expires at this time. }
        Inventory:
            type: object
            required: [actors, connectionsComplete]
            properties:
                connectionsComplete:
                    type: boolean
                    description: False when a gateway could not be queried; connection lists and counts may be incomplete.
                actors:
                    type: array
                    items:
                        type: object
                        required: [actorName, live, dormant, unknown, instances]
                        properties:
                            actorName: { type: string }
                            live: { type: integer, minimum: 0 }
                            dormant: { type: integer, minimum: 0 }
                            unknown: { type: integer, minimum: 0 }
                            instances:
                                type: array
                                items:
                                    type: object
                                    required: [actorId, status, connections, waiting]
                                    properties:
                                        actorId: { type: string }
                                        status: { type: string, enum: [live, dormant, unknown] }
                                        connections:
                                            type: array
                                            items:
                                                type: object
                                                required: [id, metadata]
                                                properties:
                                                    id: { type: string }
                                                    metadata: {}
                                        waiting:
                                            type: [array, "null"]
                                            items:
                                                type: object
                                                required: [id, operation]
                                                properties:
                                                    id: { type: string }
                                                    operation: { type: string }
        TracePage:
            type: object
            required: [epoch, cursor, capacity, evicted, dropped, persistenceFailed, records, nextCursor, resumeCursor, reset]
            properties:
                epoch: { type: string }
                cursor: { type: integer, minimum: 0 }
                capacity: { type: integer, minimum: 0 }
                evicted: { type: integer, minimum: 0 }
                dropped: { type: integer, minimum: 0 }
                persistenceFailed: { type: boolean }
                records: { type: array, items: { $ref: "#/components/schemas/TraceRecord" } }
                nextCursor: { type: [string, "null"] }
                resumeCursor: { type: string }
                reset: { type: boolean }
        StateAttribution:
            type: [object, "null"]
            required: [operation, connectionId, committedAtMs, interleaved]
            properties:
                operation: { type: string }
                connectionId: { type: [string, "null"] }
                committedAtMs: { type: integer, minimum: 0 }
                interleaved: { type: boolean, description: Other requests may have contributed to this snapshot during reentrant execution. }
        StateRecord:
            type: object
            required: [stateVersion, ownerEpoch, requestId, attribution]
            properties:
                stateVersion: { type: integer, minimum: 1 }
                ownerEpoch: { type: integer, minimum: 1 }
                requestId: { type: string }
                attribution: { $ref: "#/components/schemas/StateAttribution" }
        ActorStateResponse:
            type: object
            required: [snapshot, schema]
            properties:
                snapshot:
                    anyOf:
                        - type: "null"
                        - allOf:
                              - { $ref: "#/components/schemas/StateRecord" }
                              - type: object
                                required: [state]
                                properties:
                                    state: { type: object, additionalProperties: true }
                schema: { type: [object, "null"], description: Persisted field schema from the current deployment contract. }
        ActorStateHistory:
            type: object
            required: [records, nextBefore]
            properties:
                records: { type: array, items: { $ref: "#/components/schemas/StateRecord" } }
                nextBefore: { type: [integer, "null"], minimum: 1 }
        TraceRecord:
            type: object
            required: [projectId, sequence, eventId, hostId, sessionId, requestId, actorName, actorId, kind, operation, connectionId, startedAtMs, routingMs, durationMs, queueWaitMs, hostState, outcome]
            properties:
                projectId: { type: string, pattern: "^[A-Za-z0-9._-]{1,64}$" }
                metadata: { description: Bounded JSON metadata from an onConnect event, when retained. }
                sequence: { type: integer, minimum: 0 }
                eventId: { type: string, format: uuid }
                hostId: { type: string }
                sessionId: { type: string }
                stateVersion: { type: integer, minimum: 1, description: Latest committed version observed when this request completed; signals a storage refresh without duplicating state. }
                requestId: { type: string }
                actorName: { type: string }
                actorId: { type: string }
                kind: { type: string, enum: [method, websocket] }
                operation: { type: string }
                connectionId: { type: [string, "null"] }
                startedAtMs: { type: integer, minimum: 0 }
                routingMs: { type: number, minimum: 0, description: "Gateway routing and startup time before host dispatch." }
                durationMs: { type: number, minimum: 0 }
                queueWaitMs: { type: [number, "null"], minimum: 0 }
                hostState: { type: string, enum: [cold, warm], description: "Whether routing required host startup. Defaults to warm for historical traces without this field." }
                outcome: { type: string, enum: [completed, failed, rejected, rerouted, interrupted] }
        SocketMessageEvent:
            type: object
            required: [eventId, actorName, actorId, triggerId, connectionId, message]
            properties:
                eventId: { type: string, format: uuid }
                actorName: { type: string }
                actorId: { type: string }
                triggerId: { type: [string, "null"] }
                connectionId: { type: string }
                message:
                    oneOf:
                        - type: object
                          required: [type, data]
                          properties:
                              type: { type: string, const: text }
                              data: { type: string, description: JSON-encoded message. }
                        - type: object
                          required: [type, data]
                          properties:
                              type: { type: string, const: binary }
                              data: { type: string, contentEncoding: base64 }
                          description: Unsupported by TypeScript actors.
        Error:
            type: object
            required: [error]
            properties:
                error:
                    type: object
                    required: [code, message]
                    properties:
                        code: { type: string }
                        message: { type: string }