@monolayer/sdk 1.2.0-canary.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +25 -0
- package/dist/bin/cli.js +21609 -0
- package/dist/cjs/configuration.d.ts +65 -0
- package/dist/cjs/configuration.js +45 -0
- package/dist/cjs/index.d.ts +4 -0
- package/dist/cjs/index.js +20 -0
- package/dist/cjs/introspection.d.ts +2 -0
- package/dist/cjs/introspection.js +11 -0
- package/dist/cjs/make/broadcast.d.ts +10 -0
- package/dist/cjs/make/broadcast.js +37 -0
- package/dist/cjs/make/config.d.ts +2 -0
- package/dist/cjs/make/config.js +44 -0
- package/dist/cjs/make/cron.d.ts +9 -0
- package/dist/cjs/make/cron.js +30 -0
- package/dist/cjs/make/make.d.ts +6 -0
- package/dist/cjs/make/make.js +134 -0
- package/dist/cjs/make/manifest.d.ts +202 -0
- package/dist/cjs/make/manifest.js +165 -0
- package/dist/cjs/make/required-filtes.d.ts +1 -0
- package/dist/cjs/make/required-filtes.js +17 -0
- package/dist/cjs/make/task.d.ts +9 -0
- package/dist/cjs/make/task.js +30 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/packages/docker/df.d.ts +543 -0
- package/dist/cjs/packages/docker/df.js +395 -0
- package/dist/cjs/packages/docker/validator.d.ts +7 -0
- package/dist/cjs/packages/docker/validator.js +18 -0
- package/dist/cjs/packages/utils/create-file.d.ts +1 -0
- package/dist/cjs/packages/utils/create-file.js +18 -0
- package/dist/cjs/packages/utils/date-string.d.ts +1 -0
- package/dist/cjs/packages/utils/date-string.js +12 -0
- package/dist/cjs/packages/utils/exception.d.ts +1 -0
- package/dist/cjs/packages/utils/exception.js +8 -0
- package/dist/cjs/packages/utils/hash-value.d.ts +16 -0
- package/dist/cjs/packages/utils/hash-value.js +25 -0
- package/dist/cjs/packages/utils/import-default.d.ts +1 -0
- package/dist/cjs/packages/utils/import-default.js +14 -0
- package/dist/cjs/packages/utils/import-file.d.ts +8 -0
- package/dist/cjs/packages/utils/import-file.js +41 -0
- package/dist/cjs/packages/utils/log-with-spinner.d.ts +1 -0
- package/dist/cjs/packages/utils/log-with-spinner.js +24 -0
- package/dist/cjs/packages/utils/path.d.ts +2 -0
- package/dist/cjs/packages/utils/path.js +21 -0
- package/dist/cjs/packages/utils/playground.d.ts +1 -0
- package/dist/cjs/packages/utils/playground.js +35 -0
- package/dist/cjs/scaffolding/add-env-var.d.ts +6 -0
- package/dist/cjs/scaffolding/add-env-var.js +65 -0
- package/dist/cjs/scaffolding/add-import.d.ts +16 -0
- package/dist/cjs/scaffolding/add-import.js +43 -0
- package/dist/cjs/scaffolding/add-script.d.ts +1 -0
- package/dist/cjs/scaffolding/add-script.js +35 -0
- package/dist/cjs/scaffolding/broadcast-workload.d.ts +1 -0
- package/dist/cjs/scaffolding/broadcast-workload.js +36 -0
- package/dist/cjs/scaffolding/bucket-workload.d.ts +6 -0
- package/dist/cjs/scaffolding/bucket-workload.js +23 -0
- package/dist/cjs/scaffolding/cron-workload.d.ts +6 -0
- package/dist/cjs/scaffolding/cron-workload.js +28 -0
- package/dist/cjs/scaffolding/drizzle.d.ts +4 -0
- package/dist/cjs/scaffolding/drizzle.js +22 -0
- package/dist/cjs/scaffolding/lifecycle.d.ts +9 -0
- package/dist/cjs/scaffolding/lifecycle.js +61 -0
- package/dist/cjs/scaffolding/postgres-database-workload.d.ts +15 -0
- package/dist/cjs/scaffolding/postgres-database-workload.js +39 -0
- package/dist/cjs/scaffolding/prisma.d.ts +4 -0
- package/dist/cjs/scaffolding/prisma.js +40 -0
- package/dist/cjs/scaffolding/replace-string.d.ts +10 -0
- package/dist/cjs/scaffolding/replace-string.js +37 -0
- package/dist/cjs/scaffolding/task-workload.d.ts +6 -0
- package/dist/cjs/scaffolding/task-workload.js +30 -0
- package/dist/cjs/scaffolding/workload.d.ts +1 -0
- package/dist/cjs/scaffolding/workload.js +18 -0
- package/dist/cjs/scan/project.d.ts +23 -0
- package/dist/cjs/scan/project.js +79 -0
- package/dist/cjs/scan/workload-imports.d.ts +21 -0
- package/dist/cjs/scan/workload-imports.js +188 -0
- package/dist/cjs/test-helpers/postgres.d.ts +13 -0
- package/dist/cjs/test-helpers/postgres.js +52 -0
- package/dist/cjs/test-helpers/redis.d.ts +13 -0
- package/dist/cjs/test-helpers/redis.js +46 -0
- package/dist/cjs/test-helpers/task.d.ts +14 -0
- package/dist/cjs/test-helpers/task.js +18 -0
- package/dist/cjs/test-helpers.d.ts +3 -0
- package/dist/cjs/test-helpers.js +10 -0
- package/dist/cjs/workloads/app-lifecycle/after-rollout.d.ts +22 -0
- package/dist/cjs/workloads/app-lifecycle/after-rollout.js +28 -0
- package/dist/cjs/workloads/app-lifecycle/before-rollout.d.ts +22 -0
- package/dist/cjs/workloads/app-lifecycle/before-rollout.js +28 -0
- package/dist/cjs/workloads/app-lifecycle/bootstrap.d.ts +22 -0
- package/dist/cjs/workloads/app-lifecycle/bootstrap.js +28 -0
- package/dist/cjs/workloads/app-lifecycle/lifecycle-workload.d.ts +11 -0
- package/dist/cjs/workloads/app-lifecycle/lifecycle-workload.js +11 -0
- package/dist/cjs/workloads/assertions.d.ts +13 -0
- package/dist/cjs/workloads/assertions.js +14 -0
- package/dist/cjs/workloads/stateful/bucket.d.ts +82 -0
- package/dist/cjs/workloads/stateful/bucket.js +95 -0
- package/dist/cjs/workloads/stateful/database.d.ts +25 -0
- package/dist/cjs/workloads/stateful/database.js +42 -0
- package/dist/cjs/workloads/stateful/postgres-database.d.ts +29 -0
- package/dist/cjs/workloads/stateful/postgres-database.js +39 -0
- package/dist/cjs/workloads/stateful/redis.d.ts +30 -0
- package/dist/cjs/workloads/stateful/redis.js +40 -0
- package/dist/cjs/workloads/stateful/stateful-workload.d.ts +25 -0
- package/dist/cjs/workloads/stateful/stateful-workload.js +41 -0
- package/dist/cjs/workloads/stateless/broadcast/channel-data.d.ts +3 -0
- package/dist/cjs/workloads/stateless/broadcast/channel-data.js +6 -0
- package/dist/cjs/workloads/stateless/broadcast/client/app-sync-client.d.ts +78 -0
- package/dist/cjs/workloads/stateless/broadcast/client/app-sync-client.js +128 -0
- package/dist/cjs/workloads/stateless/broadcast/client/app-sync-publisher.d.ts +34 -0
- package/dist/cjs/workloads/stateless/broadcast/client/app-sync-publisher.js +78 -0
- package/dist/cjs/workloads/stateless/broadcast/client/authenticator.d.ts +28 -0
- package/dist/cjs/workloads/stateless/broadcast/client/authenticator.js +43 -0
- package/dist/cjs/workloads/stateless/broadcast/client/broadcast-provider.d.ts +17 -0
- package/dist/cjs/workloads/stateless/broadcast/client/broadcast-provider.js +34 -0
- package/dist/cjs/workloads/stateless/broadcast/client/client.d.ts +8 -0
- package/dist/cjs/workloads/stateless/broadcast/client/client.js +28 -0
- package/dist/cjs/workloads/stateless/broadcast/client/connectionManager.d.ts +62 -0
- package/dist/cjs/workloads/stateless/broadcast/client/connectionManager.js +166 -0
- package/dist/cjs/workloads/stateless/broadcast/client/eventEmitter.d.ts +32 -0
- package/dist/cjs/workloads/stateless/broadcast/client/eventEmitter.js +53 -0
- package/dist/cjs/workloads/stateless/broadcast/client/messageBuilder.d.ts +24 -0
- package/dist/cjs/workloads/stateless/broadcast/client/messageBuilder.js +43 -0
- package/dist/cjs/workloads/stateless/broadcast/client/parser.d.ts +12 -0
- package/dist/cjs/workloads/stateless/broadcast/client/parser.js +22 -0
- package/dist/cjs/workloads/stateless/broadcast/client/provider.d.ts +4 -0
- package/dist/cjs/workloads/stateless/broadcast/client/provider.js +11 -0
- package/dist/cjs/workloads/stateless/broadcast/client/subscriptionManager.d.ts +34 -0
- package/dist/cjs/workloads/stateless/broadcast/client/subscriptionManager.js +91 -0
- package/dist/cjs/workloads/stateless/broadcast/client/types.d.ts +72 -0
- package/dist/cjs/workloads/stateless/broadcast/client/types.js +6 -0
- package/dist/cjs/workloads/stateless/broadcast/matcher.d.ts +13 -0
- package/dist/cjs/workloads/stateless/broadcast/matcher.js +46 -0
- package/dist/cjs/workloads/stateless/broadcast/router.d.ts +103 -0
- package/dist/cjs/workloads/stateless/broadcast/router.js +98 -0
- package/dist/cjs/workloads/stateless/broadcast/types.d.ts +17 -0
- package/dist/cjs/workloads/stateless/broadcast/types.js +2 -0
- package/dist/cjs/workloads/stateless/cron.d.ts +49 -0
- package/dist/cjs/workloads/stateless/cron.js +55 -0
- package/dist/cjs/workloads/stateless/stateless-workload.d.ts +3 -0
- package/dist/cjs/workloads/stateless/stateless-workload.js +7 -0
- package/dist/cjs/workloads/stateless/task/backoffs.d.ts +9 -0
- package/dist/cjs/workloads/stateless/task/backoffs.js +17 -0
- package/dist/cjs/workloads/stateless/task/dispatcher.d.ts +3 -0
- package/dist/cjs/workloads/stateless/task/dispatcher.js +22 -0
- package/dist/cjs/workloads/stateless/task/local.d.ts +14 -0
- package/dist/cjs/workloads/stateless/task/local.js +54 -0
- package/dist/cjs/workloads/stateless/task/perform-later.d.ts +2 -0
- package/dist/cjs/workloads/stateless/task/perform-later.js +7 -0
- package/dist/cjs/workloads/stateless/task/perform-now.d.ts +5 -0
- package/dist/cjs/workloads/stateless/task/perform-now.js +24 -0
- package/dist/cjs/workloads/stateless/task/perform.d.ts +7 -0
- package/dist/cjs/workloads/stateless/task/perform.js +10 -0
- package/dist/cjs/workloads/stateless/task/task.d.ts +88 -0
- package/dist/cjs/workloads/stateless/task/task.js +61 -0
- package/dist/cjs/workloads/stateless/task/validate-data-size.d.ts +1 -0
- package/dist/cjs/workloads/stateless/task/validate-data-size.js +10 -0
- package/dist/cjs/workloads/workload.d.ts +14 -0
- package/dist/cjs/workloads/workload.js +16 -0
- package/dist/cjs/workloads.d.ts +22 -0
- package/dist/cjs/workloads.js +30 -0
- package/dist/esm/configuration.d.ts +65 -0
- package/dist/esm/configuration.js +15 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/introspection.d.ts +2 -0
- package/dist/esm/introspection.js +2 -0
- package/dist/esm/make/broadcast.d.ts +10 -0
- package/dist/esm/make/broadcast.js +30 -0
- package/dist/esm/make/config.d.ts +2 -0
- package/dist/esm/make/config.js +41 -0
- package/dist/esm/make/cron.d.ts +9 -0
- package/dist/esm/make/cron.js +23 -0
- package/dist/esm/make/make.d.ts +6 -0
- package/dist/esm/make/make.js +120 -0
- package/dist/esm/make/manifest.d.ts +202 -0
- package/dist/esm/make/manifest.js +162 -0
- package/dist/esm/make/required-filtes.d.ts +1 -0
- package/dist/esm/make/required-filtes.js +11 -0
- package/dist/esm/make/task.d.ts +9 -0
- package/dist/esm/make/task.js +23 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/packages/docker/df.d.ts +543 -0
- package/dist/esm/packages/docker/df.js +381 -0
- package/dist/esm/packages/docker/validator.d.ts +7 -0
- package/dist/esm/packages/docker/validator.js +14 -0
- package/dist/esm/packages/utils/create-file.d.ts +1 -0
- package/dist/esm/packages/utils/create-file.js +11 -0
- package/dist/esm/packages/utils/date-string.d.ts +1 -0
- package/dist/esm/packages/utils/date-string.js +8 -0
- package/dist/esm/packages/utils/exception.d.ts +1 -0
- package/dist/esm/packages/utils/exception.js +4 -0
- package/dist/esm/packages/utils/hash-value.d.ts +16 -0
- package/dist/esm/packages/utils/hash-value.js +20 -0
- package/dist/esm/packages/utils/import-default.d.ts +1 -0
- package/dist/esm/packages/utils/import-default.js +10 -0
- package/dist/esm/packages/utils/import-file.d.ts +8 -0
- package/dist/esm/packages/utils/import-file.js +13 -0
- package/dist/esm/packages/utils/log-with-spinner.d.ts +1 -0
- package/dist/esm/packages/utils/log-with-spinner.js +17 -0
- package/dist/esm/packages/utils/path.d.ts +2 -0
- package/dist/esm/packages/utils/path.js +17 -0
- package/dist/esm/packages/utils/playground.d.ts +1 -0
- package/dist/esm/packages/utils/playground.js +11 -0
- package/dist/esm/scaffolding/add-env-var.d.ts +6 -0
- package/dist/esm/scaffolding/add-env-var.js +57 -0
- package/dist/esm/scaffolding/add-import.d.ts +16 -0
- package/dist/esm/scaffolding/add-import.js +39 -0
- package/dist/esm/scaffolding/add-script.d.ts +1 -0
- package/dist/esm/scaffolding/add-script.js +29 -0
- package/dist/esm/scaffolding/broadcast-workload.d.ts +1 -0
- package/dist/esm/scaffolding/broadcast-workload.js +30 -0
- package/dist/esm/scaffolding/bucket-workload.d.ts +6 -0
- package/dist/esm/scaffolding/bucket-workload.js +17 -0
- package/dist/esm/scaffolding/cron-workload.d.ts +6 -0
- package/dist/esm/scaffolding/cron-workload.js +22 -0
- package/dist/esm/scaffolding/drizzle.d.ts +4 -0
- package/dist/esm/scaffolding/drizzle.js +19 -0
- package/dist/esm/scaffolding/lifecycle.d.ts +9 -0
- package/dist/esm/scaffolding/lifecycle.js +53 -0
- package/dist/esm/scaffolding/postgres-database-workload.d.ts +15 -0
- package/dist/esm/scaffolding/postgres-database-workload.js +31 -0
- package/dist/esm/scaffolding/prisma.d.ts +4 -0
- package/dist/esm/scaffolding/prisma.js +34 -0
- package/dist/esm/scaffolding/replace-string.d.ts +10 -0
- package/dist/esm/scaffolding/replace-string.js +30 -0
- package/dist/esm/scaffolding/task-workload.d.ts +6 -0
- package/dist/esm/scaffolding/task-workload.js +24 -0
- package/dist/esm/scaffolding/workload.d.ts +1 -0
- package/dist/esm/scaffolding/workload.js +12 -0
- package/dist/esm/scan/project.d.ts +23 -0
- package/dist/esm/scan/project.js +69 -0
- package/dist/esm/scan/workload-imports.d.ts +21 -0
- package/dist/esm/scan/workload-imports.js +144 -0
- package/dist/esm/test-helpers/postgres.d.ts +13 -0
- package/dist/esm/test-helpers/postgres.js +26 -0
- package/dist/esm/test-helpers/redis.d.ts +13 -0
- package/dist/esm/test-helpers/redis.js +20 -0
- package/dist/esm/test-helpers/task.d.ts +14 -0
- package/dist/esm/test-helpers/task.js +14 -0
- package/dist/esm/test-helpers.d.ts +3 -0
- package/dist/esm/test-helpers.js +3 -0
- package/dist/esm/workloads/app-lifecycle/after-rollout.d.ts +22 -0
- package/dist/esm/workloads/app-lifecycle/after-rollout.js +24 -0
- package/dist/esm/workloads/app-lifecycle/before-rollout.d.ts +22 -0
- package/dist/esm/workloads/app-lifecycle/before-rollout.js +24 -0
- package/dist/esm/workloads/app-lifecycle/bootstrap.d.ts +22 -0
- package/dist/esm/workloads/app-lifecycle/bootstrap.js +24 -0
- package/dist/esm/workloads/app-lifecycle/lifecycle-workload.d.ts +11 -0
- package/dist/esm/workloads/app-lifecycle/lifecycle-workload.js +7 -0
- package/dist/esm/workloads/assertions.d.ts +13 -0
- package/dist/esm/workloads/assertions.js +6 -0
- package/dist/esm/workloads/stateful/bucket.d.ts +82 -0
- package/dist/esm/workloads/stateful/bucket.js +95 -0
- package/dist/esm/workloads/stateful/database.d.ts +25 -0
- package/dist/esm/workloads/stateful/database.js +42 -0
- package/dist/esm/workloads/stateful/postgres-database.d.ts +29 -0
- package/dist/esm/workloads/stateful/postgres-database.js +35 -0
- package/dist/esm/workloads/stateful/redis.d.ts +30 -0
- package/dist/esm/workloads/stateful/redis.js +36 -0
- package/dist/esm/workloads/stateful/stateful-workload.d.ts +25 -0
- package/dist/esm/workloads/stateful/stateful-workload.js +41 -0
- package/dist/esm/workloads/stateless/broadcast/channel-data.d.ts +3 -0
- package/dist/esm/workloads/stateless/broadcast/channel-data.js +2 -0
- package/dist/esm/workloads/stateless/broadcast/client/app-sync-client.d.ts +78 -0
- package/dist/esm/workloads/stateless/broadcast/client/app-sync-client.js +130 -0
- package/dist/esm/workloads/stateless/broadcast/client/app-sync-publisher.d.ts +34 -0
- package/dist/esm/workloads/stateless/broadcast/client/app-sync-publisher.js +76 -0
- package/dist/esm/workloads/stateless/broadcast/client/authenticator.d.ts +28 -0
- package/dist/esm/workloads/stateless/broadcast/client/authenticator.js +39 -0
- package/dist/esm/workloads/stateless/broadcast/client/broadcast-provider.d.ts +17 -0
- package/dist/esm/workloads/stateless/broadcast/client/broadcast-provider.js +29 -0
- package/dist/esm/workloads/stateless/broadcast/client/client.d.ts +8 -0
- package/dist/esm/workloads/stateless/broadcast/client/client.js +25 -0
- package/dist/esm/workloads/stateless/broadcast/client/connectionManager.d.ts +62 -0
- package/dist/esm/workloads/stateless/broadcast/client/connectionManager.js +164 -0
- package/dist/esm/workloads/stateless/broadcast/client/eventEmitter.d.ts +32 -0
- package/dist/esm/workloads/stateless/broadcast/client/eventEmitter.js +50 -0
- package/dist/esm/workloads/stateless/broadcast/client/messageBuilder.d.ts +24 -0
- package/dist/esm/workloads/stateless/broadcast/client/messageBuilder.js +39 -0
- package/dist/esm/workloads/stateless/broadcast/client/parser.d.ts +12 -0
- package/dist/esm/workloads/stateless/broadcast/client/parser.js +19 -0
- package/dist/esm/workloads/stateless/broadcast/client/provider.d.ts +4 -0
- package/dist/esm/workloads/stateless/broadcast/client/provider.js +8 -0
- package/dist/esm/workloads/stateless/broadcast/client/subscriptionManager.d.ts +34 -0
- package/dist/esm/workloads/stateless/broadcast/client/subscriptionManager.js +91 -0
- package/dist/esm/workloads/stateless/broadcast/client/types.d.ts +72 -0
- package/dist/esm/workloads/stateless/broadcast/client/types.js +5 -0
- package/dist/esm/workloads/stateless/broadcast/matcher.d.ts +13 -0
- package/dist/esm/workloads/stateless/broadcast/matcher.js +43 -0
- package/dist/esm/workloads/stateless/broadcast/router.d.ts +103 -0
- package/dist/esm/workloads/stateless/broadcast/router.js +93 -0
- package/dist/esm/workloads/stateless/broadcast/server/broadcast-server.d.ts +2 -0
- package/dist/esm/workloads/stateless/broadcast/server/broadcast-server.js +316 -0
- package/dist/esm/workloads/stateless/broadcast/types.d.ts +17 -0
- package/dist/esm/workloads/stateless/broadcast/types.js +1 -0
- package/dist/esm/workloads/stateless/cron.d.ts +49 -0
- package/dist/esm/workloads/stateless/cron.js +52 -0
- package/dist/esm/workloads/stateless/stateless-workload.d.ts +3 -0
- package/dist/esm/workloads/stateless/stateless-workload.js +8 -0
- package/dist/esm/workloads/stateless/task/backoffs.d.ts +9 -0
- package/dist/esm/workloads/stateless/task/backoffs.js +14 -0
- package/dist/esm/workloads/stateless/task/dispatcher.d.ts +3 -0
- package/dist/esm/workloads/stateless/task/dispatcher.js +18 -0
- package/dist/esm/workloads/stateless/task/local.d.ts +14 -0
- package/dist/esm/workloads/stateless/task/local.js +48 -0
- package/dist/esm/workloads/stateless/task/perform-later.d.ts +2 -0
- package/dist/esm/workloads/stateless/task/perform-later.js +4 -0
- package/dist/esm/workloads/stateless/task/perform-now.d.ts +5 -0
- package/dist/esm/workloads/stateless/task/perform-now.js +18 -0
- package/dist/esm/workloads/stateless/task/perform.d.ts +7 -0
- package/dist/esm/workloads/stateless/task/perform.js +8 -0
- package/dist/esm/workloads/stateless/task/task.d.ts +88 -0
- package/dist/esm/workloads/stateless/task/task.js +59 -0
- package/dist/esm/workloads/stateless/task/validate-data-size.d.ts +1 -0
- package/dist/esm/workloads/stateless/task/validate-data-size.js +7 -0
- package/dist/esm/workloads/workload.d.ts +14 -0
- package/dist/esm/workloads/workload.js +16 -0
- package/dist/esm/workloads.d.ts +22 -0
- package/dist/esm/workloads.js +13 -0
- package/package.json +155 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module types
|
|
3
|
+
* Defines TypeScript interfaces for the AWS AppSync Events WebSocket protocol messages.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Base interface for all AppSync WebSocket messages.
|
|
7
|
+
*/
|
|
8
|
+
export interface AppSyncMessage {
|
|
9
|
+
type: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Interface for the 'connection_ack' message.
|
|
13
|
+
*/
|
|
14
|
+
export interface ConnectionAckMessage extends AppSyncMessage {
|
|
15
|
+
type: "connection_ack";
|
|
16
|
+
connectionTimeoutMs: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Interface for the 'ka' (keep-alive) message.
|
|
20
|
+
*/
|
|
21
|
+
export interface KaMessage extends AppSyncMessage {
|
|
22
|
+
type: "ka";
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Interface for 'subscribe_success' message.
|
|
26
|
+
*/
|
|
27
|
+
export interface SubscribeSuccessMessage extends AppSyncMessage {
|
|
28
|
+
type: "subscribe_success";
|
|
29
|
+
id: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Interface for 'subscribe_error' message.
|
|
33
|
+
*/
|
|
34
|
+
export interface SubscribeErrorMessage extends AppSyncMessage {
|
|
35
|
+
type: "subscribe_error";
|
|
36
|
+
id: string;
|
|
37
|
+
errors: any[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Interface for 'data' message.
|
|
41
|
+
*/
|
|
42
|
+
export interface DataMessage extends AppSyncMessage {
|
|
43
|
+
type: "data";
|
|
44
|
+
id: string;
|
|
45
|
+
event: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Interface for 'broadcast_error' message.
|
|
49
|
+
*/
|
|
50
|
+
export interface BroadcastErrorMessage extends AppSyncMessage {
|
|
51
|
+
type: "broadcast_error";
|
|
52
|
+
id: string;
|
|
53
|
+
errors: any[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Interface for 'publish_success' message.
|
|
57
|
+
*/
|
|
58
|
+
export interface PublishSuccessMessage extends AppSyncMessage {
|
|
59
|
+
type: "publish_success";
|
|
60
|
+
id: string;
|
|
61
|
+
successful: any[];
|
|
62
|
+
failed: any[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Interface for 'publish_error' message.
|
|
66
|
+
*/
|
|
67
|
+
export interface PublishErrorMessage extends AppSyncMessage {
|
|
68
|
+
type: "publish_error";
|
|
69
|
+
id: string;
|
|
70
|
+
errors: any[];
|
|
71
|
+
}
|
|
72
|
+
export type AppSyncWebSocketMessage = ConnectionAckMessage | KaMessage | SubscribeSuccessMessage | SubscribeErrorMessage | DataMessage | BroadcastErrorMessage | PublishSuccessMessage | PublishErrorMessage;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type RouteParams = {
|
|
2
|
+
[key: string]: string;
|
|
3
|
+
};
|
|
4
|
+
export declare class RouteMatcher {
|
|
5
|
+
private routes;
|
|
6
|
+
constructor(routes: string[]);
|
|
7
|
+
private buildRegex;
|
|
8
|
+
match(url: string): {
|
|
9
|
+
route: string;
|
|
10
|
+
params: RouteParams;
|
|
11
|
+
} | null;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export class RouteMatcher {
|
|
2
|
+
routes;
|
|
3
|
+
constructor(routes) {
|
|
4
|
+
this.routes = routes;
|
|
5
|
+
}
|
|
6
|
+
buildRegex(route) {
|
|
7
|
+
// Escape static segments and convert dynamic segments (e.g., [id]) into capture groups
|
|
8
|
+
const pattern = route
|
|
9
|
+
.split("/")
|
|
10
|
+
.map((segment) => {
|
|
11
|
+
if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
12
|
+
// Capture dynamic segment as a parameter
|
|
13
|
+
return "([^/]+)";
|
|
14
|
+
}
|
|
15
|
+
// Escape static segments
|
|
16
|
+
return segment.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
17
|
+
})
|
|
18
|
+
.join("/");
|
|
19
|
+
return new RegExp(`^${pattern}$`);
|
|
20
|
+
}
|
|
21
|
+
match(url) {
|
|
22
|
+
for (const route of this.routes) {
|
|
23
|
+
const regex = this.buildRegex(route);
|
|
24
|
+
const match = url.match(regex);
|
|
25
|
+
if (match) {
|
|
26
|
+
// Extract dynamic parameters from the match
|
|
27
|
+
const params = {};
|
|
28
|
+
const segments = route
|
|
29
|
+
.split("/")
|
|
30
|
+
.filter((segment) => segment.startsWith("[") && segment.endsWith("]"));
|
|
31
|
+
const values = match.slice(1);
|
|
32
|
+
segments.forEach((segment, index) => {
|
|
33
|
+
const paramName = segment.slice(1, -1); // Remove the square brackets
|
|
34
|
+
if (values[index]) {
|
|
35
|
+
params[paramName] = values[index];
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
return { route, params };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return null; // No match found
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Workload } from "../../../workloads/workload.js";
|
|
2
|
+
import type { RouteParams } from "./types.js";
|
|
3
|
+
export type IsValidSegment<S extends string> = S extends `${infer _Start}[${infer Param}]${infer After}` ? After extends `/${string}` | "" ? IsValidSegment<After> : false : true;
|
|
4
|
+
export type ValidateRouteFormat<T extends string> = IsValidSegment<T> extends true ? T : never;
|
|
5
|
+
export type ExtractRouteParamsTuple<T extends string, Acc extends string[] = []> = T extends `${string}[${infer Param}]${infer Rest}` ? ExtractRouteParamsTuple<Rest, [...Acc, Param]> : Acc;
|
|
6
|
+
export type HasDuplicates<T extends readonly any[]> = T extends [
|
|
7
|
+
infer F,
|
|
8
|
+
...infer R
|
|
9
|
+
] ? F extends R[number] ? true : HasDuplicates<R> : false;
|
|
10
|
+
export type ValidateUniqueParams<T extends string> = HasDuplicates<ExtractRouteParamsTuple<T>> extends true ? never : T;
|
|
11
|
+
export type ValidateRoute<T extends string> = ValidateRouteFormat<T> extends never ? never : ValidateUniqueParams<T> extends never ? never : T;
|
|
12
|
+
export type ValidateRoutes<T extends Record<string, any>> = {
|
|
13
|
+
[K in keyof T]: ValidateRoute<K & string> extends never ? never : T[K];
|
|
14
|
+
};
|
|
15
|
+
export type DrainOuterGeneric<T> = [T] extends [unknown] ? T : never;
|
|
16
|
+
export type Simplify<T> = DrainOuterGeneric<{
|
|
17
|
+
[K in keyof T]: T[K];
|
|
18
|
+
} & {}>;
|
|
19
|
+
/**
|
|
20
|
+
* Creates a Broadcast workloads
|
|
21
|
+
*
|
|
22
|
+
* The constructore takes a session handler and a configuration object for channels. Each channel
|
|
23
|
+
* is mapped to a path and an optional authorization handler. The channel paths can
|
|
24
|
+
* include dynamic segments, like `/users/[id]`, which are parsed and passed to the
|
|
25
|
+
* authorization logic.
|
|
26
|
+
*
|
|
27
|
+
* @template T - A record mapping channel strings to their channel data types.
|
|
28
|
+
* @template S - The type of the session object, returned by the `session` function.
|
|
29
|
+
*
|
|
30
|
+
* @param session A function that resolves to a session object. This object is available
|
|
31
|
+
* within the authorization handlers. It receives an object with `cookies` as an argument.
|
|
32
|
+
* @param channels An object where keys are route strings and values are objects defining
|
|
33
|
+
* the channel and its authorization logic.
|
|
34
|
+
* - `auth`: An optional function to authorize "PUBLISH" or "SUBSCRIBE" operations.
|
|
35
|
+
* It receives the operation type, route parameters, and the session object.
|
|
36
|
+
* - `channel`: The channel instance for the route.
|
|
37
|
+
*
|
|
38
|
+
* @returns An object containing the configured channels, an internal authorization function (`authFn`),
|
|
39
|
+
* and the session handler.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* import { channel, Broadcast } from "@monolayer/sdk";
|
|
44
|
+
*
|
|
45
|
+
* const broadcast = new Broadcast(
|
|
46
|
+
* async () => ({ userId: 1 }),
|
|
47
|
+
* {
|
|
48
|
+
* "/todos": {
|
|
49
|
+
* channel: channel<{ message: string }>(),
|
|
50
|
+
* auth: async (ctx) => {
|
|
51
|
+
* console.log("User trying to access todos:", ctx.session.userId);
|
|
52
|
+
* return true; // Allow access
|
|
53
|
+
* },
|
|
54
|
+
* },
|
|
55
|
+
* "/users/[id]": {
|
|
56
|
+
* channel: channel<{ salute: string }>(),
|
|
57
|
+
* auth: async (ctx) => {
|
|
58
|
+
* // Only allow users to access their own channel
|
|
59
|
+
* return ctx.session.userId === Number(ctx.params.id);
|
|
60
|
+
* },
|
|
61
|
+
* },
|
|
62
|
+
* }
|
|
63
|
+
* );
|
|
64
|
+
*
|
|
65
|
+
* export default broadcast;
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare class Broadcast<T extends Record<string, any>, S> extends Workload {
|
|
69
|
+
session: (opts: {
|
|
70
|
+
cookies: Record<string, string>;
|
|
71
|
+
}) => Promise<S>;
|
|
72
|
+
channels: {
|
|
73
|
+
[channel in keyof T]: ValidateRoute<channel & string> extends never ? never : {
|
|
74
|
+
auth?: (ctx: {
|
|
75
|
+
operation: "PUBLISH" | "SUBSCRIBE";
|
|
76
|
+
params: channel extends string ? Simplify<RouteParams<channel>> : never;
|
|
77
|
+
session: S;
|
|
78
|
+
}) => Promise<boolean>;
|
|
79
|
+
data: T[channel];
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
_channelDataType: {
|
|
83
|
+
[K in keyof T]: T[K];
|
|
84
|
+
};
|
|
85
|
+
constructor(initOpts: {
|
|
86
|
+
session?: (opts: {
|
|
87
|
+
cookies: Record<string, string>;
|
|
88
|
+
}) => Promise<S>;
|
|
89
|
+
channels: {
|
|
90
|
+
[channel in keyof T]: ValidateRoute<channel & string> extends never ? never : {
|
|
91
|
+
auth?: (ctx: {
|
|
92
|
+
operation: "PUBLISH" | "SUBSCRIBE";
|
|
93
|
+
params: channel extends string ? Simplify<RouteParams<channel>> : never;
|
|
94
|
+
session: S;
|
|
95
|
+
}) => Promise<boolean>;
|
|
96
|
+
data: T[channel];
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
});
|
|
100
|
+
authFn(route: string, operation: "PUBLISH" | "SUBSCRIBE", session: S): Promise<boolean>;
|
|
101
|
+
get connectionStringEnvVar(): "ML_BROADCAST_URL";
|
|
102
|
+
}
|
|
103
|
+
export type AnyBroadcast = Broadcast<any, any>;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { Workload } from "../../../workloads/workload.js";
|
|
3
|
+
import { RouteMatcher } from "./matcher.js";
|
|
4
|
+
/**
|
|
5
|
+
* Creates a Broadcast workloads
|
|
6
|
+
*
|
|
7
|
+
* The constructore takes a session handler and a configuration object for channels. Each channel
|
|
8
|
+
* is mapped to a path and an optional authorization handler. The channel paths can
|
|
9
|
+
* include dynamic segments, like `/users/[id]`, which are parsed and passed to the
|
|
10
|
+
* authorization logic.
|
|
11
|
+
*
|
|
12
|
+
* @template T - A record mapping channel strings to their channel data types.
|
|
13
|
+
* @template S - The type of the session object, returned by the `session` function.
|
|
14
|
+
*
|
|
15
|
+
* @param session A function that resolves to a session object. This object is available
|
|
16
|
+
* within the authorization handlers. It receives an object with `cookies` as an argument.
|
|
17
|
+
* @param channels An object where keys are route strings and values are objects defining
|
|
18
|
+
* the channel and its authorization logic.
|
|
19
|
+
* - `auth`: An optional function to authorize "PUBLISH" or "SUBSCRIBE" operations.
|
|
20
|
+
* It receives the operation type, route parameters, and the session object.
|
|
21
|
+
* - `channel`: The channel instance for the route.
|
|
22
|
+
*
|
|
23
|
+
* @returns An object containing the configured channels, an internal authorization function (`authFn`),
|
|
24
|
+
* and the session handler.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { channel, Broadcast } from "@monolayer/sdk";
|
|
29
|
+
*
|
|
30
|
+
* const broadcast = new Broadcast(
|
|
31
|
+
* async () => ({ userId: 1 }),
|
|
32
|
+
* {
|
|
33
|
+
* "/todos": {
|
|
34
|
+
* channel: channel<{ message: string }>(),
|
|
35
|
+
* auth: async (ctx) => {
|
|
36
|
+
* console.log("User trying to access todos:", ctx.session.userId);
|
|
37
|
+
* return true; // Allow access
|
|
38
|
+
* },
|
|
39
|
+
* },
|
|
40
|
+
* "/users/[id]": {
|
|
41
|
+
* channel: channel<{ salute: string }>(),
|
|
42
|
+
* auth: async (ctx) => {
|
|
43
|
+
* // Only allow users to access their own channel
|
|
44
|
+
* return ctx.session.userId === Number(ctx.params.id);
|
|
45
|
+
* },
|
|
46
|
+
* },
|
|
47
|
+
* }
|
|
48
|
+
* );
|
|
49
|
+
*
|
|
50
|
+
* export default broadcast;
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
54
|
+
export class Broadcast extends Workload {
|
|
55
|
+
session;
|
|
56
|
+
channels;
|
|
57
|
+
constructor(initOpts) {
|
|
58
|
+
super("broadcast");
|
|
59
|
+
this.session =
|
|
60
|
+
initOpts.session ??
|
|
61
|
+
(async () => {
|
|
62
|
+
return {};
|
|
63
|
+
});
|
|
64
|
+
this.channels = initOpts.channels;
|
|
65
|
+
}
|
|
66
|
+
async authFn(route, operation, session) {
|
|
67
|
+
const auth = {};
|
|
68
|
+
for (const routeName of Object.keys(this.channels)) {
|
|
69
|
+
if (this.channels[routeName]) {
|
|
70
|
+
auth[`${path.join("default", routeName)}`] =
|
|
71
|
+
this.channels[routeName].auth;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const matcher = new RouteMatcher(Object.keys(this.channels).map((r) => path.join("default", r)));
|
|
75
|
+
const match = matcher.match(route);
|
|
76
|
+
if (match) {
|
|
77
|
+
const routeAuth = auth[route];
|
|
78
|
+
if (routeAuth === undefined)
|
|
79
|
+
return true;
|
|
80
|
+
return await routeAuth({
|
|
81
|
+
session: session,
|
|
82
|
+
params: match.params,
|
|
83
|
+
operation,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
get connectionStringEnvVar() {
|
|
91
|
+
return "ML_BROADCAST_URL";
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable max-lines */
|
|
3
|
+
import { WebSocketServer } from "ws";
|
|
4
|
+
const PORT = 9311;
|
|
5
|
+
const PING_INTERVAL = 1000 * 60; // 60 seconds
|
|
6
|
+
class AppSyncTestServer {
|
|
7
|
+
wss;
|
|
8
|
+
session;
|
|
9
|
+
clients;
|
|
10
|
+
interval = null;
|
|
11
|
+
connectionTimeoutMs;
|
|
12
|
+
channelAuth;
|
|
13
|
+
constructor(opts) {
|
|
14
|
+
this.wss = new WebSocketServer({ port: opts.port });
|
|
15
|
+
this.clients = new Set();
|
|
16
|
+
this.connectionTimeoutMs = opts.connectionTimeoutMs ?? 300000;
|
|
17
|
+
this.channelAuth = opts.channelAuth;
|
|
18
|
+
this.session = opts.session;
|
|
19
|
+
this.setupServer();
|
|
20
|
+
}
|
|
21
|
+
setupServer() {
|
|
22
|
+
this.wss.on("headers", (d) => {
|
|
23
|
+
console.log(d);
|
|
24
|
+
});
|
|
25
|
+
this.wss.on("connection", async (ws, request) => {
|
|
26
|
+
console.log(request.url);
|
|
27
|
+
const client = ws;
|
|
28
|
+
client.isAlive = true;
|
|
29
|
+
client.subscriptions = new Map();
|
|
30
|
+
console.log("Client connected");
|
|
31
|
+
const protocol = request.headers["sec-websocket-protocol"];
|
|
32
|
+
const authProtocol = protocol?.split(",")[1]?.trim();
|
|
33
|
+
const authProtocolName = protocol?.split(",")[0]?.trim();
|
|
34
|
+
if (authProtocol && authProtocolName === "aws-appsync-event-ws") {
|
|
35
|
+
try {
|
|
36
|
+
const encodedHeader = authProtocol.substring("header-".length);
|
|
37
|
+
const decodedHeader = Buffer.from(encodedHeader, "base64url").toString("utf8");
|
|
38
|
+
console.log("Decoded", decodedHeader);
|
|
39
|
+
const auth = JSON.parse(decodedHeader);
|
|
40
|
+
console.log("Authorization header:", auth);
|
|
41
|
+
if (auth.Authorization === undefined) {
|
|
42
|
+
console.error("Unauthorized");
|
|
43
|
+
client.close(3000, "Unauthorized");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
client._authorizationToken = auth.Authorization;
|
|
47
|
+
if (this.session) {
|
|
48
|
+
client._session = await this.session({ cookies: {} });
|
|
49
|
+
}
|
|
50
|
+
this.clients.add(client);
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
console.error("Failed to parse authorization header:", e);
|
|
54
|
+
client.close(1008, "Invalid authorization header");
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
console.error("Mising authorization:");
|
|
60
|
+
client.close(1008, "Missing authorization");
|
|
61
|
+
}
|
|
62
|
+
client.on("pong", () => {
|
|
63
|
+
client.isAlive = true;
|
|
64
|
+
});
|
|
65
|
+
client.on("message", async (message) => {
|
|
66
|
+
console.log(`Received message: ${message}`);
|
|
67
|
+
try {
|
|
68
|
+
const parsedMessage = JSON.parse(message);
|
|
69
|
+
console.log(parsedMessage);
|
|
70
|
+
await this.handleMessage(client, parsedMessage);
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
console.error("Failed to parse message:", e);
|
|
74
|
+
client.send(JSON.stringify({ type: "error", message: "Invalid JSON message" }));
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
client.on("close", () => {
|
|
78
|
+
console.log("Client disconnected");
|
|
79
|
+
this.clients.delete(client);
|
|
80
|
+
});
|
|
81
|
+
client.on("error", (error) => {
|
|
82
|
+
console.error("WebSocket error:", error);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
this.interval = setInterval(() => {
|
|
86
|
+
this.clients.forEach((client) => {
|
|
87
|
+
if (client.isAlive === false) {
|
|
88
|
+
console.log("Client not alive, terminating connection");
|
|
89
|
+
return client.terminate();
|
|
90
|
+
}
|
|
91
|
+
client.isAlive = false;
|
|
92
|
+
client.ping();
|
|
93
|
+
});
|
|
94
|
+
}, PING_INTERVAL);
|
|
95
|
+
this.wss.on("close", () => {
|
|
96
|
+
if (this.interval) {
|
|
97
|
+
clearInterval(this.interval);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
console.log("AppSync Test Server started");
|
|
101
|
+
}
|
|
102
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
103
|
+
async handleMessage(client, message) {
|
|
104
|
+
switch (message.type) {
|
|
105
|
+
case "connection_init":
|
|
106
|
+
client.connectionTimeoutMs = this.connectionTimeoutMs;
|
|
107
|
+
client.send(JSON.stringify({
|
|
108
|
+
type: "connection_ack",
|
|
109
|
+
connectionTimeoutMs: client.connectionTimeoutMs,
|
|
110
|
+
}));
|
|
111
|
+
break;
|
|
112
|
+
case "subscribe":
|
|
113
|
+
if (!message.id || !message.channel) {
|
|
114
|
+
client.send(JSON.stringify({
|
|
115
|
+
type: "subscribe_error",
|
|
116
|
+
id: message.id,
|
|
117
|
+
errors: [
|
|
118
|
+
{
|
|
119
|
+
errorType: "ValidationError",
|
|
120
|
+
message: "Missing id or channel",
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
}));
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (client.subscriptions.has(message.id)) {
|
|
127
|
+
client.send(JSON.stringify({
|
|
128
|
+
type: "subscribe_error",
|
|
129
|
+
id: message.id,
|
|
130
|
+
errors: [
|
|
131
|
+
{
|
|
132
|
+
errorType: "DuplicateSubscriptionError",
|
|
133
|
+
message: "Subscription ID already exists",
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
}));
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (this.channelAuth) {
|
|
140
|
+
try {
|
|
141
|
+
const isAuthorized = await this.channelAuth(message.channel, "SUBSCRIBE", client._session);
|
|
142
|
+
if (!isAuthorized) {
|
|
143
|
+
console.error("Unauthorized");
|
|
144
|
+
client.send(JSON.stringify({
|
|
145
|
+
type: "subscribe_error",
|
|
146
|
+
id: message.id,
|
|
147
|
+
errors: [
|
|
148
|
+
{
|
|
149
|
+
errorType: "Unauthorized",
|
|
150
|
+
message: "Unauthorized to subscribe",
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
}));
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
console.error("Internal Error");
|
|
159
|
+
client.send(JSON.stringify({
|
|
160
|
+
type: "internal_error",
|
|
161
|
+
id: message.id,
|
|
162
|
+
errors: [
|
|
163
|
+
{
|
|
164
|
+
errorType: "Internal Error",
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
}));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
client.subscriptions.set(message.id, message.channel);
|
|
172
|
+
client.send(JSON.stringify({ type: "subscribe_success", id: message.id }));
|
|
173
|
+
console.log(`Client subscribed to channel: ${message.channel} with id: ${message.id}`);
|
|
174
|
+
break;
|
|
175
|
+
case "unsubscribe":
|
|
176
|
+
if (!message.id) {
|
|
177
|
+
client.send(JSON.stringify({
|
|
178
|
+
type: "unsubscribe_error",
|
|
179
|
+
id: message.id,
|
|
180
|
+
errors: [{ errorType: "ValidationError", message: "Missing id" }],
|
|
181
|
+
}));
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (client.subscriptions.delete(message.id)) {
|
|
185
|
+
client.send(JSON.stringify({ type: "unsubscribe_success", id: message.id }));
|
|
186
|
+
console.log(`Client unsubscribed from id: ${message.id}`);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
client.send(JSON.stringify({
|
|
190
|
+
type: "unsubscribe_error",
|
|
191
|
+
id: message.id,
|
|
192
|
+
errors: [
|
|
193
|
+
{
|
|
194
|
+
errorType: "UnknownOperationError",
|
|
195
|
+
message: `Unknown subscription id ${message.id}`,
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
}));
|
|
199
|
+
}
|
|
200
|
+
break;
|
|
201
|
+
case "publish":
|
|
202
|
+
if (!message.id || !message.channel || !message.events) {
|
|
203
|
+
client.send(JSON.stringify({
|
|
204
|
+
type: "publish_error",
|
|
205
|
+
id: message.id,
|
|
206
|
+
errors: [
|
|
207
|
+
{
|
|
208
|
+
errorType: "ValidationError",
|
|
209
|
+
message: "Missing id, channel, or events",
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
}));
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
console.log(`Client publishing to channel: ${message.channel} with events:`, message.events);
|
|
216
|
+
if (this.channelAuth) {
|
|
217
|
+
try {
|
|
218
|
+
const isAuthorized = await this.channelAuth(message.channel, "PUBLISH", {});
|
|
219
|
+
if (!isAuthorized) {
|
|
220
|
+
console.error("Unauthorized");
|
|
221
|
+
client.send(JSON.stringify({
|
|
222
|
+
type: "subscribe_error",
|
|
223
|
+
id: message.id,
|
|
224
|
+
errors: [
|
|
225
|
+
{
|
|
226
|
+
errorType: "Unauthorized",
|
|
227
|
+
message: "Unauthorized to subscribe",
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
}));
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
console.error("Internal Error");
|
|
236
|
+
client.send(JSON.stringify({
|
|
237
|
+
type: "internal_error",
|
|
238
|
+
id: message.id,
|
|
239
|
+
errors: [
|
|
240
|
+
{
|
|
241
|
+
errorType: "Internal Error",
|
|
242
|
+
},
|
|
243
|
+
],
|
|
244
|
+
}));
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
this.broadcast(message.channel, message.events, message.id);
|
|
249
|
+
console.log("message", message);
|
|
250
|
+
client.send(JSON.stringify({
|
|
251
|
+
type: "publish_success",
|
|
252
|
+
id: message.id,
|
|
253
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
254
|
+
successful: message.events.map((_, index) => ({
|
|
255
|
+
identifier: `event-${index}`,
|
|
256
|
+
index,
|
|
257
|
+
})),
|
|
258
|
+
failed: [],
|
|
259
|
+
}));
|
|
260
|
+
break;
|
|
261
|
+
default:
|
|
262
|
+
client.send(JSON.stringify({ type: "error", message: "Unknown message type" }));
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
broadcast(channel, events, publishId) {
|
|
267
|
+
this.clients.forEach((client) => {
|
|
268
|
+
client.subscriptions.forEach((subscribedChannel, subscriptionId) => {
|
|
269
|
+
if (subscribedChannel === channel) {
|
|
270
|
+
events.forEach((event) => {
|
|
271
|
+
client.send(JSON.stringify({
|
|
272
|
+
type: "data",
|
|
273
|
+
id: subscriptionId,
|
|
274
|
+
event: [event],
|
|
275
|
+
publishId: publishId, // Include publishId for correlation if needed
|
|
276
|
+
}));
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
close() {
|
|
283
|
+
this.wss.close();
|
|
284
|
+
if (this.interval) {
|
|
285
|
+
clearInterval(this.interval);
|
|
286
|
+
}
|
|
287
|
+
console.log("AppSync Test Server closed");
|
|
288
|
+
}
|
|
289
|
+
stopKeepAlive() {
|
|
290
|
+
if (this.interval) {
|
|
291
|
+
clearInterval(this.interval);
|
|
292
|
+
this.interval = null;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
sendKeepAlive(client) {
|
|
296
|
+
client.send(JSON.stringify({ type: "ka" }));
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
async function main() {
|
|
300
|
+
const routesPath = "/app/workloads/broadcast.js";
|
|
301
|
+
const ru = await import(routesPath);
|
|
302
|
+
const server = new AppSyncTestServer({
|
|
303
|
+
port: PORT,
|
|
304
|
+
channelAuth: ru.authFn,
|
|
305
|
+
session: ru.session,
|
|
306
|
+
});
|
|
307
|
+
process.on("SIGINT", () => {
|
|
308
|
+
server.close();
|
|
309
|
+
process.exit();
|
|
310
|
+
});
|
|
311
|
+
process.on("SIGTERM", () => {
|
|
312
|
+
server.close();
|
|
313
|
+
process.exit();
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type Channel<T> = {
|
|
2
|
+
_data: T;
|
|
3
|
+
subscribed?: (ctx: any) => void;
|
|
4
|
+
unsubscribed?: (ctx: any) => void;
|
|
5
|
+
};
|
|
6
|
+
export type ChannelData<T extends Channel<any>> = T extends Channel<infer D> ? D : never;
|
|
7
|
+
export type Channels = Record<string, Channel<any>>;
|
|
8
|
+
export type ExtractRouteParamsTuple<T extends string, Acc extends string[] = []> = T extends `${string}[${infer Param}]${infer Rest}` ? ExtractRouteParamsTuple<Rest, [...Acc, Param]> : Acc;
|
|
9
|
+
export type HasDuplicates<T extends readonly any[]> = T extends [
|
|
10
|
+
infer F,
|
|
11
|
+
...infer R
|
|
12
|
+
] ? F extends R[number] ? true : HasDuplicates<R> : false;
|
|
13
|
+
export type ValidateUniqueParams<T extends string> = HasDuplicates<ExtractRouteParamsTuple<T>> extends true ? ["❌ Duplicate route params not allowed in", T] : T;
|
|
14
|
+
export type TupleToParamObject<T extends readonly string[]> = {
|
|
15
|
+
[K in T[number]]: string;
|
|
16
|
+
};
|
|
17
|
+
export type RouteParams<T extends string> = TupleToParamObject<ExtractRouteParamsTuple<T>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|