@webiny/api-websockets 0.0.0-unstable.e622468070 → 0.0.0-unstable.e6f0dc8ca7

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.
@@ -45,6 +45,11 @@ export class WebsocketsContext {
45
45
  } catch (error) {
46
46
  return Result.fail(new WebsocketServiceError(error));
47
47
  }
48
+
49
+ // Defensively filter connections that were created in the last 3 hours.
50
+ // This protects from attempting to send messages to stale connections.
51
+ const threeHoursAgo = new Date(Date.now() - 3 * 60 * 60 * 1000).toISOString();
52
+ connections = connections.filter(c => c.connectedOn >= threeHoursAgo);
48
53
  return Result.ok(connections);
49
54
  }
50
55
  async disconnect(params, notify = true) {
@@ -1 +1 @@
1
- {"version":3,"names":["Result","WebsocketServiceError","WebsocketForceDisconnectError","WebsocketForceDisconnectNotificationError","WebsocketsContext","constructor","registry","transport","send","identity","data","result","listConnections","where","identityId","id","isFail","fail","error","value","ok","sendToConnections","connections","params","listViaIdentity","listViaConnections","tenant","listViaTenant","listAll","disconnect","notify","connection","unregister","action"],"sources":["WebsocketsContext.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport type {\n IWebsocketsConnectionRegistry,\n IWebsocketsConnectionRegistryData\n} from \"~/registry/index.js\";\nimport type {\n IWebsocketsContextObject,\n IWebsocketsContextDisconnectConnectionsParams,\n IWebsocketsContextListConnectionsParams,\n IWebsocketsIdentity\n} from \"./abstractions/IWebsocketsContext.js\";\nimport type {\n IWebsocketsTransport,\n IWebsocketsTransportSendConnection,\n IWebsocketsTransportSendData\n} from \"~/transport/index.js\";\nimport type { GenericRecord } from \"@webiny/api/types.js\";\nimport {\n WebsocketServiceError,\n WebsocketForceDisconnectError,\n WebsocketForceDisconnectNotificationError\n} from \"~/features/WebsocketService/errors.js\";\nimport { WebsocketService } from \"~/features/WebsocketService/index.js\";\n\nexport class WebsocketsContext implements IWebsocketsContextObject {\n public readonly registry: IWebsocketsConnectionRegistry;\n private readonly transport: IWebsocketsTransport;\n\n constructor(registry: IWebsocketsConnectionRegistry, transport: IWebsocketsTransport) {\n this.registry = registry;\n this.transport = transport;\n }\n\n public async send<T extends GenericRecord = GenericRecord>(\n identity: Pick<IWebsocketsIdentity, \"id\">,\n data: IWebsocketsTransportSendData<T>\n ): Promise<Result<void, WebsocketService.Error>> {\n const result = await this.listConnections({\n where: {\n identityId: identity.id\n }\n });\n\n if (result.isFail()) {\n return Result.fail(result.error);\n }\n\n try {\n await this.transport.send<T>(result.value, data);\n } catch (error) {\n return Result.fail(new WebsocketServiceError(error));\n }\n\n return Result.ok();\n }\n\n public async sendToConnections<T extends GenericRecord = GenericRecord>(\n connections: IWebsocketsTransportSendConnection[],\n data: IWebsocketsTransportSendData<T>\n ): Promise<Result<void, WebsocketService.Error>> {\n try {\n await this.transport.send<T>(connections, data);\n } catch (error) {\n return Result.fail(new WebsocketServiceError(error));\n }\n\n return Result.ok();\n }\n\n public async listConnections(\n params?: IWebsocketsContextListConnectionsParams\n ): Promise<Result<IWebsocketsConnectionRegistryData[], WebsocketService.Error>> {\n let connections: IWebsocketsConnectionRegistryData[] = [];\n\n try {\n const where = params?.where || {};\n if (where.identityId) {\n connections = await this.registry.listViaIdentity(where.identityId);\n } else if (where.connections) {\n connections = await this.registry.listViaConnections(where.connections);\n } else if (where.tenant) {\n connections = await this.registry.listViaTenant(where.tenant);\n } else {\n connections = await this.registry.listAll();\n }\n } catch (error) {\n return Result.fail(new WebsocketServiceError(error));\n }\n\n return Result.ok(connections);\n }\n\n public async disconnect(\n params?: IWebsocketsContextDisconnectConnectionsParams,\n notify = true\n ): Promise<Result<IWebsocketsConnectionRegistryData[], WebsocketService.Error>> {\n const result = await this.listConnections(params);\n if (result.isFail()) {\n return Result.fail(result.error);\n }\n\n const connections = result.value;\n\n for (const connection of connections) {\n try {\n await this.registry.unregister(connection);\n } catch {\n // do nothing\n }\n }\n\n if (notify) {\n try {\n await this.transport.send(connections, {\n action: \"forcedDisconnect\"\n });\n } catch (error) {\n return Result.fail(new WebsocketForceDisconnectNotificationError(error));\n }\n }\n\n try {\n await this.transport.disconnect(connections);\n } catch (error) {\n return Result.fail(new WebsocketForceDisconnectError(error));\n }\n\n return Result.ok(connections);\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["Result","WebsocketServiceError","WebsocketForceDisconnectError","WebsocketForceDisconnectNotificationError","WebsocketsContext","constructor","registry","transport","send","identity","data","result","listConnections","where","identityId","id","isFail","fail","error","value","ok","sendToConnections","connections","params","listViaIdentity","listViaConnections","tenant","listViaTenant","listAll","threeHoursAgo","Date","now","toISOString","filter","c","connectedOn","disconnect","notify","connection","unregister","action"],"sources":["WebsocketsContext.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport type {\n IWebsocketsConnectionRegistry,\n IWebsocketsConnectionRegistryData\n} from \"~/registry/index.js\";\nimport type {\n IWebsocketsContextObject,\n IWebsocketsContextDisconnectConnectionsParams,\n IWebsocketsContextListConnectionsParams,\n IWebsocketsIdentity\n} from \"./abstractions/IWebsocketsContext.js\";\nimport type {\n IWebsocketsTransport,\n IWebsocketsTransportSendConnection,\n IWebsocketsTransportSendData\n} from \"~/transport/index.js\";\nimport type { GenericRecord } from \"@webiny/api/types.js\";\nimport {\n WebsocketServiceError,\n WebsocketForceDisconnectError,\n WebsocketForceDisconnectNotificationError\n} from \"~/features/WebsocketService/errors.js\";\nimport { WebsocketService } from \"~/features/WebsocketService/index.js\";\n\nexport class WebsocketsContext implements IWebsocketsContextObject {\n public readonly registry: IWebsocketsConnectionRegistry;\n private readonly transport: IWebsocketsTransport;\n\n constructor(registry: IWebsocketsConnectionRegistry, transport: IWebsocketsTransport) {\n this.registry = registry;\n this.transport = transport;\n }\n\n public async send<T extends GenericRecord = GenericRecord>(\n identity: Pick<IWebsocketsIdentity, \"id\">,\n data: IWebsocketsTransportSendData<T>\n ): Promise<Result<void, WebsocketService.Error>> {\n const result = await this.listConnections({\n where: {\n identityId: identity.id\n }\n });\n\n if (result.isFail()) {\n return Result.fail(result.error);\n }\n\n try {\n await this.transport.send<T>(result.value, data);\n } catch (error) {\n return Result.fail(new WebsocketServiceError(error));\n }\n\n return Result.ok();\n }\n\n public async sendToConnections<T extends GenericRecord = GenericRecord>(\n connections: IWebsocketsTransportSendConnection[],\n data: IWebsocketsTransportSendData<T>\n ): Promise<Result<void, WebsocketService.Error>> {\n try {\n await this.transport.send<T>(connections, data);\n } catch (error) {\n return Result.fail(new WebsocketServiceError(error));\n }\n\n return Result.ok();\n }\n\n public async listConnections(\n params?: IWebsocketsContextListConnectionsParams\n ): Promise<Result<IWebsocketsConnectionRegistryData[], WebsocketService.Error>> {\n let connections: IWebsocketsConnectionRegistryData[] = [];\n\n try {\n const where = params?.where || {};\n if (where.identityId) {\n connections = await this.registry.listViaIdentity(where.identityId);\n } else if (where.connections) {\n connections = await this.registry.listViaConnections(where.connections);\n } else if (where.tenant) {\n connections = await this.registry.listViaTenant(where.tenant);\n } else {\n connections = await this.registry.listAll();\n }\n } catch (error) {\n return Result.fail(new WebsocketServiceError(error));\n }\n\n // Defensively filter connections that were created in the last 3 hours.\n // This protects from attempting to send messages to stale connections.\n const threeHoursAgo = new Date(Date.now() - 3 * 60 * 60 * 1000).toISOString();\n connections = connections.filter(c => c.connectedOn >= threeHoursAgo);\n\n return Result.ok(connections);\n }\n\n public async disconnect(\n params?: IWebsocketsContextDisconnectConnectionsParams,\n notify = true\n ): Promise<Result<IWebsocketsConnectionRegistryData[], WebsocketService.Error>> {\n const result = await this.listConnections(params);\n if (result.isFail()) {\n return Result.fail(result.error);\n }\n\n const connections = result.value;\n\n for (const connection of connections) {\n try {\n await this.registry.unregister(connection);\n } catch {\n // do nothing\n }\n }\n\n if (notify) {\n try {\n await this.transport.send(connections, {\n action: \"forcedDisconnect\"\n });\n } catch (error) {\n return Result.fail(new WebsocketForceDisconnectNotificationError(error));\n }\n }\n\n try {\n await this.transport.disconnect(connections);\n } catch (error) {\n return Result.fail(new WebsocketForceDisconnectError(error));\n }\n\n return Result.ok(connections);\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1,4 +1,4 @@
1
- import { IdentityContext } from "@webiny/api-core/features/IdentityContext";
1
+ import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/index.js";
2
2
  import { NotAuthorizedError } from "@webiny/api-core/features/security/shared/index.js";
3
3
  /**
4
4
  * Simple permission check. Only full access can access the websockets API via GraphQL - ({name: "*"})
@@ -1 +1 @@
1
- {"version":3,"names":["IdentityContext","NotAuthorizedError","checkPermissions","context","identityContext","container","resolve","permissions","getPermissions","length"],"sources":["checkPermissions.ts"],"sourcesContent":["import { IdentityContext } from \"@webiny/api-core/features/IdentityContext\";\nimport { NotAuthorizedError } from \"@webiny/api-core/features/security/shared/index.js\";\nimport type { Context, WebsocketsPermission } from \"~/types.js\";\n\n/**\n * Simple permission check. Only full access can access the websockets API via GraphQL - ({name: \"*\"})\n *\n * @throws\n */\nexport const checkPermissions = async (context: Context): Promise<void> => {\n const identityContext = context.container.resolve(IdentityContext);\n const permissions = await identityContext.getPermissions<WebsocketsPermission>(\"websockets\");\n\n if (permissions.length === 0) {\n throw new NotAuthorizedError();\n }\n};\n"],"mappings":"AAAA,SAASA,eAAe,QAAQ,2CAA2C;AAC3E,SAASC,kBAAkB,QAAQ,oDAAoD;AAGvF;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,gBAAgB,GAAG,MAAOC,OAAgB,IAAoB;EACvE,MAAMC,eAAe,GAAGD,OAAO,CAACE,SAAS,CAACC,OAAO,CAACN,eAAe,CAAC;EAClE,MAAMO,WAAW,GAAG,MAAMH,eAAe,CAACI,cAAc,CAAuB,YAAY,CAAC;EAE5F,IAAID,WAAW,CAACE,MAAM,KAAK,CAAC,EAAE;IAC1B,MAAM,IAAIR,kBAAkB,CAAC,CAAC;EAClC;AACJ,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["IdentityContext","NotAuthorizedError","checkPermissions","context","identityContext","container","resolve","permissions","getPermissions","length"],"sources":["checkPermissions.ts"],"sourcesContent":["import { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/index.js\";\nimport { NotAuthorizedError } from \"@webiny/api-core/features/security/shared/index.js\";\nimport type { Context, WebsocketsPermission } from \"~/types.js\";\n\n/**\n * Simple permission check. Only full access can access the websockets API via GraphQL - ({name: \"*\"})\n *\n * @throws\n */\nexport const checkPermissions = async (context: Context): Promise<void> => {\n const identityContext = context.container.resolve(IdentityContext);\n const permissions = await identityContext.getPermissions<WebsocketsPermission>(\"websockets\");\n\n if (permissions.length === 0) {\n throw new NotAuthorizedError();\n }\n};\n"],"mappings":"AAAA,SAASA,eAAe,QAAQ,6DAA6D;AAC7F,SAASC,kBAAkB,QAAQ,oDAAoD;AAGvF;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,gBAAgB,GAAG,MAAOC,OAAgB,IAAoB;EACvE,MAAMC,eAAe,GAAGD,OAAO,CAACE,SAAS,CAACC,OAAO,CAACN,eAAe,CAAC;EAClE,MAAMO,WAAW,GAAG,MAAMH,eAAe,CAACI,cAAc,CAAuB,YAAY,CAAC;EAE5F,IAAID,WAAW,CAACE,MAAM,KAAK,CAAC,EAAE;IAC1B,MAAM,IAAIR,kBAAkB,CAAC,CAAC;EAClC;AACJ,CAAC","ignoreList":[]}
package/package.json CHANGED
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "name": "@webiny/api-websockets",
3
- "version": "0.0.0-unstable.e622468070",
3
+ "version": "0.0.0-unstable.e6f0dc8ca7",
4
4
  "type": "module",
5
- "main": "index.js",
6
5
  "repository": {
7
6
  "type": "git",
8
7
  "url": "https://github.com/webiny/webiny-js.git"
@@ -17,33 +16,33 @@
17
16
  },
18
17
  "license": "MIT",
19
18
  "dependencies": {
20
- "@webiny/api": "0.0.0-unstable.e622468070",
21
- "@webiny/api-core": "0.0.0-unstable.e622468070",
22
- "@webiny/aws-sdk": "0.0.0-unstable.e622468070",
23
- "@webiny/db-dynamodb": "0.0.0-unstable.e622468070",
24
- "@webiny/error": "0.0.0-unstable.e622468070",
25
- "@webiny/feature": "0.0.0-unstable.e622468070",
26
- "@webiny/handler": "0.0.0-unstable.e622468070",
27
- "@webiny/handler-aws": "0.0.0-unstable.e622468070",
28
- "@webiny/plugins": "0.0.0-unstable.e622468070",
29
- "@webiny/utils": "0.0.0-unstable.e622468070",
30
- "type-fest": "5.4.4",
31
- "zod": "3.25.76"
19
+ "@webiny/api": "0.0.0-unstable.e6f0dc8ca7",
20
+ "@webiny/api-core": "0.0.0-unstable.e6f0dc8ca7",
21
+ "@webiny/aws-sdk": "0.0.0-unstable.e6f0dc8ca7",
22
+ "@webiny/db-dynamodb": "0.0.0-unstable.e6f0dc8ca7",
23
+ "@webiny/error": "0.0.0-unstable.e6f0dc8ca7",
24
+ "@webiny/feature": "0.0.0-unstable.e6f0dc8ca7",
25
+ "@webiny/handler": "0.0.0-unstable.e6f0dc8ca7",
26
+ "@webiny/handler-aws": "0.0.0-unstable.e6f0dc8ca7",
27
+ "@webiny/plugins": "0.0.0-unstable.e6f0dc8ca7",
28
+ "@webiny/utils": "0.0.0-unstable.e6f0dc8ca7",
29
+ "type-fest": "5.6.0",
30
+ "zod": "4.4.3"
32
31
  },
33
32
  "devDependencies": {
34
- "@webiny/api-headless-cms": "0.0.0-unstable.e622468070",
35
- "@webiny/build-tools": "0.0.0-unstable.e622468070",
36
- "@webiny/handler-db": "0.0.0-unstable.e622468070",
37
- "@webiny/handler-graphql": "0.0.0-unstable.e622468070",
38
- "@webiny/project-utils": "0.0.0-unstable.e622468070",
39
- "graphql": "16.12.0",
40
- "rimraf": "6.1.2",
41
- "typescript": "5.9.3",
42
- "vitest": "3.2.4"
33
+ "@webiny/api-headless-cms": "0.0.0-unstable.e6f0dc8ca7",
34
+ "@webiny/build-tools": "0.0.0-unstable.e6f0dc8ca7",
35
+ "@webiny/handler-db": "0.0.0-unstable.e6f0dc8ca7",
36
+ "@webiny/handler-graphql": "0.0.0-unstable.e6f0dc8ca7",
37
+ "@webiny/project-utils": "0.0.0-unstable.e6f0dc8ca7",
38
+ "graphql": "16.14.0",
39
+ "rimraf": "6.1.3",
40
+ "typescript": "6.0.3",
41
+ "vitest": "4.1.5"
43
42
  },
44
43
  "publishConfig": {
45
44
  "access": "public",
46
45
  "directory": "dist"
47
46
  },
48
- "gitHead": "e622468070839dc3f9552c85bf2bbac12d2ef88f"
47
+ "gitHead": "e6f0dc8ca741c1fcc3fec9a5b9e86fdd49544641"
49
48
  }
@@ -1 +1 @@
1
- {"version":3,"names":["WebinyError","WebsocketsEventRequestContextEventType","WebsocketsRoutePlugin","middleware","WebsocketsRunner","constructor","context","registry","validator","response","run","input","event","validate","ex","result","error","message","code","data","stack","connectionId","domainName","stage","eventType","requestContext","messageId","body","JSON","stringify","json","parse","respond","executeRoute","routeKey","getRoutePlugins","route","plugins","byType","type","filter","plugin","length","reverse","getTenant","tenant","tenancy","getCurrentTenant","id","getIdentity","identity","security","action","map","params","next","statusCode","console","connection","dataToSend","websockets","sendToConnections"],"sources":["WebsocketsRunner.ts"],"sourcesContent":["import WebinyError from \"@webiny/error\";\nimport type {\n IWebsocketsEvent,\n IWebsocketsEventData,\n IWebsocketsEventRequestContext,\n IWebsocketsIncomingEvent,\n WebsocketsEventRoute\n} from \"~/handler/types.js\";\nimport { WebsocketsEventRequestContextEventType } from \"~/handler/types.js\";\nimport type { Context } from \"~/types.js\";\nimport type { IWebsocketsEventValidator } from \"~/validator/index.js\";\nimport type {\n IWebsocketsRunner,\n IWebsocketsRunnerResponse\n} from \"./abstractions/IWebsocketsRunner.js\";\nimport type { IWebsocketsRoutePluginCallableParams } from \"~/plugins/index.js\";\nimport { WebsocketsRoutePlugin } from \"~/plugins/index.js\";\nimport { middleware } from \"~/utils/middleware.js\";\nimport type { IWebsocketsConnectionRegistry } from \"~/registry/index.js\";\nimport type {\n IWebsocketsResponse,\n IWebsocketsResponseErrorResult,\n IWebsocketsResponseOkResult\n} from \"~/response/index.js\";\nimport type { IWebsocketsTransportSendConnection } from \"~/transport/index.js\";\nimport type { IWebsocketsIdentity } from \"~/context/index.js\";\n\ntype MiddlewareParams<C extends Context = Context> = Pick<\n IWebsocketsRoutePluginCallableParams<C>,\n \"context\" | \"event\" | \"registry\"\n>;\n\ninterface IWebsocketsRunnerRespondParams\n extends Pick<\n IWebsocketsEventRequestContext,\n \"connectionId\" | \"domainName\" | \"stage\" | \"eventType\"\n > {\n messageId?: string;\n result: IWebsocketsResponseOkResult | IWebsocketsResponseErrorResult;\n}\n\nexport class WebsocketsRunner implements IWebsocketsRunner {\n private readonly context: Context;\n private readonly registry: IWebsocketsConnectionRegistry;\n private readonly validator: IWebsocketsEventValidator;\n private readonly response: IWebsocketsResponse;\n\n public constructor(\n context: Context,\n registry: IWebsocketsConnectionRegistry,\n validator: IWebsocketsEventValidator,\n response: IWebsocketsResponse\n ) {\n this.context = context;\n this.registry = registry;\n this.validator = validator;\n this.response = response;\n }\n\n public async run<T extends IWebsocketsEventData = IWebsocketsEventData>(\n input: IWebsocketsIncomingEvent\n ): Promise<IWebsocketsRunnerResponse> {\n let event: IWebsocketsEvent<T> | undefined;\n try {\n event = await this.validator.validate<T>(input);\n } catch (ex) {\n const result = this.response.error({\n message: \"Validation failed.\",\n error: {\n message: ex.message,\n code: ex.code,\n data: ex.data,\n stack: ex.stack\n }\n });\n\n const { connectionId, domainName, stage, eventType } = input.requestContext || {};\n let messageId: string | undefined;\n try {\n const body =\n typeof input.body === \"string\" ? input.body : JSON.stringify(input.body || {});\n const json = JSON.parse(body);\n messageId = json.messageId;\n } catch {\n // Do nothing\n }\n if (!connectionId || !stage || !domainName || !eventType) {\n return result;\n }\n\n await this.respond({\n connectionId,\n domainName,\n stage,\n eventType,\n messageId,\n result\n });\n return result;\n }\n\n let result: IWebsocketsResponseOkResult | IWebsocketsResponseErrorResult;\n try {\n result = await this.executeRoute(event);\n } catch (ex) {\n result = this.response.error({\n message: `Route \"${event.requestContext.routeKey}\" action failed.`,\n error: {\n message: ex.message,\n code: ex.code,\n data: ex.data,\n stack: ex.stack\n }\n });\n }\n try {\n await this.respond({\n ...event.requestContext,\n messageId: event.body?.messageId,\n result\n });\n return result;\n } catch (ex) {\n return this.response.error({\n message: \"Failed to respond to the request.\",\n error: {\n message: ex.message,\n code: ex.code,\n data: {\n ...ex.data,\n result\n },\n stack: ex.stack\n }\n });\n }\n }\n\n private getRoutePlugins(route: WebsocketsEventRoute | string): WebsocketsRoutePlugin[] {\n const plugins = this.context.plugins\n .byType<WebsocketsRoutePlugin>(WebsocketsRoutePlugin.type)\n .filter(plugin => {\n return plugin.route === route;\n });\n if (plugins.length === 0) {\n throw new WebinyError(\n `There are no plugins for the route: ${route}.`,\n \"NO_ROUTE_PLUGINS\",\n {\n route\n }\n );\n }\n return plugins;\n }\n\n private async executeRoute(event: IWebsocketsEvent): Promise<IWebsocketsRunnerResponse> {\n /**\n * We will always fetch plugins in reverse order, so that users can override our default ones if necessary.\n */\n const plugins = this.getRoutePlugins(event.requestContext.routeKey).reverse();\n\n const getTenant = () => {\n const tenant = this.context.tenancy.getCurrentTenant();\n return tenant?.id || null;\n };\n\n const getIdentity = (): IWebsocketsIdentity | null => {\n const identity = this.context.security.getIdentity();\n return identity || null;\n };\n\n const action = middleware<MiddlewareParams, IWebsocketsRunnerResponse>(\n plugins.map(plugin => {\n return async (params, next) => {\n return plugin.run({\n registry: params.registry,\n event: params.event,\n context: params.context,\n getTenant,\n getIdentity,\n response: this.response,\n next\n });\n };\n })\n );\n\n const result = await action({\n event,\n registry: this.registry,\n context: this.context\n });\n if (result) {\n return result;\n }\n const message = \"No response from the route action.\";\n return this.response.error({\n message,\n error: {\n message,\n code: \"NO_RESPONSE\"\n },\n statusCode: 404\n });\n }\n\n private async respond(params: IWebsocketsRunnerRespondParams): Promise<void> {\n const { connectionId, domainName, stage, eventType, result, messageId } = params;\n if (eventType !== WebsocketsEventRequestContextEventType.message) {\n return;\n } else if (!connectionId || !domainName || !stage) {\n const message = \"No connectionId, domainName or stage.\";\n const data = {\n connectionId,\n domainName,\n stage\n };\n console.error(message, JSON.stringify(data));\n throw new WebinyError(message, \"GENERAL_ERROR\", data);\n }\n const connection: IWebsocketsTransportSendConnection = {\n connectionId,\n domainName,\n stage\n };\n\n const dataToSend = {\n ...result,\n messageId\n };\n await this.context.websockets.sendToConnections([connection], dataToSend);\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["WebinyError","WebsocketsEventRequestContextEventType","WebsocketsRoutePlugin","middleware","WebsocketsRunner","constructor","context","registry","validator","response","run","input","event","validate","ex","result","error","message","code","data","stack","connectionId","domainName","stage","eventType","requestContext","messageId","body","JSON","stringify","json","parse","respond","executeRoute","routeKey","getRoutePlugins","route","plugins","byType","type","filter","plugin","length","reverse","getTenant","tenant","tenancy","getCurrentTenant","id","getIdentity","identity","security","action","map","params","next","statusCode","console","connection","dataToSend","websockets","sendToConnections"],"sources":["WebsocketsRunner.ts"],"sourcesContent":["import WebinyError from \"@webiny/error\";\nimport type {\n IWebsocketsEvent,\n IWebsocketsEventData,\n IWebsocketsEventRequestContext,\n IWebsocketsIncomingEvent,\n WebsocketsEventRoute\n} from \"~/handler/types.js\";\nimport { WebsocketsEventRequestContextEventType } from \"~/handler/types.js\";\nimport type { Context } from \"~/types.js\";\nimport type { IWebsocketsEventValidator } from \"~/validator/index.js\";\nimport type {\n IWebsocketsRunner,\n IWebsocketsRunnerResponse\n} from \"./abstractions/IWebsocketsRunner.js\";\nimport type { IWebsocketsRoutePluginCallableParams } from \"~/plugins/index.js\";\nimport { WebsocketsRoutePlugin } from \"~/plugins/index.js\";\nimport { middleware } from \"~/utils/middleware.js\";\nimport type { IWebsocketsConnectionRegistry } from \"~/registry/index.js\";\nimport type {\n IWebsocketsResponse,\n IWebsocketsResponseErrorResult,\n IWebsocketsResponseOkResult\n} from \"~/response/index.js\";\nimport type { IWebsocketsTransportSendConnection } from \"~/transport/index.js\";\nimport type { IWebsocketsIdentity } from \"~/context/index.js\";\n\ntype MiddlewareParams<C extends Context = Context> = Pick<\n IWebsocketsRoutePluginCallableParams<C>,\n \"context\" | \"event\" | \"registry\"\n>;\n\ninterface IWebsocketsRunnerRespondParams extends Pick<\n IWebsocketsEventRequestContext,\n \"connectionId\" | \"domainName\" | \"stage\" | \"eventType\"\n> {\n messageId?: string;\n result: IWebsocketsResponseOkResult | IWebsocketsResponseErrorResult;\n}\n\nexport class WebsocketsRunner implements IWebsocketsRunner {\n private readonly context: Context;\n private readonly registry: IWebsocketsConnectionRegistry;\n private readonly validator: IWebsocketsEventValidator;\n private readonly response: IWebsocketsResponse;\n\n public constructor(\n context: Context,\n registry: IWebsocketsConnectionRegistry,\n validator: IWebsocketsEventValidator,\n response: IWebsocketsResponse\n ) {\n this.context = context;\n this.registry = registry;\n this.validator = validator;\n this.response = response;\n }\n\n public async run<T extends IWebsocketsEventData = IWebsocketsEventData>(\n input: IWebsocketsIncomingEvent\n ): Promise<IWebsocketsRunnerResponse> {\n let event: IWebsocketsEvent<T> | undefined;\n try {\n event = await this.validator.validate<T>(input);\n } catch (ex) {\n const result = this.response.error({\n message: \"Validation failed.\",\n error: {\n message: ex.message,\n code: ex.code,\n data: ex.data,\n stack: ex.stack\n }\n });\n\n const { connectionId, domainName, stage, eventType } = input.requestContext || {};\n let messageId: string | undefined;\n try {\n const body =\n typeof input.body === \"string\" ? input.body : JSON.stringify(input.body || {});\n const json = JSON.parse(body);\n messageId = json.messageId;\n } catch {\n // Do nothing\n }\n if (!connectionId || !stage || !domainName || !eventType) {\n return result;\n }\n\n await this.respond({\n connectionId,\n domainName,\n stage,\n eventType,\n messageId,\n result\n });\n return result;\n }\n\n let result: IWebsocketsResponseOkResult | IWebsocketsResponseErrorResult;\n try {\n result = await this.executeRoute(event);\n } catch (ex) {\n result = this.response.error({\n message: `Route \"${event.requestContext.routeKey}\" action failed.`,\n error: {\n message: ex.message,\n code: ex.code,\n data: ex.data,\n stack: ex.stack\n }\n });\n }\n try {\n await this.respond({\n ...event.requestContext,\n messageId: event.body?.messageId,\n result\n });\n return result;\n } catch (ex) {\n return this.response.error({\n message: \"Failed to respond to the request.\",\n error: {\n message: ex.message,\n code: ex.code,\n data: {\n ...ex.data,\n result\n },\n stack: ex.stack\n }\n });\n }\n }\n\n private getRoutePlugins(route: WebsocketsEventRoute | string): WebsocketsRoutePlugin[] {\n const plugins = this.context.plugins\n .byType<WebsocketsRoutePlugin>(WebsocketsRoutePlugin.type)\n .filter(plugin => {\n return plugin.route === route;\n });\n if (plugins.length === 0) {\n throw new WebinyError(\n `There are no plugins for the route: ${route}.`,\n \"NO_ROUTE_PLUGINS\",\n {\n route\n }\n );\n }\n return plugins;\n }\n\n private async executeRoute(event: IWebsocketsEvent): Promise<IWebsocketsRunnerResponse> {\n /**\n * We will always fetch plugins in reverse order, so that users can override our default ones if necessary.\n */\n const plugins = this.getRoutePlugins(event.requestContext.routeKey).reverse();\n\n const getTenant = () => {\n const tenant = this.context.tenancy.getCurrentTenant();\n return tenant?.id || null;\n };\n\n const getIdentity = (): IWebsocketsIdentity | null => {\n const identity = this.context.security.getIdentity();\n return identity || null;\n };\n\n const action = middleware<MiddlewareParams, IWebsocketsRunnerResponse>(\n plugins.map(plugin => {\n return async (params, next) => {\n return plugin.run({\n registry: params.registry,\n event: params.event,\n context: params.context,\n getTenant,\n getIdentity,\n response: this.response,\n next\n });\n };\n })\n );\n\n const result = await action({\n event,\n registry: this.registry,\n context: this.context\n });\n if (result) {\n return result;\n }\n const message = \"No response from the route action.\";\n return this.response.error({\n message,\n error: {\n message,\n code: \"NO_RESPONSE\"\n },\n statusCode: 404\n });\n }\n\n private async respond(params: IWebsocketsRunnerRespondParams): Promise<void> {\n const { connectionId, domainName, stage, eventType, result, messageId } = params;\n if (eventType !== WebsocketsEventRequestContextEventType.message) {\n return;\n } else if (!connectionId || !domainName || !stage) {\n const message = \"No connectionId, domainName or stage.\";\n const data = {\n connectionId,\n domainName,\n stage\n };\n console.error(message, JSON.stringify(data));\n throw new WebinyError(message, \"GENERAL_ERROR\", data);\n }\n const connection: IWebsocketsTransportSendConnection = {\n connectionId,\n domainName,\n stage\n };\n\n const dataToSend = {\n ...result,\n messageId\n };\n await this.context.websockets.sendToConnections([connection], dataToSend);\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -2,7 +2,7 @@ import zod from "zod";
2
2
  import { WebsocketsEventRequestContextEventType } from "../handler/types.js";
3
3
  import { createZodError } from "@webiny/utils";
4
4
  const validation = zod.object({
5
- headers: zod.object({}).passthrough().optional(),
5
+ headers: zod.looseObject({}).optional(),
6
6
  requestContext: zod.object({
7
7
  connectionId: zod.string(),
8
8
  stage: zod.string(),
@@ -47,13 +47,13 @@ const validation = zod.object({
47
47
  fatal: true
48
48
  });
49
49
  });
50
- const bodyValidation = zod.object({
50
+ const bodyValidation = zod.looseObject({
51
51
  token: zod.string(),
52
52
  tenant: zod.string(),
53
53
  messageId: zod.string().nullish(),
54
54
  action: zod.string(),
55
- data: zod.object({}).passthrough().nullish()
56
- }).passthrough().optional();
55
+ data: zod.looseObject({}).nullish()
56
+ }).optional();
57
57
  export class WebsocketsEventValidator {
58
58
  async validate(input) {
59
59
  const result = await validation.safeParseAsync(input);
@@ -1 +1 @@
1
- {"version":3,"names":["zod","WebsocketsEventRequestContextEventType","createZodError","validation","object","headers","passthrough","optional","requestContext","connectionId","string","stage","connectedAt","number","domainName","eventType","enum","connect","message","disconnect","routeKey","body","transform","value","context","undefined","JSON","parse","ex","console","error","log","addIssue","path","code","ZodIssueCode","custom","fatal","superRefine","output","bodyValidation","token","tenant","messageId","nullish","action","data","WebsocketsEventValidator","validate","input","result","safeParseAsync","success","bodyResult"],"sources":["WebsocketsEventValidator.ts"],"sourcesContent":["import zod from \"zod\";\nimport type { IWebsocketsEvent, IWebsocketsEventData } from \"~/handler/types.js\";\nimport { WebsocketsEventRequestContextEventType } from \"~/handler/types.js\";\nimport type {\n IWebsocketsEventValidator,\n IWebsocketsEventValidatorValidateParams\n} from \"./abstractions/IWebsocketsEventValidator.js\";\nimport { createZodError } from \"@webiny/utils\";\n\nconst validation = zod\n .object({\n headers: zod.object({}).passthrough().optional(),\n requestContext: zod.object({\n connectionId: zod.string(),\n stage: zod.string(),\n connectedAt: zod.number(),\n domainName: zod.string(),\n eventType: zod.enum([\n WebsocketsEventRequestContextEventType.connect,\n WebsocketsEventRequestContextEventType.message,\n WebsocketsEventRequestContextEventType.disconnect\n ]),\n routeKey: zod.string()\n }),\n body: zod\n .string()\n .transform<IWebsocketsEventData>((value, context) => {\n if (!value) {\n return undefined;\n }\n try {\n return JSON.parse(value);\n } catch (ex) {\n /**\n * We want to log the error, for easier debugging.\n */\n console.error(`Failed body validation: ${ex.message}`);\n console.log(`Body: ${value}`);\n /**\n * And we want to add an issue to the context, so that the user knows what went wrong.\n */\n context.addIssue({\n path: [],\n message: `Invalid JSON: ${ex.message}`,\n code: zod.ZodIssueCode.custom,\n fatal: true\n });\n }\n })\n .optional()\n })\n .superRefine((output, context) => {\n if (output.requestContext.eventType !== WebsocketsEventRequestContextEventType.message) {\n return;\n } else if (output.body) {\n return;\n }\n context.addIssue({\n path: [\"body\"],\n message: \"There must be a body defined when having a message event.\",\n code: zod.ZodIssueCode.custom,\n fatal: true\n });\n });\n\nconst bodyValidation = zod\n .object({\n token: zod.string(),\n tenant: zod.string(),\n messageId: zod.string().nullish(),\n action: zod.string(),\n data: zod.object({}).passthrough().nullish()\n })\n .passthrough()\n .optional();\n\nexport class WebsocketsEventValidator implements IWebsocketsEventValidator {\n public async validate<T extends IWebsocketsEventData = IWebsocketsEventData>(\n input: IWebsocketsEventValidatorValidateParams\n ): Promise<IWebsocketsEvent<T>> {\n const result = await validation.safeParseAsync(input);\n if (!result.success) {\n throw createZodError(result.error);\n }\n const bodyResult = await bodyValidation.safeParseAsync(result.data.body);\n if (!bodyResult.success) {\n throw createZodError(bodyResult.error);\n }\n return {\n ...result.data,\n body: {\n ...((bodyResult.data || {}) as T)\n }\n };\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["zod","WebsocketsEventRequestContextEventType","createZodError","validation","object","headers","looseObject","optional","requestContext","connectionId","string","stage","connectedAt","number","domainName","eventType","enum","connect","message","disconnect","routeKey","body","transform","value","context","undefined","JSON","parse","ex","console","error","log","addIssue","path","code","ZodIssueCode","custom","fatal","superRefine","output","bodyValidation","token","tenant","messageId","nullish","action","data","WebsocketsEventValidator","validate","input","result","safeParseAsync","success","bodyResult"],"sources":["WebsocketsEventValidator.ts"],"sourcesContent":["import zod from \"zod\";\nimport type { IWebsocketsEvent, IWebsocketsEventData } from \"~/handler/types.js\";\nimport { WebsocketsEventRequestContextEventType } from \"~/handler/types.js\";\nimport type {\n IWebsocketsEventValidator,\n IWebsocketsEventValidatorValidateParams\n} from \"./abstractions/IWebsocketsEventValidator.js\";\nimport { createZodError } from \"@webiny/utils\";\n\nconst validation = zod\n .object({\n headers: zod.looseObject({}).optional(),\n requestContext: zod.object({\n connectionId: zod.string(),\n stage: zod.string(),\n connectedAt: zod.number(),\n domainName: zod.string(),\n eventType: zod.enum([\n WebsocketsEventRequestContextEventType.connect,\n WebsocketsEventRequestContextEventType.message,\n WebsocketsEventRequestContextEventType.disconnect\n ]),\n routeKey: zod.string()\n }),\n body: zod\n .string()\n .transform<IWebsocketsEventData>((value, context) => {\n if (!value) {\n return undefined;\n }\n try {\n return JSON.parse(value);\n } catch (ex) {\n /**\n * We want to log the error, for easier debugging.\n */\n console.error(`Failed body validation: ${ex.message}`);\n console.log(`Body: ${value}`);\n /**\n * And we want to add an issue to the context, so that the user knows what went wrong.\n */\n context.addIssue({\n path: [],\n message: `Invalid JSON: ${ex.message}`,\n code: zod.ZodIssueCode.custom,\n fatal: true\n });\n }\n })\n .optional()\n })\n .superRefine((output, context) => {\n if (output.requestContext.eventType !== WebsocketsEventRequestContextEventType.message) {\n return;\n } else if (output.body) {\n return;\n }\n context.addIssue({\n path: [\"body\"],\n message: \"There must be a body defined when having a message event.\",\n code: zod.ZodIssueCode.custom,\n fatal: true\n });\n });\n\nconst bodyValidation = zod\n .looseObject({\n token: zod.string(),\n tenant: zod.string(),\n messageId: zod.string().nullish(),\n action: zod.string(),\n data: zod.looseObject({}).nullish()\n })\n .optional();\n\nexport class WebsocketsEventValidator implements IWebsocketsEventValidator {\n public async validate<T extends IWebsocketsEventData = IWebsocketsEventData>(\n input: IWebsocketsEventValidatorValidateParams\n ): Promise<IWebsocketsEvent<T>> {\n const result = await validation.safeParseAsync(input);\n if (!result.success) {\n throw createZodError(result.error);\n }\n const bodyResult = await bodyValidation.safeParseAsync(result.data.body);\n if (!bodyResult.success) {\n throw createZodError(bodyResult.error);\n }\n return {\n ...result.data,\n body: {\n ...((bodyResult.data || {}) as T)\n }\n };\n }\n}\n"],"mappings":"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","ignoreList":[]}