https://github.com/manuel-lohmus/ws13
A simple and easy-to-use WebSocket protocol implementation
https://github.com/manuel-lohmus/ws13
communication real-time websocket websockets-server ws ws13
Last synced: 8 months ago
JSON representation
A simple and easy-to-use WebSocket protocol implementation
- Host: GitHub
- URL: https://github.com/manuel-lohmus/ws13
- Owner: manuel-lohmus
- License: mit
- Created: 2024-12-23T20:42:17.000Z (over 1 year ago)
- Default Branch: master
- Last Pushed: 2025-02-27T20:45:01.000Z (over 1 year ago)
- Last Synced: 2025-03-24T19:39:29.665Z (over 1 year ago)
- Topics: communication, real-time, websocket, websockets-server, ws, ws13
- Language: JavaScript
- Homepage:
- Size: 306 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.html
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
README
:root {
--markdown-font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", system-ui, "Ubuntu", "Droid Sans", sans-serif;
--markdown-font-size: 14px;
--markdown-line-height: 1.6;
--vscode-font-family: "Segoe WPC", "Segoe UI", sans-serif;
--vscode-font-weight: normal;
--vscode-font-size: 13px;
--vscode-editor-font-family: Consolas, "Courier New", monospace;
--vscode-editor-font-weight: normal;
--vscode-editor-font-size: 14px;
--vscode-foreground: #616161;
--vscode-errorForeground: #a1260d;
--vscode-descriptionForeground: #717171;
--vscode-icon-foreground: #424242;
--vscode-focusBorder: #0090f1;
--vscode-textSeparator-foreground: rgba(0, 0, 0, 0.18);
--vscode-textLink-foreground: #006ab1;
--vscode-textLink-activeForeground: #006ab1;
--vscode-textPreformat-foreground: #a31515;
--vscode-textBlockQuote-background: rgba(127, 127, 127, 0.1);
--vscode-textBlockQuote-border: rgba(0, 122, 204, 0.5);
--vscode-textCodeBlock-background: rgba(220, 220, 220, 0.4);
--vscode-widget-shadow: #a8a8a8;
--vscode-input-background: #ffffff;
--vscode-input-foreground: #616161;
--vscode-inputOption-activeBorder: rgba(0, 122, 204, 0);
--vscode-inputOption-activeBackground: rgba(0, 144, 241, 0.2);
--vscode-inputOption-activeForeground: #000000;
--vscode-input-placeholderForeground: #767676;
--vscode-inputValidation-infoBackground: #d6ecf2;
--vscode-inputValidation-infoBorder: #007acc;
--vscode-inputValidation-warningBackground: #f6f5d2;
--vscode-inputValidation-warningBorder: #b89500;
--vscode-inputValidation-errorBackground: #f2dede;
--vscode-inputValidation-errorBorder: #be1100;
--vscode-dropdown-background: #ffffff;
--vscode-dropdown-border: #cecece;
--vscode-checkbox-background: #ffffff;
--vscode-checkbox-border: #cecece;
--vscode-button-foreground: #ffffff;
--vscode-button-background: #007acc;
--vscode-button-hoverBackground: #0062a3;
--vscode-button-secondaryForeground: #ffffff;
--vscode-button-secondaryBackground: #5f6a79;
--vscode-button-secondaryHoverBackground: #4c5561;
--vscode-badge-background: #c4c4c4;
--vscode-badge-foreground: #333333;
--vscode-scrollbar-shadow: #dddddd;
--vscode-scrollbarSlider-background: rgba(100, 100, 100, 0.4);
--vscode-scrollbarSlider-hoverBackground: rgba(100, 100, 100, 0.7);
--vscode-scrollbarSlider-activeBackground: rgba(0, 0, 0, 0.6);
--vscode-progressBar-background: #0e70c0;
--vscode-editorError-foreground: #e51400;
--vscode-editorWarning-foreground: #e9a700;
--vscode-editorInfo-foreground: #75beff;
--vscode-editorHint-foreground: #6c6c6c;
--vscode-editor-background: #ffffff;
--vscode-editor-foreground: #000000;
--vscode-editorWidget-background: #f3f3f3;
--vscode-editorWidget-foreground: #616161;
--vscode-editorWidget-border: #c8c8c8;
--vscode-quickInput-background: #f3f3f3;
--vscode-quickInput-foreground: #616161;
--vscode-quickInputTitle-background: rgba(0, 0, 0, 0.06);
--vscode-pickerGroup-foreground: #0066bf;
--vscode-pickerGroup-border: #cccedb;
--vscode-editor-selectionBackground: #add6ff;
--vscode-editor-inactiveSelectionBackground: #e5ebf1;
--vscode-editor-selectionHighlightBackground: rgba(173, 214, 255, 0.5);
--vscode-editor-findMatchBackground: #a8ac94;
--vscode-editor-findMatchHighlightBackground: rgba(234, 92, 0, 0.33);
--vscode-editor-findRangeHighlightBackground: rgba(180, 180, 180, 0.3);
--vscode-searchEditor-findMatchBackground: rgba(234, 92, 0, 0.22);
--vscode-editor-hoverHighlightBackground: rgba(173, 214, 255, 0.15);
--vscode-editorHoverWidget-background: #f3f3f3;
--vscode-editorHoverWidget-foreground: #616161;
--vscode-editorHoverWidget-border: #c8c8c8;
--vscode-editorHoverWidget-statusBarBackground: #e7e7e7;
--vscode-editorLink-activeForeground: #0000ff;
--vscode-editorLightBulb-foreground: #ddb100;
--vscode-editorLightBulbAutoFix-foreground: #007acc;
--vscode-diffEditor-insertedTextBackground: rgba(155, 185, 85, 0.2);
--vscode-diffEditor-removedTextBackground: rgba(255, 0, 0, 0.2);
--vscode-diffEditor-diagonalFill: rgba(34, 34, 34, 0.2);
--vscode-list-focusBackground: #d6ebff;
--vscode-list-activeSelectionBackground: #0074e8;
--vscode-list-activeSelectionForeground: #ffffff;
--vscode-list-inactiveSelectionBackground: #e4e6f1;
--vscode-list-hoverBackground: #e8e8e8;
--vscode-list-dropBackground: #d6ebff;
--vscode-list-highlightForeground: #0066bf;
--vscode-list-invalidItemForeground: #b89500;
--vscode-list-errorForeground: #b01011;
--vscode-list-warningForeground: #855f00;
--vscode-listFilterWidget-background: #efc1ad;
--vscode-listFilterWidget-outline: rgba(0, 0, 0, 0);
--vscode-listFilterWidget-noMatchesOutline: #be1100;
--vscode-list-filterMatchBackground: rgba(234, 92, 0, 0.33);
--vscode-tree-indentGuidesStroke: #a9a9a9;
--vscode-list-deemphasizedForeground: #8e8e90;
--vscode-menu-foreground: #616161;
--vscode-menu-background: #ffffff;
--vscode-menu-selectionForeground: #ffffff;
--vscode-menu-selectionBackground: #0074e8;
--vscode-menu-separatorBackground: #888888;
--vscode-editor-snippetTabstopHighlightBackground: rgba(10, 50, 100, 0.2);
--vscode-editor-snippetFinalTabstopHighlightBorder: rgba(10, 50, 100, 0.5);
--vscode-breadcrumb-foreground: rgba(97, 97, 97, 0.8);
--vscode-breadcrumb-background: #ffffff;
--vscode-breadcrumb-focusForeground: #4e4e4e;
--vscode-breadcrumb-activeSelectionForeground: #4e4e4e;
--vscode-breadcrumbPicker-background: #f3f3f3;
--vscode-merge-currentHeaderBackground: rgba(64, 200, 174, 0.5);
--vscode-merge-currentContentBackground: rgba(64, 200, 174, 0.2);
--vscode-merge-incomingHeaderBackground: rgba(64, 166, 255, 0.5);
--vscode-merge-incomingContentBackground: rgba(64, 166, 255, 0.2);
--vscode-merge-commonHeaderBackground: rgba(96, 96, 96, 0.4);
--vscode-merge-commonContentBackground: rgba(96, 96, 96, 0.16);
--vscode-editorOverviewRuler-currentContentForeground: rgba(64, 200, 174, 0.5);
--vscode-editorOverviewRuler-incomingContentForeground: rgba(64, 166, 255, 0.5);
--vscode-editorOverviewRuler-commonContentForeground: rgba(96, 96, 96, 0.4);
--vscode-editorOverviewRuler-findMatchForeground: rgba(209, 134, 22, 0.49);
--vscode-editorOverviewRuler-selectionHighlightForeground: rgba(160, 160, 160, 0.8);
--vscode-minimap-findMatchHighlight: #d18616;
--vscode-minimap-selectionHighlight: #add6ff;
--vscode-minimap-errorHighlight: rgba(255, 18, 18, 0.7);
--vscode-minimap-warningHighlight: #e9a700;
--vscode-minimapSlider-background: rgba(100, 100, 100, 0.2);
--vscode-minimapSlider-hoverBackground: rgba(100, 100, 100, 0.35);
--vscode-minimapSlider-activeBackground: rgba(0, 0, 0, 0.3);
--vscode-problemsErrorIcon-foreground: #e51400;
--vscode-problemsWarningIcon-foreground: #e9a700;
--vscode-problemsInfoIcon-foreground: #75beff;
--vscode-editor-lineHighlightBorder: #eeeeee;
--vscode-editor-rangeHighlightBackground: rgba(253, 255, 0, 0.2);
--vscode-editor-symbolHighlightBackground: rgba(234, 92, 0, 0.33);
--vscode-editorCursor-foreground: #000000;
--vscode-editorWhitespace-foreground: rgba(51, 51, 51, 0.2);
--vscode-editorIndentGuide-background: #d3d3d3;
--vscode-editorIndentGuide-activeBackground: #939393;
--vscode-editorLineNumber-foreground: #237893;
--vscode-editorActiveLineNumber-foreground: #0b216f;
--vscode-editorLineNumber-activeForeground: #0b216f;
--vscode-editorRuler-foreground: #d3d3d3;
--vscode-editorCodeLens-foreground: #999999;
--vscode-editorBracketMatch-background: rgba(0, 100, 0, 0.1);
--vscode-editorBracketMatch-border: #b9b9b9;
--vscode-editorOverviewRuler-border: rgba(127, 127, 127, 0.3);
--vscode-editorGutter-background: #ffffff;
--vscode-editorUnnecessaryCode-opacity: rgba(0, 0, 0, 0.47);
--vscode-editorOverviewRuler-rangeHighlightForeground: rgba(0, 122, 204, 0.6);
--vscode-editorOverviewRuler-errorForeground: rgba(255, 18, 18, 0.7);
--vscode-editorOverviewRuler-warningForeground: #e9a700;
--vscode-editorOverviewRuler-infoForeground: #75beff;
--vscode-editorOverviewRuler-bracketMatchForeground: #a0a0a0;
--vscode-symbolIcon-arrayForeground: #616161;
--vscode-symbolIcon-booleanForeground: #616161;
--vscode-symbolIcon-classForeground: #d67e00;
--vscode-symbolIcon-colorForeground: #616161;
--vscode-symbolIcon-constantForeground: #616161;
--vscode-symbolIcon-constructorForeground: #652d90;
--vscode-symbolIcon-enumeratorForeground: #d67e00;
--vscode-symbolIcon-enumeratorMemberForeground: #007acc;
--vscode-symbolIcon-eventForeground: #d67e00;
--vscode-symbolIcon-fieldForeground: #007acc;
--vscode-symbolIcon-fileForeground: #616161;
--vscode-symbolIcon-folderForeground: #616161;
--vscode-symbolIcon-functionForeground: #652d90;
--vscode-symbolIcon-interfaceForeground: #007acc;
--vscode-symbolIcon-keyForeground: #616161;
--vscode-symbolIcon-keywordForeground: #616161;
--vscode-symbolIcon-methodForeground: #652d90;
--vscode-symbolIcon-moduleForeground: #616161;
--vscode-symbolIcon-namespaceForeground: #616161;
--vscode-symbolIcon-nullForeground: #616161;
--vscode-symbolIcon-numberForeground: #616161;
--vscode-symbolIcon-objectForeground: #616161;
--vscode-symbolIcon-operatorForeground: #616161;
--vscode-symbolIcon-packageForeground: #616161;
--vscode-symbolIcon-propertyForeground: #616161;
--vscode-symbolIcon-referenceForeground: #616161;
--vscode-symbolIcon-snippetForeground: #616161;
--vscode-symbolIcon-stringForeground: #616161;
--vscode-symbolIcon-structForeground: #616161;
--vscode-symbolIcon-textForeground: #616161;
--vscode-symbolIcon-typeParameterForeground: #616161;
--vscode-symbolIcon-unitForeground: #616161;
--vscode-symbolIcon-variableForeground: #007acc;
--vscode-editor-foldBackground: rgba(173, 214, 255, 0.3);
--vscode-editorGutter-foldingControlForeground: #424242;
--vscode-editor-onTypeRenameBackground: rgba(255, 0, 0, 0.3);
--vscode-editorSuggestWidget-background: #f3f3f3;
--vscode-editorSuggestWidget-border: #c8c8c8;
--vscode-editorSuggestWidget-foreground: #000000;
--vscode-editorSuggestWidget-selectedBackground: #d6ebff;
--vscode-editorSuggestWidget-highlightForeground: #0066bf;
--vscode-editor-wordHighlightBackground: rgba(87, 87, 87, 0.25);
--vscode-editor-wordHighlightStrongBackground: rgba(14, 99, 156, 0.25);
--vscode-editorOverviewRuler-wordHighlightForeground: rgba(160, 160, 160, 0.8);
--vscode-editorOverviewRuler-wordHighlightStrongForeground: rgba(192, 160, 192, 0.8);
--vscode-peekViewTitle-background: #ffffff;
--vscode-peekViewTitleLabel-foreground: #333333;
--vscode-peekViewTitleDescription-foreground: rgba(97, 97, 97, 0.9);
--vscode-peekView-border: #007acc;
--vscode-peekViewResult-background: #f3f3f3;
--vscode-peekViewResult-lineForeground: #646465;
--vscode-peekViewResult-fileForeground: #1e1e1e;
--vscode-peekViewResult-selectionBackground: rgba(51, 153, 255, 0.2);
--vscode-peekViewResult-selectionForeground: #6c6c6c;
--vscode-peekViewEditor-background: #f2f8fc;
--vscode-peekViewEditorGutter-background: #f2f8fc;
--vscode-peekViewResult-matchHighlightBackground: rgba(234, 92, 0, 0.3);
--vscode-peekViewEditor-matchHighlightBackground: rgba(245, 216, 2, 0.87);
--vscode-editorMarkerNavigationError-background: #e51400;
--vscode-editorMarkerNavigationWarning-background: #e9a700;
--vscode-editorMarkerNavigationInfo-background: #75beff;
--vscode-editorMarkerNavigation-background: #ffffff;
--vscode-tab-activeBackground: #ffffff;
--vscode-tab-unfocusedActiveBackground: #ffffff;
--vscode-tab-inactiveBackground: #ececec;
--vscode-tab-unfocusedInactiveBackground: #ececec;
--vscode-tab-activeForeground: #333333;
--vscode-tab-inactiveForeground: rgba(51, 51, 51, 0.7);
--vscode-tab-unfocusedActiveForeground: rgba(51, 51, 51, 0.7);
--vscode-tab-unfocusedInactiveForeground: rgba(51, 51, 51, 0.35);
--vscode-tab-activeModifiedBorder: #33aaee;
--vscode-tab-inactiveModifiedBorder: rgba(51, 170, 238, 0.5);
--vscode-tab-unfocusedActiveModifiedBorder: rgba(51, 170, 238, 0.7);
--vscode-tab-unfocusedInactiveModifiedBorder: rgba(51, 170, 238, 0.25);
--vscode-tab-border: #f3f3f3;
--vscode-editorPane-background: #ffffff;
--vscode-editorGroupHeader-tabsBackground: #f3f3f3;
--vscode-editorGroupHeader-noTabsBackground: #ffffff;
--vscode-editorGroup-border: #e7e7e7;
--vscode-editorGroup-dropBackground: rgba(38, 119, 203, 0.18);
--vscode-imagePreview-border: rgba(128, 128, 128, 0.35);
--vscode-panel-background: #ffffff;
--vscode-panel-border: rgba(128, 128, 128, 0.35);
--vscode-panelTitle-activeForeground: #424242;
--vscode-panelTitle-inactiveForeground: rgba(66, 66, 66, 0.75);
--vscode-panelTitle-activeBorder: #424242;
--vscode-panelInput-border: #dddddd;
--vscode-panel-dropBorder: #424242;
--vscode-panelSection-dropBackground: rgba(38, 119, 203, 0.18);
--vscode-panelSectionHeader-background: rgba(128, 128, 128, 0.2);
--vscode-panelSection-border: rgba(128, 128, 128, 0.35);
--vscode-statusBar-foreground: #ffffff;
--vscode-statusBar-noFolderForeground: #ffffff;
--vscode-statusBar-background: #007acc;
--vscode-statusBar-noFolderBackground: #68217a;
--vscode-statusBarItem-activeBackground: rgba(255, 255, 255, 0.18);
--vscode-statusBarItem-hoverBackground: rgba(255, 255, 255, 0.12);
--vscode-statusBarItem-prominentForeground: #ffffff;
--vscode-statusBarItem-prominentBackground: rgba(0, 0, 0, 0.5);
--vscode-statusBarItem-prominentHoverBackground: rgba(0, 0, 0, 0.3);
--vscode-activityBar-background: #2c2c2c;
--vscode-activityBar-foreground: #ffffff;
--vscode-activityBar-inactiveForeground: rgba(255, 255, 255, 0.4);
--vscode-activityBar-activeBorder: #ffffff;
--vscode-activityBar-dropBorder: #ffffff;
--vscode-activityBarBadge-background: #007acc;
--vscode-activityBarBadge-foreground: #ffffff;
--vscode-statusBarItem-remoteBackground: #16825d;
--vscode-statusBarItem-remoteForeground: #ffffff;
--vscode-extensionBadge-remoteBackground: #007acc;
--vscode-extensionBadge-remoteForeground: #ffffff;
--vscode-sideBar-background: #f3f3f3;
--vscode-sideBarTitle-foreground: #6f6f6f;
--vscode-sideBar-dropBackground: rgba(38, 119, 203, 0.18);
--vscode-sideBarSectionHeader-background: rgba(0, 0, 0, 0);
--vscode-sideBarSectionHeader-border: rgba(97, 97, 97, 0.19);
--vscode-titleBar-activeForeground: #333333;
--vscode-titleBar-inactiveForeground: rgba(51, 51, 51, 0.6);
--vscode-titleBar-activeBackground: #dddddd;
--vscode-titleBar-inactiveBackground: rgba(221, 221, 221, 0.6);
--vscode-menubar-selectionForeground: #333333;
--vscode-menubar-selectionBackground: rgba(0, 0, 0, 0.1);
--vscode-notifications-foreground: #616161;
--vscode-notifications-background: #f3f3f3;
--vscode-notificationLink-foreground: #006ab1;
--vscode-notificationCenterHeader-background: #e7e7e7;
--vscode-notifications-border: #e7e7e7;
--vscode-notificationsErrorIcon-foreground: #e51400;
--vscode-notificationsWarningIcon-foreground: #e9a700;
--vscode-notificationsInfoIcon-foreground: #75beff;
--vscode-editorGutter-commentRangeForeground: #c5c5c5;
--vscode-editor-stackFrameHighlightBackground: rgba(255, 255, 102, 0.45);
--vscode-editor-focusedStackFrameHighlightBackground: rgba(206, 231, 206, 0.45);
--vscode-terminal-foreground: #333333;
--vscode-terminal-selectionBackground: rgba(0, 0, 0, 0.25);
--vscode-terminal-border: rgba(128, 128, 128, 0.35);
--vscode-statusBar-debuggingBackground: #cc6633;
--vscode-statusBar-debuggingForeground: #ffffff;
--vscode-settings-headerForeground: #444444;
--vscode-settings-modifiedItemIndicator: #66afe0;
--vscode-settings-dropdownBackground: #ffffff;
--vscode-settings-dropdownBorder: #cecece;
--vscode-settings-dropdownListBorder: #c8c8c8;
--vscode-settings-checkboxBackground: #ffffff;
--vscode-settings-checkboxBorder: #cecece;
--vscode-settings-textInputBackground: #ffffff;
--vscode-settings-textInputForeground: #616161;
--vscode-settings-textInputBorder: #cecece;
--vscode-settings-numberInputBackground: #ffffff;
--vscode-settings-numberInputForeground: #616161;
--vscode-settings-numberInputBorder: #cecece;
--vscode-debugExceptionWidget-border: #a31515;
--vscode-debugExceptionWidget-background: #f1dfde;
--vscode-editorGutter-modifiedBackground: #66afe0;
--vscode-editorGutter-addedBackground: #81b88b;
--vscode-editorGutter-deletedBackground: #ca4b51;
--vscode-minimapGutter-modifiedBackground: #66afe0;
--vscode-minimapGutter-addedBackground: #81b88b;
--vscode-minimapGutter-deletedBackground: #ca4b51;
--vscode-editorOverviewRuler-modifiedForeground: rgba(102, 175, 224, 0.6);
--vscode-editorOverviewRuler-addedForeground: rgba(129, 184, 139, 0.6);
--vscode-editorOverviewRuler-deletedForeground: rgba(202, 75, 81, 0.6);
--vscode-searchEditor-textInputBorder: #cecece;
--vscode-debugIcon-breakpointForeground: #e51400;
--vscode-debugIcon-breakpointDisabledForeground: #848484;
--vscode-debugIcon-breakpointUnverifiedForeground: #848484;
--vscode-debugIcon-breakpointCurrentStackframeForeground: #ffcc00;
--vscode-debugIcon-breakpointStackframeForeground: #89d185;
--vscode-debugToolBar-background: #f3f3f3;
--vscode-debugIcon-startForeground: #388a34;
--vscode-debugIcon-pauseForeground: #007acc;
--vscode-debugIcon-stopForeground: #a1260d;
--vscode-debugIcon-disconnectForeground: #a1260d;
--vscode-debugIcon-restartForeground: #388a34;
--vscode-debugIcon-stepOverForeground: #007acc;
--vscode-debugIcon-stepIntoForeground: #007acc;
--vscode-debugIcon-stepOutForeground: #007acc;
--vscode-debugIcon-continueForeground: #007acc;
--vscode-debugIcon-stepBackForeground: #007acc;
--vscode-debugTokenExpression-name: #9b46b0;
--vscode-debugTokenExpression-value: rgba(108, 108, 108, 0.8);
--vscode-debugTokenExpression-string: #a31515;
--vscode-debugTokenExpression-boolean: #0000ff;
--vscode-debugTokenExpression-number: #098658;
--vscode-debugTokenExpression-error: #e51400;
--vscode-debugView-exceptionLabelForeground: #ffffff;
--vscode-debugView-exceptionLabelBackground: #a31515;
--vscode-debugView-stateLabelForeground: #616161;
--vscode-debugView-stateLabelBackground: rgba(136, 136, 136, 0.27);
--vscode-debugView-valueChangedHighlight: #569cd6;
--vscode-debugConsole-infoForeground: #75beff;
--vscode-debugConsole-warningForeground: #e9a700;
--vscode-debugConsole-errorForeground: #a1260d;
--vscode-debugConsole-sourceForeground: #616161;
--vscode-debugConsoleInputIcon-foreground: #616161;
--vscode-extensionButton-prominentBackground: #327e36;
--vscode-extensionButton-prominentForeground: #ffffff;
--vscode-extensionButton-prominentHoverBackground: #28632b;
--vscode-notebook-cellBorderColor: #dae3e9;
--vscode-notebook-focusedEditorBorder: #0090f1;
--vscode-notebookStatusSuccessIcon-foreground: #388a34;
--vscode-notebookStatusErrorIcon-foreground: #a1260d;
--vscode-notebookStatusRunningIcon-foreground: #616161;
--vscode-notebook-outputContainerBackgroundColor: rgba(200, 221, 241, 0.31);
--vscode-notebook-cellToolbarSeparator: rgba(128, 128, 128, 0.35);
--vscode-notebook-focusedCellBackground: rgba(200, 221, 241, 0.31);
--vscode-notebook-cellHoverBackground: rgba(200, 221, 241, 0.22);
--vscode-notebook-focusedCellBorder: rgba(0, 0, 0, 0.12);
--vscode-notebook-cellStatusBarItemHoverBackground: rgba(0, 0, 0, 0.08);
--vscode-notebook-cellInsertionIndicator: #0090f1;
--vscode-notebookScrollbarSlider-background: rgba(100, 100, 100, 0.4);
--vscode-notebookScrollbarSlider-hoverBackground: rgba(100, 100, 100, 0.7);
--vscode-notebookScrollbarSlider-activeBackground: rgba(0, 0, 0, 0.6);
--vscode-notebook-symbolHighlightBackground: rgba(253, 255, 0, 0.2);
--vscode-scm-providerBorder: #c8c8c8;
--vscode-terminal-ansiBlack: #000000;
--vscode-terminal-ansiRed: #cd3131;
--vscode-terminal-ansiGreen: #00bc00;
--vscode-terminal-ansiYellow: #949800;
--vscode-terminal-ansiBlue: #0451a5;
--vscode-terminal-ansiMagenta: #bc05bc;
--vscode-terminal-ansiCyan: #0598bc;
--vscode-terminal-ansiWhite: #555555;
--vscode-terminal-ansiBrightBlack: #666666;
--vscode-terminal-ansiBrightRed: #cd3131;
--vscode-terminal-ansiBrightGreen: #14ce14;
--vscode-terminal-ansiBrightYellow: #b5ba00;
--vscode-terminal-ansiBrightBlue: #0451a5;
--vscode-terminal-ansiBrightMagenta: #bc05bc;
--vscode-terminal-ansiBrightCyan: #0598bc;
--vscode-terminal-ansiBrightWhite: #a5a5a5;
--vscode-gitDecoration-addedResourceForeground: #587c0c;
--vscode-gitDecoration-modifiedResourceForeground: #895503;
--vscode-gitDecoration-deletedResourceForeground: #ad0707;
--vscode-gitDecoration-untrackedResourceForeground: #007100;
--vscode-gitDecoration-ignoredResourceForeground: #8e8e90;
--vscode-gitDecoration-conflictingResourceForeground: #6c6cc4;
--vscode-gitDecoration-submoduleResourceForeground: #1258a7;
--vscode-gitlens-gutterBackgroundColor: rgba(0, 0, 0, 0.05);
--vscode-gitlens-gutterForegroundColor: #747474;
--vscode-gitlens-gutterUncommittedForegroundColor: rgba(0, 188, 242, 0.6);
--vscode-gitlens-trailingLineBackgroundColor: rgba(0, 0, 0, 0);
--vscode-gitlens-trailingLineForegroundColor: rgba(153, 153, 153, 0.35);
--vscode-gitlens-lineHighlightBackgroundColor: rgba(0, 188, 242, 0.2);
--vscode-gitlens-lineHighlightOverviewRulerColor: rgba(0, 188, 242, 0.6);
--vscode-issues-newIssueDecoration: rgba(0, 0, 0, 0.28);
}
body {
background-color: var(--vscode-editor-background);
color: var(--vscode-editor-foreground);
font-family: var(--vscode-font-family);
font-weight: var(--vscode-font-weight);
font-size: var(--vscode-font-size);
margin: 0;
padding: 0 20px;
}
img {
max-width: 100%;
max-height: 100%;
}
a {
color: var(--vscode-textLink-foreground);
}
a:hover {
color: var(--vscode-textLink-activeForeground);
}
a:focus,
input:focus,
select:focus,
textarea:focus {
outline: 1px solid -webkit-focus-ring-color;
outline-offset: -1px;
}
code {
color: var(--vscode-textPreformat-foreground);
}
blockquote {
background: var(--vscode-textBlockQuote-background);
border-color: var(--vscode-textBlockQuote-border);
}
kbd {
color: var(--vscode-editor-foreground);
border-radius: 3px;
vertical-align: middle;
padding: 1px 3px;
background-color: hsla(0, 0%, 50%, .17);
border: 1px solid rgba(71, 71, 71, .4);
border-bottom-color: rgba(88, 88, 88, .4);
box-shadow: inset 0 -1px 0 rgba(88, 88, 88, .4);
}
.vscode-light kbd {
background-color: hsla(0, 0%, 87%, .5);
border: 1px solid hsla(0, 0%, 80%, .7);
border-bottom-color: hsla(0, 0%, 73%, .7);
box-shadow: inset 0 -1px 0 hsla(0, 0%, 73%, .7);
}
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-corner {
background-color: var(--vscode-editor-background);
}
::-webkit-scrollbar-thumb {
background-color: var(--vscode-scrollbarSlider-background);
}
::-webkit-scrollbar-thumb:hover {
background-color: var(--vscode-scrollbarSlider-hoverBackground);
}
::-webkit-scrollbar-thumb:active {
background-color: var(--vscode-scrollbarSlider-activeBackground);
}
.emoji {
height: 20px;
}
pre {
white-space: pre-wrap;
}
.page-break {
display: block;
page-break-after: always;
}
.no-page-break {
page-break-inside: avoid;
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.vscode-dark img[src$=\#gh-light-mode-only],
.vscode-light img[src$=\#gh-dark-mode-only],
.vscode-high-contrast:not(.vscode-high-contrast-light) img[src$=\#gh-light-mode-only],
.vscode-high-contrast-light img[src$=\#gh-dark-mode-only] {
display: none;
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
html,
body {
font-family: var(--markdown-font-family, -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", system-ui, "Ubuntu", "Droid Sans", sans-serif);
font-size: var(--markdown-font-size, 14px);
padding: 0 26px;
line-height: var(--markdown-line-height, 22px);
word-wrap: break-word;
}
body {
padding-top: 1em;
}
/* Reset margin top for elements */
h1,
h2,
h3,
h4,
h5,
h6,
p,
ol,
ul,
pre {
margin-top: 0;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: 600;
margin-top: 24px;
margin-bottom: 16px;
line-height: 1.25;
}
#code-csp-warning {
position: fixed;
top: 0;
right: 0;
color: white;
margin: 16px;
text-align: center;
font-size: 12px;
font-family: sans-serif;
background-color: #444444;
cursor: pointer;
padding: 6px;
box-shadow: 1px 1px 1px rgba(0, 0, 0, .25);
}
#code-csp-warning:hover {
text-decoration: none;
background-color: #007acc;
box-shadow: 2px 2px 2px rgba(0, 0, 0, .25);
}
body.scrollBeyondLastLine {
margin-bottom: calc(100vh - 22px);
}
body.showEditorSelection .code-line {
position: relative;
}
body.showEditorSelection :not(tr, ul, ol).code-active-line:before,
body.showEditorSelection :not(tr, ul, ol).code-line:hover:before {
content: "";
display: block;
position: absolute;
top: 0;
left: -12px;
height: 100%;
}
.vscode-high-contrast.showEditorSelection :not(tr, ul, ol).code-line .code-line:hover:before {
border-left: none;
}
body.showEditorSelection li.code-active-line:before,
body.showEditorSelection li.code-line:hover:before {
left: -30px;
}
.vscode-light.showEditorSelection .code-active-line:before {
border-left: 3px solid rgba(0, 0, 0, 0.15);
}
.vscode-light.showEditorSelection .code-line:hover:before {
border-left: 3px solid rgba(0, 0, 0, 0.40);
}
.vscode-dark.showEditorSelection .code-active-line:before {
border-left: 3px solid rgba(255, 255, 255, 0.4);
}
.vscode-dark.showEditorSelection .code-line:hover:before {
border-left: 3px solid rgba(255, 255, 255, 0.60);
}
.vscode-high-contrast.showEditorSelection .code-active-line:before {
border-left: 3px solid rgba(255, 160, 0, 0.7);
}
.vscode-high-contrast.showEditorSelection .code-line:hover:before {
border-left: 3px solid rgba(255, 160, 0, 1);
}
/* Prevent `sub` and `sup` elements from affecting line height */
sub,
sup {
line-height: 0;
}
ul ul:first-child,
ul ol:first-child,
ol ul:first-child,
ol ol:first-child {
margin-bottom: 0;
}
img,
video {
max-width: 100%;
max-height: 100%;
}
a {
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
a:focus,
input:focus,
select:focus,
textarea:focus {
outline: 1px solid -webkit-focus-ring-color;
outline-offset: -1px;
}
p {
margin-bottom: 16px;
}
li p {
margin-bottom: 0.7em;
}
ul,
ol {
margin-bottom: 0.7em;
}
hr {
border: 0;
height: 1px;
border-bottom: 1px solid;
}
h1 {
font-size: 2em;
margin-top: 0;
padding-bottom: 0.3em;
border-bottom-width: 1px;
border-bottom-style: solid;
}
h2 {
font-size: 1.5em;
padding-bottom: 0.3em;
border-bottom-width: 1px;
border-bottom-style: solid;
}
h3 {
font-size: 1.25em;
}
h4 {
font-size: 1em;
}
h5 {
font-size: 0.875em;
}
h6 {
font-size: 0.85em;
}
table {
border-collapse: collapse;
margin-bottom: 0.7em;
}
th {
text-align: left;
border-bottom: 1px solid;
}
th,
td {
padding: 5px 10px;
}
table>tbody>tr+tr>td {
border-top: 1px solid;
}
blockquote {
margin: 0;
padding: 0px 16px 0 10px;
border-left-width: 5px;
border-left-style: solid;
border-radius: 2px;
}
code {
font-family: var(--vscode-editor-font-family, "SF Mono", Monaco, Menlo, Consolas, "Ubuntu Mono", "Liberation Mono", "DejaVu Sans Mono", "Courier New", monospace);
font-size: 1em;
line-height: 1.357em;
}
body.wordWrap pre {
white-space: pre-wrap;
}
pre:not(.hljs),
pre.hljs code>div {
padding: 16px;
border-radius: 3px;
overflow: auto;
}
pre code {
display: inline-block;
color: var(--vscode-editor-foreground);
tab-size: 4;
background: none;
}
/** Theming */
pre {
background-color: var(--vscode-textCodeBlock-background);
border: 1px solid var(--vscode-widget-border);
}
.vscode-high-contrast h1 {
border-color: rgb(0, 0, 0);
}
.vscode-light th {
border-color: rgba(0, 0, 0, 0.69);
}
.vscode-dark th {
border-color: rgba(255, 255, 255, 0.69);
}
.vscode-light h1,
.vscode-light h2,
.vscode-light hr,
.vscode-light td {
border-color: rgba(0, 0, 0, 0.18);
}
.vscode-dark h1,
.vscode-dark h2,
.vscode-dark hr,
.vscode-dark td {
border-color: rgba(255, 255, 255, 0.18);
}
/*
https://raw.githubusercontent.com/isagalaev/highlight.js/master/src/styles/vs2015.css
*/
/*
* Visual Studio 2015 dark style
* Author: Nicolas LLOBERA <nllobera@gmail.com>
*/
.hljs-keyword,
.hljs-literal,
.hljs-symbol,
.hljs-name {
color: #569CD6;
}
.hljs-link {
color: #569CD6;
text-decoration: underline;
}
.hljs-built_in,
.hljs-type {
color: #4EC9B0;
}
.hljs-number,
.hljs-class {
color: #B8D7A3;
}
.hljs-string,
.hljs-meta-string {
color: #D69D85;
}
.hljs-regexp,
.hljs-template-tag {
color: #9A5334;
}
.hljs-subst,
.hljs-function,
.hljs-title,
.hljs-params,
.hljs-formula {
color: #DCDCDC;
}
.hljs-comment,
.hljs-quote {
color: #57A64A;
font-style: italic;
}
.hljs-doctag {
color: #608B4E;
}
.hljs-meta,
.hljs-meta-keyword,
.hljs-tag {
color: #9B9B9B;
}
.hljs-variable,
.hljs-template-variable {
color: #BD63C5;
}
.hljs-attr,
.hljs-attribute,
.hljs-builtin-name {
color: #9CDCFE;
}
.hljs-section {
color: gold;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
/*.hljs-code {
font-family:'Monospace';
}*/
.hljs-bullet,
.hljs-selector-tag,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #D7BA7D;
}
.hljs-addition {
background-color: var(--vscode-diffEditor-insertedTextBackground, rgba(155, 185, 85, 0.2));
color: rgb(155, 185, 85);
display: inline-block;
width: 100%;
}
.hljs-deletion {
background: var(--vscode-diffEditor-removedTextBackground, rgba(255, 0, 0, 0.2));
color: rgb(255, 0, 0);
display: inline-block;
width: 100%;
}
/*
From https://raw.githubusercontent.com/isagalaev/highlight.js/master/src/styles/vs.css
*/
/*
Visual Studio-like style based on original C# coloring by Jason Diamond <jason@diamond.name>
*/
.vscode-light .hljs-function,
.vscode-light .hljs-params,
.vscode-light .hljs-number,
.vscode-light .hljs-class {
color: inherit;
}
.vscode-light .hljs-comment,
.vscode-light .hljs-quote,
.vscode-light .hljs-number,
.vscode-light .hljs-class,
.vscode-light .hljs-variable {
color: #008000;
}
.vscode-light .hljs-keyword,
.vscode-light .hljs-selector-tag,
.vscode-light .hljs-name,
.vscode-light .hljs-tag {
color: #00f;
}
.vscode-light .hljs-built_in,
.vscode-light .hljs-builtin-name {
color: #007acc;
}
.vscode-light .hljs-string,
.vscode-light .hljs-section,
.vscode-light .hljs-attribute,
.vscode-light .hljs-literal,
.vscode-light .hljs-template-tag,
.vscode-light .hljs-template-variable,
.vscode-light .hljs-type {
color: #a31515;
}
.vscode-light .hljs-subst,
.vscode-light .hljs-selector-attr,
.vscode-light .hljs-selector-pseudo,
.vscode-light .hljs-meta,
.vscode-light .hljs-meta-keyword {
color: #2b91af;
}
.vscode-light .hljs-title,
.vscode-light .hljs-doctag {
color: #808080;
}
.vscode-light .hljs-attr {
color: #f00;
}
.vscode-light .hljs-symbol,
.vscode-light .hljs-bullet,
.vscode-light .hljs-link {
color: #00b0e8;
}
.vscode-light .hljs-emphasis {
font-style: italic;
}
.vscode-light .hljs-strong {
font-weight: bold;
}
@font-face {
font-family: KaTeX_AMS;
font-style: normal;
font-weight: 400;
src: url(fonts/KaTeX_AMS-Regular.woff2) format("woff2"), url(fonts/KaTeX_AMS-Regular.woff) format("woff"), url(fonts/KaTeX_AMS-Regular.ttf) format("truetype")
}
@font-face {
font-family: KaTeX_Caligraphic;
font-style: normal;
font-weight: 700;
src: url(fonts/KaTeX_Caligraphic-Bold.woff2) format("woff2"), url(fonts/KaTeX_Caligraphic-Bold.woff) format("woff"), url(fonts/KaTeX_Caligraphic-Bold.ttf) format("truetype")
}
@font-face {
font-family: KaTeX_Caligraphic;
font-style: normal;
font-weight: 400;
src: url(fonts/KaTeX_Caligraphic-Regular.woff2) format("woff2"), url(fonts/KaTeX_Caligraphic-Regular.woff) format("woff"), url(fonts/KaTeX_Caligraphic-Regular.ttf) format("truetype")
}
@font-face {
font-family: KaTeX_Fraktur;
font-style: normal;
font-weight: 700;
src: url(fonts/KaTeX_Fraktur-Bold.woff2) format("woff2"), url(fonts/KaTeX_Fraktur-Bold.woff) format("woff"), url(fonts/KaTeX_Fraktur-Bold.ttf) format("truetype")
}
@font-face {
font-family: KaTeX_Fraktur;
font-style: normal;
font-weight: 400;
src: url(fonts/KaTeX_Fraktur-Regular.woff2) format("woff2"), url(fonts/KaTeX_Fraktur-Regular.woff) format("woff"), url(fonts/KaTeX_Fraktur-Regular.ttf) format("truetype")
}
@font-face {
font-family: KaTeX_Main;
font-style: normal;
font-weight: 700;
src: url(fonts/KaTeX_Main-Bold.woff2) format("woff2"), url(fonts/KaTeX_Main-Bold.woff) format("woff"), url(fonts/KaTeX_Main-Bold.ttf) format("truetype")
}
@font-face {
font-family: KaTeX_Main;
font-style: italic;
font-weight: 700;
src: url(fonts/KaTeX_Main-BoldItalic.woff2) format("woff2"), url(fonts/KaTeX_Main-BoldItalic.woff) format("woff"), url(fonts/KaTeX_Main-BoldItalic.ttf) format("truetype")
}
@font-face {
font-family: KaTeX_Main;
font-style: italic;
font-weight: 400;
src: url(fonts/KaTeX_Main-Italic.woff2) format("woff2"), url(fonts/KaTeX_Main-Italic.woff) format("woff"), url(fonts/KaTeX_Main-Italic.ttf) format("truetype")
}
@font-face {
font-family: KaTeX_Main;
font-style: normal;
font-weight: 400;
src: url(fonts/KaTeX_Main-Regular.woff2) format("woff2"), url(fonts/KaTeX_Main-Regular.woff) format("woff"), url(fonts/KaTeX_Main-Regular.ttf) format("truetype")
}
@font-face {
font-family: KaTeX_Math;
font-style: italic;
font-weight: 700;
src: url(fonts/KaTeX_Math-BoldItalic.woff2) format("woff2"), url(fonts/KaTeX_Math-BoldItalic.woff) format("woff"), url(fonts/KaTeX_Math-BoldItalic.ttf) format("truetype")
}
@font-face {
font-family: KaTeX_Math;
font-style: italic;
font-weight: 400;
src: url(fonts/KaTeX_Math-Italic.woff2) format("woff2"), url(fonts/KaTeX_Math-Italic.woff) format("woff"), url(fonts/KaTeX_Math-Italic.ttf) format("truetype")
}
@font-face {
font-family: "KaTeX_SansSerif";
font-style: normal;
font-weight: 700;
src: url(fonts/KaTeX_SansSerif-Bold.woff2) format("woff2"), url(fonts/KaTeX_SansSerif-Bold.woff) format("woff"), url(fonts/KaTeX_SansSerif-Bold.ttf) format("truetype")
}
@font-face {
font-family: "KaTeX_SansSerif";
font-style: italic;
font-weight: 400;
src: url(fonts/KaTeX_SansSerif-Italic.woff2) format("woff2"), url(fonts/KaTeX_SansSerif-Italic.woff) format("woff"), url(fonts/KaTeX_SansSerif-Italic.ttf) format("truetype")
}
@font-face {
font-family: "KaTeX_SansSerif";
font-style: normal;
font-weight: 400;
src: url(fonts/KaTeX_SansSerif-Regular.woff2) format("woff2"), url(fonts/KaTeX_SansSerif-Regular.woff) format("woff"), url(fonts/KaTeX_SansSerif-Regular.ttf) format("truetype")
}
@font-face {
font-family: KaTeX_Script;
font-style: normal;
font-weight: 400;
src: url(fonts/KaTeX_Script-Regular.woff2) format("woff2"), url(fonts/KaTeX_Script-Regular.woff) format("woff"), url(fonts/KaTeX_Script-Regular.ttf) format("truetype")
}
@font-face {
font-family: KaTeX_Size1;
font-style: normal;
font-weight: 400;
src: url(fonts/KaTeX_Size1-Regular.woff2) format("woff2"), url(fonts/KaTeX_Size1-Regular.woff) format("woff"), url(fonts/KaTeX_Size1-Regular.ttf) format("truetype")
}
@font-face {
font-family: KaTeX_Size2;
font-style: normal;
font-weight: 400;
src: url(fonts/KaTeX_Size2-Regular.woff2) format("woff2"), url(fonts/KaTeX_Size2-Regular.woff) format("woff"), url(fonts/KaTeX_Size2-Regular.ttf) format("truetype")
}
@font-face {
font-family: KaTeX_Size3;
font-style: normal;
font-weight: 400;
src: url(fonts/KaTeX_Size3-Regular.woff2) format("woff2"), url(fonts/KaTeX_Size3-Regular.woff) format("woff"), url(fonts/KaTeX_Size3-Regular.ttf) format("truetype")
}
@font-face {
font-family: KaTeX_Size4;
font-style: normal;
font-weight: 400;
src: url(fonts/KaTeX_Size4-Regular.woff2) format("woff2"), url(fonts/KaTeX_Size4-Regular.woff) format("woff"), url(fonts/KaTeX_Size4-Regular.ttf) format("truetype")
}
@font-face {
font-family: KaTeX_Typewriter;
font-style: normal;
font-weight: 400;
src: url(fonts/KaTeX_Typewriter-Regular.woff2) format("woff2"), url(fonts/KaTeX_Typewriter-Regular.woff) format("woff"), url(fonts/KaTeX_Typewriter-Regular.ttf) format("truetype")
}
.katex {
font: normal 1.21em KaTeX_Main, Times New Roman, serif;
line-height: 1.2;
text-indent: 0;
text-rendering: auto
}
.katex * {
-ms-high-contrast-adjust: none !important;
border-color: currentColor
}
.katex .katex-version:after {
content: "0.16.21"
}
.katex .katex-mathml {
clip: rect(1px, 1px, 1px, 1px);
border: 0;
height: 1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px
}
.katex .katex-html>.newline {
display: block
}
.katex .base {
position: relative;
white-space: nowrap;
width: -webkit-min-content;
width: -moz-min-content;
width: min-content
}
.katex .base,
.katex .strut {
display: inline-block
}
.katex .textbf {
font-weight: 700
}
.katex .textit {
font-style: italic
}
.katex .textrm {
font-family: KaTeX_Main
}
.katex .textsf {
font-family: KaTeX_SansSerif
}
.katex .texttt {
font-family: KaTeX_Typewriter
}
.katex .mathnormal {
font-family: KaTeX_Math;
font-style: italic
}
.katex .mathit {
font-family: KaTeX_Main;
font-style: italic
}
.katex .mathrm {
font-style: normal
}
.katex .mathbf {
font-family: KaTeX_Main;
font-weight: 700
}
.katex .boldsymbol {
font-family: KaTeX_Math;
font-style: italic;
font-weight: 700
}
.katex .amsrm,
.katex .mathbb,
.katex .textbb {
font-family: KaTeX_AMS
}
.katex .mathcal {
font-family: KaTeX_Caligraphic
}
.katex .mathfrak,
.katex .textfrak {
font-family: KaTeX_Fraktur
}
.katex .mathboldfrak,
.katex .textboldfrak {
font-family: KaTeX_Fraktur;
font-weight: 700
}
.katex .mathtt {
font-family: KaTeX_Typewriter
}
.katex .mathscr,
.katex .textscr {
font-family: KaTeX_Script
}
.katex .mathsf,
.katex .textsf {
font-family: KaTeX_SansSerif
}
.katex .mathboldsf,
.katex .textboldsf {
font-family: KaTeX_SansSerif;
font-weight: 700
}
.katex .mathitsf,
.katex .mathsfit,
.katex .textitsf {
font-family: KaTeX_SansSerif;
font-style: italic
}
.katex .mainrm {
font-family: KaTeX_Main;
font-style: normal
}
.katex .vlist-t {
border-collapse: collapse;
display: inline-table;
table-layout: fixed
}
.katex .vlist-r {
display: table-row
}
.katex .vlist {
display: table-cell;
position: relative;
vertical-align: bottom
}
.katex .vlist>span {
display: block;
height: 0;
position: relative
}
.katex .vlist>span>span {
display: inline-block
}
.katex .vlist>span>.pstrut {
overflow: hidden;
width: 0
}
.katex .vlist-t2 {
margin-right: -2px
}
.katex .vlist-s {
display: table-cell;
font-size: 1px;
min-width: 2px;
vertical-align: bottom;
width: 2px
}
.katex .vbox {
align-items: baseline;
display: inline-flex;
flex-direction: column
}
.katex .hbox {
width: 100%
}
.katex .hbox,
.katex .thinbox {
display: inline-flex;
flex-direction: row
}
.katex .thinbox {
max-width: 0;
width: 0
}
.katex .msupsub {
text-align: left
}
.katex .mfrac>span>span {
text-align: center
}
.katex .mfrac .frac-line {
border-bottom-style: solid;
display: inline-block;
width: 100%
}
.katex .hdashline,
.katex .hline,
.katex .mfrac .frac-line,
.katex .overline .overline-line,
.katex .rule,
.katex .underline .underline-line {
min-height: 1px
}
.katex .mspace {
display: inline-block
}
.katex .clap,
.katex .llap,
.katex .rlap {
position: relative;
width: 0
}
.katex .clap>.inner,
.katex .llap>.inner,
.katex .rlap>.inner {
position: absolute
}
.katex .clap>.fix,
.katex .llap>.fix,
.katex .rlap>.fix {
display: inline-block
}
.katex .llap>.inner {
right: 0
}
.katex .clap>.inner,
.katex .rlap>.inner {
left: 0
}
.katex .clap>.inner>span {
margin-left: -50%;
margin-right: 50%
}
.katex .rule {
border: 0 solid;
display: inline-block;
position: relative
}
.katex .hline,
.katex .overline .overline-line,
.katex .underline .underline-line {
border-bottom-style: solid;
display: inline-block;
width: 100%
}
.katex .hdashline {
border-bottom-style: dashed;
display: inline-block;
width: 100%
}
.katex .sqrt>.root {
margin-left: .2777777778em;
margin-right: -.5555555556em
}
.katex .fontsize-ensurer.reset-size1.size1,
.katex .sizing.reset-size1.size1 {
font-size: 1em
}
.katex .fontsize-ensurer.reset-size1.size2,
.katex .sizing.reset-size1.size2 {
font-size: 1.2em
}
.katex .fontsize-ensurer.reset-size1.size3,
.katex .sizing.reset-size1.size3 {
font-size: 1.4em
}
.katex .fontsize-ensurer.reset-size1.size4,
.katex .sizing.reset-size1.size4 {
font-size: 1.6em
}
.katex .fontsize-ensurer.reset-size1.size5,
.katex .sizing.reset-size1.size5 {
font-size: 1.8em
}
.katex .fontsize-ensurer.reset-size1.size6,
.katex .sizing.reset-size1.size6 {
font-size: 2em
}
.katex .fontsize-ensurer.reset-size1.size7,
.katex .sizing.reset-size1.size7 {
font-size: 2.4em
}
.katex .fontsize-ensurer.reset-size1.size8,
.katex .sizing.reset-size1.size8 {
font-size: 2.88em
}
.katex .fontsize-ensurer.reset-size1.size9,
.katex .sizing.reset-size1.size9 {
font-size: 3.456em
}
.katex .fontsize-ensurer.reset-size1.size10,
.katex .sizing.reset-size1.size10 {
font-size: 4.148em
}
.katex .fontsize-ensurer.reset-size1.size11,
.katex .sizing.reset-size1.size11 {
font-size: 4.976em
}
.katex .fontsize-ensurer.reset-size2.size1,
.katex .sizing.reset-size2.size1 {
font-size: .8333333333em
}
.katex .fontsize-ensurer.reset-size2.size2,
.katex .sizing.reset-size2.size2 {
font-size: 1em
}
.katex .fontsize-ensurer.reset-size2.size3,
.katex .sizing.reset-size2.size3 {
font-size: 1.1666666667em
}
.katex .fontsize-ensurer.reset-size2.size4,
.katex .sizing.reset-size2.size4 {
font-size: 1.3333333333em
}
.katex .fontsize-ensurer.reset-size2.size5,
.katex .sizing.reset-size2.size5 {
font-size: 1.5em
}
.katex .fontsize-ensurer.reset-size2.size6,
.katex .sizing.reset-size2.size6 {
font-size: 1.6666666667em
}
.katex .fontsize-ensurer.reset-size2.size7,
.katex .sizing.reset-size2.size7 {
font-size: 2em
}
.katex .fontsize-ensurer.reset-size2.size8,
.katex .sizing.reset-size2.size8 {
font-size: 2.4em
}
.katex .fontsize-ensurer.reset-size2.size9,
.katex .sizing.reset-size2.size9 {
font-size: 2.88em
}
.katex .fontsize-ensurer.reset-size2.size10,
.katex .sizing.reset-size2.size10 {
font-size: 3.4566666667em
}
.katex .fontsize-ensurer.reset-size2.size11,
.katex .sizing.reset-size2.size11 {
font-size: 4.1466666667em
}
.katex .fontsize-ensurer.reset-size3.size1,
.katex .sizing.reset-size3.size1 {
font-size: .7142857143em
}
.katex .fontsize-ensurer.reset-size3.size2,
.katex .sizing.reset-size3.size2 {
font-size: .8571428571em
}
.katex .fontsize-ensurer.reset-size3.size3,
.katex .sizing.reset-size3.size3 {
font-size: 1em
}
.katex .fontsize-ensurer.reset-size3.size4,
.katex .sizing.reset-size3.size4 {
font-size: 1.1428571429em
}
.katex .fontsize-ensurer.reset-size3.size5,
.katex .sizing.reset-size3.size5 {
font-size: 1.2857142857em
}
.katex .fontsize-ensurer.reset-size3.size6,
.katex .sizing.reset-size3.size6 {
font-size: 1.4285714286em
}
.katex .fontsize-ensurer.reset-size3.size7,
.katex .sizing.reset-size3.size7 {
font-size: 1.7142857143em
}
.katex .fontsize-ensurer.reset-size3.size8,
.katex .sizing.reset-size3.size8 {
font-size: 2.0571428571em
}
.katex .fontsize-ensurer.reset-size3.size9,
.katex .sizing.reset-size3.size9 {
font-size: 2.4685714286em
}
.katex .fontsize-ensurer.reset-size3.size10,
.katex .sizing.reset-size3.size10 {
font-size: 2.9628571429em
}
.katex .fontsize-ensurer.reset-size3.size11,
.katex .sizing.reset-size3.size11 {
font-size: 3.5542857143em
}
.katex .fontsize-ensurer.reset-size4.size1,
.katex .sizing.reset-size4.size1 {
font-size: .625em
}
.katex .fontsize-ensurer.reset-size4.size2,
.katex .sizing.reset-size4.size2 {
font-size: .75em
}
.katex .fontsize-ensurer.reset-size4.size3,
.katex .sizing.reset-size4.size3 {
font-size: .875em
}
.katex .fontsize-ensurer.reset-size4.size4,
.katex .sizing.reset-size4.size4 {
font-size: 1em
}
.katex .fontsize-ensurer.reset-size4.size5,
.katex .sizing.reset-size4.size5 {
font-size: 1.125em
}
.katex .fontsize-ensurer.reset-size4.size6,
.katex .sizing.reset-size4.size6 {
font-size: 1.25em
}
.katex .fontsize-ensurer.reset-size4.size7,
.katex .sizing.reset-size4.size7 {
font-size: 1.5em
}
.katex .fontsize-ensurer.reset-size4.size8,
.katex .sizing.reset-size4.size8 {
font-size: 1.8em
}
.katex .fontsize-ensurer.reset-size4.size9,
.katex .sizing.reset-size4.size9 {
font-size: 2.16em
}
.katex .fontsize-ensurer.reset-size4.size10,
.katex .sizing.reset-size4.size10 {
font-size: 2.5925em
}
.katex .fontsize-ensurer.reset-size4.size11,
.katex .sizing.reset-size4.size11 {
font-size: 3.11em
}
.katex .fontsize-ensurer.reset-size5.size1,
.katex .sizing.reset-size5.size1 {
font-size: .5555555556em
}
.katex .fontsize-ensurer.reset-size5.size2,
.katex .sizing.reset-size5.size2 {
font-size: .6666666667em
}
.katex .fontsize-ensurer.reset-size5.size3,
.katex .sizing.reset-size5.size3 {
font-size: .7777777778em
}
.katex .fontsize-ensurer.reset-size5.size4,
.katex .sizing.reset-size5.size4 {
font-size: .8888888889em
}
.katex .fontsize-ensurer.reset-size5.size5,
.katex .sizing.reset-size5.size5 {
font-size: 1em
}
.katex .fontsize-ensurer.reset-size5.size6,
.katex .sizing.reset-size5.size6 {
font-size: 1.1111111111em
}
.katex .fontsize-ensurer.reset-size5.size7,
.katex .sizing.reset-size5.size7 {
font-size: 1.3333333333em
}
.katex .fontsize-ensurer.reset-size5.size8,
.katex .sizing.reset-size5.size8 {
font-size: 1.6em
}
.katex .fontsize-ensurer.reset-size5.size9,
.katex .sizing.reset-size5.size9 {
font-size: 1.92em
}
.katex .fontsize-ensurer.reset-size5.size10,
.katex .sizing.reset-size5.size10 {
font-size: 2.3044444444em
}
.katex .fontsize-ensurer.reset-size5.size11,
.katex .sizing.reset-size5.size11 {
font-size: 2.7644444444em
}
.katex .fontsize-ensurer.reset-size6.size1,
.katex .sizing.reset-size6.size1 {
font-size: .5em
}
.katex .fontsize-ensurer.reset-size6.size2,
.katex .sizing.reset-size6.size2 {
font-size: .6em
}
.katex .fontsize-ensurer.reset-size6.size3,
.katex .sizing.reset-size6.size3 {
font-size: .7em
}
.katex .fontsize-ensurer.reset-size6.size4,
.katex .sizing.reset-size6.size4 {
font-size: .8em
}
.katex .fontsize-ensurer.reset-size6.size5,
.katex .sizing.reset-size6.size5 {
font-size: .9em
}
.katex .fontsize-ensurer.reset-size6.size6,
.katex .sizing.reset-size6.size6 {
font-size: 1em
}
.katex .fontsize-ensurer.reset-size6.size7,
.katex .sizing.reset-size6.size7 {
font-size: 1.2em
}
.katex .fontsize-ensurer.reset-size6.size8,
.katex .sizing.reset-size6.size8 {
font-size: 1.44em
}
.katex .fontsize-ensurer.reset-size6.size9,
.katex .sizing.reset-size6.size9 {
font-size: 1.728em
}
.katex .fontsize-ensurer.reset-size6.size10,
.katex .sizing.reset-size6.size10 {
font-size: 2.074em
}
.katex .fontsize-ensurer.reset-size6.size11,
.katex .sizing.reset-size6.size11 {
font-size: 2.488em
}
.katex .fontsize-ensurer.reset-size7.size1,
.katex .sizing.reset-size7.size1 {
font-size: .4166666667em
}
.katex .fontsize-ensurer.reset-size7.size2,
.katex .sizing.reset-size7.size2 {
font-size: .5em
}
.katex .fontsize-ensurer.reset-size7.size3,
.katex .sizing.reset-size7.size3 {
font-size: .5833333333em
}
.katex .fontsize-ensurer.reset-size7.size4,
.katex .sizing.reset-size7.size4 {
font-size: .6666666667em
}
.katex .fontsize-ensurer.reset-size7.size5,
.katex .sizing.reset-size7.size5 {
font-size: .75em
}
.katex .fontsize-ensurer.reset-size7.size6,
.katex .sizing.reset-size7.size6 {
font-size: .8333333333em
}
.katex .fontsize-ensurer.reset-size7.size7,
.katex .sizing.reset-size7.size7 {
font-size: 1em
}
.katex .fontsize-ensurer.reset-size7.size8,
.katex .sizing.reset-size7.size8 {
font-size: 1.2em
}
.katex .fontsize-ensurer.reset-size7.size9,
.katex .sizing.reset-size7.size9 {
font-size: 1.44em
}
.katex .fontsize-ensurer.reset-size7.size10,
.katex .sizing.reset-size7.size10 {
font-size: 1.7283333333em
}
.katex .fontsize-ensurer.reset-size7.size11,
.katex .sizing.reset-size7.size11 {
font-size: 2.0733333333em
}
.katex .fontsize-ensurer.reset-size8.size1,
.katex .sizing.reset-size8.size1 {
font-size: .3472222222em
}
.katex .fontsize-ensurer.reset-size8.size2,
.katex .sizing.reset-size8.size2 {
font-size: .4166666667em
}
.katex .fontsize-ensurer.reset-size8.size3,
.katex .sizing.reset-size8.size3 {
font-size: .4861111111em
}
.katex .fontsize-ensurer.reset-size8.size4,
.katex .sizing.reset-size8.size4 {
font-size: .5555555556em
}
.katex .fontsize-ensurer.reset-size8.size5,
.katex .sizing.reset-size8.size5 {
font-size: .625em
}
.katex .fontsize-ensurer.reset-size8.size6,
.katex .sizing.reset-size8.size6 {
font-size: .6944444444em
}
.katex .fontsize-ensurer.reset-size8.size7,
.katex .sizing.reset-size8.size7 {
font-size: .8333333333em
}
.katex .fontsize-ensurer.reset-size8.size8,
.katex .sizing.reset-size8.size8 {
font-size: 1em
}
.katex .fontsize-ensurer.reset-size8.size9,
.katex .sizing.reset-size8.size9 {
font-size: 1.2em
}
.katex .fontsize-ensurer.reset-size8.size10,
.katex .sizing.reset-size8.size10 {
font-size: 1.4402777778em
}
.katex .fontsize-ensurer.reset-size8.size11,
.katex .sizing.reset-size8.size11 {
font-size: 1.7277777778em
}
.katex .fontsize-ensurer.reset-size9.size1,
.katex .sizing.reset-size9.size1 {
font-size: .2893518519em
}
.katex .fontsize-ensurer.reset-size9.size2,
.katex .sizing.reset-size9.size2 {
font-size: .3472222222em
}
.katex .fontsize-ensurer.reset-size9.size3,
.katex .sizing.reset-size9.size3 {
font-size: .4050925926em
}
.katex .fontsize-ensurer.reset-size9.size4,
.katex .sizing.reset-size9.size4 {
font-size: .462962963em
}
.katex .fontsize-ensurer.reset-size9.size5,
.katex .sizing.reset-size9.size5 {
font-size: .5208333333em
}
.katex .fontsize-ensurer.reset-size9.size6,
.katex .sizing.reset-size9.size6 {
font-size: .5787037037em
}
.katex .fontsize-ensurer.reset-size9.size7,
.katex .sizing.reset-size9.size7 {
font-size: .6944444444em
}
.katex .fontsize-ensurer.reset-size9.size8,
.katex .sizing.reset-size9.size8 {
font-size: .8333333333em
}
.katex .fontsize-ensurer.reset-size9.size9,
.katex .sizing.reset-size9.size9 {
font-size: 1em
}
.katex .fontsize-ensurer.reset-size9.size10,
.katex .sizing.reset-size9.size10 {
font-size: 1.2002314815em
}
.katex .fontsize-ensurer.reset-size9.size11,
.katex .sizing.reset-size9.size11 {
font-size: 1.4398148148em
}
.katex .fontsize-ensurer.reset-size10.size1,
.katex .sizing.reset-size10.size1 {
font-size: .2410800386em
}
.katex .fontsize-ensurer.reset-size10.size2,
.katex .sizing.reset-size10.size2 {
font-size: .2892960463em
}
.katex .fontsize-ensurer.reset-size10.size3,
.katex .sizing.reset-size10.size3 {
font-size: .337512054em
}
.katex .fontsize-ensurer.reset-size10.size4,
.katex .sizing.reset-size10.size4 {
font-size: .3857280617em
}
.katex .fontsize-ensurer.reset-size10.size5,
.katex .sizing.reset-size10.size5 {
font-size: .4339440694em
}
.katex .fontsize-ensurer.reset-size10.size6,
.katex .sizing.reset-size10.size6 {
font-size: .4821600771em
}
.katex .fontsize-ensurer.reset-size10.size7,
.katex .sizing.reset-size10.size7 {
font-size: .5785920926em
}
.katex .fontsize-ensurer.reset-size10.size8,
.katex .sizing.reset-size10.size8 {
font-size: .6943105111em
}
.katex .fontsize-ensurer.reset-size10.size9,
.katex .sizing.reset-size10.size9 {
font-size: .8331726133em
}
.katex .fontsize-ensurer.reset-size10.size10,
.katex .sizing.reset-size10.size10 {
font-size: 1em
}
.katex .fontsize-ensurer.reset-size10.size11,
.katex .sizing.reset-size10.size11 {
font-size: 1.1996142719em
}
.katex .fontsize-ensurer.reset-size11.size1,
.katex .sizing.reset-size11.size1 {
font-size: .2009646302em
}
.katex .fontsize-ensurer.reset-size11.size2,
.katex .sizing.reset-size11.size2 {
font-size: .2411575563em
}
.katex .fontsize-ensurer.reset-size11.size3,
.katex .sizing.reset-size11.size3 {
font-size: .2813504823em
}
.katex .fontsize-ensurer.reset-size11.size4,
.katex .sizing.reset-size11.size4 {
font-size: .3215434084em
}
.katex .fontsize-ensurer.reset-size11.size5,
.katex .sizing.reset-size11.size5 {
font-size: .3617363344em
}
.katex .fontsize-ensurer.reset-size11.size6,
.katex .sizing.reset-size11.size6 {
font-size: .4019292605em
}
.katex .fontsize-ensurer.reset-size11.size7,
.katex .sizing.reset-size11.size7 {
font-size: .4823151125em
}
.katex .fontsize-ensurer.reset-size11.size8,
.katex .sizing.reset-size11.size8 {
font-size: .578778135em
}
.katex .fontsize-ensurer.reset-size11.size9,
.katex .sizing.reset-size11.size9 {
font-size: .6945337621em
}
.katex .fontsize-ensurer.reset-size11.size10,
.katex .sizing.reset-size11.size10 {
font-size: .8336012862em
}
.katex .fontsize-ensurer.reset-size11.size11,
.katex .sizing.reset-size11.size11 {
font-size: 1em
}
.katex .delimsizing.size1 {
font-family: KaTeX_Size1
}
.katex .delimsizing.size2 {
font-family: KaTeX_Size2
}
.katex .delimsizing.size3 {
font-family: KaTeX_Size3
}
.katex .delimsizing.size4 {
font-family: KaTeX_Size4
}
.katex .delimsizing.mult .delim-size1>span {
font-family: KaTeX_Size1
}
.katex .delimsizing.mult .delim-size4>span {
font-family: KaTeX_Size4
}
.katex .nulldelimiter {
display: inline-block;
width: .12em
}
.katex .delimcenter,
.katex .op-symbol {
position: relative
}
.katex .op-symbol.small-op {
font-family: KaTeX_Size1
}
.katex .op-symbol.large-op {
font-family: KaTeX_Size2
}
.katex .accent>.vlist-t,
.katex .op-limits>.vlist-t {
text-align: center
}
.katex .accent .accent-body {
position: relative
}
.katex .accent .accent-body:not(.accent-full) {
width: 0
}
.katex .overlay {
display: block
}
.katex .mtable .vertical-separator {
display: inline-block;
min-width: 1px
}
.katex .mtable .arraycolsep {
display: inline-block
}
.katex .mtable .col-align-c>.vlist-t {
text-align: center
}
.katex .mtable .col-align-l>.vlist-t {
text-align: left
}
.katex .mtable .col-align-r>.vlist-t {
text-align: right
}
.katex .svg-align {
text-align: left
}
.katex svg {
fill: currentColor;
stroke: currentColor;
fill-rule: nonzero;
fill-opacity: 1;
stroke-width: 1;
stroke-linecap: butt;
stroke-linejoin: miter;
stroke-miterlimit: 4;
stroke-dasharray: none;
stroke-dashoffset: 0;
stroke-opacity: 1;
display: block;
height: inherit;
position: absolute;
width: 100%
}
.katex svg path {
stroke: none
}
.katex img {
border-style: none;
max-height: none;
max-width: none;
min-height: 0;
min-width: 0
}
.katex .stretchy {
display: block;
overflow: hidden;
position: relative;
width: 100%
}
.katex .stretchy:after,
.katex .stretchy:before {
content: ""
}
.katex .hide-tail {
overflow: hidden;
position: relative;
width: 100%
}
.katex .halfarrow-left {
left: 0;
overflow: hidden;
position: absolute;
width: 50.2%
}
.katex .halfarrow-right {
overflow: hidden;
position: absolute;
right: 0;
width: 50.2%
}
.katex .brace-left {
left: 0;
overflow: hidden;
position: absolute;
width: 25.1%
}
.katex .brace-center {
left: 25%;
overflow: hidden;
position: absolute;
width: 50%
}
.katex .brace-right {
overflow: hidden;
position: absolute;
right: 0;
width: 25.1%
}
.katex .x-arrow-pad {
padding: 0 .5em
}
.katex .cd-arrow-pad {
padding: 0 .55556em 0 .27778em
}
.katex .mover,
.katex .munder,
.katex .x-arrow {
text-align: center
}
.katex .boxpad {
padding: 0 .3em
}
.katex .fbox,
.katex .fcolorbox {
border: .04em solid;
box-sizing: border-box
}
.katex .cancel-pad {
padding: 0 .2em
}
.katex .cancel-lap {
margin-left: -.2em;
margin-right: -.2em
}
.katex .sout {
border-bottom-style: solid;
border-bottom-width: .08em
}
.katex .angl {
border-right: .049em solid;
border-top: .049em solid;
box-sizing: border-box;
margin-right: .03889em
}
.katex .anglpad {
padding: 0 .03889em
}
.katex .eqn-num:before {
content: "(" counter(katexEqnNo) ")";
counter-increment: katexEqnNo
}
.katex .mml-eqn-num:before {
content: "(" counter(mmlEqnNo) ")";
counter-increment: mmlEqnNo
}
.katex .mtr-glue {
width: 50%
}
.katex .cd-vert-arrow {
display: inline-block;
position: relative
}
.katex .cd-label-left {
display: inline-block;
position: absolute;
right: calc(50% + .3em);
text-align: left
}
.katex .cd-label-right {
display: inline-block;
left: calc(50% + .3em);
position: absolute;
text-align: right
}
.katex-display {
display: block;
margin: 1em 0;
text-align: center
}
.katex-display>.katex {
display: block;
text-align: center;
white-space: nowrap
}
.katex-display>.katex>.katex-html {
display: block;
position: relative
}
.katex-display>.katex>.katex-html>.tag {
position: absolute;
right: 0
}
.katex-display.leqno>.katex>.katex-html>.tag {
left: 0;
right: auto
}
.katex-display.fleqn>.katex {
padding-left: 2em;
text-align: left
}
body {
counter-reset: katexEqnNo mmlEqnNo
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.katex-error {
color: var(--vscode-editorError-foreground);
}
ws13 โ WebSocket API
v1.1.0
Modular, extensible and operations-friendly WebSocket framework for
Node.js. This release focuses on a small, stable core so dependent projects can proceed; extensions (channels, auth, history, events, admin, routing, heartbeat, message-meta,
permessage-deflate) exist as planned work and will be completed and documented in follow-up
releases.
Status: core stable and testable โ extensions work in progress (APIs
present in repository; integration examples available in examples/).
๐ Table of Contents
- โจ
Highlights - ๐ฆ
Installation - ๐ Quick start
- ๐งฉ
Core API - ๐งช Tests
- ๐งฉ Extension roadmap
- ๐
Operational notes - ๐
Project Structure -
๐ License - MIT
โจ Highlights (v1.1.0)
- Small, well-tested core for WebSocket handshake, frame
parsing/serialisation and basic client/server modes. -
createRegistry()โ lightweight connection registry
with broadcast and auto-clean. -
attachServer(server, opts)โ simple HTTP upgrade
wiring. - Built-in support for
permessage-deflate(RFC 7692)
provided as an optional extension instance. - Client-side reconnect helpers (configurable) and heartbeat
primitives in core. - TypeScript definitions included ('index.d.ts') for IDE support.
- Tests included for core registry and basic behaviour (see
'index.test.js').
Extensions (channels, events, history,
admin, routing,
message-meta, heartbeat) are available as separate modules
in the repo but marked WIP โ README below points to that.
๐ฆ Installation
npm:
npm install ws13
yarn:
yarn add ws13
๐ Quick start โ
minimal server
This example uses the core createWebSocket exported from the package.
const http = require('http');
const createWebSocket = require('ws13');
const server = http.createServer();
const { registry } = createWebSocket.attachServer(server, {
onConnect(ws, req) {
ws.send('Welcome');
ws.on('message', (evt) => {
// simple echo
ws.send(`Echo: ${evt.data}`);
});
}
});
server.listen(8080);
Client (Node.js reusing createWebSocket in client mode):
const http = require('http');
const createWebSocket = require('ws13');
const req = http.request({ host: '127.0.0.1', port: 8080, path: '/' });
const ws = createWebSocket({ request: req });
ws.on('open', () => ws.send('hello'));
ws.on('message', (evt) => console.log(evt.data));
Browser clients should use the native WebSocket API (wss:// for TLS).
๐งฉ Core API (summary)
-
createWebSocket(options): create client or server
WebSocket-like instance - options highlights:
request(IncomingMessage |
ClientRequest),socket,protocol,origin,
heartbeatInterval_ms,extension(or null),autoReconnect,
requestFactory,shouldReconnect,isDebug. - returned object is EventEmitter-like and supports:
send(data),sendPing(data),sendPong(data),
heartbeat(cb),close(code, reason). Properties:readyState,
ip,port,latency_ms,bufferedAmount,
protocol,extensions,url. -
createRegistry(): returns
{ add(ws), delete(ws), broadcast(data), size(), clients:Set } -
registryauto-cleans clients on
close/error. -
attachServer(server, { registry?, onConnect? }):
attaches upgrade handler and returns{ registry }. - Default
permessage-deflateextension is provided
in core (createPermessageDeflate) and can be disabled viacreateWebSocket({ extension: null }).
TypeScript definitions are available at 'index.d.ts' for full shapes
and options.
๐งช Tests
Project ships basic tests for the core. Use test-runner-lite (or
Node directly) to run tests.
Run all tests:
npm test
Run the core test directly:
node ./index.test.js
Example core tests included:
- registry add/delete and automatic cleanup on close/error
- attachServer integration behaviour
- basic createWebSocket attachment helpers
Add more tests as needed; tests live next to core and in each
extension folder when implemented.
๐งฉ Extension roadmap
(short)
The following extensions exist as separate modules and will be fully
documented and stabilised in subsequent releases.
Current status: prototype/partial implementations present in repo.
-
channelsโ channel-based pub/sub -
message-metaโ typed messages with meta
(wrap/unwrap) -
heartbeatโ idle/timeout hooks and monitor
-
historyโ per-channel replay buffer (last N
messages) -
eventsโ JSON-RPC style event emitter
(ws.onEvent / ws.emitEvent) -
adminโ HTTP + WebSocket admin API, CSV/JSON
export, disconnect/latency endpoints, live dashboard -
routingโ targeted delivery (sendToUser,
sendToRole, sendToIp) -
authโ authentication and role-based
authorization
If your project relies on a specific extension, tell me which one
and I will prioritise finishing it and publishing a stable interface.
๐ Operational notes
- Default
heartbeatInterval_msin core is 30s (can
be changed per socket). - When enabling compression, configure
maxDecompressSizeto protect against decompression attacks. - Registry clients are a Set; if you need ordered lists or
sharding, wrap registry accordingly. - The core focuses on correctness of handshake and frame handling
โ if you need production tuning (backpressure handling, batching or socket pooling) we can add recommended
patterns.
๐ Project Structure
ws13/
core/
index.d.ts
index.js
index.test.js
permessage-deflate.js
README.md
extensions/
admin/
index.d.ts
index.js
index.test.js
README.md
express-middleware.d.ts
express-middleware.js
examples/
admin-api/
server.js
admin-dashboard/
admin-dashboard.html
admin-express-integration/
index.js
README.md
auth/
index.d.ts
index.js
index.test.js
README.md
examples/
auth-channels-client.js
auth-channels-server.js
server-with-admin.js
channels/
index.d.ts
index.js
index.test.js
README.md
examples/
channels/
client.js
server.js
events/
index.d.ts
index.js
index.test.js
README.md
examples/
events/
client.js
server.js
heartbeat/
index.d.ts
index.js
index.test.js
README.md
examples/
heartbeat/
client.js
history/
index.d.ts
index.js
index.test.js
README.md
sqlite-adapter.js
sqlite-adapter.test.js
examples/
history/
client.js
server.js
message-meta/
index.d.ts
index.js
index.test.js
README.md
examples/
message-meta/
client.js
server.js
routing-server.js
routing/
index.d.ts
index.js
index.test.js
README.md
examples/
routing/
client.js
server.js
logo/
logo-ws13.png
browser.js
index.d.ts
index.js
LICENSE
package.json
README.md
testRunner.js
wrapper.mjs
๐ Contributing &
development
- If you need only the core to unblock dependent projects, use
the provided core export and tests. Extensions will follow; they are useful but not required for core
adoption. - Tell me which extension to stabilise first (
channels,history,events,
auth,adminor
routing) and Iโll prepare stable API docs,
tests, and examples.
๐ License
This project is licensed under the MIT License.
Copyright ยฉ Manuel Lรตhmus