@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 { Draft11Message, Draft11MessageType } from
|
|
16
|
+
} from './rules.js'
|
|
17
|
+
import type { Draft11Message, Draft11MessageType } from './types.js'
|
|
18
18
|
|
|
19
19
|
function violation(
|
|
20
|
-
code: ProtocolViolation<Draft11MessageType>[
|
|
20
|
+
code: ProtocolViolation<Draft11MessageType>['code'],
|
|
21
21
|
message: string,
|
|
22
22
|
currentPhase: SessionPhase,
|
|
23
23
|
offendingMessage: Draft11MessageType,
|
|
24
24
|
): ProtocolViolation<Draft11MessageType> {
|
|
25
|
-
return { code, message, currentPhase, offendingMessage }
|
|
25
|
+
return { code, message, currentPhase, offendingMessage }
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export class Draft11SessionFSM {
|
|
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<Draft11MessageType> {
|
|
57
|
-
return getLegalOutgoing(this._phase, this._role)
|
|
57
|
+
return getLegalOutgoing(this._phase, this._role)
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
get legalIncoming(): ReadonlySet<Draft11MessageType> {
|
|
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: Draft11Message,
|
|
66
|
-
direction:
|
|
66
|
+
direction: 'inbound' | 'outbound',
|
|
67
67
|
): ProtocolViolation<Draft11MessageType> | 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 Draft11SessionFSM {
|
|
|
93
93
|
): ProtocolViolation<Draft11MessageType> | 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,208 +108,215 @@ export class Draft11SessionFSM {
|
|
|
108
108
|
): ProtocolViolation<Draft11MessageType> | 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: Draft11Message): ValidationResult<Draft11MessageType> {
|
|
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: Draft11Message): TransitionResult<Draft11MessageType> {
|
|
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: Draft11Message): TransitionResult<Draft11MessageType> {
|
|
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: Draft11Message,
|
|
154
|
-
direction:
|
|
154
|
+
direction: 'inbound' | 'outbound',
|
|
155
155
|
): TransitionResult<Draft11MessageType> {
|
|
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
|
// Fetch lifecycle
|
|
193
|
-
case
|
|
194
|
-
return this.handleFetch(message, sideEffects)
|
|
195
|
-
case
|
|
196
|
-
return this.handleFetchOk(message, sideEffects)
|
|
197
|
-
case
|
|
198
|
-
return this.handleFetchError(message, sideEffects)
|
|
199
|
-
case
|
|
200
|
-
return this.handleFetchCancel(message, sideEffects)
|
|
193
|
+
case 'fetch':
|
|
194
|
+
return this.handleFetch(message, sideEffects)
|
|
195
|
+
case 'fetch_ok':
|
|
196
|
+
return this.handleFetchOk(message, sideEffects)
|
|
197
|
+
case 'fetch_error':
|
|
198
|
+
return this.handleFetchError(message, sideEffects)
|
|
199
|
+
case 'fetch_cancel':
|
|
200
|
+
return this.handleFetchCancel(message, sideEffects)
|
|
201
201
|
|
|
202
202
|
// Subscribe announces lifecycle
|
|
203
|
-
case
|
|
204
|
-
return this.handleSubscribeAnnounces(message, sideEffects)
|
|
205
|
-
case
|
|
206
|
-
return this.handleSubscribeAnnouncesOk(message, sideEffects)
|
|
207
|
-
case
|
|
208
|
-
return this.handleSubscribeAnnouncesError(message, sideEffects)
|
|
203
|
+
case 'subscribe_announces':
|
|
204
|
+
return this.handleSubscribeAnnounces(message, sideEffects)
|
|
205
|
+
case 'subscribe_announces_ok':
|
|
206
|
+
return this.handleSubscribeAnnouncesOk(message, sideEffects)
|
|
207
|
+
case 'subscribe_announces_error':
|
|
208
|
+
return this.handleSubscribeAnnouncesError(message, sideEffects)
|
|
209
209
|
|
|
210
210
|
// Track status lifecycle
|
|
211
|
-
case
|
|
212
|
-
return this.handleTrackStatusRequest(message, sideEffects)
|
|
213
|
-
case
|
|
214
|
-
return this.handleTrackStatusResponse(message, sideEffects)
|
|
211
|
+
case 'track_status_request':
|
|
212
|
+
return this.handleTrackStatusRequest(message, sideEffects)
|
|
213
|
+
case 'track_status':
|
|
214
|
+
return this.handleTrackStatusResponse(message, sideEffects)
|
|
215
215
|
|
|
216
216
|
// Other ready-phase messages
|
|
217
217
|
default:
|
|
218
|
-
return this.handleReadyPhaseMessage(message)
|
|
218
|
+
return this.handleReadyPhaseMessage(message)
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
private handleClientSetup(
|
|
223
|
-
direction:
|
|
223
|
+
direction: 'inbound' | 'outbound',
|
|
224
224
|
): TransitionResult<Draft11MessageType> {
|
|
225
|
-
if (this._phase !==
|
|
225
|
+
if (this._phase !== 'idle') {
|
|
226
226
|
return {
|
|
227
227
|
ok: false,
|
|
228
228
|
violation: violation(
|
|
229
|
-
|
|
230
|
-
|
|
229
|
+
'SETUP_VIOLATION',
|
|
230
|
+
'CLIENT_SETUP already sent/received',
|
|
231
231
|
this._phase,
|
|
232
|
-
|
|
232
|
+
'client_setup',
|
|
233
233
|
),
|
|
234
|
-
}
|
|
234
|
+
}
|
|
235
235
|
}
|
|
236
|
-
if (direction ===
|
|
236
|
+
if (direction === 'outbound' && this._role !== 'client') {
|
|
237
237
|
return {
|
|
238
238
|
ok: false,
|
|
239
239
|
violation: violation(
|
|
240
|
-
|
|
241
|
-
|
|
240
|
+
'ROLE_VIOLATION',
|
|
241
|
+
'Only client can send CLIENT_SETUP',
|
|
242
242
|
this._phase,
|
|
243
|
-
|
|
243
|
+
'client_setup',
|
|
244
244
|
),
|
|
245
|
-
}
|
|
245
|
+
}
|
|
246
246
|
}
|
|
247
|
-
this._phase =
|
|
248
|
-
return { ok: true, phase: this._phase, sideEffects: [] }
|
|
247
|
+
this._phase = 'setup'
|
|
248
|
+
return { ok: true, phase: this._phase, sideEffects: [] }
|
|
249
249
|
}
|
|
250
250
|
|
|
251
251
|
private handleServerSetup(
|
|
252
|
-
direction:
|
|
252
|
+
direction: 'inbound' | 'outbound',
|
|
253
253
|
): TransitionResult<Draft11MessageType> {
|
|
254
|
-
if (this._phase !==
|
|
254
|
+
if (this._phase !== 'setup') {
|
|
255
255
|
return {
|
|
256
256
|
ok: false,
|
|
257
257
|
violation: violation(
|
|
258
|
-
|
|
259
|
-
|
|
258
|
+
'SETUP_VIOLATION',
|
|
259
|
+
'SERVER_SETUP before CLIENT_SETUP',
|
|
260
260
|
this._phase,
|
|
261
|
-
|
|
261
|
+
'server_setup',
|
|
262
262
|
),
|
|
263
|
-
}
|
|
263
|
+
}
|
|
264
264
|
}
|
|
265
|
-
if (direction ===
|
|
265
|
+
if (direction === 'outbound' && this._role !== 'server') {
|
|
266
266
|
return {
|
|
267
267
|
ok: false,
|
|
268
268
|
violation: violation(
|
|
269
|
-
|
|
270
|
-
|
|
269
|
+
'ROLE_VIOLATION',
|
|
270
|
+
'Only server can send SERVER_SETUP',
|
|
271
271
|
this._phase,
|
|
272
|
-
|
|
272
|
+
'server_setup',
|
|
273
273
|
),
|
|
274
|
-
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
this._phase = 'ready'
|
|
277
|
+
return {
|
|
278
|
+
ok: true,
|
|
279
|
+
phase: this._phase,
|
|
280
|
+
sideEffects: [{ type: 'session-ready' }],
|
|
275
281
|
}
|
|
276
|
-
this._phase = "ready";
|
|
277
|
-
return { ok: true, phase: this._phase, sideEffects: [{ type: "session-ready" }] };
|
|
278
282
|
}
|
|
279
283
|
|
|
280
284
|
private handleGoAway(
|
|
281
285
|
message: Draft11Message,
|
|
282
286
|
sideEffects: SideEffect[],
|
|
283
287
|
): TransitionResult<Draft11MessageType> {
|
|
284
|
-
if (this._phase !==
|
|
288
|
+
if (this._phase !== 'ready' && this._phase !== 'draining') {
|
|
285
289
|
return {
|
|
286
290
|
ok: false,
|
|
287
291
|
violation: violation(
|
|
288
|
-
|
|
292
|
+
'UNEXPECTED_MESSAGE',
|
|
289
293
|
`GOAWAY not valid in phase ${this._phase}`,
|
|
290
294
|
this._phase,
|
|
291
|
-
|
|
295
|
+
'goaway',
|
|
292
296
|
),
|
|
293
|
-
}
|
|
297
|
+
}
|
|
294
298
|
}
|
|
295
|
-
this._phase =
|
|
296
|
-
const goaway = message as import(
|
|
297
|
-
sideEffects.push({
|
|
298
|
-
|
|
299
|
+
this._phase = 'draining'
|
|
300
|
+
const goaway = message as import('./types.js').Draft11GoAway
|
|
301
|
+
sideEffects.push({
|
|
302
|
+
type: 'session-draining',
|
|
303
|
+
goAwayUri: goaway.new_session_uri,
|
|
304
|
+
})
|
|
305
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
299
306
|
}
|
|
300
307
|
|
|
301
308
|
private requireReady(msgType: Draft11MessageType): ProtocolViolation<Draft11MessageType> | null {
|
|
302
|
-
if (this._phase !==
|
|
309
|
+
if (this._phase !== 'ready' && this._phase !== 'draining') {
|
|
303
310
|
return violation(
|
|
304
|
-
this._phase ===
|
|
305
|
-
?
|
|
306
|
-
:
|
|
311
|
+
this._phase === 'idle' || this._phase === 'setup'
|
|
312
|
+
? 'MESSAGE_BEFORE_SETUP'
|
|
313
|
+
: 'UNEXPECTED_MESSAGE',
|
|
307
314
|
`${msgType} requires ready phase, current: ${this._phase}`,
|
|
308
315
|
this._phase,
|
|
309
316
|
msgType,
|
|
310
|
-
)
|
|
317
|
+
)
|
|
311
318
|
}
|
|
312
|
-
return null
|
|
319
|
+
return null
|
|
313
320
|
}
|
|
314
321
|
|
|
315
322
|
// ─── Subscribe lifecycle ───
|
|
@@ -318,184 +325,187 @@ export class Draft11SessionFSM {
|
|
|
318
325
|
message: Draft11Message,
|
|
319
326
|
sideEffects: SideEffect[],
|
|
320
327
|
): TransitionResult<Draft11MessageType> {
|
|
321
|
-
const err = this.requireReady(message.type)
|
|
322
|
-
if (err) return { ok: false, violation: err }
|
|
323
|
-
const sub = message as import(
|
|
324
|
-
const dupErr = this.checkDuplicateRequestId(sub.request_id, message.type)
|
|
325
|
-
if (dupErr) return { ok: false, violation: dupErr }
|
|
326
|
-
this._requestIds.add(sub.request_id)
|
|
328
|
+
const err = this.requireReady(message.type)
|
|
329
|
+
if (err) return { ok: false, violation: err }
|
|
330
|
+
const sub = message as import('./types.js').Draft11Subscribe
|
|
331
|
+
const dupErr = this.checkDuplicateRequestId(sub.request_id, message.type)
|
|
332
|
+
if (dupErr) return { ok: false, violation: dupErr }
|
|
333
|
+
this._requestIds.add(sub.request_id)
|
|
327
334
|
this._subscriptions.set(sub.request_id, {
|
|
328
335
|
subscribeId: sub.request_id,
|
|
329
|
-
phase:
|
|
336
|
+
phase: 'pending',
|
|
330
337
|
trackNamespace: sub.track_namespace,
|
|
331
338
|
trackName: sub.track_name,
|
|
332
|
-
})
|
|
333
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
339
|
+
})
|
|
340
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
334
341
|
}
|
|
335
342
|
|
|
336
343
|
private handleSubscribeOk(
|
|
337
344
|
message: Draft11Message,
|
|
338
345
|
sideEffects: SideEffect[],
|
|
339
346
|
): TransitionResult<Draft11MessageType> {
|
|
340
|
-
const err = this.requireReady(message.type)
|
|
341
|
-
if (err) return { ok: false, violation: err }
|
|
342
|
-
const ok = message as import(
|
|
343
|
-
const idErr = this.checkKnownRequestId(ok.request_id, message.type)
|
|
344
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
345
|
-
const existing = this._subscriptions.get(ok.request_id)
|
|
347
|
+
const err = this.requireReady(message.type)
|
|
348
|
+
if (err) return { ok: false, violation: err }
|
|
349
|
+
const ok = message as import('./types.js').Draft11SubscribeOk
|
|
350
|
+
const idErr = this.checkKnownRequestId(ok.request_id, message.type)
|
|
351
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
352
|
+
const existing = this._subscriptions.get(ok.request_id)
|
|
346
353
|
if (!existing)
|
|
347
354
|
return {
|
|
348
355
|
ok: false,
|
|
349
356
|
violation: violation(
|
|
350
|
-
|
|
357
|
+
'UNKNOWN_REQUEST_ID',
|
|
351
358
|
`No subscription with request ID ${ok.request_id}`,
|
|
352
359
|
this._phase,
|
|
353
360
|
message.type,
|
|
354
361
|
),
|
|
355
|
-
}
|
|
356
|
-
if (existing.phase !==
|
|
362
|
+
}
|
|
363
|
+
if (existing.phase !== 'pending')
|
|
357
364
|
return {
|
|
358
365
|
ok: false,
|
|
359
366
|
violation: violation(
|
|
360
|
-
|
|
367
|
+
'STATE_VIOLATION',
|
|
361
368
|
`Subscription ${ok.request_id} is ${existing.phase}, not pending`,
|
|
362
369
|
this._phase,
|
|
363
370
|
message.type,
|
|
364
371
|
),
|
|
365
|
-
}
|
|
366
|
-
this._subscriptions.set(ok.request_id, { ...existing, phase:
|
|
367
|
-
sideEffects.push({
|
|
368
|
-
|
|
372
|
+
}
|
|
373
|
+
this._subscriptions.set(ok.request_id, { ...existing, phase: 'active' })
|
|
374
|
+
sideEffects.push({
|
|
375
|
+
type: 'subscription-activated',
|
|
376
|
+
subscribeId: ok.request_id,
|
|
377
|
+
})
|
|
378
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
369
379
|
}
|
|
370
380
|
|
|
371
381
|
private handleSubscribeError(
|
|
372
382
|
message: Draft11Message,
|
|
373
383
|
sideEffects: SideEffect[],
|
|
374
384
|
): TransitionResult<Draft11MessageType> {
|
|
375
|
-
const err = this.requireReady(message.type)
|
|
376
|
-
if (err) return { ok: false, violation: err }
|
|
377
|
-
const subErr = message as import(
|
|
378
|
-
const idErr = this.checkKnownRequestId(subErr.request_id, message.type)
|
|
379
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
380
|
-
const existing = this._subscriptions.get(subErr.request_id)
|
|
385
|
+
const err = this.requireReady(message.type)
|
|
386
|
+
if (err) return { ok: false, violation: err }
|
|
387
|
+
const subErr = message as import('./types.js').Draft11SubscribeError
|
|
388
|
+
const idErr = this.checkKnownRequestId(subErr.request_id, message.type)
|
|
389
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
390
|
+
const existing = this._subscriptions.get(subErr.request_id)
|
|
381
391
|
if (!existing)
|
|
382
392
|
return {
|
|
383
393
|
ok: false,
|
|
384
394
|
violation: violation(
|
|
385
|
-
|
|
395
|
+
'UNKNOWN_REQUEST_ID',
|
|
386
396
|
`No subscription with request ID ${subErr.request_id}`,
|
|
387
397
|
this._phase,
|
|
388
398
|
message.type,
|
|
389
399
|
),
|
|
390
|
-
}
|
|
391
|
-
if (existing.phase !==
|
|
400
|
+
}
|
|
401
|
+
if (existing.phase !== 'pending')
|
|
392
402
|
return {
|
|
393
403
|
ok: false,
|
|
394
404
|
violation: violation(
|
|
395
|
-
|
|
405
|
+
'STATE_VIOLATION',
|
|
396
406
|
`Subscription ${subErr.request_id} is ${existing.phase}, not pending`,
|
|
397
407
|
this._phase,
|
|
398
408
|
message.type,
|
|
399
409
|
),
|
|
400
|
-
}
|
|
401
|
-
this._subscriptions.set(subErr.request_id, { ...existing, phase:
|
|
410
|
+
}
|
|
411
|
+
this._subscriptions.set(subErr.request_id, { ...existing, phase: 'error' })
|
|
402
412
|
sideEffects.push({
|
|
403
|
-
type:
|
|
413
|
+
type: 'subscription-ended',
|
|
404
414
|
subscribeId: subErr.request_id,
|
|
405
415
|
reason: subErr.reason_phrase,
|
|
406
|
-
})
|
|
407
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
416
|
+
})
|
|
417
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
408
418
|
}
|
|
409
419
|
|
|
410
420
|
private handleSubscribeUpdate(
|
|
411
421
|
message: Draft11Message,
|
|
412
422
|
sideEffects: SideEffect[],
|
|
413
423
|
): TransitionResult<Draft11MessageType> {
|
|
414
|
-
const err = this.requireReady(message.type)
|
|
415
|
-
if (err) return { ok: false, violation: err }
|
|
416
|
-
const update = message as import(
|
|
417
|
-
const idErr = this.checkKnownRequestId(update.request_id, message.type)
|
|
418
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
419
|
-
const existing = this._subscriptions.get(update.request_id)
|
|
424
|
+
const err = this.requireReady(message.type)
|
|
425
|
+
if (err) return { ok: false, violation: err }
|
|
426
|
+
const update = message as import('./types.js').Draft11SubscribeUpdate
|
|
427
|
+
const idErr = this.checkKnownRequestId(update.request_id, message.type)
|
|
428
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
429
|
+
const existing = this._subscriptions.get(update.request_id)
|
|
420
430
|
if (!existing)
|
|
421
431
|
return {
|
|
422
432
|
ok: false,
|
|
423
433
|
violation: violation(
|
|
424
|
-
|
|
434
|
+
'UNKNOWN_REQUEST_ID',
|
|
425
435
|
`No subscription with request ID ${update.request_id}`,
|
|
426
436
|
this._phase,
|
|
427
437
|
message.type,
|
|
428
438
|
),
|
|
429
|
-
}
|
|
430
|
-
if (existing.phase !==
|
|
439
|
+
}
|
|
440
|
+
if (existing.phase !== 'active')
|
|
431
441
|
return {
|
|
432
442
|
ok: false,
|
|
433
443
|
violation: violation(
|
|
434
|
-
|
|
444
|
+
'STATE_VIOLATION',
|
|
435
445
|
`Subscription ${update.request_id} is ${existing.phase}, not active`,
|
|
436
446
|
this._phase,
|
|
437
447
|
message.type,
|
|
438
448
|
),
|
|
439
|
-
}
|
|
440
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
449
|
+
}
|
|
450
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
441
451
|
}
|
|
442
452
|
|
|
443
453
|
private handleSubscribeDone(
|
|
444
454
|
message: Draft11Message,
|
|
445
455
|
sideEffects: SideEffect[],
|
|
446
456
|
): TransitionResult<Draft11MessageType> {
|
|
447
|
-
const err = this.requireReady(message.type)
|
|
448
|
-
if (err) return { ok: false, violation: err }
|
|
449
|
-
const done = message as import(
|
|
450
|
-
const idErr = this.checkKnownRequestId(done.request_id, message.type)
|
|
451
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
452
|
-
const existing = this._subscriptions.get(done.request_id)
|
|
457
|
+
const err = this.requireReady(message.type)
|
|
458
|
+
if (err) return { ok: false, violation: err }
|
|
459
|
+
const done = message as import('./types.js').Draft11SubscribeDone
|
|
460
|
+
const idErr = this.checkKnownRequestId(done.request_id, message.type)
|
|
461
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
462
|
+
const existing = this._subscriptions.get(done.request_id)
|
|
453
463
|
if (!existing)
|
|
454
464
|
return {
|
|
455
465
|
ok: false,
|
|
456
466
|
violation: violation(
|
|
457
|
-
|
|
467
|
+
'UNKNOWN_REQUEST_ID',
|
|
458
468
|
`No subscription with request ID ${done.request_id}`,
|
|
459
469
|
this._phase,
|
|
460
470
|
message.type,
|
|
461
471
|
),
|
|
462
|
-
}
|
|
463
|
-
this._subscriptions.set(done.request_id, { ...existing, phase:
|
|
472
|
+
}
|
|
473
|
+
this._subscriptions.set(done.request_id, { ...existing, phase: 'done' })
|
|
464
474
|
sideEffects.push({
|
|
465
|
-
type:
|
|
475
|
+
type: 'subscription-ended',
|
|
466
476
|
subscribeId: done.request_id,
|
|
467
477
|
reason: done.reason_phrase,
|
|
468
|
-
})
|
|
469
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
478
|
+
})
|
|
479
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
470
480
|
}
|
|
471
481
|
|
|
472
482
|
private handleUnsubscribe(
|
|
473
483
|
message: Draft11Message,
|
|
474
484
|
sideEffects: SideEffect[],
|
|
475
485
|
): TransitionResult<Draft11MessageType> {
|
|
476
|
-
const err = this.requireReady(message.type)
|
|
477
|
-
if (err) return { ok: false, violation: err }
|
|
478
|
-
const unsub = message as import(
|
|
479
|
-
const idErr = this.checkKnownRequestId(unsub.request_id, message.type)
|
|
480
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
481
|
-
const existing = this._subscriptions.get(unsub.request_id)
|
|
486
|
+
const err = this.requireReady(message.type)
|
|
487
|
+
if (err) return { ok: false, violation: err }
|
|
488
|
+
const unsub = message as import('./types.js').Draft11Unsubscribe
|
|
489
|
+
const idErr = this.checkKnownRequestId(unsub.request_id, message.type)
|
|
490
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
491
|
+
const existing = this._subscriptions.get(unsub.request_id)
|
|
482
492
|
if (!existing)
|
|
483
493
|
return {
|
|
484
494
|
ok: false,
|
|
485
495
|
violation: violation(
|
|
486
|
-
|
|
496
|
+
'UNKNOWN_REQUEST_ID',
|
|
487
497
|
`No subscription with request ID ${unsub.request_id}`,
|
|
488
498
|
this._phase,
|
|
489
499
|
message.type,
|
|
490
500
|
),
|
|
491
|
-
}
|
|
492
|
-
this._subscriptions.set(unsub.request_id, { ...existing, phase:
|
|
501
|
+
}
|
|
502
|
+
this._subscriptions.set(unsub.request_id, { ...existing, phase: 'done' })
|
|
493
503
|
sideEffects.push({
|
|
494
|
-
type:
|
|
504
|
+
type: 'subscription-ended',
|
|
495
505
|
subscribeId: unsub.request_id,
|
|
496
|
-
reason:
|
|
497
|
-
})
|
|
498
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
506
|
+
reason: 'unsubscribed',
|
|
507
|
+
})
|
|
508
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
499
509
|
}
|
|
500
510
|
|
|
501
511
|
// ─── Announce lifecycle ───
|
|
@@ -504,69 +514,78 @@ export class Draft11SessionFSM {
|
|
|
504
514
|
message: Draft11Message,
|
|
505
515
|
sideEffects: SideEffect[],
|
|
506
516
|
): TransitionResult<Draft11MessageType> {
|
|
507
|
-
const err = this.requireReady(message.type)
|
|
508
|
-
if (err) return { ok: false, violation: err }
|
|
509
|
-
const ann = message as import(
|
|
510
|
-
const nsKey = ann.track_namespace.join(
|
|
511
|
-
this._requestIds.add(ann.request_id)
|
|
512
|
-
this._announces.set(nsKey, {
|
|
513
|
-
|
|
517
|
+
const err = this.requireReady(message.type)
|
|
518
|
+
if (err) return { ok: false, violation: err }
|
|
519
|
+
const ann = message as import('./types.js').Draft11Announce
|
|
520
|
+
const nsKey = ann.track_namespace.join('/')
|
|
521
|
+
this._requestIds.add(ann.request_id)
|
|
522
|
+
this._announces.set(nsKey, {
|
|
523
|
+
namespace: ann.track_namespace,
|
|
524
|
+
phase: 'pending',
|
|
525
|
+
})
|
|
526
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
514
527
|
}
|
|
515
528
|
|
|
516
529
|
private handleAnnounceOk(
|
|
517
530
|
message: Draft11Message,
|
|
518
531
|
sideEffects: SideEffect[],
|
|
519
532
|
): TransitionResult<Draft11MessageType> {
|
|
520
|
-
const err = this.requireReady(message.type)
|
|
521
|
-
if (err) return { ok: false, violation: err }
|
|
522
|
-
const ok = message as import(
|
|
523
|
-
const idErr = this.checkKnownRequestId(ok.request_id, message.type)
|
|
524
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
525
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
533
|
+
const err = this.requireReady(message.type)
|
|
534
|
+
if (err) return { ok: false, violation: err }
|
|
535
|
+
const ok = message as import('./types.js').Draft11AnnounceOk
|
|
536
|
+
const idErr = this.checkKnownRequestId(ok.request_id, message.type)
|
|
537
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
538
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
526
539
|
}
|
|
527
540
|
|
|
528
541
|
private handleAnnounceError(
|
|
529
542
|
message: Draft11Message,
|
|
530
543
|
sideEffects: SideEffect[],
|
|
531
544
|
): TransitionResult<Draft11MessageType> {
|
|
532
|
-
const err = this.requireReady(message.type)
|
|
533
|
-
if (err) return { ok: false, violation: err }
|
|
534
|
-
const annErr = message as import(
|
|
535
|
-
const idErr = this.checkKnownRequestId(annErr.request_id, message.type)
|
|
536
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
537
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
545
|
+
const err = this.requireReady(message.type)
|
|
546
|
+
if (err) return { ok: false, violation: err }
|
|
547
|
+
const annErr = message as import('./types.js').Draft11AnnounceError
|
|
548
|
+
const idErr = this.checkKnownRequestId(annErr.request_id, message.type)
|
|
549
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
550
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
538
551
|
}
|
|
539
552
|
|
|
540
553
|
private handleUnannounce(
|
|
541
554
|
message: Draft11Message,
|
|
542
555
|
sideEffects: SideEffect[],
|
|
543
556
|
): TransitionResult<Draft11MessageType> {
|
|
544
|
-
const err = this.requireReady(message.type)
|
|
545
|
-
if (err) return { ok: false, violation: err }
|
|
546
|
-
const unann = message as import(
|
|
547
|
-
const nsKey = unann.track_namespace.join(
|
|
548
|
-
const existing = this._announces.get(nsKey)
|
|
557
|
+
const err = this.requireReady(message.type)
|
|
558
|
+
if (err) return { ok: false, violation: err }
|
|
559
|
+
const unann = message as import('./types.js').Draft11Unannounce
|
|
560
|
+
const nsKey = unann.track_namespace.join('/')
|
|
561
|
+
const existing = this._announces.get(nsKey)
|
|
549
562
|
if (existing) {
|
|
550
|
-
this._announces.delete(nsKey)
|
|
551
|
-
sideEffects.push({
|
|
563
|
+
this._announces.delete(nsKey)
|
|
564
|
+
sideEffects.push({
|
|
565
|
+
type: 'announce-ended',
|
|
566
|
+
namespace: unann.track_namespace,
|
|
567
|
+
})
|
|
552
568
|
}
|
|
553
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
569
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
554
570
|
}
|
|
555
571
|
|
|
556
572
|
private handleAnnounceCancel(
|
|
557
573
|
message: Draft11Message,
|
|
558
574
|
sideEffects: SideEffect[],
|
|
559
575
|
): TransitionResult<Draft11MessageType> {
|
|
560
|
-
const err = this.requireReady(message.type)
|
|
561
|
-
if (err) return { ok: false, violation: err }
|
|
562
|
-
const cancel = message as import(
|
|
563
|
-
const nsKey = cancel.track_namespace.join(
|
|
564
|
-
const existing = this._announces.get(nsKey)
|
|
576
|
+
const err = this.requireReady(message.type)
|
|
577
|
+
if (err) return { ok: false, violation: err }
|
|
578
|
+
const cancel = message as import('./types.js').Draft11AnnounceCancel
|
|
579
|
+
const nsKey = cancel.track_namespace.join('/')
|
|
580
|
+
const existing = this._announces.get(nsKey)
|
|
565
581
|
if (existing) {
|
|
566
|
-
this._announces.delete(nsKey)
|
|
567
|
-
sideEffects.push({
|
|
582
|
+
this._announces.delete(nsKey)
|
|
583
|
+
sideEffects.push({
|
|
584
|
+
type: 'announce-ended',
|
|
585
|
+
namespace: cancel.track_namespace,
|
|
586
|
+
})
|
|
568
587
|
}
|
|
569
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
588
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
570
589
|
}
|
|
571
590
|
|
|
572
591
|
// ─── Fetch lifecycle ───
|
|
@@ -575,103 +594,110 @@ export class Draft11SessionFSM {
|
|
|
575
594
|
message: Draft11Message,
|
|
576
595
|
sideEffects: SideEffect[],
|
|
577
596
|
): TransitionResult<Draft11MessageType> {
|
|
578
|
-
const err = this.requireReady(message.type)
|
|
579
|
-
if (err) return { ok: false, violation: err }
|
|
580
|
-
const fetch = message as import(
|
|
581
|
-
const dupErr = this.checkDuplicateRequestId(fetch.request_id, message.type)
|
|
582
|
-
if (dupErr) return { ok: false, violation: dupErr }
|
|
583
|
-
this._requestIds.add(fetch.request_id)
|
|
584
|
-
this._fetches.set(fetch.request_id, {
|
|
585
|
-
|
|
597
|
+
const err = this.requireReady(message.type)
|
|
598
|
+
if (err) return { ok: false, violation: err }
|
|
599
|
+
const fetch = message as import('./types.js').Draft11Fetch
|
|
600
|
+
const dupErr = this.checkDuplicateRequestId(fetch.request_id, message.type)
|
|
601
|
+
if (dupErr) return { ok: false, violation: dupErr }
|
|
602
|
+
this._requestIds.add(fetch.request_id)
|
|
603
|
+
this._fetches.set(fetch.request_id, {
|
|
604
|
+
requestId: fetch.request_id,
|
|
605
|
+
phase: 'pending',
|
|
606
|
+
})
|
|
607
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
586
608
|
}
|
|
587
609
|
|
|
588
610
|
private handleFetchOk(
|
|
589
611
|
message: Draft11Message,
|
|
590
612
|
sideEffects: SideEffect[],
|
|
591
613
|
): TransitionResult<Draft11MessageType> {
|
|
592
|
-
const err = this.requireReady(message.type)
|
|
593
|
-
if (err) return { ok: false, violation: err }
|
|
594
|
-
const ok = message as import(
|
|
595
|
-
const idErr = this.checkKnownRequestId(ok.request_id, message.type)
|
|
596
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
597
|
-
const existing = this._fetches.get(ok.request_id)
|
|
614
|
+
const err = this.requireReady(message.type)
|
|
615
|
+
if (err) return { ok: false, violation: err }
|
|
616
|
+
const ok = message as import('./types.js').Draft11FetchOk
|
|
617
|
+
const idErr = this.checkKnownRequestId(ok.request_id, message.type)
|
|
618
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
619
|
+
const existing = this._fetches.get(ok.request_id)
|
|
598
620
|
if (!existing)
|
|
599
621
|
return {
|
|
600
622
|
ok: false,
|
|
601
623
|
violation: violation(
|
|
602
|
-
|
|
624
|
+
'UNKNOWN_REQUEST_ID',
|
|
603
625
|
`No fetch with request ID ${ok.request_id}`,
|
|
604
626
|
this._phase,
|
|
605
627
|
message.type,
|
|
606
628
|
),
|
|
607
|
-
}
|
|
608
|
-
if (existing.phase !==
|
|
629
|
+
}
|
|
630
|
+
if (existing.phase !== 'pending')
|
|
609
631
|
return {
|
|
610
632
|
ok: false,
|
|
611
633
|
violation: violation(
|
|
612
|
-
|
|
634
|
+
'STATE_VIOLATION',
|
|
613
635
|
`Fetch ${ok.request_id} is ${existing.phase}, not pending`,
|
|
614
636
|
this._phase,
|
|
615
637
|
message.type,
|
|
616
638
|
),
|
|
617
|
-
}
|
|
618
|
-
this._fetches.set(ok.request_id, { ...existing, phase:
|
|
619
|
-
sideEffects.push({ type:
|
|
620
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
639
|
+
}
|
|
640
|
+
this._fetches.set(ok.request_id, { ...existing, phase: 'active' })
|
|
641
|
+
sideEffects.push({ type: 'fetch-activated', requestId: ok.request_id })
|
|
642
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
621
643
|
}
|
|
622
644
|
|
|
623
645
|
private handleFetchError(
|
|
624
646
|
message: Draft11Message,
|
|
625
647
|
sideEffects: SideEffect[],
|
|
626
648
|
): TransitionResult<Draft11MessageType> {
|
|
627
|
-
const err = this.requireReady(message.type)
|
|
628
|
-
if (err) return { ok: false, violation: err }
|
|
629
|
-
const fetchErr = message as import(
|
|
630
|
-
const idErr = this.checkKnownRequestId(fetchErr.request_id, message.type)
|
|
631
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
632
|
-
const existing = this._fetches.get(fetchErr.request_id)
|
|
649
|
+
const err = this.requireReady(message.type)
|
|
650
|
+
if (err) return { ok: false, violation: err }
|
|
651
|
+
const fetchErr = message as import('./types.js').Draft11FetchError
|
|
652
|
+
const idErr = this.checkKnownRequestId(fetchErr.request_id, message.type)
|
|
653
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
654
|
+
const existing = this._fetches.get(fetchErr.request_id)
|
|
633
655
|
if (!existing)
|
|
634
656
|
return {
|
|
635
657
|
ok: false,
|
|
636
658
|
violation: violation(
|
|
637
|
-
|
|
659
|
+
'UNKNOWN_REQUEST_ID',
|
|
638
660
|
`No fetch with request ID ${fetchErr.request_id}`,
|
|
639
661
|
this._phase,
|
|
640
662
|
message.type,
|
|
641
663
|
),
|
|
642
|
-
}
|
|
643
|
-
this._fetches.set(fetchErr.request_id, { ...existing, phase:
|
|
664
|
+
}
|
|
665
|
+
this._fetches.set(fetchErr.request_id, { ...existing, phase: 'error' })
|
|
644
666
|
sideEffects.push({
|
|
645
|
-
type:
|
|
667
|
+
type: 'fetch-ended',
|
|
646
668
|
requestId: fetchErr.request_id,
|
|
647
669
|
reason: fetchErr.reason_phrase,
|
|
648
|
-
})
|
|
649
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
670
|
+
})
|
|
671
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
650
672
|
}
|
|
651
673
|
|
|
652
674
|
private handleFetchCancel(
|
|
653
675
|
message: Draft11Message,
|
|
654
676
|
sideEffects: SideEffect[],
|
|
655
677
|
): TransitionResult<Draft11MessageType> {
|
|
656
|
-
const err = this.requireReady(message.type)
|
|
657
|
-
if (err) return { ok: false, violation: err }
|
|
658
|
-
const cancel = message as import(
|
|
659
|
-
const idErr = this.checkKnownRequestId(cancel.request_id, message.type)
|
|
660
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
661
|
-
const existing = this._fetches.get(cancel.request_id)
|
|
678
|
+
const err = this.requireReady(message.type)
|
|
679
|
+
if (err) return { ok: false, violation: err }
|
|
680
|
+
const cancel = message as import('./types.js').Draft11FetchCancel
|
|
681
|
+
const idErr = this.checkKnownRequestId(cancel.request_id, message.type)
|
|
682
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
683
|
+
const existing = this._fetches.get(cancel.request_id)
|
|
662
684
|
if (!existing)
|
|
663
685
|
return {
|
|
664
686
|
ok: false,
|
|
665
687
|
violation: violation(
|
|
666
|
-
|
|
688
|
+
'UNKNOWN_REQUEST_ID',
|
|
667
689
|
`No fetch with request ID ${cancel.request_id}`,
|
|
668
690
|
this._phase,
|
|
669
691
|
message.type,
|
|
670
692
|
),
|
|
671
|
-
}
|
|
672
|
-
this._fetches.set(cancel.request_id, { ...existing, phase:
|
|
673
|
-
sideEffects.push({
|
|
674
|
-
|
|
693
|
+
}
|
|
694
|
+
this._fetches.set(cancel.request_id, { ...existing, phase: 'cancelled' })
|
|
695
|
+
sideEffects.push({
|
|
696
|
+
type: 'fetch-ended',
|
|
697
|
+
requestId: cancel.request_id,
|
|
698
|
+
reason: 'cancelled',
|
|
699
|
+
})
|
|
700
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
675
701
|
}
|
|
676
702
|
|
|
677
703
|
// ─── Subscribe announces lifecycle ───
|
|
@@ -680,37 +706,37 @@ export class Draft11SessionFSM {
|
|
|
680
706
|
message: Draft11Message,
|
|
681
707
|
sideEffects: SideEffect[],
|
|
682
708
|
): TransitionResult<Draft11MessageType> {
|
|
683
|
-
const err = this.requireReady(message.type)
|
|
684
|
-
if (err) return { ok: false, violation: err }
|
|
685
|
-
const sa = message as import(
|
|
686
|
-
const dupErr = this.checkDuplicateRequestId(sa.request_id, message.type)
|
|
687
|
-
if (dupErr) return { ok: false, violation: dupErr }
|
|
688
|
-
this._requestIds.add(sa.request_id)
|
|
689
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
709
|
+
const err = this.requireReady(message.type)
|
|
710
|
+
if (err) return { ok: false, violation: err }
|
|
711
|
+
const sa = message as import('./types.js').Draft11SubscribeAnnounces
|
|
712
|
+
const dupErr = this.checkDuplicateRequestId(sa.request_id, message.type)
|
|
713
|
+
if (dupErr) return { ok: false, violation: dupErr }
|
|
714
|
+
this._requestIds.add(sa.request_id)
|
|
715
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
690
716
|
}
|
|
691
717
|
|
|
692
718
|
private handleSubscribeAnnouncesOk(
|
|
693
719
|
message: Draft11Message,
|
|
694
720
|
sideEffects: SideEffect[],
|
|
695
721
|
): TransitionResult<Draft11MessageType> {
|
|
696
|
-
const err = this.requireReady(message.type)
|
|
697
|
-
if (err) return { ok: false, violation: err }
|
|
698
|
-
const ok = message as import(
|
|
699
|
-
const idErr = this.checkKnownRequestId(ok.request_id, message.type)
|
|
700
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
701
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
722
|
+
const err = this.requireReady(message.type)
|
|
723
|
+
if (err) return { ok: false, violation: err }
|
|
724
|
+
const ok = message as import('./types.js').Draft11SubscribeAnnouncesOk
|
|
725
|
+
const idErr = this.checkKnownRequestId(ok.request_id, message.type)
|
|
726
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
727
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
702
728
|
}
|
|
703
729
|
|
|
704
730
|
private handleSubscribeAnnouncesError(
|
|
705
731
|
message: Draft11Message,
|
|
706
732
|
sideEffects: SideEffect[],
|
|
707
733
|
): TransitionResult<Draft11MessageType> {
|
|
708
|
-
const err = this.requireReady(message.type)
|
|
709
|
-
if (err) return { ok: false, violation: err }
|
|
710
|
-
const saErr = message as import(
|
|
711
|
-
const idErr = this.checkKnownRequestId(saErr.request_id, message.type)
|
|
712
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
713
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
734
|
+
const err = this.requireReady(message.type)
|
|
735
|
+
if (err) return { ok: false, violation: err }
|
|
736
|
+
const saErr = message as import('./types.js').Draft11SubscribeAnnouncesError
|
|
737
|
+
const idErr = this.checkKnownRequestId(saErr.request_id, message.type)
|
|
738
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
739
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
714
740
|
}
|
|
715
741
|
|
|
716
742
|
// ─── Track status lifecycle ───
|
|
@@ -719,40 +745,40 @@ export class Draft11SessionFSM {
|
|
|
719
745
|
message: Draft11Message,
|
|
720
746
|
sideEffects: SideEffect[],
|
|
721
747
|
): TransitionResult<Draft11MessageType> {
|
|
722
|
-
const err = this.requireReady(message.type)
|
|
723
|
-
if (err) return { ok: false, violation: err }
|
|
724
|
-
const tsr = message as import(
|
|
725
|
-
const dupErr = this.checkDuplicateRequestId(tsr.request_id, message.type)
|
|
726
|
-
if (dupErr) return { ok: false, violation: dupErr }
|
|
727
|
-
this._requestIds.add(tsr.request_id)
|
|
728
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
748
|
+
const err = this.requireReady(message.type)
|
|
749
|
+
if (err) return { ok: false, violation: err }
|
|
750
|
+
const tsr = message as import('./types.js').Draft11TrackStatusRequest
|
|
751
|
+
const dupErr = this.checkDuplicateRequestId(tsr.request_id, message.type)
|
|
752
|
+
if (dupErr) return { ok: false, violation: dupErr }
|
|
753
|
+
this._requestIds.add(tsr.request_id)
|
|
754
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
729
755
|
}
|
|
730
756
|
|
|
731
757
|
private handleTrackStatusResponse(
|
|
732
758
|
message: Draft11Message,
|
|
733
759
|
sideEffects: SideEffect[],
|
|
734
760
|
): TransitionResult<Draft11MessageType> {
|
|
735
|
-
const err = this.requireReady(message.type)
|
|
736
|
-
if (err) return { ok: false, violation: err }
|
|
737
|
-
const ts = message as import(
|
|
738
|
-
const idErr = this.checkKnownRequestId(ts.request_id, message.type)
|
|
739
|
-
if (idErr) return { ok: false, violation: idErr }
|
|
740
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
761
|
+
const err = this.requireReady(message.type)
|
|
762
|
+
if (err) return { ok: false, violation: err }
|
|
763
|
+
const ts = message as import('./types.js').Draft11TrackStatus
|
|
764
|
+
const idErr = this.checkKnownRequestId(ts.request_id, message.type)
|
|
765
|
+
if (idErr) return { ok: false, violation: idErr }
|
|
766
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
741
767
|
}
|
|
742
768
|
|
|
743
769
|
// ─── Generic ready-phase handler ───
|
|
744
770
|
|
|
745
771
|
private handleReadyPhaseMessage(message: Draft11Message): TransitionResult<Draft11MessageType> {
|
|
746
|
-
const err = this.requireReady(message.type)
|
|
747
|
-
if (err) return { ok: false, violation: err }
|
|
748
|
-
return { ok: true, phase: this._phase, sideEffects: [] }
|
|
772
|
+
const err = this.requireReady(message.type)
|
|
773
|
+
if (err) return { ok: false, violation: err }
|
|
774
|
+
return { ok: true, phase: this._phase, sideEffects: [] }
|
|
749
775
|
}
|
|
750
776
|
|
|
751
777
|
reset(): void {
|
|
752
|
-
this._phase =
|
|
753
|
-
this._subscriptions.clear()
|
|
754
|
-
this._announces.clear()
|
|
755
|
-
this._fetches.clear()
|
|
756
|
-
this._requestIds.clear()
|
|
778
|
+
this._phase = 'idle'
|
|
779
|
+
this._subscriptions.clear()
|
|
780
|
+
this._announces.clear()
|
|
781
|
+
this._fetches.clear()
|
|
782
|
+
this._requestIds.clear()
|
|
757
783
|
}
|
|
758
784
|
}
|