@moqtap/codec 0.2.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +100 -99
- package/dist/{chunk-RZHAPEXO.js → chunk-2A57DRXV.js} +36 -10
- package/dist/{chunk-73MWUKSJ.js → chunk-2UTVXWFF.js} +190 -102
- package/dist/{chunk-JTVCOMBI.cjs → chunk-3XKO6PCR.cjs} +290 -183
- package/dist/{chunk-ACQ4CUJP.cjs → chunk-4BDEU3D4.cjs} +237 -158
- package/dist/{chunk-4N4INRE7.cjs → chunk-4HBKHNU2.cjs} +144 -110
- package/dist/{chunk-2ZT6CVSE.js → chunk-4IVZZOY3.js} +269 -162
- package/dist/{chunk-GLBQDG4L.cjs → chunk-5O764MBD.cjs} +508 -117
- package/dist/chunk-7KBAWOBA.js +1212 -0
- package/dist/{chunk-JSQM2MG3.js → chunk-7QOPNSDF.js} +44 -12
- package/dist/{chunk-SYHW3FLI.cjs → chunk-7RE6KSIY.cjs} +28 -8
- package/dist/{chunk-YG5KJESI.js → chunk-AY6IAHUM.js} +28 -8
- package/dist/{chunk-EFM5T7OM.js → chunk-BLQDWOSG.js} +36 -10
- package/dist/{chunk-UYXTY6ZQ.cjs → chunk-E65QKRSN.cjs} +20 -12
- package/dist/{chunk-BISI45MN.cjs → chunk-EAHE3IOG.cjs} +44 -12
- package/dist/{chunk-PZBPH2D7.js → chunk-GCBFHZW6.js} +216 -137
- package/dist/{chunk-GXEW4COZ.cjs → chunk-H5NSL4MO.cjs} +36 -10
- package/dist/chunk-HZHSO7EW.cjs +1212 -0
- package/dist/{chunk-KZCYQ7ED.cjs → chunk-IILNSDEQ.cjs} +69 -41
- package/dist/{chunk-4XYGE53S.cjs → chunk-J3XCPBW3.cjs} +36 -10
- package/dist/{chunk-6AEHWULA.cjs → chunk-JKOEJZ5B.cjs} +28 -8
- package/dist/{chunk-RUPCJTC3.cjs → chunk-JL3NEW3O.cjs} +23 -1
- package/dist/{chunk-G7GI7LJA.js → chunk-LORZMJJB.js} +36 -10
- package/dist/{chunk-DUBCL3WF.cjs → chunk-LV5C6MEC.cjs} +36 -10
- package/dist/{chunk-ENURAVHI.cjs → chunk-MYXAD5JC.cjs} +44 -12
- package/dist/{chunk-FXZ2MYKJ.js → chunk-MZ7HUCGJ.js} +20 -12
- package/dist/{chunk-S74DWJE2.cjs → chunk-OKG2HT25.cjs} +277 -88
- package/dist/{chunk-BGWGVINJ.cjs → chunk-PKEOQSSZ.cjs} +144 -110
- package/dist/{chunk-2GODRVT5.js → chunk-Q46ZURKX.js} +325 -48
- package/dist/{chunk-UR6JKS56.js → chunk-Q7IGWV3P.js} +41 -9
- package/dist/{chunk-XSNX2IUJ.js → chunk-RW4UG7CN.js} +121 -87
- package/dist/{chunk-DWK5ZQZ4.js → chunk-RZTLQAKF.js} +28 -8
- package/dist/{chunk-UNS34PTA.cjs → chunk-S6IPIN66.cjs} +44 -12
- package/dist/{chunk-YIG2C3LF.cjs → chunk-SDWRXXOO.cjs} +214 -126
- package/dist/{chunk-CEH7ESNC.js → chunk-SHMA4PBY.js} +121 -87
- package/dist/{chunk-MC7W6PMI.js → chunk-U3ZVLT5L.js} +483 -135
- package/dist/{chunk-VJUUZ4W2.cjs → chunk-UJU63EFY.cjs} +374 -97
- package/dist/{chunk-7L43FE6P.js → chunk-VOU7PNHI.js} +23 -1
- package/dist/{chunk-E6E3NQYU.js → chunk-WRHGCVYN.js} +44 -12
- package/dist/{chunk-FPISPJ5N.cjs → chunk-XNWYLVGU.cjs} +529 -181
- package/dist/{chunk-U3IPZYPX.js → chunk-XS77RBY7.js} +228 -39
- package/dist/{chunk-JGG7CMSZ.cjs → chunk-XZE5R57R.cjs} +144 -110
- package/dist/{chunk-77MNXX3M.js → chunk-Y6KCSM3V.js} +121 -87
- package/dist/{chunk-TLYNOOQP.cjs → chunk-YTPZZI2M.cjs} +41 -9
- package/dist/{chunk-7DUBLRXC.js → chunk-YWRCSQBA.js} +44 -12
- package/dist/{chunk-MRJWLGYH.js → chunk-Z3VKP3PJ.js} +69 -41
- package/dist/{chunk-E6P74GDT.js → chunk-Z6U26IRI.js} +464 -73
- package/dist/{codec-FvGCxIhr.d.ts → codec-25u4_1HS.d.ts} +4 -4
- package/dist/{codec-DRcsBCsb.d.ts → codec-3Ppy_5Gd.d.ts} +4 -4
- package/dist/{codec-BdVMRMOI.d.ts → codec-BB0U8MF2.d.cts} +4 -4
- package/dist/{codec-B2cH-f5V.d.cts → codec-BHHfBTnV.d.ts} +4 -4
- package/dist/{codec-B5K73Bdj.d.ts → codec-BN6jk0Td.d.cts} +4 -4
- package/dist/{codec-R8GrCPt2.d.ts → codec-BU0gaSZm.d.ts} +4 -4
- package/dist/{codec-Bq-tLtfP.d.ts → codec-C-Yk2RNa.d.ts} +4 -4
- package/dist/codec-CFWQY9Lj.d.cts +18 -0
- package/dist/{codec-CPlK3Pi5.d.ts → codec-COy4uuPO.d.cts} +4 -4
- package/dist/codec-CewFCsEy.d.ts +18 -0
- package/dist/{codec-KXHvXZVb.d.cts → codec-Ck7ZwFF1.d.cts} +4 -4
- package/dist/{codec-DZhZSIii.d.cts → codec-D2QVSH9D.d.ts} +4 -4
- package/dist/{codec-BwFgpeQu.d.ts → codec-DDUBJGn0.d.cts} +4 -4
- package/dist/{codec-BFeliJFc.d.ts → codec-DNfml-se.d.ts} +4 -4
- package/dist/{codec-C4n1PS09.d.cts → codec-DoOGjjDq.d.cts} +4 -4
- package/dist/{codec-Bap882Fh.d.cts → codec-J7ekOSMc.d.ts} +4 -4
- package/dist/{codec-SKBeHQk7.d.ts → codec-R9TJCq-E.d.cts} +4 -4
- package/dist/{codec-DNUIgLqc.d.cts → codec-ZwV-Njt6.d.ts} +4 -4
- package/dist/{codec-HgBgHkFI.d.cts → codec-j819z_hL.d.cts} +4 -4
- package/dist/{codec-DY4QH364.d.cts → codec-w8z2j_uo.d.cts} +4 -4
- package/dist/{codec-CPvPq0sb.d.cts → codec-wtt6WF1K.d.ts} +4 -4
- package/dist/{codec-BUMjz0J4.d.cts → codec-z6_2PSzi.d.cts} +4 -4
- package/dist/{draft7-session.cjs → draft07-session.cjs} +2 -2
- package/dist/draft07-session.d.cts +8 -0
- package/dist/draft07-session.d.ts +8 -0
- package/dist/{draft7-session.js → draft07-session.js} +1 -1
- package/dist/draft07.cjs +129 -0
- package/dist/draft07.d.cts +67 -0
- package/dist/draft07.d.ts +67 -0
- package/dist/draft07.js +129 -0
- package/dist/draft08-session.cjs +6 -0
- package/dist/draft08-session.d.cts +8 -0
- package/dist/draft08-session.d.ts +8 -0
- package/dist/{draft8-session.js → draft08-session.js} +1 -1
- package/dist/draft08.cjs +119 -0
- package/dist/{draft8.d.cts → draft08.d.cts} +15 -13
- package/dist/{draft8.d.ts → draft08.d.ts} +15 -13
- package/dist/{draft8.js → draft08.js} +7 -4
- package/dist/draft09-session.cjs +6 -0
- package/dist/draft09-session.d.cts +8 -0
- package/dist/draft09-session.d.ts +8 -0
- package/dist/{draft9-session.js → draft09-session.js} +1 -1
- package/dist/draft09.cjs +119 -0
- package/dist/{draft9.d.cts → draft09.d.cts} +15 -13
- package/dist/{draft9.d.ts → draft09.d.ts} +15 -13
- package/dist/{draft9.js → draft09.js} +7 -4
- package/dist/draft10-session.cjs +2 -2
- package/dist/draft10-session.d.cts +6 -6
- package/dist/draft10-session.d.ts +6 -6
- package/dist/draft10-session.js +1 -1
- package/dist/draft10.cjs +8 -5
- package/dist/draft10.d.cts +14 -12
- package/dist/draft10.d.ts +14 -12
- package/dist/draft10.js +16 -13
- package/dist/draft11-session.cjs +2 -2
- package/dist/draft11-session.d.cts +6 -6
- package/dist/draft11-session.d.ts +6 -6
- package/dist/draft11-session.js +1 -1
- package/dist/draft11.cjs +8 -5
- package/dist/draft11.d.cts +14 -12
- package/dist/draft11.d.ts +14 -12
- package/dist/draft11.js +16 -13
- package/dist/draft12-session.cjs +2 -2
- package/dist/draft12-session.d.cts +6 -6
- package/dist/draft12-session.d.ts +6 -6
- package/dist/draft12-session.js +1 -1
- package/dist/draft12.cjs +8 -5
- package/dist/draft12.d.cts +16 -14
- package/dist/draft12.d.ts +16 -14
- package/dist/draft12.js +16 -13
- package/dist/draft13-session.cjs +2 -2
- package/dist/draft13-session.d.cts +6 -6
- package/dist/draft13-session.d.ts +6 -6
- package/dist/draft13-session.js +1 -1
- package/dist/draft13.cjs +8 -5
- package/dist/draft13.d.cts +16 -14
- package/dist/draft13.d.ts +16 -14
- package/dist/draft13.js +16 -13
- package/dist/draft14-session.cjs +2 -2
- package/dist/draft14-session.d.cts +6 -6
- package/dist/draft14-session.d.ts +6 -6
- package/dist/draft14-session.js +1 -1
- package/dist/draft14.cjs +14 -5
- package/dist/draft14.d.cts +14 -12
- package/dist/draft14.d.ts +14 -12
- package/dist/draft14.js +13 -4
- package/dist/draft15-session.cjs +2 -2
- package/dist/draft15-session.d.cts +6 -6
- package/dist/draft15-session.d.ts +6 -6
- package/dist/draft15-session.js +1 -1
- package/dist/draft15.cjs +8 -5
- package/dist/draft15.d.cts +14 -12
- package/dist/draft15.d.ts +14 -12
- package/dist/draft15.js +16 -13
- package/dist/draft16-session.cjs +2 -2
- package/dist/draft16-session.d.cts +6 -6
- package/dist/draft16-session.d.ts +6 -6
- package/dist/draft16-session.js +1 -1
- package/dist/draft16.cjs +8 -5
- package/dist/draft16.d.cts +14 -12
- package/dist/draft16.d.ts +14 -12
- package/dist/draft16.js +16 -13
- package/dist/draft17-session.cjs +2 -2
- package/dist/draft17-session.d.cts +7 -7
- package/dist/draft17-session.d.ts +7 -7
- package/dist/draft17-session.js +1 -1
- package/dist/draft17.cjs +8 -5
- package/dist/draft17.d.cts +11 -9
- package/dist/draft17.d.ts +11 -9
- package/dist/draft17.js +16 -13
- package/dist/index.cjs +52 -74
- package/dist/index.d.cts +41 -60
- package/dist/index.d.ts +41 -60
- package/dist/index.js +40 -62
- package/dist/{session-types-CJIFbTPd.d.ts → session-types-C7UONex5.d.cts} +28 -27
- package/dist/{session-types-Cbq8IGCP.d.cts → session-types-X-IYEGoG.d.ts} +28 -27
- package/dist/session.cjs +46 -13
- package/dist/session.d.cts +29 -11
- package/dist/session.d.ts +29 -11
- package/dist/session.js +46 -13
- package/dist/{types-DxSFvL2b.d.cts → types--Q7_DcvP.d.cts} +43 -39
- package/dist/{types-DxSFvL2b.d.ts → types--Q7_DcvP.d.ts} +43 -39
- package/dist/{types-B0FT5Qs2.d.cts → types-0IWbU9Z_.d.cts} +36 -36
- package/dist/{types-B0FT5Qs2.d.ts → types-0IWbU9Z_.d.ts} +36 -36
- package/dist/{types-gQsr0AAA.d.cts → types-B3g5G9KP.d.cts} +36 -36
- package/dist/{types-gQsr0AAA.d.ts → types-B3g5G9KP.d.ts} +36 -36
- package/dist/{types-Pme7sua0.d.cts → types-BFpFNM_m.d.cts} +57 -32
- package/dist/{types-Pme7sua0.d.ts → types-BFpFNM_m.d.ts} +57 -32
- package/dist/{types-8gUGeMgs.d.cts → types-Br7fm2mf.d.cts} +48 -26
- package/dist/{types-8gUGeMgs.d.ts → types-Br7fm2mf.d.ts} +48 -26
- package/dist/{types-BeAVNU-F.d.cts → types-C2qKTRR_.d.cts} +50 -45
- package/dist/{types-BeAVNU-F.d.ts → types-C2qKTRR_.d.ts} +50 -45
- package/dist/{types-DKpsfD3i.d.cts → types-DEaypVsD.d.cts} +115 -55
- package/dist/{types-DKpsfD3i.d.ts → types-DEaypVsD.d.ts} +115 -55
- package/dist/types-Dl4IaAHR.d.cts +282 -0
- package/dist/types-Dl4IaAHR.d.ts +282 -0
- package/dist/{types-CDa7F5ct.d.cts → types-DrQpTW1G.d.cts} +58 -50
- package/dist/{types-CDa7F5ct.d.ts → types-DrQpTW1G.d.ts} +58 -50
- package/dist/types-DuIO7cWK.d.cts +25 -0
- package/dist/types-DuIO7cWK.d.ts +25 -0
- package/dist/{types-B9A2g05r.d.cts → types-DuxfOYiO.d.cts} +47 -31
- package/dist/{types-B9A2g05r.d.ts → types-DuxfOYiO.d.ts} +47 -31
- package/dist/{types-D1dI_oTX.d.cts → types-jV1yDDBA.d.cts} +36 -36
- package/dist/{types-D1dI_oTX.d.ts → types-jV1yDDBA.d.ts} +36 -36
- package/package.json +192 -192
- package/src/core/buffer-reader.ts +130 -130
- package/src/core/buffer-writer.ts +100 -100
- package/src/core/errors.ts +1 -1
- package/src/core/hex.ts +21 -21
- package/src/core/session-types.ts +61 -59
- package/src/core/types.ts +18 -361
- package/src/drafts/draft07/codec.ts +1058 -938
- package/src/drafts/draft07/data-streams.ts +240 -240
- package/src/drafts/draft07/index.ts +124 -89
- package/src/drafts/draft07/messages.ts +76 -42
- package/src/drafts/draft07/rules.ts +107 -101
- package/src/drafts/draft07/session-fsm.ts +315 -287
- package/src/drafts/draft07/session.ts +8 -6
- package/src/drafts/draft07/types.ts +406 -72
- package/src/drafts/draft07/varint.ts +51 -51
- package/src/drafts/draft08/codec.ts +985 -953
- package/src/drafts/draft08/data-streams.ts +363 -359
- package/src/drafts/draft08/index.ts +10 -9
- package/src/drafts/draft08/messages.ts +59 -59
- package/src/drafts/draft08/rules.ts +73 -73
- package/src/drafts/draft08/session-fsm.ts +335 -303
- package/src/drafts/draft08/session.ts +6 -7
- package/src/drafts/draft08/types.ts +380 -384
- package/src/drafts/draft09/codec.ts +977 -945
- package/src/drafts/draft09/data-streams.ts +336 -332
- package/src/drafts/draft09/index.ts +10 -9
- package/src/drafts/draft09/messages.ts +59 -59
- package/src/drafts/draft09/rules.ts +73 -73
- package/src/drafts/draft09/session-fsm.ts +335 -303
- package/src/drafts/draft09/session.ts +6 -7
- package/src/drafts/draft09/types.ts +380 -384
- package/src/drafts/draft10/codec.ts +977 -945
- package/src/drafts/draft10/data-streams.ts +336 -332
- package/src/drafts/draft10/index.ts +10 -9
- package/src/drafts/draft10/messages.ts +59 -59
- package/src/drafts/draft10/rules.ts +73 -73
- package/src/drafts/draft10/session-fsm.ts +335 -303
- package/src/drafts/draft10/session.ts +6 -7
- package/src/drafts/draft10/types.ts +380 -384
- package/src/drafts/draft11/codec.ts +1054 -988
- package/src/drafts/draft11/data-streams.ts +316 -269
- package/src/drafts/draft11/index.ts +10 -9
- package/src/drafts/draft11/messages.ts +60 -59
- package/src/drafts/draft11/rules.ts +73 -73
- package/src/drafts/draft11/session-fsm.ts +359 -333
- package/src/drafts/draft11/session.ts +6 -7
- package/src/drafts/draft11/types.ts +385 -381
- package/src/drafts/draft12/codec.ts +1178 -1122
- package/src/drafts/draft12/data-streams.ts +324 -275
- package/src/drafts/draft12/index.ts +10 -9
- package/src/drafts/draft12/messages.ts +67 -66
- package/src/drafts/draft12/rules.ts +79 -79
- package/src/drafts/draft12/session-fsm.ts +384 -358
- package/src/drafts/draft12/session.ts +6 -7
- package/src/drafts/draft12/types.ts +424 -419
- package/src/drafts/draft13/codec.ts +1296 -1206
- package/src/drafts/draft13/data-streams.ts +326 -275
- package/src/drafts/draft13/index.ts +10 -9
- package/src/drafts/draft13/messages.ts +73 -68
- package/src/drafts/draft13/rules.ts +81 -81
- package/src/drafts/draft13/session-fsm.ts +392 -366
- package/src/drafts/draft13/session.ts +6 -7
- package/src/drafts/draft13/types.ts +447 -438
- package/src/drafts/draft14/codec.ts +1347 -1043
- package/src/drafts/draft14/data-streams.ts +831 -813
- package/src/drafts/draft14/index.ts +17 -9
- package/src/drafts/draft14/messages.ts +65 -65
- package/src/drafts/draft14/rules.ts +81 -81
- package/src/drafts/draft14/session-fsm.ts +415 -405
- package/src/drafts/draft14/session.ts +6 -7
- package/src/drafts/draft14/types.ts +451 -381
- package/src/drafts/draft15/codec.ts +1138 -978
- package/src/drafts/draft15/data-streams.ts +842 -794
- package/src/drafts/draft15/index.ts +10 -9
- package/src/drafts/draft15/messages.ts +54 -53
- package/src/drafts/draft15/rules.ts +67 -67
- package/src/drafts/draft15/session-fsm.ts +319 -299
- package/src/drafts/draft15/session.ts +6 -7
- package/src/drafts/draft15/types.ts +357 -339
- package/src/drafts/draft16/codec.ts +1242 -966
- package/src/drafts/draft16/data-streams.ts +835 -789
- package/src/drafts/draft16/index.ts +10 -9
- package/src/drafts/draft16/messages.ts +56 -55
- package/src/drafts/draft16/rules.ts +69 -69
- package/src/drafts/draft16/session-fsm.ts +319 -299
- package/src/drafts/draft16/session.ts +6 -7
- package/src/drafts/draft16/types.ts +386 -357
- package/src/drafts/draft17/codec.ts +1209 -971
- package/src/drafts/draft17/data-streams.ts +969 -758
- package/src/drafts/draft17/index.ts +9 -7
- package/src/drafts/draft17/messages.ts +43 -42
- package/src/drafts/draft17/rules.ts +58 -58
- package/src/drafts/draft17/session-fsm.ts +248 -216
- package/src/drafts/draft17/session.ts +5 -5
- package/src/drafts/draft17/types.ts +337 -313
- package/src/index.ts +85 -274
- package/src/session.ts +63 -25
- package/dist/chunk-FZDIEHQL.cjs +0 -1042
- package/dist/chunk-HDWJ2GDE.js +0 -24
- package/dist/chunk-KNDYS3DK.cjs +0 -24
- package/dist/chunk-N2KBF5Q2.js +0 -1042
- package/dist/draft7-session.d.cts +0 -7
- package/dist/draft7-session.d.ts +0 -7
- package/dist/draft7.cjs +0 -72
- package/dist/draft7.d.cts +0 -148
- package/dist/draft7.d.ts +0 -148
- package/dist/draft7.js +0 -72
- package/dist/draft8-session.cjs +0 -6
- package/dist/draft8-session.d.cts +0 -8
- package/dist/draft8-session.d.ts +0 -8
- package/dist/draft8.cjs +0 -116
- package/dist/draft9-session.cjs +0 -6
- package/dist/draft9-session.d.cts +0 -8
- package/dist/draft9-session.d.ts +0 -8
- package/dist/draft9.cjs +0 -116
- package/dist/types-QNXoxC9Y.d.cts +0 -236
- package/dist/types-QNXoxC9Y.d.ts +0 -236
- package/src/drafts/draft07/announce-fsm.ts +0 -2
- package/src/drafts/draft07/parameters.ts +0 -12
- package/src/drafts/draft07/subscription-fsm.ts +0 -3
|
@@ -7,84 +7,84 @@ import type {
|
|
|
7
7
|
SubscriptionState,
|
|
8
8
|
TransitionResult,
|
|
9
9
|
ValidationResult,
|
|
10
|
-
} from
|
|
10
|
+
} from '../../core/session-types.js'
|
|
11
11
|
import {
|
|
12
12
|
CLIENT_ONLY_MESSAGES,
|
|
13
13
|
getLegalIncoming,
|
|
14
14
|
getLegalOutgoing,
|
|
15
15
|
SERVER_ONLY_MESSAGES,
|
|
16
|
-
} from
|
|
17
|
-
import type { Draft12Message, Draft12MessageType } from
|
|
16
|
+
} from './rules.js'
|
|
17
|
+
import type { Draft12Message, Draft12MessageType } from './types.js'
|
|
18
18
|
|
|
19
19
|
function violation(
|
|
20
|
-
code: ProtocolViolation<Draft12MessageType>[
|
|
20
|
+
code: ProtocolViolation<Draft12MessageType>['code'],
|
|
21
21
|
message: string,
|
|
22
22
|
currentPhase: SessionPhase,
|
|
23
23
|
offendingMessage: Draft12MessageType,
|
|
24
24
|
): ProtocolViolation<Draft12MessageType> {
|
|
25
|
-
return { code, message, currentPhase, offendingMessage }
|
|
25
|
+
return { code, message, currentPhase, offendingMessage }
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export class Draft12SessionFSM {
|
|
29
|
-
private _phase: SessionPhase =
|
|
30
|
-
private _role:
|
|
31
|
-
private _subscriptions = new Map<bigint, SubscriptionState>()
|
|
32
|
-
private _announces = new Map<string, AnnounceState>()
|
|
33
|
-
private _fetches = new Map<bigint, FetchState>()
|
|
34
|
-
private _requestIds = new Set<bigint>()
|
|
29
|
+
private _phase: SessionPhase = 'idle'
|
|
30
|
+
private _role: 'client' | 'server'
|
|
31
|
+
private _subscriptions = new Map<bigint, SubscriptionState>()
|
|
32
|
+
private _announces = new Map<string, AnnounceState>()
|
|
33
|
+
private _fetches = new Map<bigint, FetchState>()
|
|
34
|
+
private _requestIds = new Set<bigint>()
|
|
35
35
|
|
|
36
|
-
constructor(role:
|
|
37
|
-
this._role = role
|
|
36
|
+
constructor(role: 'client' | 'server') {
|
|
37
|
+
this._role = role
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
get phase(): SessionPhase {
|
|
41
|
-
return this._phase
|
|
41
|
+
return this._phase
|
|
42
42
|
}
|
|
43
|
-
get role():
|
|
44
|
-
return this._role
|
|
43
|
+
get role(): 'client' | 'server' {
|
|
44
|
+
return this._role
|
|
45
45
|
}
|
|
46
46
|
get subscriptions(): ReadonlyMap<bigint, SubscriptionState> {
|
|
47
|
-
return this._subscriptions
|
|
47
|
+
return this._subscriptions
|
|
48
48
|
}
|
|
49
49
|
get announces(): ReadonlyMap<string, AnnounceState> {
|
|
50
|
-
return this._announces
|
|
50
|
+
return this._announces
|
|
51
51
|
}
|
|
52
52
|
get fetches(): ReadonlyMap<bigint, FetchState> {
|
|
53
|
-
return this._fetches
|
|
53
|
+
return this._fetches
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
get legalOutgoing(): ReadonlySet<Draft12MessageType> {
|
|
57
|
-
return getLegalOutgoing(this._phase, this._role)
|
|
57
|
+
return getLegalOutgoing(this._phase, this._role)
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
get legalIncoming(): ReadonlySet<Draft12MessageType> {
|
|
61
|
-
return getLegalIncoming(this._phase, this._role)
|
|
61
|
+
return getLegalIncoming(this._phase, this._role)
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
private checkRole(
|
|
65
65
|
message: Draft12Message,
|
|
66
|
-
direction:
|
|
66
|
+
direction: 'inbound' | 'outbound',
|
|
67
67
|
): ProtocolViolation<Draft12MessageType> | null {
|
|
68
68
|
const senderRole =
|
|
69
|
-
direction ===
|
|
69
|
+
direction === 'outbound' ? this._role : this._role === 'client' ? 'server' : 'client'
|
|
70
70
|
|
|
71
|
-
if (CLIENT_ONLY_MESSAGES.has(message.type) && senderRole !==
|
|
71
|
+
if (CLIENT_ONLY_MESSAGES.has(message.type) && senderRole !== 'client') {
|
|
72
72
|
return violation(
|
|
73
|
-
|
|
73
|
+
'ROLE_VIOLATION',
|
|
74
74
|
`${message.type} can only be sent by client`,
|
|
75
75
|
this._phase,
|
|
76
76
|
message.type,
|
|
77
|
-
)
|
|
77
|
+
)
|
|
78
78
|
}
|
|
79
|
-
if (SERVER_ONLY_MESSAGES.has(message.type) && senderRole !==
|
|
79
|
+
if (SERVER_ONLY_MESSAGES.has(message.type) && senderRole !== 'server') {
|
|
80
80
|
return violation(
|
|
81
|
-
|
|
81
|
+
'ROLE_VIOLATION',
|
|
82
82
|
`${message.type} can only be sent by server`,
|
|
83
83
|
this._phase,
|
|
84
84
|
message.type,
|
|
85
|
-
)
|
|
85
|
+
)
|
|
86
86
|
}
|
|
87
|
-
return null
|
|
87
|
+
return null
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
private checkDuplicateRequestId(
|
|
@@ -93,13 +93,13 @@ export class Draft12SessionFSM {
|
|
|
93
93
|
): ProtocolViolation<Draft12MessageType> | null {
|
|
94
94
|
if (this._requestIds.has(requestId)) {
|
|
95
95
|
return violation(
|
|
96
|
-
|
|
96
|
+
'DUPLICATE_REQUEST_ID',
|
|
97
97
|
`Request ID ${requestId} already in use`,
|
|
98
98
|
this._phase,
|
|
99
99
|
msgType,
|
|
100
|
-
)
|
|
100
|
+
)
|
|
101
101
|
}
|
|
102
|
-
return null
|
|
102
|
+
return null
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
private checkKnownRequestId(
|
|
@@ -108,216 +108,223 @@ export class Draft12SessionFSM {
|
|
|
108
108
|
): ProtocolViolation<Draft12MessageType> | null {
|
|
109
109
|
if (!this._requestIds.has(requestId)) {
|
|
110
110
|
return violation(
|
|
111
|
-
|
|
111
|
+
'UNKNOWN_REQUEST_ID',
|
|
112
112
|
`No request with ID ${requestId}`,
|
|
113
113
|
this._phase,
|
|
114
114
|
msgType,
|
|
115
|
-
)
|
|
115
|
+
)
|
|
116
116
|
}
|
|
117
|
-
return null
|
|
117
|
+
return null
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
validateOutgoing(message: Draft12Message): ValidationResult<Draft12MessageType> {
|
|
121
|
-
const roleViolation = this.checkRole(message,
|
|
122
|
-
if (roleViolation) return { ok: false, violation: roleViolation }
|
|
121
|
+
const roleViolation = this.checkRole(message, 'outbound')
|
|
122
|
+
if (roleViolation) return { ok: false, violation: roleViolation }
|
|
123
123
|
|
|
124
124
|
if (!this.legalOutgoing.has(message.type)) {
|
|
125
125
|
return {
|
|
126
126
|
ok: false,
|
|
127
127
|
violation: violation(
|
|
128
|
-
this._phase ===
|
|
129
|
-
?
|
|
130
|
-
:
|
|
128
|
+
this._phase === 'idle' || this._phase === 'setup'
|
|
129
|
+
? 'MESSAGE_BEFORE_SETUP'
|
|
130
|
+
: 'UNEXPECTED_MESSAGE',
|
|
131
131
|
`Cannot send ${message.type} in phase ${this._phase}`,
|
|
132
132
|
this._phase,
|
|
133
133
|
message.type,
|
|
134
134
|
),
|
|
135
|
-
}
|
|
135
|
+
}
|
|
136
136
|
}
|
|
137
|
-
return { ok: true }
|
|
137
|
+
return { ok: true }
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
receive(message: Draft12Message): TransitionResult<Draft12MessageType> {
|
|
141
|
-
const roleViolation = this.checkRole(message,
|
|
142
|
-
if (roleViolation) return { ok: false, violation: roleViolation }
|
|
143
|
-
return this.applyTransition(message,
|
|
141
|
+
const roleViolation = this.checkRole(message, 'inbound')
|
|
142
|
+
if (roleViolation) return { ok: false, violation: roleViolation }
|
|
143
|
+
return this.applyTransition(message, 'inbound')
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
send(message: Draft12Message): TransitionResult<Draft12MessageType> {
|
|
147
|
-
const roleViolation = this.checkRole(message,
|
|
148
|
-
if (roleViolation) return { ok: false, violation: roleViolation }
|
|
149
|
-
return this.applyTransition(message,
|
|
147
|
+
const roleViolation = this.checkRole(message, 'outbound')
|
|
148
|
+
if (roleViolation) return { ok: false, violation: roleViolation }
|
|
149
|
+
return this.applyTransition(message, 'outbound')
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
private applyTransition(
|
|
153
153
|
message: Draft12Message,
|
|
154
|
-
direction:
|
|
154
|
+
direction: 'inbound' | 'outbound',
|
|
155
155
|
): TransitionResult<Draft12MessageType> {
|
|
156
|
-
const sideEffects: SideEffect[] = []
|
|
156
|
+
const sideEffects: SideEffect[] = []
|
|
157
157
|
|
|
158
158
|
switch (message.type) {
|
|
159
|
-
case
|
|
160
|
-
return this.handleClientSetup(direction)
|
|
161
|
-
case
|
|
162
|
-
return this.handleServerSetup(direction)
|
|
163
|
-
case
|
|
164
|
-
return this.handleGoAway(message, sideEffects)
|
|
159
|
+
case 'client_setup':
|
|
160
|
+
return this.handleClientSetup(direction)
|
|
161
|
+
case 'server_setup':
|
|
162
|
+
return this.handleServerSetup(direction)
|
|
163
|
+
case 'goaway':
|
|
164
|
+
return this.handleGoAway(message, sideEffects)
|
|
165
165
|
|
|
166
166
|
// Subscribe lifecycle
|
|
167
|
-
case
|
|
168
|
-
return this.handleSubscribe(message, sideEffects)
|
|
169
|
-
case
|
|
170
|
-
return this.handleSubscribeOk(message, sideEffects)
|
|
171
|
-
case
|
|
172
|
-
return this.handleSubscribeError(message, sideEffects)
|
|
173
|
-
case
|
|
174
|
-
return this.handleSubscribeUpdate(message, sideEffects)
|
|
175
|
-
case
|
|
176
|
-
return this.handleSubscribeDone(message, sideEffects)
|
|
177
|
-
case
|
|
178
|
-
return this.handleUnsubscribe(message, sideEffects)
|
|
167
|
+
case 'subscribe':
|
|
168
|
+
return this.handleSubscribe(message, sideEffects)
|
|
169
|
+
case 'subscribe_ok':
|
|
170
|
+
return this.handleSubscribeOk(message, sideEffects)
|
|
171
|
+
case 'subscribe_error':
|
|
172
|
+
return this.handleSubscribeError(message, sideEffects)
|
|
173
|
+
case 'subscribe_update':
|
|
174
|
+
return this.handleSubscribeUpdate(message, sideEffects)
|
|
175
|
+
case 'subscribe_done':
|
|
176
|
+
return this.handleSubscribeDone(message, sideEffects)
|
|
177
|
+
case 'unsubscribe':
|
|
178
|
+
return this.handleUnsubscribe(message, sideEffects)
|
|
179
179
|
|
|
180
180
|
// Announce lifecycle
|
|
181
|
-
case
|
|
182
|
-
return this.handleAnnounce(message, sideEffects)
|
|
183
|
-
case
|
|
184
|
-
return this.handleAnnounceOk(message, sideEffects)
|
|
185
|
-
case
|
|
186
|
-
return this.handleAnnounceError(message, sideEffects)
|
|
187
|
-
case
|
|
188
|
-
return this.handleUnannounce(message, sideEffects)
|
|
189
|
-
case
|
|
190
|
-
return this.handleAnnounceCancel(message, sideEffects)
|
|
181
|
+
case 'announce':
|
|
182
|
+
return this.handleAnnounce(message, sideEffects)
|
|
183
|
+
case 'announce_ok':
|
|
184
|
+
return this.handleAnnounceOk(message, sideEffects)
|
|
185
|
+
case 'announce_error':
|
|
186
|
+
return this.handleAnnounceError(message, sideEffects)
|
|
187
|
+
case 'unannounce':
|
|
188
|
+
return this.handleUnannounce(message, sideEffects)
|
|
189
|
+
case 'announce_cancel':
|
|
190
|
+
return this.handleAnnounceCancel(message, sideEffects)
|
|
191
191
|
|
|
192
192
|
// Publish lifecycle
|
|
193
|
-
case
|
|
194
|
-
return this.handlePublish(message, sideEffects)
|
|
195
|
-
case
|
|
196
|
-
return this.handlePublishOk(message, sideEffects)
|
|
197
|
-
case
|
|
198
|
-
return this.handlePublishError(message, sideEffects)
|
|
193
|
+
case 'publish':
|
|
194
|
+
return this.handlePublish(message, sideEffects)
|
|
195
|
+
case 'publish_ok':
|
|
196
|
+
return this.handlePublishOk(message, sideEffects)
|
|
197
|
+
case 'publish_error':
|
|
198
|
+
return this.handlePublishError(message, sideEffects)
|
|
199
199
|
|
|
200
200
|
// Fetch lifecycle
|
|
201
|
-
case
|
|
202
|
-
return this.handleFetch(message, sideEffects)
|
|
203
|
-
case
|
|
204
|
-
return this.handleFetchOk(message, sideEffects)
|
|
205
|
-
case
|
|
206
|
-
return this.handleFetchError(message, sideEffects)
|
|
207
|
-
case
|
|
208
|
-
return this.handleFetchCancel(message, sideEffects)
|
|
201
|
+
case 'fetch':
|
|
202
|
+
return this.handleFetch(message, sideEffects)
|
|
203
|
+
case 'fetch_ok':
|
|
204
|
+
return this.handleFetchOk(message, sideEffects)
|
|
205
|
+
case 'fetch_error':
|
|
206
|
+
return this.handleFetchError(message, sideEffects)
|
|
207
|
+
case 'fetch_cancel':
|
|
208
|
+
return this.handleFetchCancel(message, sideEffects)
|
|
209
209
|
|
|
210
210
|
// Subscribe announces lifecycle
|
|
211
|
-
case
|
|
212
|
-
return this.handleSubscribeAnnounces(message, sideEffects)
|
|
213
|
-
case
|
|
214
|
-
return this.handleSubscribeAnnouncesOk(message, sideEffects)
|
|
215
|
-
case
|
|
216
|
-
return this.handleSubscribeAnnouncesError(message, sideEffects)
|
|
211
|
+
case 'subscribe_announces':
|
|
212
|
+
return this.handleSubscribeAnnounces(message, sideEffects)
|
|
213
|
+
case 'subscribe_announces_ok':
|
|
214
|
+
return this.handleSubscribeAnnouncesOk(message, sideEffects)
|
|
215
|
+
case 'subscribe_announces_error':
|
|
216
|
+
return this.handleSubscribeAnnouncesError(message, sideEffects)
|
|
217
217
|
|
|
218
218
|
// Track status lifecycle
|
|
219
|
-
case
|
|
220
|
-
return this.handleTrackStatusRequest(message, sideEffects)
|
|
221
|
-
case
|
|
222
|
-
return this.handleTrackStatusResponse(message, sideEffects)
|
|
219
|
+
case 'track_status_request':
|
|
220
|
+
return this.handleTrackStatusRequest(message, sideEffects)
|
|
221
|
+
case 'track_status':
|
|
222
|
+
return this.handleTrackStatusResponse(message, sideEffects)
|
|
223
223
|
|
|
224
224
|
// Other ready-phase messages
|
|
225
225
|
default:
|
|
226
|
-
return this.handleReadyPhaseMessage(message)
|
|
226
|
+
return this.handleReadyPhaseMessage(message)
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
private handleClientSetup(
|
|
231
|
-
direction:
|
|
231
|
+
direction: 'inbound' | 'outbound',
|
|
232
232
|
): TransitionResult<Draft12MessageType> {
|
|
233
|
-
if (this._phase !==
|
|
233
|
+
if (this._phase !== 'idle') {
|
|
234
234
|
return {
|
|
235
235
|
ok: false,
|
|
236
236
|
violation: violation(
|
|
237
|
-
|
|
238
|
-
|
|
237
|
+
'SETUP_VIOLATION',
|
|
238
|
+
'CLIENT_SETUP already sent/received',
|
|
239
239
|
this._phase,
|
|
240
|
-
|
|
240
|
+
'client_setup',
|
|
241
241
|
),
|
|
242
|
-
}
|
|
242
|
+
}
|
|
243
243
|
}
|
|
244
|
-
if (direction ===
|
|
244
|
+
if (direction === 'outbound' && this._role !== 'client') {
|
|
245
245
|
return {
|
|
246
246
|
ok: false,
|
|
247
247
|
violation: violation(
|
|
248
|
-
|
|
249
|
-
|
|
248
|
+
'ROLE_VIOLATION',
|
|
249
|
+
'Only client can send CLIENT_SETUP',
|
|
250
250
|
this._phase,
|
|
251
|
-
|
|
251
|
+
'client_setup',
|
|
252
252
|
),
|
|
253
|
-
}
|
|
253
|
+
}
|
|
254
254
|
}
|
|
255
|
-
this._phase =
|
|
256
|
-
return { ok: true, phase: this._phase, sideEffects: [] }
|
|
255
|
+
this._phase = 'setup'
|
|
256
|
+
return { ok: true, phase: this._phase, sideEffects: [] }
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
private handleServerSetup(
|
|
260
|
-
direction:
|
|
260
|
+
direction: 'inbound' | 'outbound',
|
|
261
261
|
): TransitionResult<Draft12MessageType> {
|
|
262
|
-
if (this._phase !==
|
|
262
|
+
if (this._phase !== 'setup') {
|
|
263
263
|
return {
|
|
264
264
|
ok: false,
|
|
265
265
|
violation: violation(
|
|
266
|
-
|
|
267
|
-
|
|
266
|
+
'SETUP_VIOLATION',
|
|
267
|
+
'SERVER_SETUP before CLIENT_SETUP',
|
|
268
268
|
this._phase,
|
|
269
|
-
|
|
269
|
+
'server_setup',
|
|
270
270
|
),
|
|
271
|
-
}
|
|
271
|
+
}
|
|
272
272
|
}
|
|
273
|
-
if (direction ===
|
|
273
|
+
if (direction === 'outbound' && this._role !== 'server') {
|
|
274
274
|
return {
|
|
275
275
|
ok: false,
|
|
276
276
|
violation: violation(
|
|
277
|
-
|
|
278
|
-
|
|
277
|
+
'ROLE_VIOLATION',
|
|
278
|
+
'Only server can send SERVER_SETUP',
|
|
279
279
|
this._phase,
|
|
280
|
-
|
|
280
|
+
'server_setup',
|
|
281
281
|
),
|
|
282
|
-
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
this._phase = 'ready'
|
|
285
|
+
return {
|
|
286
|
+
ok: true,
|
|
287
|
+
phase: this._phase,
|
|
288
|
+
sideEffects: [{ type: 'session-ready' }],
|
|
283
289
|
}
|
|
284
|
-
this._phase = "ready";
|
|
285
|
-
return { ok: true, phase: this._phase, sideEffects: [{ type: "session-ready" }] };
|
|
286
290
|
}
|
|
287
291
|
|
|
288
292
|
private handleGoAway(
|
|
289
293
|
message: Draft12Message,
|
|
290
294
|
sideEffects: SideEffect[],
|
|
291
295
|
): TransitionResult<Draft12MessageType> {
|
|
292
|
-
if (this._phase !==
|
|
296
|
+
if (this._phase !== 'ready' && this._phase !== 'draining') {
|
|
293
297
|
return {
|
|
294
298
|
ok: false,
|
|
295
299
|
violation: violation(
|
|
296
|
-
|
|
300
|
+
'UNEXPECTED_MESSAGE',
|
|
297
301
|
`GOAWAY not valid in phase ${this._phase}`,
|
|
298
302
|
this._phase,
|
|
299
|
-
|
|
303
|
+
'goaway',
|
|
300
304
|
),
|
|
301
|
-
}
|
|
305
|
+
}
|
|
302
306
|
}
|
|
303
|
-
this._phase =
|
|
304
|
-
const goaway = message as import(
|
|
305
|
-
sideEffects.push({
|
|
306
|
-
|
|
307
|
+
this._phase = 'draining'
|
|
308
|
+
const goaway = message as import('./types.js').Draft12GoAway
|
|
309
|
+
sideEffects.push({
|
|
310
|
+
type: 'session-draining',
|
|
311
|
+
goAwayUri: goaway.new_session_uri,
|
|
312
|
+
})
|
|
313
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
307
314
|
}
|
|
308
315
|
|
|
309
316
|
private requireReady(msgType: Draft12MessageType): ProtocolViolation<Draft12MessageType> | null {
|
|
310
|
-
if (this._phase !==
|
|
317
|
+
if (this._phase !== 'ready' && this._phase !== 'draining') {
|
|
311
318
|
return violation(
|
|
312
|
-
this._phase ===
|
|
313
|
-
?
|
|
314
|
-
:
|
|
319
|
+
this._phase === 'idle' || this._phase === 'setup'
|
|
320
|
+
? 'MESSAGE_BEFORE_SETUP'
|
|
321
|
+
: 'UNEXPECTED_MESSAGE',
|
|
315
322
|
`${msgType} requires ready phase, current: ${this._phase}`,
|
|
316
323
|
this._phase,
|
|
317
324
|
msgType,
|
|
318
|
-
)
|
|
325
|
+
)
|
|
319
326
|
}
|
|
320
|
-
return null
|
|
327
|
+
return null
|
|
321
328
|
}
|
|
322
329
|
|
|
323
330
|
// ─── Subscribe lifecycle ───
|
|
@@ -326,184 +333,187 @@ export class Draft12SessionFSM {
|
|
|
326
333
|
message: Draft12Message,
|
|
327
334
|
sideEffects: SideEffect[],
|
|
328
335
|
): TransitionResult<Draft12MessageType> {
|
|
329
|
-
const err = this.requireReady(message.type)
|
|
330
|
-
if (err) return { ok: false, violation: err }
|
|
331
|
-
const sub = message as import(
|
|
332
|
-
const dupErr = this.checkDuplicateRequestId(sub.request_id, message.type)
|
|
333
|
-
if (dupErr) return { ok: false, violation: dupErr }
|
|
334
|
-
this._requestIds.add(sub.request_id)
|
|
336
|
+
const err = this.requireReady(message.type)
|
|
337
|
+
if (err) return { ok: false, violation: err }
|
|
338
|
+
const sub = message as import('./types.js').Draft12Subscribe
|
|
339
|
+
const dupErr = this.checkDuplicateRequestId(sub.request_id, message.type)
|
|
340
|
+
if (dupErr) return { ok: false, violation: dupErr }
|
|
341
|
+
this._requestIds.add(sub.request_id)
|
|
335
342
|
this._subscriptions.set(sub.request_id, {
|
|
336
343
|
subscribeId: sub.request_id,
|
|
337
|
-
phase:
|
|
344
|
+
phase: 'pending',
|
|
338
345
|
trackNamespace: sub.track_namespace,
|
|
339
346
|
trackName: sub.track_name,
|
|
340
|
-
})
|
|
341
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
347
|
+
})
|
|
348
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
342
349
|
}
|
|
343
350
|
|
|
344
351
|
private handleSubscribeOk(
|
|
345
352
|
message: Draft12Message,
|
|
346
353
|
sideEffects: SideEffect[],
|
|
347
354
|
): TransitionResult<Draft12MessageType> {
|
|
348
|
-
const err = this.requireReady(message.type)
|
|
349
|
-
if (err) return { ok: false, violation: err }
|
|
350
|
-
const ok = message as import(
|
|
351
|
-
const idErr = this.checkKnownRequestId(ok.request_id, message.type)
|
|
352
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
353
|
-
const existing = this._subscriptions.get(ok.request_id)
|
|
355
|
+
const err = this.requireReady(message.type)
|
|
356
|
+
if (err) return { ok: false, violation: err }
|
|
357
|
+
const ok = message as import('./types.js').Draft12SubscribeOk
|
|
358
|
+
const idErr = this.checkKnownRequestId(ok.request_id, message.type)
|
|
359
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
360
|
+
const existing = this._subscriptions.get(ok.request_id)
|
|
354
361
|
if (!existing)
|
|
355
362
|
return {
|
|
356
363
|
ok: false,
|
|
357
364
|
violation: violation(
|
|
358
|
-
|
|
365
|
+
'UNKNOWN_REQUEST_ID',
|
|
359
366
|
`No subscription with request ID ${ok.request_id}`,
|
|
360
367
|
this._phase,
|
|
361
368
|
message.type,
|
|
362
369
|
),
|
|
363
|
-
}
|
|
364
|
-
if (existing.phase !==
|
|
370
|
+
}
|
|
371
|
+
if (existing.phase !== 'pending')
|
|
365
372
|
return {
|
|
366
373
|
ok: false,
|
|
367
374
|
violation: violation(
|
|
368
|
-
|
|
375
|
+
'STATE_VIOLATION',
|
|
369
376
|
`Subscription ${ok.request_id} is ${existing.phase}, not pending`,
|
|
370
377
|
this._phase,
|
|
371
378
|
message.type,
|
|
372
379
|
),
|
|
373
|
-
}
|
|
374
|
-
this._subscriptions.set(ok.request_id, { ...existing, phase:
|
|
375
|
-
sideEffects.push({
|
|
376
|
-
|
|
380
|
+
}
|
|
381
|
+
this._subscriptions.set(ok.request_id, { ...existing, phase: 'active' })
|
|
382
|
+
sideEffects.push({
|
|
383
|
+
type: 'subscription-activated',
|
|
384
|
+
subscribeId: ok.request_id,
|
|
385
|
+
})
|
|
386
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
377
387
|
}
|
|
378
388
|
|
|
379
389
|
private handleSubscribeError(
|
|
380
390
|
message: Draft12Message,
|
|
381
391
|
sideEffects: SideEffect[],
|
|
382
392
|
): TransitionResult<Draft12MessageType> {
|
|
383
|
-
const err = this.requireReady(message.type)
|
|
384
|
-
if (err) return { ok: false, violation: err }
|
|
385
|
-
const subErr = message as import(
|
|
386
|
-
const idErr = this.checkKnownRequestId(subErr.request_id, message.type)
|
|
387
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
388
|
-
const existing = this._subscriptions.get(subErr.request_id)
|
|
393
|
+
const err = this.requireReady(message.type)
|
|
394
|
+
if (err) return { ok: false, violation: err }
|
|
395
|
+
const subErr = message as import('./types.js').Draft12SubscribeError
|
|
396
|
+
const idErr = this.checkKnownRequestId(subErr.request_id, message.type)
|
|
397
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
398
|
+
const existing = this._subscriptions.get(subErr.request_id)
|
|
389
399
|
if (!existing)
|
|
390
400
|
return {
|
|
391
401
|
ok: false,
|
|
392
402
|
violation: violation(
|
|
393
|
-
|
|
403
|
+
'UNKNOWN_REQUEST_ID',
|
|
394
404
|
`No subscription with request ID ${subErr.request_id}`,
|
|
395
405
|
this._phase,
|
|
396
406
|
message.type,
|
|
397
407
|
),
|
|
398
|
-
}
|
|
399
|
-
if (existing.phase !==
|
|
408
|
+
}
|
|
409
|
+
if (existing.phase !== 'pending')
|
|
400
410
|
return {
|
|
401
411
|
ok: false,
|
|
402
412
|
violation: violation(
|
|
403
|
-
|
|
413
|
+
'STATE_VIOLATION',
|
|
404
414
|
`Subscription ${subErr.request_id} is ${existing.phase}, not pending`,
|
|
405
415
|
this._phase,
|
|
406
416
|
message.type,
|
|
407
417
|
),
|
|
408
|
-
}
|
|
409
|
-
this._subscriptions.set(subErr.request_id, { ...existing, phase:
|
|
418
|
+
}
|
|
419
|
+
this._subscriptions.set(subErr.request_id, { ...existing, phase: 'error' })
|
|
410
420
|
sideEffects.push({
|
|
411
|
-
type:
|
|
421
|
+
type: 'subscription-ended',
|
|
412
422
|
subscribeId: subErr.request_id,
|
|
413
423
|
reason: subErr.reason_phrase,
|
|
414
|
-
})
|
|
415
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
424
|
+
})
|
|
425
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
416
426
|
}
|
|
417
427
|
|
|
418
428
|
private handleSubscribeUpdate(
|
|
419
429
|
message: Draft12Message,
|
|
420
430
|
sideEffects: SideEffect[],
|
|
421
431
|
): TransitionResult<Draft12MessageType> {
|
|
422
|
-
const err = this.requireReady(message.type)
|
|
423
|
-
if (err) return { ok: false, violation: err }
|
|
424
|
-
const update = message as import(
|
|
425
|
-
const idErr = this.checkKnownRequestId(update.request_id, message.type)
|
|
426
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
427
|
-
const existing = this._subscriptions.get(update.request_id)
|
|
432
|
+
const err = this.requireReady(message.type)
|
|
433
|
+
if (err) return { ok: false, violation: err }
|
|
434
|
+
const update = message as import('./types.js').Draft12SubscribeUpdate
|
|
435
|
+
const idErr = this.checkKnownRequestId(update.request_id, message.type)
|
|
436
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
437
|
+
const existing = this._subscriptions.get(update.request_id)
|
|
428
438
|
if (!existing)
|
|
429
439
|
return {
|
|
430
440
|
ok: false,
|
|
431
441
|
violation: violation(
|
|
432
|
-
|
|
442
|
+
'UNKNOWN_REQUEST_ID',
|
|
433
443
|
`No subscription with request ID ${update.request_id}`,
|
|
434
444
|
this._phase,
|
|
435
445
|
message.type,
|
|
436
446
|
),
|
|
437
|
-
}
|
|
438
|
-
if (existing.phase !==
|
|
447
|
+
}
|
|
448
|
+
if (existing.phase !== 'active')
|
|
439
449
|
return {
|
|
440
450
|
ok: false,
|
|
441
451
|
violation: violation(
|
|
442
|
-
|
|
452
|
+
'STATE_VIOLATION',
|
|
443
453
|
`Subscription ${update.request_id} is ${existing.phase}, not active`,
|
|
444
454
|
this._phase,
|
|
445
455
|
message.type,
|
|
446
456
|
),
|
|
447
|
-
}
|
|
448
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
457
|
+
}
|
|
458
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
449
459
|
}
|
|
450
460
|
|
|
451
461
|
private handleSubscribeDone(
|
|
452
462
|
message: Draft12Message,
|
|
453
463
|
sideEffects: SideEffect[],
|
|
454
464
|
): TransitionResult<Draft12MessageType> {
|
|
455
|
-
const err = this.requireReady(message.type)
|
|
456
|
-
if (err) return { ok: false, violation: err }
|
|
457
|
-
const done = message as import(
|
|
458
|
-
const idErr = this.checkKnownRequestId(done.request_id, message.type)
|
|
459
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
460
|
-
const existing = this._subscriptions.get(done.request_id)
|
|
465
|
+
const err = this.requireReady(message.type)
|
|
466
|
+
if (err) return { ok: false, violation: err }
|
|
467
|
+
const done = message as import('./types.js').Draft12SubscribeDone
|
|
468
|
+
const idErr = this.checkKnownRequestId(done.request_id, message.type)
|
|
469
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
470
|
+
const existing = this._subscriptions.get(done.request_id)
|
|
461
471
|
if (!existing)
|
|
462
472
|
return {
|
|
463
473
|
ok: false,
|
|
464
474
|
violation: violation(
|
|
465
|
-
|
|
475
|
+
'UNKNOWN_REQUEST_ID',
|
|
466
476
|
`No subscription with request ID ${done.request_id}`,
|
|
467
477
|
this._phase,
|
|
468
478
|
message.type,
|
|
469
479
|
),
|
|
470
|
-
}
|
|
471
|
-
this._subscriptions.set(done.request_id, { ...existing, phase:
|
|
480
|
+
}
|
|
481
|
+
this._subscriptions.set(done.request_id, { ...existing, phase: 'done' })
|
|
472
482
|
sideEffects.push({
|
|
473
|
-
type:
|
|
483
|
+
type: 'subscription-ended',
|
|
474
484
|
subscribeId: done.request_id,
|
|
475
485
|
reason: done.reason_phrase,
|
|
476
|
-
})
|
|
477
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
486
|
+
})
|
|
487
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
478
488
|
}
|
|
479
489
|
|
|
480
490
|
private handleUnsubscribe(
|
|
481
491
|
message: Draft12Message,
|
|
482
492
|
sideEffects: SideEffect[],
|
|
483
493
|
): TransitionResult<Draft12MessageType> {
|
|
484
|
-
const err = this.requireReady(message.type)
|
|
485
|
-
if (err) return { ok: false, violation: err }
|
|
486
|
-
const unsub = message as import(
|
|
487
|
-
const idErr = this.checkKnownRequestId(unsub.request_id, message.type)
|
|
488
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
489
|
-
const existing = this._subscriptions.get(unsub.request_id)
|
|
494
|
+
const err = this.requireReady(message.type)
|
|
495
|
+
if (err) return { ok: false, violation: err }
|
|
496
|
+
const unsub = message as import('./types.js').Draft12Unsubscribe
|
|
497
|
+
const idErr = this.checkKnownRequestId(unsub.request_id, message.type)
|
|
498
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
499
|
+
const existing = this._subscriptions.get(unsub.request_id)
|
|
490
500
|
if (!existing)
|
|
491
501
|
return {
|
|
492
502
|
ok: false,
|
|
493
503
|
violation: violation(
|
|
494
|
-
|
|
504
|
+
'UNKNOWN_REQUEST_ID',
|
|
495
505
|
`No subscription with request ID ${unsub.request_id}`,
|
|
496
506
|
this._phase,
|
|
497
507
|
message.type,
|
|
498
508
|
),
|
|
499
|
-
}
|
|
500
|
-
this._subscriptions.set(unsub.request_id, { ...existing, phase:
|
|
509
|
+
}
|
|
510
|
+
this._subscriptions.set(unsub.request_id, { ...existing, phase: 'done' })
|
|
501
511
|
sideEffects.push({
|
|
502
|
-
type:
|
|
512
|
+
type: 'subscription-ended',
|
|
503
513
|
subscribeId: unsub.request_id,
|
|
504
|
-
reason:
|
|
505
|
-
})
|
|
506
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
514
|
+
reason: 'unsubscribed',
|
|
515
|
+
})
|
|
516
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
507
517
|
}
|
|
508
518
|
|
|
509
519
|
// ─── Announce lifecycle ───
|
|
@@ -512,69 +522,78 @@ export class Draft12SessionFSM {
|
|
|
512
522
|
message: Draft12Message,
|
|
513
523
|
sideEffects: SideEffect[],
|
|
514
524
|
): TransitionResult<Draft12MessageType> {
|
|
515
|
-
const err = this.requireReady(message.type)
|
|
516
|
-
if (err) return { ok: false, violation: err }
|
|
517
|
-
const ann = message as import(
|
|
518
|
-
const nsKey = ann.track_namespace.join(
|
|
519
|
-
this._requestIds.add(ann.request_id)
|
|
520
|
-
this._announces.set(nsKey, {
|
|
521
|
-
|
|
525
|
+
const err = this.requireReady(message.type)
|
|
526
|
+
if (err) return { ok: false, violation: err }
|
|
527
|
+
const ann = message as import('./types.js').Draft12Announce
|
|
528
|
+
const nsKey = ann.track_namespace.join('/')
|
|
529
|
+
this._requestIds.add(ann.request_id)
|
|
530
|
+
this._announces.set(nsKey, {
|
|
531
|
+
namespace: ann.track_namespace,
|
|
532
|
+
phase: 'pending',
|
|
533
|
+
})
|
|
534
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
522
535
|
}
|
|
523
536
|
|
|
524
537
|
private handleAnnounceOk(
|
|
525
538
|
message: Draft12Message,
|
|
526
539
|
sideEffects: SideEffect[],
|
|
527
540
|
): TransitionResult<Draft12MessageType> {
|
|
528
|
-
const err = this.requireReady(message.type)
|
|
529
|
-
if (err) return { ok: false, violation: err }
|
|
530
|
-
const ok = message as import(
|
|
531
|
-
const idErr = this.checkKnownRequestId(ok.request_id, message.type)
|
|
532
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
533
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
541
|
+
const err = this.requireReady(message.type)
|
|
542
|
+
if (err) return { ok: false, violation: err }
|
|
543
|
+
const ok = message as import('./types.js').Draft12AnnounceOk
|
|
544
|
+
const idErr = this.checkKnownRequestId(ok.request_id, message.type)
|
|
545
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
546
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
534
547
|
}
|
|
535
548
|
|
|
536
549
|
private handleAnnounceError(
|
|
537
550
|
message: Draft12Message,
|
|
538
551
|
sideEffects: SideEffect[],
|
|
539
552
|
): TransitionResult<Draft12MessageType> {
|
|
540
|
-
const err = this.requireReady(message.type)
|
|
541
|
-
if (err) return { ok: false, violation: err }
|
|
542
|
-
const annErr = message as import(
|
|
543
|
-
const idErr = this.checkKnownRequestId(annErr.request_id, message.type)
|
|
544
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
545
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
553
|
+
const err = this.requireReady(message.type)
|
|
554
|
+
if (err) return { ok: false, violation: err }
|
|
555
|
+
const annErr = message as import('./types.js').Draft12AnnounceError
|
|
556
|
+
const idErr = this.checkKnownRequestId(annErr.request_id, message.type)
|
|
557
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
558
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
546
559
|
}
|
|
547
560
|
|
|
548
561
|
private handleUnannounce(
|
|
549
562
|
message: Draft12Message,
|
|
550
563
|
sideEffects: SideEffect[],
|
|
551
564
|
): TransitionResult<Draft12MessageType> {
|
|
552
|
-
const err = this.requireReady(message.type)
|
|
553
|
-
if (err) return { ok: false, violation: err }
|
|
554
|
-
const unann = message as import(
|
|
555
|
-
const nsKey = unann.track_namespace.join(
|
|
556
|
-
const existing = this._announces.get(nsKey)
|
|
565
|
+
const err = this.requireReady(message.type)
|
|
566
|
+
if (err) return { ok: false, violation: err }
|
|
567
|
+
const unann = message as import('./types.js').Draft12Unannounce
|
|
568
|
+
const nsKey = unann.track_namespace.join('/')
|
|
569
|
+
const existing = this._announces.get(nsKey)
|
|
557
570
|
if (existing) {
|
|
558
|
-
this._announces.delete(nsKey)
|
|
559
|
-
sideEffects.push({
|
|
571
|
+
this._announces.delete(nsKey)
|
|
572
|
+
sideEffects.push({
|
|
573
|
+
type: 'announce-ended',
|
|
574
|
+
namespace: unann.track_namespace,
|
|
575
|
+
})
|
|
560
576
|
}
|
|
561
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
577
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
562
578
|
}
|
|
563
579
|
|
|
564
580
|
private handleAnnounceCancel(
|
|
565
581
|
message: Draft12Message,
|
|
566
582
|
sideEffects: SideEffect[],
|
|
567
583
|
): TransitionResult<Draft12MessageType> {
|
|
568
|
-
const err = this.requireReady(message.type)
|
|
569
|
-
if (err) return { ok: false, violation: err }
|
|
570
|
-
const cancel = message as import(
|
|
571
|
-
const nsKey = cancel.track_namespace.join(
|
|
572
|
-
const existing = this._announces.get(nsKey)
|
|
584
|
+
const err = this.requireReady(message.type)
|
|
585
|
+
if (err) return { ok: false, violation: err }
|
|
586
|
+
const cancel = message as import('./types.js').Draft12AnnounceCancel
|
|
587
|
+
const nsKey = cancel.track_namespace.join('/')
|
|
588
|
+
const existing = this._announces.get(nsKey)
|
|
573
589
|
if (existing) {
|
|
574
|
-
this._announces.delete(nsKey)
|
|
575
|
-
sideEffects.push({
|
|
590
|
+
this._announces.delete(nsKey)
|
|
591
|
+
sideEffects.push({
|
|
592
|
+
type: 'announce-ended',
|
|
593
|
+
namespace: cancel.track_namespace,
|
|
594
|
+
})
|
|
576
595
|
}
|
|
577
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
596
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
578
597
|
}
|
|
579
598
|
|
|
580
599
|
// ─── Publish lifecycle ───
|
|
@@ -583,37 +602,37 @@ export class Draft12SessionFSM {
|
|
|
583
602
|
message: Draft12Message,
|
|
584
603
|
sideEffects: SideEffect[],
|
|
585
604
|
): TransitionResult<Draft12MessageType> {
|
|
586
|
-
const err = this.requireReady(message.type)
|
|
587
|
-
if (err) return { ok: false, violation: err }
|
|
588
|
-
const pub = message as import(
|
|
589
|
-
const dupErr = this.checkDuplicateRequestId(pub.request_id, message.type)
|
|
590
|
-
if (dupErr) return { ok: false, violation: dupErr }
|
|
591
|
-
this._requestIds.add(pub.request_id)
|
|
592
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
605
|
+
const err = this.requireReady(message.type)
|
|
606
|
+
if (err) return { ok: false, violation: err }
|
|
607
|
+
const pub = message as import('./types.js').Draft12Publish
|
|
608
|
+
const dupErr = this.checkDuplicateRequestId(pub.request_id, message.type)
|
|
609
|
+
if (dupErr) return { ok: false, violation: dupErr }
|
|
610
|
+
this._requestIds.add(pub.request_id)
|
|
611
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
593
612
|
}
|
|
594
613
|
|
|
595
614
|
private handlePublishOk(
|
|
596
615
|
message: Draft12Message,
|
|
597
616
|
sideEffects: SideEffect[],
|
|
598
617
|
): TransitionResult<Draft12MessageType> {
|
|
599
|
-
const err = this.requireReady(message.type)
|
|
600
|
-
if (err) return { ok: false, violation: err }
|
|
601
|
-
const ok = message as import(
|
|
602
|
-
const idErr = this.checkKnownRequestId(ok.request_id, message.type)
|
|
603
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
604
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
618
|
+
const err = this.requireReady(message.type)
|
|
619
|
+
if (err) return { ok: false, violation: err }
|
|
620
|
+
const ok = message as import('./types.js').Draft12PublishOk
|
|
621
|
+
const idErr = this.checkKnownRequestId(ok.request_id, message.type)
|
|
622
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
623
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
605
624
|
}
|
|
606
625
|
|
|
607
626
|
private handlePublishError(
|
|
608
627
|
message: Draft12Message,
|
|
609
628
|
sideEffects: SideEffect[],
|
|
610
629
|
): TransitionResult<Draft12MessageType> {
|
|
611
|
-
const err = this.requireReady(message.type)
|
|
612
|
-
if (err) return { ok: false, violation: err }
|
|
613
|
-
const pubErr = message as import(
|
|
614
|
-
const idErr = this.checkKnownRequestId(pubErr.request_id, message.type)
|
|
615
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
616
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
630
|
+
const err = this.requireReady(message.type)
|
|
631
|
+
if (err) return { ok: false, violation: err }
|
|
632
|
+
const pubErr = message as import('./types.js').Draft12PublishError
|
|
633
|
+
const idErr = this.checkKnownRequestId(pubErr.request_id, message.type)
|
|
634
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
635
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
617
636
|
}
|
|
618
637
|
|
|
619
638
|
// ─── Fetch lifecycle ───
|
|
@@ -622,103 +641,110 @@ export class Draft12SessionFSM {
|
|
|
622
641
|
message: Draft12Message,
|
|
623
642
|
sideEffects: SideEffect[],
|
|
624
643
|
): TransitionResult<Draft12MessageType> {
|
|
625
|
-
const err = this.requireReady(message.type)
|
|
626
|
-
if (err) return { ok: false, violation: err }
|
|
627
|
-
const fetch = message as import(
|
|
628
|
-
const dupErr = this.checkDuplicateRequestId(fetch.request_id, message.type)
|
|
629
|
-
if (dupErr) return { ok: false, violation: dupErr }
|
|
630
|
-
this._requestIds.add(fetch.request_id)
|
|
631
|
-
this._fetches.set(fetch.request_id, {
|
|
632
|
-
|
|
644
|
+
const err = this.requireReady(message.type)
|
|
645
|
+
if (err) return { ok: false, violation: err }
|
|
646
|
+
const fetch = message as import('./types.js').Draft12Fetch
|
|
647
|
+
const dupErr = this.checkDuplicateRequestId(fetch.request_id, message.type)
|
|
648
|
+
if (dupErr) return { ok: false, violation: dupErr }
|
|
649
|
+
this._requestIds.add(fetch.request_id)
|
|
650
|
+
this._fetches.set(fetch.request_id, {
|
|
651
|
+
requestId: fetch.request_id,
|
|
652
|
+
phase: 'pending',
|
|
653
|
+
})
|
|
654
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
633
655
|
}
|
|
634
656
|
|
|
635
657
|
private handleFetchOk(
|
|
636
658
|
message: Draft12Message,
|
|
637
659
|
sideEffects: SideEffect[],
|
|
638
660
|
): TransitionResult<Draft12MessageType> {
|
|
639
|
-
const err = this.requireReady(message.type)
|
|
640
|
-
if (err) return { ok: false, violation: err }
|
|
641
|
-
const ok = message as import(
|
|
642
|
-
const idErr = this.checkKnownRequestId(ok.request_id, message.type)
|
|
643
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
644
|
-
const existing = this._fetches.get(ok.request_id)
|
|
661
|
+
const err = this.requireReady(message.type)
|
|
662
|
+
if (err) return { ok: false, violation: err }
|
|
663
|
+
const ok = message as import('./types.js').Draft12FetchOk
|
|
664
|
+
const idErr = this.checkKnownRequestId(ok.request_id, message.type)
|
|
665
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
666
|
+
const existing = this._fetches.get(ok.request_id)
|
|
645
667
|
if (!existing)
|
|
646
668
|
return {
|
|
647
669
|
ok: false,
|
|
648
670
|
violation: violation(
|
|
649
|
-
|
|
671
|
+
'UNKNOWN_REQUEST_ID',
|
|
650
672
|
`No fetch with request ID ${ok.request_id}`,
|
|
651
673
|
this._phase,
|
|
652
674
|
message.type,
|
|
653
675
|
),
|
|
654
|
-
}
|
|
655
|
-
if (existing.phase !==
|
|
676
|
+
}
|
|
677
|
+
if (existing.phase !== 'pending')
|
|
656
678
|
return {
|
|
657
679
|
ok: false,
|
|
658
680
|
violation: violation(
|
|
659
|
-
|
|
681
|
+
'STATE_VIOLATION',
|
|
660
682
|
`Fetch ${ok.request_id} is ${existing.phase}, not pending`,
|
|
661
683
|
this._phase,
|
|
662
684
|
message.type,
|
|
663
685
|
),
|
|
664
|
-
}
|
|
665
|
-
this._fetches.set(ok.request_id, { ...existing, phase:
|
|
666
|
-
sideEffects.push({ type:
|
|
667
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
686
|
+
}
|
|
687
|
+
this._fetches.set(ok.request_id, { ...existing, phase: 'active' })
|
|
688
|
+
sideEffects.push({ type: 'fetch-activated', requestId: ok.request_id })
|
|
689
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
668
690
|
}
|
|
669
691
|
|
|
670
692
|
private handleFetchError(
|
|
671
693
|
message: Draft12Message,
|
|
672
694
|
sideEffects: SideEffect[],
|
|
673
695
|
): TransitionResult<Draft12MessageType> {
|
|
674
|
-
const err = this.requireReady(message.type)
|
|
675
|
-
if (err) return { ok: false, violation: err }
|
|
676
|
-
const fetchErr = message as import(
|
|
677
|
-
const idErr = this.checkKnownRequestId(fetchErr.request_id, message.type)
|
|
678
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
679
|
-
const existing = this._fetches.get(fetchErr.request_id)
|
|
696
|
+
const err = this.requireReady(message.type)
|
|
697
|
+
if (err) return { ok: false, violation: err }
|
|
698
|
+
const fetchErr = message as import('./types.js').Draft12FetchError
|
|
699
|
+
const idErr = this.checkKnownRequestId(fetchErr.request_id, message.type)
|
|
700
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
701
|
+
const existing = this._fetches.get(fetchErr.request_id)
|
|
680
702
|
if (!existing)
|
|
681
703
|
return {
|
|
682
704
|
ok: false,
|
|
683
705
|
violation: violation(
|
|
684
|
-
|
|
706
|
+
'UNKNOWN_REQUEST_ID',
|
|
685
707
|
`No fetch with request ID ${fetchErr.request_id}`,
|
|
686
708
|
this._phase,
|
|
687
709
|
message.type,
|
|
688
710
|
),
|
|
689
|
-
}
|
|
690
|
-
this._fetches.set(fetchErr.request_id, { ...existing, phase:
|
|
711
|
+
}
|
|
712
|
+
this._fetches.set(fetchErr.request_id, { ...existing, phase: 'error' })
|
|
691
713
|
sideEffects.push({
|
|
692
|
-
type:
|
|
714
|
+
type: 'fetch-ended',
|
|
693
715
|
requestId: fetchErr.request_id,
|
|
694
716
|
reason: fetchErr.reason_phrase,
|
|
695
|
-
})
|
|
696
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
717
|
+
})
|
|
718
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
697
719
|
}
|
|
698
720
|
|
|
699
721
|
private handleFetchCancel(
|
|
700
722
|
message: Draft12Message,
|
|
701
723
|
sideEffects: SideEffect[],
|
|
702
724
|
): TransitionResult<Draft12MessageType> {
|
|
703
|
-
const err = this.requireReady(message.type)
|
|
704
|
-
if (err) return { ok: false, violation: err }
|
|
705
|
-
const cancel = message as import(
|
|
706
|
-
const idErr = this.checkKnownRequestId(cancel.request_id, message.type)
|
|
707
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
708
|
-
const existing = this._fetches.get(cancel.request_id)
|
|
725
|
+
const err = this.requireReady(message.type)
|
|
726
|
+
if (err) return { ok: false, violation: err }
|
|
727
|
+
const cancel = message as import('./types.js').Draft12FetchCancel
|
|
728
|
+
const idErr = this.checkKnownRequestId(cancel.request_id, message.type)
|
|
729
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
730
|
+
const existing = this._fetches.get(cancel.request_id)
|
|
709
731
|
if (!existing)
|
|
710
732
|
return {
|
|
711
733
|
ok: false,
|
|
712
734
|
violation: violation(
|
|
713
|
-
|
|
735
|
+
'UNKNOWN_REQUEST_ID',
|
|
714
736
|
`No fetch with request ID ${cancel.request_id}`,
|
|
715
737
|
this._phase,
|
|
716
738
|
message.type,
|
|
717
739
|
),
|
|
718
|
-
}
|
|
719
|
-
this._fetches.set(cancel.request_id, { ...existing, phase:
|
|
720
|
-
sideEffects.push({
|
|
721
|
-
|
|
740
|
+
}
|
|
741
|
+
this._fetches.set(cancel.request_id, { ...existing, phase: 'cancelled' })
|
|
742
|
+
sideEffects.push({
|
|
743
|
+
type: 'fetch-ended',
|
|
744
|
+
requestId: cancel.request_id,
|
|
745
|
+
reason: 'cancelled',
|
|
746
|
+
})
|
|
747
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
722
748
|
}
|
|
723
749
|
|
|
724
750
|
// ─── Subscribe announces lifecycle ───
|
|
@@ -727,37 +753,37 @@ export class Draft12SessionFSM {
|
|
|
727
753
|
message: Draft12Message,
|
|
728
754
|
sideEffects: SideEffect[],
|
|
729
755
|
): TransitionResult<Draft12MessageType> {
|
|
730
|
-
const err = this.requireReady(message.type)
|
|
731
|
-
if (err) return { ok: false, violation: err }
|
|
732
|
-
const sa = message as import(
|
|
733
|
-
const dupErr = this.checkDuplicateRequestId(sa.request_id, message.type)
|
|
734
|
-
if (dupErr) return { ok: false, violation: dupErr }
|
|
735
|
-
this._requestIds.add(sa.request_id)
|
|
736
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
756
|
+
const err = this.requireReady(message.type)
|
|
757
|
+
if (err) return { ok: false, violation: err }
|
|
758
|
+
const sa = message as import('./types.js').Draft12SubscribeAnnounces
|
|
759
|
+
const dupErr = this.checkDuplicateRequestId(sa.request_id, message.type)
|
|
760
|
+
if (dupErr) return { ok: false, violation: dupErr }
|
|
761
|
+
this._requestIds.add(sa.request_id)
|
|
762
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
737
763
|
}
|
|
738
764
|
|
|
739
765
|
private handleSubscribeAnnouncesOk(
|
|
740
766
|
message: Draft12Message,
|
|
741
767
|
sideEffects: SideEffect[],
|
|
742
768
|
): TransitionResult<Draft12MessageType> {
|
|
743
|
-
const err = this.requireReady(message.type)
|
|
744
|
-
if (err) return { ok: false, violation: err }
|
|
745
|
-
const ok = message as import(
|
|
746
|
-
const idErr = this.checkKnownRequestId(ok.request_id, message.type)
|
|
747
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
748
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
769
|
+
const err = this.requireReady(message.type)
|
|
770
|
+
if (err) return { ok: false, violation: err }
|
|
771
|
+
const ok = message as import('./types.js').Draft12SubscribeAnnouncesOk
|
|
772
|
+
const idErr = this.checkKnownRequestId(ok.request_id, message.type)
|
|
773
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
774
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
749
775
|
}
|
|
750
776
|
|
|
751
777
|
private handleSubscribeAnnouncesError(
|
|
752
778
|
message: Draft12Message,
|
|
753
779
|
sideEffects: SideEffect[],
|
|
754
780
|
): TransitionResult<Draft12MessageType> {
|
|
755
|
-
const err = this.requireReady(message.type)
|
|
756
|
-
if (err) return { ok: false, violation: err }
|
|
757
|
-
const saErr = message as import(
|
|
758
|
-
const idErr = this.checkKnownRequestId(saErr.request_id, message.type)
|
|
759
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
760
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
781
|
+
const err = this.requireReady(message.type)
|
|
782
|
+
if (err) return { ok: false, violation: err }
|
|
783
|
+
const saErr = message as import('./types.js').Draft12SubscribeAnnouncesError
|
|
784
|
+
const idErr = this.checkKnownRequestId(saErr.request_id, message.type)
|
|
785
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
786
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
761
787
|
}
|
|
762
788
|
|
|
763
789
|
// ─── Track status lifecycle ───
|
|
@@ -766,40 +792,40 @@ export class Draft12SessionFSM {
|
|
|
766
792
|
message: Draft12Message,
|
|
767
793
|
sideEffects: SideEffect[],
|
|
768
794
|
): TransitionResult<Draft12MessageType> {
|
|
769
|
-
const err = this.requireReady(message.type)
|
|
770
|
-
if (err) return { ok: false, violation: err }
|
|
771
|
-
const tsr = message as import(
|
|
772
|
-
const dupErr = this.checkDuplicateRequestId(tsr.request_id, message.type)
|
|
773
|
-
if (dupErr) return { ok: false, violation: dupErr }
|
|
774
|
-
this._requestIds.add(tsr.request_id)
|
|
775
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
795
|
+
const err = this.requireReady(message.type)
|
|
796
|
+
if (err) return { ok: false, violation: err }
|
|
797
|
+
const tsr = message as import('./types.js').Draft12TrackStatusRequest
|
|
798
|
+
const dupErr = this.checkDuplicateRequestId(tsr.request_id, message.type)
|
|
799
|
+
if (dupErr) return { ok: false, violation: dupErr }
|
|
800
|
+
this._requestIds.add(tsr.request_id)
|
|
801
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
776
802
|
}
|
|
777
803
|
|
|
778
804
|
private handleTrackStatusResponse(
|
|
779
805
|
message: Draft12Message,
|
|
780
806
|
sideEffects: SideEffect[],
|
|
781
807
|
): TransitionResult<Draft12MessageType> {
|
|
782
|
-
const err = this.requireReady(message.type)
|
|
783
|
-
if (err) return { ok: false, violation: err }
|
|
784
|
-
const ts = message as import(
|
|
785
|
-
const idErr = this.checkKnownRequestId(ts.request_id, message.type)
|
|
786
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
787
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
808
|
+
const err = this.requireReady(message.type)
|
|
809
|
+
if (err) return { ok: false, violation: err }
|
|
810
|
+
const ts = message as import('./types.js').Draft12TrackStatus
|
|
811
|
+
const idErr = this.checkKnownRequestId(ts.request_id, message.type)
|
|
812
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
813
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
788
814
|
}
|
|
789
815
|
|
|
790
816
|
// ─── Generic ready-phase handler ───
|
|
791
817
|
|
|
792
818
|
private handleReadyPhaseMessage(message: Draft12Message): TransitionResult<Draft12MessageType> {
|
|
793
|
-
const err = this.requireReady(message.type)
|
|
794
|
-
if (err) return { ok: false, violation: err }
|
|
795
|
-
return { ok: true, phase: this._phase, sideEffects: [] }
|
|
819
|
+
const err = this.requireReady(message.type)
|
|
820
|
+
if (err) return { ok: false, violation: err }
|
|
821
|
+
return { ok: true, phase: this._phase, sideEffects: [] }
|
|
796
822
|
}
|
|
797
823
|
|
|
798
824
|
reset(): void {
|
|
799
|
-
this._phase =
|
|
800
|
-
this._subscriptions.clear()
|
|
801
|
-
this._announces.clear()
|
|
802
|
-
this._fetches.clear()
|
|
803
|
-
this._requestIds.clear()
|
|
825
|
+
this._phase = 'idle'
|
|
826
|
+
this._subscriptions.clear()
|
|
827
|
+
this._announces.clear()
|
|
828
|
+
this._fetches.clear()
|
|
829
|
+
this._requestIds.clear()
|
|
804
830
|
}
|
|
805
831
|
}
|