@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
|
@@ -8,60 +8,60 @@ import type {
|
|
|
8
8
|
SubscriptionState,
|
|
9
9
|
TransitionResult,
|
|
10
10
|
ValidationResult,
|
|
11
|
-
} from
|
|
12
|
-
import { getLegalIncoming, getLegalOutgoing } from
|
|
13
|
-
import type { Draft17Message, Draft17MessageType } from
|
|
11
|
+
} from '../../core/session-types.js'
|
|
12
|
+
import { getLegalIncoming, getLegalOutgoing } from './rules.js'
|
|
13
|
+
import type { Draft17Message, Draft17MessageType } from './types.js'
|
|
14
14
|
|
|
15
15
|
function violation(
|
|
16
|
-
code: ProtocolViolation<Draft17MessageType>[
|
|
16
|
+
code: ProtocolViolation<Draft17MessageType>['code'],
|
|
17
17
|
message: string,
|
|
18
18
|
currentPhase: SessionPhase,
|
|
19
19
|
offendingMessage: Draft17MessageType,
|
|
20
20
|
): ProtocolViolation<Draft17MessageType> {
|
|
21
|
-
return { code, message, currentPhase, offendingMessage }
|
|
21
|
+
return { code, message, currentPhase, offendingMessage }
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export class Draft17SessionFSM {
|
|
25
|
-
private _phase: SessionPhase =
|
|
26
|
-
private _role:
|
|
27
|
-
private _setupDirection:
|
|
28
|
-
private _subscriptions = new Map<bigint, SubscriptionState>()
|
|
29
|
-
private _publishes = new Map<bigint, PublishState>()
|
|
30
|
-
private _fetches = new Map<bigint, FetchState>()
|
|
31
|
-
private _requestIds = new Set<bigint>()
|
|
32
|
-
private _pendingSubscribes: bigint[] = []
|
|
33
|
-
private _pendingPublishes: bigint[] = []
|
|
34
|
-
private _pendingFetches: bigint[] = []
|
|
35
|
-
|
|
36
|
-
constructor(role:
|
|
37
|
-
this._role = role
|
|
25
|
+
private _phase: SessionPhase = 'idle'
|
|
26
|
+
private _role: 'client' | 'server'
|
|
27
|
+
private _setupDirection: 'inbound' | 'outbound' | null = null
|
|
28
|
+
private _subscriptions = new Map<bigint, SubscriptionState>()
|
|
29
|
+
private _publishes = new Map<bigint, PublishState>()
|
|
30
|
+
private _fetches = new Map<bigint, FetchState>()
|
|
31
|
+
private _requestIds = new Set<bigint>()
|
|
32
|
+
private _pendingSubscribes: bigint[] = []
|
|
33
|
+
private _pendingPublishes: bigint[] = []
|
|
34
|
+
private _pendingFetches: bigint[] = []
|
|
35
|
+
|
|
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 new Map()
|
|
50
|
+
return new Map()
|
|
51
51
|
}
|
|
52
52
|
get publishes(): ReadonlyMap<bigint, PublishState> {
|
|
53
|
-
return this._publishes
|
|
53
|
+
return this._publishes
|
|
54
54
|
}
|
|
55
55
|
get fetches(): ReadonlyMap<bigint, FetchState> {
|
|
56
|
-
return this._fetches
|
|
56
|
+
return this._fetches
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
get legalOutgoing(): ReadonlySet<Draft17MessageType> {
|
|
60
|
-
return getLegalOutgoing(this._phase, this._role)
|
|
60
|
+
return getLegalOutgoing(this._phase, this._role)
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
get legalIncoming(): ReadonlySet<Draft17MessageType> {
|
|
64
|
-
return getLegalIncoming(this._phase, this._role)
|
|
64
|
+
return getLegalIncoming(this._phase, this._role)
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
private checkDuplicateRequestId(
|
|
@@ -70,13 +70,13 @@ export class Draft17SessionFSM {
|
|
|
70
70
|
): ProtocolViolation<Draft17MessageType> | null {
|
|
71
71
|
if (this._requestIds.has(requestId)) {
|
|
72
72
|
return violation(
|
|
73
|
-
|
|
73
|
+
'DUPLICATE_REQUEST_ID',
|
|
74
74
|
`Request ID ${requestId} already in use`,
|
|
75
75
|
this._phase,
|
|
76
76
|
msgType,
|
|
77
|
-
)
|
|
77
|
+
)
|
|
78
78
|
}
|
|
79
|
-
return null
|
|
79
|
+
return null
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
validateOutgoing(message: Draft17Message): ValidationResult<Draft17MessageType> {
|
|
@@ -84,320 +84,352 @@ export class Draft17SessionFSM {
|
|
|
84
84
|
return {
|
|
85
85
|
ok: false,
|
|
86
86
|
violation: violation(
|
|
87
|
-
this._phase ===
|
|
88
|
-
?
|
|
89
|
-
:
|
|
87
|
+
this._phase === 'idle' || this._phase === 'setup'
|
|
88
|
+
? 'MESSAGE_BEFORE_SETUP'
|
|
89
|
+
: 'UNEXPECTED_MESSAGE',
|
|
90
90
|
`Cannot send ${message.type} in phase ${this._phase}`,
|
|
91
91
|
this._phase,
|
|
92
92
|
message.type,
|
|
93
93
|
),
|
|
94
|
-
}
|
|
94
|
+
}
|
|
95
95
|
}
|
|
96
|
-
return { ok: true }
|
|
96
|
+
return { ok: true }
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
receive(message: Draft17Message): TransitionResult<Draft17MessageType> {
|
|
100
|
-
return this.applyTransition(message,
|
|
100
|
+
return this.applyTransition(message, 'inbound')
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
send(message: Draft17Message): TransitionResult<Draft17MessageType> {
|
|
104
|
-
return this.applyTransition(message,
|
|
104
|
+
return this.applyTransition(message, 'outbound')
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
private applyTransition(
|
|
108
108
|
message: Draft17Message,
|
|
109
|
-
direction:
|
|
109
|
+
direction: 'inbound' | 'outbound',
|
|
110
110
|
): TransitionResult<Draft17MessageType> {
|
|
111
|
-
const sideEffects: SideEffect[] = []
|
|
111
|
+
const sideEffects: SideEffect[] = []
|
|
112
112
|
|
|
113
113
|
switch (message.type) {
|
|
114
|
-
case
|
|
115
|
-
return this.handleSetup(direction)
|
|
116
|
-
case
|
|
117
|
-
return this.handleGoAway(message, sideEffects)
|
|
118
|
-
|
|
119
|
-
case
|
|
120
|
-
return this.handleSubscribe(message, sideEffects)
|
|
121
|
-
case
|
|
122
|
-
return this.handleSubscribeOk(message, sideEffects)
|
|
123
|
-
case
|
|
124
|
-
return this.handleRequestUpdate(message, sideEffects)
|
|
125
|
-
|
|
126
|
-
case
|
|
127
|
-
return this.handlePublish(message, sideEffects)
|
|
128
|
-
case
|
|
129
|
-
return this.handlePublishOk(sideEffects)
|
|
130
|
-
case
|
|
131
|
-
return this.handlePublishDone(message, sideEffects)
|
|
132
|
-
|
|
133
|
-
case
|
|
134
|
-
return this.handleFetch(message, sideEffects)
|
|
135
|
-
case
|
|
136
|
-
return this.handleFetchOk(sideEffects)
|
|
137
|
-
|
|
138
|
-
case
|
|
139
|
-
return this.handleRequestOk(sideEffects)
|
|
140
|
-
case
|
|
141
|
-
return this.handleRequestError(sideEffects)
|
|
114
|
+
case 'setup':
|
|
115
|
+
return this.handleSetup(direction)
|
|
116
|
+
case 'goaway':
|
|
117
|
+
return this.handleGoAway(message, sideEffects)
|
|
118
|
+
|
|
119
|
+
case 'subscribe':
|
|
120
|
+
return this.handleSubscribe(message, sideEffects)
|
|
121
|
+
case 'subscribe_ok':
|
|
122
|
+
return this.handleSubscribeOk(message, sideEffects)
|
|
123
|
+
case 'request_update':
|
|
124
|
+
return this.handleRequestUpdate(message, sideEffects)
|
|
125
|
+
|
|
126
|
+
case 'publish':
|
|
127
|
+
return this.handlePublish(message, sideEffects)
|
|
128
|
+
case 'publish_ok':
|
|
129
|
+
return this.handlePublishOk(sideEffects)
|
|
130
|
+
case 'publish_done':
|
|
131
|
+
return this.handlePublishDone(message, sideEffects)
|
|
132
|
+
|
|
133
|
+
case 'fetch':
|
|
134
|
+
return this.handleFetch(message, sideEffects)
|
|
135
|
+
case 'fetch_ok':
|
|
136
|
+
return this.handleFetchOk(sideEffects)
|
|
137
|
+
|
|
138
|
+
case 'request_ok':
|
|
139
|
+
return this.handleRequestOk(sideEffects)
|
|
140
|
+
case 'request_error':
|
|
141
|
+
return this.handleRequestError(sideEffects)
|
|
142
142
|
|
|
143
143
|
default:
|
|
144
|
-
return this.handleReadyPhaseMessage(message)
|
|
144
|
+
return this.handleReadyPhaseMessage(message)
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
private handleSetup(direction:
|
|
149
|
-
if (this._phase ===
|
|
150
|
-
this._setupDirection = direction
|
|
151
|
-
this._phase =
|
|
152
|
-
return { ok: true, phase: this._phase, sideEffects: [] }
|
|
148
|
+
private handleSetup(direction: 'inbound' | 'outbound'): TransitionResult<Draft17MessageType> {
|
|
149
|
+
if (this._phase === 'idle') {
|
|
150
|
+
this._setupDirection = direction
|
|
151
|
+
this._phase = 'setup'
|
|
152
|
+
return { ok: true, phase: this._phase, sideEffects: [] }
|
|
153
153
|
}
|
|
154
|
-
if (this._phase ===
|
|
154
|
+
if (this._phase === 'setup') {
|
|
155
155
|
if (direction === this._setupDirection) {
|
|
156
156
|
return {
|
|
157
157
|
ok: false,
|
|
158
158
|
violation: violation(
|
|
159
|
-
|
|
160
|
-
`Second SETUP must be ${this._setupDirection ===
|
|
159
|
+
'SETUP_VIOLATION',
|
|
160
|
+
`Second SETUP must be ${this._setupDirection === 'inbound' ? 'outbound' : 'inbound'}, got ${direction}`,
|
|
161
161
|
this._phase,
|
|
162
|
-
|
|
162
|
+
'setup',
|
|
163
163
|
),
|
|
164
|
-
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
this._phase = 'ready'
|
|
167
|
+
return {
|
|
168
|
+
ok: true,
|
|
169
|
+
phase: this._phase,
|
|
170
|
+
sideEffects: [{ type: 'session-ready' }],
|
|
165
171
|
}
|
|
166
|
-
this._phase = "ready";
|
|
167
|
-
return { ok: true, phase: this._phase, sideEffects: [{ type: "session-ready" }] };
|
|
168
172
|
}
|
|
169
173
|
return {
|
|
170
174
|
ok: false,
|
|
171
175
|
violation: violation(
|
|
172
|
-
|
|
173
|
-
|
|
176
|
+
'SETUP_VIOLATION',
|
|
177
|
+
'SETUP not valid in current phase',
|
|
174
178
|
this._phase,
|
|
175
|
-
|
|
179
|
+
'setup',
|
|
176
180
|
),
|
|
177
|
-
}
|
|
181
|
+
}
|
|
178
182
|
}
|
|
179
183
|
|
|
180
184
|
private handleGoAway(
|
|
181
185
|
message: Draft17Message,
|
|
182
186
|
sideEffects: SideEffect[],
|
|
183
187
|
): TransitionResult<Draft17MessageType> {
|
|
184
|
-
if (this._phase !==
|
|
188
|
+
if (this._phase !== 'ready' && this._phase !== 'draining') {
|
|
185
189
|
return {
|
|
186
190
|
ok: false,
|
|
187
191
|
violation: violation(
|
|
188
|
-
|
|
192
|
+
'UNEXPECTED_MESSAGE',
|
|
189
193
|
`GOAWAY not valid in phase ${this._phase}`,
|
|
190
194
|
this._phase,
|
|
191
|
-
|
|
195
|
+
'goaway',
|
|
192
196
|
),
|
|
193
|
-
}
|
|
197
|
+
}
|
|
194
198
|
}
|
|
195
|
-
this._phase =
|
|
196
|
-
const goaway = message as import(
|
|
197
|
-
sideEffects.push({
|
|
198
|
-
|
|
199
|
+
this._phase = 'draining'
|
|
200
|
+
const goaway = message as import('./types.js').Draft17GoAway
|
|
201
|
+
sideEffects.push({
|
|
202
|
+
type: 'session-draining',
|
|
203
|
+
goAwayUri: goaway.new_session_uri,
|
|
204
|
+
})
|
|
205
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
199
206
|
}
|
|
200
207
|
|
|
201
208
|
private requireReady(msgType: Draft17MessageType): ProtocolViolation<Draft17MessageType> | null {
|
|
202
|
-
if (this._phase !==
|
|
209
|
+
if (this._phase !== 'ready' && this._phase !== 'draining') {
|
|
203
210
|
return violation(
|
|
204
|
-
this._phase ===
|
|
205
|
-
?
|
|
206
|
-
:
|
|
211
|
+
this._phase === 'idle' || this._phase === 'setup'
|
|
212
|
+
? 'MESSAGE_BEFORE_SETUP'
|
|
213
|
+
: 'UNEXPECTED_MESSAGE',
|
|
207
214
|
`${msgType} requires ready phase, current: ${this._phase}`,
|
|
208
215
|
this._phase,
|
|
209
216
|
msgType,
|
|
210
|
-
)
|
|
217
|
+
)
|
|
211
218
|
}
|
|
212
|
-
return null
|
|
219
|
+
return null
|
|
213
220
|
}
|
|
214
221
|
|
|
215
222
|
private handleSubscribe(
|
|
216
223
|
message: Draft17Message,
|
|
217
224
|
sideEffects: SideEffect[],
|
|
218
225
|
): TransitionResult<Draft17MessageType> {
|
|
219
|
-
const err = this.requireReady(message.type)
|
|
220
|
-
if (err) return { ok: false, violation: err }
|
|
221
|
-
const sub = message as import(
|
|
222
|
-
const dupErr = this.checkDuplicateRequestId(sub.request_id, message.type)
|
|
223
|
-
if (dupErr) return { ok: false, violation: dupErr }
|
|
224
|
-
this._requestIds.add(sub.request_id)
|
|
226
|
+
const err = this.requireReady(message.type)
|
|
227
|
+
if (err) return { ok: false, violation: err }
|
|
228
|
+
const sub = message as import('./types.js').Draft17Subscribe
|
|
229
|
+
const dupErr = this.checkDuplicateRequestId(sub.request_id, message.type)
|
|
230
|
+
if (dupErr) return { ok: false, violation: dupErr }
|
|
231
|
+
this._requestIds.add(sub.request_id)
|
|
225
232
|
this._subscriptions.set(sub.request_id, {
|
|
226
233
|
subscribeId: sub.request_id,
|
|
227
|
-
phase:
|
|
234
|
+
phase: 'pending',
|
|
228
235
|
trackNamespace: sub.track_namespace,
|
|
229
236
|
trackName: sub.track_name,
|
|
230
|
-
})
|
|
231
|
-
this._pendingSubscribes.push(sub.request_id)
|
|
232
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
237
|
+
})
|
|
238
|
+
this._pendingSubscribes.push(sub.request_id)
|
|
239
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
233
240
|
}
|
|
234
241
|
|
|
235
242
|
private handleSubscribeOk(
|
|
236
243
|
_message: Draft17Message,
|
|
237
244
|
sideEffects: SideEffect[],
|
|
238
245
|
): TransitionResult<Draft17MessageType> {
|
|
239
|
-
const err = this.requireReady(
|
|
240
|
-
if (err) return { ok: false, violation: err }
|
|
241
|
-
const requestId = this._pendingSubscribes.shift()
|
|
246
|
+
const err = this.requireReady('subscribe_ok')
|
|
247
|
+
if (err) return { ok: false, violation: err }
|
|
248
|
+
const requestId = this._pendingSubscribes.shift()
|
|
242
249
|
if (requestId === undefined) {
|
|
243
250
|
return {
|
|
244
251
|
ok: false,
|
|
245
252
|
violation: violation(
|
|
246
|
-
|
|
247
|
-
|
|
253
|
+
'UNEXPECTED_MESSAGE',
|
|
254
|
+
'SUBSCRIBE_OK with no pending subscribe',
|
|
248
255
|
this._phase,
|
|
249
|
-
|
|
256
|
+
'subscribe_ok',
|
|
250
257
|
),
|
|
251
|
-
}
|
|
258
|
+
}
|
|
252
259
|
}
|
|
253
|
-
const existing = this._subscriptions.get(requestId)
|
|
254
|
-
if (existing && existing.phase ===
|
|
255
|
-
this._subscriptions.set(requestId, { ...existing, phase:
|
|
256
|
-
sideEffects.push({
|
|
260
|
+
const existing = this._subscriptions.get(requestId)
|
|
261
|
+
if (existing && existing.phase === 'pending') {
|
|
262
|
+
this._subscriptions.set(requestId, { ...existing, phase: 'active' })
|
|
263
|
+
sideEffects.push({
|
|
264
|
+
type: 'subscription-activated',
|
|
265
|
+
subscribeId: requestId,
|
|
266
|
+
})
|
|
257
267
|
}
|
|
258
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
268
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
259
269
|
}
|
|
260
270
|
|
|
261
271
|
private handleRequestUpdate(
|
|
262
272
|
message: Draft17Message,
|
|
263
273
|
sideEffects: SideEffect[],
|
|
264
274
|
): TransitionResult<Draft17MessageType> {
|
|
265
|
-
const err = this.requireReady(message.type)
|
|
266
|
-
if (err) return { ok: false, violation: err }
|
|
267
|
-
const update = message as import(
|
|
268
|
-
const dupErr = this.checkDuplicateRequestId(update.request_id, message.type)
|
|
269
|
-
if (dupErr) return { ok: false, violation: dupErr }
|
|
270
|
-
this._requestIds.add(update.request_id)
|
|
271
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
275
|
+
const err = this.requireReady(message.type)
|
|
276
|
+
if (err) return { ok: false, violation: err }
|
|
277
|
+
const update = message as import('./types.js').Draft17RequestUpdate
|
|
278
|
+
const dupErr = this.checkDuplicateRequestId(update.request_id, message.type)
|
|
279
|
+
if (dupErr) return { ok: false, violation: dupErr }
|
|
280
|
+
this._requestIds.add(update.request_id)
|
|
281
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
272
282
|
}
|
|
273
283
|
|
|
274
284
|
private handlePublish(
|
|
275
285
|
message: Draft17Message,
|
|
276
286
|
sideEffects: SideEffect[],
|
|
277
287
|
): TransitionResult<Draft17MessageType> {
|
|
278
|
-
const err = this.requireReady(message.type)
|
|
279
|
-
if (err) return { ok: false, violation: err }
|
|
280
|
-
const pub = message as import(
|
|
281
|
-
const dupErr = this.checkDuplicateRequestId(pub.request_id, message.type)
|
|
282
|
-
if (dupErr) return { ok: false, violation: dupErr }
|
|
283
|
-
this._requestIds.add(pub.request_id)
|
|
284
|
-
this._publishes.set(pub.request_id, {
|
|
285
|
-
|
|
286
|
-
|
|
288
|
+
const err = this.requireReady(message.type)
|
|
289
|
+
if (err) return { ok: false, violation: err }
|
|
290
|
+
const pub = message as import('./types.js').Draft17Publish
|
|
291
|
+
const dupErr = this.checkDuplicateRequestId(pub.request_id, message.type)
|
|
292
|
+
if (dupErr) return { ok: false, violation: dupErr }
|
|
293
|
+
this._requestIds.add(pub.request_id)
|
|
294
|
+
this._publishes.set(pub.request_id, {
|
|
295
|
+
requestId: pub.request_id,
|
|
296
|
+
phase: 'pending',
|
|
297
|
+
})
|
|
298
|
+
this._pendingPublishes.push(pub.request_id)
|
|
299
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
287
300
|
}
|
|
288
301
|
|
|
289
302
|
private handlePublishOk(sideEffects: SideEffect[]): TransitionResult<Draft17MessageType> {
|
|
290
|
-
const err = this.requireReady(
|
|
291
|
-
if (err) return { ok: false, violation: err }
|
|
292
|
-
const requestId = this._pendingPublishes.shift()
|
|
303
|
+
const err = this.requireReady('publish_ok')
|
|
304
|
+
if (err) return { ok: false, violation: err }
|
|
305
|
+
const requestId = this._pendingPublishes.shift()
|
|
293
306
|
if (requestId === undefined) {
|
|
294
307
|
return {
|
|
295
308
|
ok: false,
|
|
296
309
|
violation: violation(
|
|
297
|
-
|
|
298
|
-
|
|
310
|
+
'UNEXPECTED_MESSAGE',
|
|
311
|
+
'PUBLISH_OK with no pending publish',
|
|
299
312
|
this._phase,
|
|
300
|
-
|
|
313
|
+
'publish_ok',
|
|
301
314
|
),
|
|
302
|
-
}
|
|
315
|
+
}
|
|
303
316
|
}
|
|
304
|
-
const existing = this._publishes.get(requestId)
|
|
305
|
-
if (existing && existing.phase ===
|
|
306
|
-
this._publishes.set(requestId, { ...existing, phase:
|
|
307
|
-
sideEffects.push({ type:
|
|
317
|
+
const existing = this._publishes.get(requestId)
|
|
318
|
+
if (existing && existing.phase === 'pending') {
|
|
319
|
+
this._publishes.set(requestId, { ...existing, phase: 'active' })
|
|
320
|
+
sideEffects.push({ type: 'publish-activated', requestId })
|
|
308
321
|
}
|
|
309
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
322
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
310
323
|
}
|
|
311
324
|
|
|
312
325
|
private handlePublishDone(
|
|
313
326
|
_message: Draft17Message,
|
|
314
327
|
sideEffects: SideEffect[],
|
|
315
328
|
): TransitionResult<Draft17MessageType> {
|
|
316
|
-
const err = this.requireReady(
|
|
317
|
-
if (err) return { ok: false, violation: err }
|
|
329
|
+
const err = this.requireReady('publish_done')
|
|
330
|
+
if (err) return { ok: false, violation: err }
|
|
318
331
|
// PUBLISH_DONE has no request_id in draft-17; dequeue oldest active publish
|
|
319
332
|
for (const [reqId, pub] of this._publishes) {
|
|
320
|
-
if (pub.phase ===
|
|
321
|
-
this._publishes.set(reqId, { ...pub, phase:
|
|
322
|
-
sideEffects.push({
|
|
323
|
-
|
|
333
|
+
if (pub.phase === 'active') {
|
|
334
|
+
this._publishes.set(reqId, { ...pub, phase: 'done' })
|
|
335
|
+
sideEffects.push({
|
|
336
|
+
type: 'publish-ended',
|
|
337
|
+
requestId: reqId,
|
|
338
|
+
reason: 'done',
|
|
339
|
+
})
|
|
340
|
+
break
|
|
324
341
|
}
|
|
325
342
|
}
|
|
326
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
343
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
327
344
|
}
|
|
328
345
|
|
|
329
346
|
private handleFetch(
|
|
330
347
|
message: Draft17Message,
|
|
331
348
|
sideEffects: SideEffect[],
|
|
332
349
|
): TransitionResult<Draft17MessageType> {
|
|
333
|
-
const err = this.requireReady(message.type)
|
|
334
|
-
if (err) return { ok: false, violation: err }
|
|
335
|
-
const fetch = message as import(
|
|
336
|
-
const dupErr = this.checkDuplicateRequestId(fetch.request_id, message.type)
|
|
337
|
-
if (dupErr) return { ok: false, violation: dupErr }
|
|
338
|
-
this._requestIds.add(fetch.request_id)
|
|
339
|
-
this._fetches.set(fetch.request_id, {
|
|
340
|
-
|
|
341
|
-
|
|
350
|
+
const err = this.requireReady(message.type)
|
|
351
|
+
if (err) return { ok: false, violation: err }
|
|
352
|
+
const fetch = message as import('./types.js').Draft17Fetch
|
|
353
|
+
const dupErr = this.checkDuplicateRequestId(fetch.request_id, message.type)
|
|
354
|
+
if (dupErr) return { ok: false, violation: dupErr }
|
|
355
|
+
this._requestIds.add(fetch.request_id)
|
|
356
|
+
this._fetches.set(fetch.request_id, {
|
|
357
|
+
requestId: fetch.request_id,
|
|
358
|
+
phase: 'pending',
|
|
359
|
+
})
|
|
360
|
+
this._pendingFetches.push(fetch.request_id)
|
|
361
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
342
362
|
}
|
|
343
363
|
|
|
344
364
|
private handleFetchOk(sideEffects: SideEffect[]): TransitionResult<Draft17MessageType> {
|
|
345
|
-
const err = this.requireReady(
|
|
346
|
-
if (err) return { ok: false, violation: err }
|
|
347
|
-
const requestId = this._pendingFetches.shift()
|
|
365
|
+
const err = this.requireReady('fetch_ok')
|
|
366
|
+
if (err) return { ok: false, violation: err }
|
|
367
|
+
const requestId = this._pendingFetches.shift()
|
|
348
368
|
if (requestId === undefined) {
|
|
349
369
|
return {
|
|
350
370
|
ok: false,
|
|
351
371
|
violation: violation(
|
|
352
|
-
|
|
353
|
-
|
|
372
|
+
'UNEXPECTED_MESSAGE',
|
|
373
|
+
'FETCH_OK with no pending fetch',
|
|
354
374
|
this._phase,
|
|
355
|
-
|
|
375
|
+
'fetch_ok',
|
|
356
376
|
),
|
|
357
|
-
}
|
|
377
|
+
}
|
|
358
378
|
}
|
|
359
|
-
const existing = this._fetches.get(requestId)
|
|
360
|
-
if (existing && existing.phase ===
|
|
361
|
-
this._fetches.set(requestId, { ...existing, phase:
|
|
362
|
-
sideEffects.push({ type:
|
|
379
|
+
const existing = this._fetches.get(requestId)
|
|
380
|
+
if (existing && existing.phase === 'pending') {
|
|
381
|
+
this._fetches.set(requestId, { ...existing, phase: 'active' })
|
|
382
|
+
sideEffects.push({ type: 'fetch-activated', requestId })
|
|
363
383
|
}
|
|
364
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
384
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
365
385
|
}
|
|
366
386
|
|
|
367
387
|
private handleRequestError(sideEffects: SideEffect[]): TransitionResult<Draft17MessageType> {
|
|
368
|
-
const err = this.requireReady(
|
|
369
|
-
if (err) return { ok: false, violation: err }
|
|
388
|
+
const err = this.requireReady('request_error')
|
|
389
|
+
if (err) return { ok: false, violation: err }
|
|
370
390
|
// REQUEST_ERROR can target any pending request — try FIFO dequeue from each queue
|
|
371
|
-
const subId = this.dequeuePending(this._pendingSubscribes, this._subscriptions)
|
|
391
|
+
const subId = this.dequeuePending(this._pendingSubscribes, this._subscriptions)
|
|
372
392
|
if (subId !== undefined) {
|
|
373
|
-
const sub = this._subscriptions.get(subId)
|
|
374
|
-
this._subscriptions.set(subId, { ...sub, phase:
|
|
375
|
-
sideEffects.push({
|
|
376
|
-
|
|
393
|
+
const sub = this._subscriptions.get(subId)!
|
|
394
|
+
this._subscriptions.set(subId, { ...sub, phase: 'error' })
|
|
395
|
+
sideEffects.push({
|
|
396
|
+
type: 'subscription-ended',
|
|
397
|
+
subscribeId: subId,
|
|
398
|
+
reason: 'request_error',
|
|
399
|
+
})
|
|
400
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
377
401
|
}
|
|
378
|
-
const pubId = this.dequeuePending(this._pendingPublishes, this._publishes)
|
|
402
|
+
const pubId = this.dequeuePending(this._pendingPublishes, this._publishes)
|
|
379
403
|
if (pubId !== undefined) {
|
|
380
|
-
const pub = this._publishes.get(pubId)
|
|
381
|
-
this._publishes.set(pubId, { ...pub, phase:
|
|
382
|
-
sideEffects.push({
|
|
383
|
-
|
|
404
|
+
const pub = this._publishes.get(pubId)!
|
|
405
|
+
this._publishes.set(pubId, { ...pub, phase: 'error' })
|
|
406
|
+
sideEffects.push({
|
|
407
|
+
type: 'publish-ended',
|
|
408
|
+
requestId: pubId,
|
|
409
|
+
reason: 'request_error',
|
|
410
|
+
})
|
|
411
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
384
412
|
}
|
|
385
|
-
const fetchId = this.dequeuePending(this._pendingFetches, this._fetches)
|
|
413
|
+
const fetchId = this.dequeuePending(this._pendingFetches, this._fetches)
|
|
386
414
|
if (fetchId !== undefined) {
|
|
387
|
-
const f = this._fetches.get(fetchId)
|
|
388
|
-
this._fetches.set(fetchId, { ...f, phase:
|
|
389
|
-
sideEffects.push({
|
|
390
|
-
|
|
415
|
+
const f = this._fetches.get(fetchId)!
|
|
416
|
+
this._fetches.set(fetchId, { ...f, phase: 'error' })
|
|
417
|
+
sideEffects.push({
|
|
418
|
+
type: 'fetch-ended',
|
|
419
|
+
requestId: fetchId,
|
|
420
|
+
reason: 'request_error',
|
|
421
|
+
})
|
|
422
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
391
423
|
}
|
|
392
424
|
// Could be for subscribe_namespace, publish_namespace, track_status — allow through
|
|
393
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
425
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
394
426
|
}
|
|
395
427
|
|
|
396
428
|
private handleRequestOk(sideEffects: SideEffect[]): TransitionResult<Draft17MessageType> {
|
|
397
|
-
const err = this.requireReady(
|
|
398
|
-
if (err) return { ok: false, violation: err }
|
|
429
|
+
const err = this.requireReady('request_ok')
|
|
430
|
+
if (err) return { ok: false, violation: err }
|
|
399
431
|
// REQUEST_OK is for subscribe_namespace, publish_namespace, track_status — allow through
|
|
400
|
-
return { ok: true, phase: this._phase, sideEffects }
|
|
432
|
+
return { ok: true, phase: this._phase, sideEffects }
|
|
401
433
|
}
|
|
402
434
|
|
|
403
435
|
private dequeuePending(
|
|
@@ -405,33 +437,33 @@ export class Draft17SessionFSM {
|
|
|
405
437
|
stateMap: ReadonlyMap<bigint, { phase: string }>,
|
|
406
438
|
): bigint | undefined {
|
|
407
439
|
while (queue.length > 0) {
|
|
408
|
-
const id = queue[0]
|
|
409
|
-
const state = stateMap.get(id)
|
|
410
|
-
if (state && state.phase ===
|
|
411
|
-
queue.shift()
|
|
412
|
-
return id
|
|
440
|
+
const id = queue[0]!
|
|
441
|
+
const state = stateMap.get(id)
|
|
442
|
+
if (state && state.phase === 'pending') {
|
|
443
|
+
queue.shift()
|
|
444
|
+
return id
|
|
413
445
|
}
|
|
414
446
|
// Skip non-pending entries (already resolved by type-specific handler)
|
|
415
|
-
queue.shift()
|
|
447
|
+
queue.shift()
|
|
416
448
|
}
|
|
417
|
-
return undefined
|
|
449
|
+
return undefined
|
|
418
450
|
}
|
|
419
451
|
|
|
420
452
|
private handleReadyPhaseMessage(message: Draft17Message): TransitionResult<Draft17MessageType> {
|
|
421
|
-
const err = this.requireReady(message.type)
|
|
422
|
-
if (err) return { ok: false, violation: err }
|
|
423
|
-
return { ok: true, phase: this._phase, sideEffects: [] }
|
|
453
|
+
const err = this.requireReady(message.type)
|
|
454
|
+
if (err) return { ok: false, violation: err }
|
|
455
|
+
return { ok: true, phase: this._phase, sideEffects: [] }
|
|
424
456
|
}
|
|
425
457
|
|
|
426
458
|
reset(): void {
|
|
427
|
-
this._phase =
|
|
428
|
-
this._setupDirection = null
|
|
429
|
-
this._subscriptions.clear()
|
|
430
|
-
this._publishes.clear()
|
|
431
|
-
this._fetches.clear()
|
|
432
|
-
this._requestIds.clear()
|
|
433
|
-
this._pendingSubscribes.length = 0
|
|
434
|
-
this._pendingPublishes.length = 0
|
|
435
|
-
this._pendingFetches.length = 0
|
|
459
|
+
this._phase = 'idle'
|
|
460
|
+
this._setupDirection = null
|
|
461
|
+
this._subscriptions.clear()
|
|
462
|
+
this._publishes.clear()
|
|
463
|
+
this._fetches.clear()
|
|
464
|
+
this._requestIds.clear()
|
|
465
|
+
this._pendingSubscribes.length = 0
|
|
466
|
+
this._pendingPublishes.length = 0
|
|
467
|
+
this._pendingFetches.length = 0
|
|
436
468
|
}
|
|
437
469
|
}
|