@bitrix24/b24jssdk
Version:
Bitrix24 REST API JavaScript SDK
1 lines • 18.7 kB
Source Map (JSON)
{"version":3,"file":"pull.mjs","sources":["../../../src/types/pull.ts"],"sourcesContent":["import type { LoggerInterface } from '../logger'\nimport type { TypeB24 } from './b24'\nimport type { ISODate, NumberString } from './common'\n\nexport type TypePullMessage = {\n command: string\n params: Record<string, any>\n extra: Record<string, any>\n}\n\nexport type TypePullClientMessageBody = {\n module_id: string\n command: string\n params: any\n extra?: {\n revision_web?: number\n sender?: {\n type: SenderType\n }\n server_time_unix?: number\n server_time_ago?: number\n }\n}\n\nexport enum ConnectionType {\n Undefined = 'undefined',\n WebSocket = 'webSocket',\n LongPolling = 'longPolling'\n}\n\nexport type TypeConnector = {\n setLogger(logger: LoggerInterface): void\n destroy(): void\n connect(): void\n disconnect(code: number, reason: string): void\n send(buffer: ArrayBuffer | string): boolean\n connected: boolean\n connectionPath: string\n}\n\nexport type ConnectorParent = {\n session: TypePullClientSession\n getConnectionPath(connectionType: ConnectionType): string\n getPublicationPath(): string\n setLastMessageId(lastMessageId: string): void\n isProtobufSupported(): boolean\n isJsonRpc(): boolean\n}\n\nexport type ConnectorCallbacks = {\n onOpen: () => void\n onDisconnect: (response: { code: number, reason: string }) => void\n onError: (error: Error) => void\n onMessage: (response: string | ArrayBuffer) => void\n}\n\nexport type ConnectorConfig = {\n parent: ConnectorParent\n onOpen?: () => void\n onDisconnect?: (response: { code: number, reason: string }) => void\n onError?: (error: Error) => void\n onMessage?: (response: string | ArrayBuffer) => void\n}\n\nexport type StorageManagerParams = {\n userId?: number\n siteId?: string\n}\n\nexport type TypeStorageManager = {\n setLogger(logger: LoggerInterface): void\n getLogger(): LoggerInterface\n\n set(name: string, value: any): void\n get(name: string, defaultValue: any): any\n remove(name: string): void\n compareKey(eventKey: string, userKey: string): boolean\n}\n\nexport enum LsKeys {\n PullConfig = 'bx-pull-config',\n WebsocketBlocked = 'bx-pull-websocket-blocked',\n LongPollingBlocked = 'bx-pull-longpolling-blocked',\n LoggingEnabled = 'bx-pull-logging-enabled'\n}\n\nexport type SharedConfigCallbacks = {\n onWebSocketBlockChanged: (response: { isWebSocketBlocked: boolean }) => void\n}\n\nexport type SharedConfigParams = {\n storage?: TypeStorageManager\n onWebSocketBlockChanged?: (response: { isWebSocketBlocked: boolean }) => void\n}\n\nexport enum PullStatus {\n Online = 'online',\n Offline = 'offline',\n Connecting = 'connect'\n}\n\nexport enum SenderType {\n Unknown = 0,\n Client = 1,\n Backend = 2\n}\n\nexport enum SubscriptionType {\n Server = 'server',\n Client = 'client',\n Online = 'online',\n Status = 'status',\n Revision = 'revision'\n}\n\nexport type TypeSubscriptionOptions = {\n /**\n * Subscription type\n */\n type?: SubscriptionType\n\n /**\n * Name of the module\n */\n moduleId?: string\n\n /**\n * Name of the command\n */\n command?: null | string\n\n /**\n * Function, that will be called for incoming messages\n */\n // eslint-disable-next-line\n\tcallback: Function\n}\n\nexport interface UserStatusCallback {\n (params: { userId: number, isOnline: boolean }): void\n}\n\nexport interface CommandHandlerFunctionV1 {\n (\n data: Record<string, any>,\n info?: {\n type: SubscriptionType\n moduleId?: string\n }\n ): void\n}\n\nexport interface CommandHandlerFunctionV2 {\n (\n params: Record<string, any>,\n extra: Record<string, any>,\n command: string,\n info?: {\n type: SubscriptionType\n moduleId: string\n }\n ): void\n}\n\nexport interface TypeSubscriptionCommandHandler {\n getModuleId: () => string\n getSubscriptionType?: () => SubscriptionType\n getMap?: () => Record<string, CommandHandlerFunctionV2>\n [key: string]: CommandHandlerFunctionV2 | undefined\n}\n\nexport type TypePullClientEmitConfig = {\n type: SubscriptionType\n moduleId?: string\n data?: Record<string, any>\n}\n\nexport enum CloseReasons {\n NORMAL_CLOSURE = 1000,\n SERVER_DIE = 1001,\n CONFIG_REPLACED = 3000,\n CHANNEL_EXPIRED = 3001,\n SERVER_RESTARTED = 3002,\n CONFIG_EXPIRED = 3003,\n MANUAL = 3004,\n STUCK = 3005,\n WRONG_CHANNEL_ID = 4010,\n\n /**\n * Codes the SERVER sends, below. Everything above EXCEPT `WRONG_CHANNEL_ID`\n * is a code the CLIENT sends — `PullClient` passes those to `disconnect()` /\n * `restart()` when it is the one ending the connection — and the two\n * directions must not be mixed up: passing `TOO_MANY_MESSAGES` to\n * `disconnect()` would be meaningless. `WRONG_CHANNEL_ID` is the exception\n * and always was: it arrives on the `close` event like the ones below (see\n * `PullClient.onWebSocketDisconnect`), which is why they share an enum, and\n * why a single reverse lookup over it turns a numeric `CloseEvent.code` into\n * a name.\n *\n * These arrive on the socket's `close` event, and that is the only place\n * they appear — they never reach a caller as an error. A refused frame is\n * reported to come back as a close with one of these and a reason string\n * rather than as an answer, though the same audit describes at least one\n * refusal path that produces no response at all, so \"no close code\" is not\n * the same as \"not refused\".\n *\n * Frame-level, i.e. \"the publish you just made was rejected\":\n * `WRONG_REQUEST_DATA`, `REQUEST_COMMAND_NOT_ALLOWED`,\n * `WRONG_REQUEST_COMMAND`, `TOO_MANY_MESSAGES`, `NO_CHANNELS_FOUND`,\n * `TOO_MANY_CHANNELS`, `INVALID_CHANNEL_ID`, `PRIVATE_CHANNEL_NOT_ALLOWED`,\n * `INVALID_CHANNEL_SIGNATURE`.\n *\n * Connection-level, i.e. \"this connection is not usable\", and NOT a verdict\n * on any particular frame: `WRONG_CHANNEL_ID` (above), `NO_PUBLIC_CHANNEL_ID`\n * and `TOO_MANY_CONNECTIONS`. A caller branching on \"is it 401x, so my\n * publish failed\" would misclassify all three.\n *\n * Reported by a third-party audit of an on-prem stand's push-server sources,\n * which is not in this repository and cannot be verified from it. Treat every\n * per-code description below as informed documentation rather than as\n * contract; the NUMBERS are what the `close` event gives you either way. See\n * `.github/contributing/pull-protobuf.md`.\n *\n * Connection-level: the connection has no public channel bound to it.\n */\n NO_PUBLIC_CHANNEL_ID = 4012,\n /** `RequestBatch.decode` threw, or `requests` was empty — a structurally malformed frame. */\n WRONG_REQUEST_DATA = 4013,\n /** Not `incomingMessages` or `channelStats`. */\n REQUEST_COMMAND_NOT_ALLOWED = 4014,\n /** No handler for the command. */\n WRONG_REQUEST_COMMAND = 4015,\n /** Per the audit: more than 100 messages in one batch. */\n TOO_MANY_MESSAGES = 4016,\n /** The message addressed nobody — `receivers` was empty. */\n NO_CHANNELS_FOUND = 4017,\n /** Per the audit: more than 100 channels in one request. */\n TOO_MANY_CHANNELS = 4018,\n /** Per the audit: a trusted-connection check, not reachable from a browser client. */\n INVALID_CHANNEL_ID = 4019,\n /** `Receiver.isPrivate` was true. A client may not publish to a private channel. */\n PRIVATE_CHANNEL_NOT_ALLOWED = 4020,\n /** `Receiver.signature` did not match the server's HMAC for that channel. */\n INVALID_CHANNEL_SIGNATURE = 4021,\n /** Connection-level. Per the audit: more than 100 connections on one channel. */\n TOO_MANY_CONNECTIONS = 4029\n}\n\n/**\n * Is this close code the server rejecting the frame that was just published?\n *\n * Not simply \"is it 401x\". `WRONG_CHANNEL_ID`, `NO_PUBLIC_CHANNEL_ID` and\n * `TOO_MANY_CONNECTIONS` are in that range and are connection-level — they say\n * the connection is unusable, not that a particular publish was refused.\n */\nexport function isFrameRefusalCloseCode(code: number): boolean {\n return FRAME_REFUSAL_CLOSE_CODES.has(code)\n}\n\n/**\n * Membership by name, not by range.\n *\n * A range test over 4013-4021 gives the same answers today, and only because\n * the allocation happens to be contiguous — nothing holds it that way. Adding\n * a connection-level code inside the range, or a frame-level one outside it,\n * would then need two edits that look unrelated, and the one nobody makes is\n * the test. Listing the members makes it a single edit.\n */\nconst FRAME_REFUSAL_CLOSE_CODES: ReadonlySet<number> = new Set([\n CloseReasons.WRONG_REQUEST_DATA,\n CloseReasons.REQUEST_COMMAND_NOT_ALLOWED,\n CloseReasons.WRONG_REQUEST_COMMAND,\n CloseReasons.TOO_MANY_MESSAGES,\n CloseReasons.NO_CHANNELS_FOUND,\n CloseReasons.TOO_MANY_CHANNELS,\n CloseReasons.INVALID_CHANNEL_ID,\n CloseReasons.PRIVATE_CHANNEL_NOT_ALLOWED,\n CloseReasons.INVALID_CHANNEL_SIGNATURE\n])\n\nexport enum SystemCommands {\n CHANNEL_EXPIRE = 'CHANNEL_EXPIRE',\n CONFIG_EXPIRE = 'CONFIG_EXPIRE',\n SERVER_RESTART = 'SERVER_RESTART'\n}\n\nexport enum ServerMode {\n Shared = 'shared',\n Personal = 'personal'\n}\n\nexport type RpcError = {\n code: number\n message: string\n}\n\nexport const ListRpcError = {\n Parse: { code: -32700, message: 'Parse error' } as RpcError,\n InvalidRequest: { code: -32600, message: 'Invalid Request' } as RpcError,\n MethodNotFound: { code: -32601, message: 'Method not found' } as RpcError,\n InvalidParams: { code: -32602, message: 'Invalid params' } as RpcError,\n Internal: { code: -32603, message: 'Internal error' } as RpcError\n} as const\n\nexport type JsonRpcRequest = {\n method: string\n params: any\n id: number\n}\n\nexport type RpcCommand = {\n jsonrpc: string\n method: string\n params: any\n id: number\n}\n\nexport type RpcRequest = RpcCommand & {}\n\nexport type RpcCommandResult = {\n jsonrpc?: string\n id?: number\n /**\n * @fix this TypeRpcResponseAwaiters.resolve(response)\n */\n result?: any\n error?: RpcError\n}\n\nexport enum RpcMethod {\n Publish = 'publish',\n GetUsersLastSeen = 'getUsersLastSeen',\n Ping = 'ping',\n ListChannels = 'listChannels',\n SubscribeStatusChange = 'subscribeStatusChange',\n UnsubscribeStatusChange = 'unsubscribeStatusChange'\n}\n\nexport type TypeRpcResponseAwaiters = {\n /**\n * @fix this RpcCommandResult.result\n */\n resolve: (response: any) => void\n reject: (error: string | RpcError) => void\n timeout: number\n}\n\nexport type TypeJsonRpcConfig = {\n connector: TypeConnector\n handlers: Record<string, (params: any) => RpcCommandResult>\n}\n\nexport type TypePublicIdDescriptor = {\n id?: string\n user_id?: NumberString\n public_id?: string\n signature?: string\n start: ISODate\n end: ISODate\n type?: string\n}\n\nexport type TypeChanel = {\n userId: number\n publicId: string\n signature: string\n start: Date\n end: Date\n}\n\nexport type TypeChannelManagerParams = {\n b24: TypeB24\n getPublicListMethod: string\n}\n\nexport type TypePullClientSession = {\n mid: null | string\n tag: null | string\n time: null | number\n history: any\n lastMessageIds: string[]\n messageCount: number\n}\n\nexport type TypeSessionEvent = {\n mid: string\n tag?: string\n time?: number\n text: Record<string, any> | TypePullClientMessageBody\n}\n\nexport type TypePullClientParams = {\n b24: TypeB24\n skipCheckRevision?: boolean\n restApplication?: string\n siteId?: string\n\n guestMode?: boolean\n guestUserId?: number\n\n userId?: number\n\n serverEnabled?: boolean\n configGetMethod?: string\n getPublicListMethod?: string\n skipStorageInit?: boolean\n configTimestamp?: number\n\n /**\n * Which protobuf implementation encodes and decodes the push-server frames.\n *\n * - `'vendored'` (default) — the copy of protobuf.js that has always shipped\n * with the SDK. Long in production, and 94 kB of the bundle.\n * - `'lite'` — the hand-written codec for the ten structures this client\n * actually uses. Same bytes on well-formed input; more tolerant than the\n * library on damaged input, and deliberately different in a few places\n * listed in `.github/contributing/pull-protobuf.md`.\n *\n * Choosing `'lite'` does NOT make the bundle smaller: both codecs are\n * imported statically and chosen at runtime, so both ship regardless. The\n * saving arrives only when the vendored library is deleted.\n *\n * **Not part of the public contract.** This is the SDK's own migration switch,\n * visible only because the type it sits on is exported. It is kept off the\n * documentation site, and it will be **removed without a deprecation cycle**\n * — see the `@internal` carve-out in\n * `.github/contributing/package-structure.md`. Do not build on it.\n *\n * @internal\n *\n * @experimental Agreement between the two is checked by a hand-written\n * differential and by a seeded fuzz differential over thousands of generated\n * frames in both directions (`test/integration/pull/protobuf-lite-*.spec.ts`),\n * and on two frames recorded from a live portal. All of that shows they\n * AGREE, not that either is right against the server. The lite codec's\n * production exposure is still close to none, which is why the default stays\n * on the vendored library.\n *\n * What ends it is not a single fixture but four steps, in order: the three\n * deliberate divergences signed off; the fuzz corpus frozen into golden\n * vectors while the library can still produce them; the oracle-free tests\n * kept; and a release with `'lite'` as the default before the deletion.\n * See `.github/contributing/pull-protobuf.md`.\n */\n protobufCodec?: 'vendored' | 'lite'\n}\n\nexport type TypePullClientConfig = {\n /**\n * @fix this\n */\n clientId: null\n api: {\n revision_mobile: number\n revision_web: number\n }\n channels: {\n private?: TypePublicIdDescriptor\n shared?: TypePublicIdDescriptor\n }\n publicChannels: Record<string, TypePublicIdDescriptor>\n server: {\n timeShift: number\n config_timestamp: number\n long_polling: string\n long_pooling_secure: string\n mode: string\n publish: string\n publish_enabled: boolean\n publish_secure: string\n server_enabled: boolean\n version: number\n websocket: string\n websocket_enabled: boolean\n websocket_secure: string\n }\n jwt: null | string\n exp: number\n}\n\nexport type TypePullClientMessageBatch = {\n userList?: number[]\n channelList?: (\n | string\n | {\n publicId: string\n signature: string\n }\n )[]\n body: TypePullClientMessageBody\n expiry?: number\n}\n"],"names":["ConnectionType","LsKeys","PullStatus","SenderType","SubscriptionType","CloseReasons","SystemCommands","ServerMode","RpcMethod"],"mappings":"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"}