diff --git a/.eslintrc.json b/.eslintrc.json index aa0bda1c..95df15bd 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -25,6 +25,12 @@ "import/no-named-as-default": "off" }, "overrides": [ + { + "files": ["packages/example-graphql-events/*.ts"], + "env": { + "node": true + } + }, { "files": ["*.spec.ts"], "env": { diff --git a/.github/workflows/test-examples.yml b/.github/workflows/test-examples.yml new file mode 100644 index 00000000..01759a87 --- /dev/null +++ b/.github/workflows/test-examples.yml @@ -0,0 +1,17 @@ +on: pull_request +name: Test examples + +jobs: + build-example-graphql-events: + name: Build Example GraphQL Events + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - uses: actions/setup-node@v4 + with: + node-version: 20.x + cache: 'yarn' + - name: Install Deps + run: yarn install --immutable + - name: Build + run: yarn workspace qminder-graphql-events-example build diff --git a/package.json b/package.json index 5bf7cfa4..62d629f8 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "scripts": { "test": "jest", "test-node": "jest --env=node", - "lint-eslint": "eslint --ext ts .", + "lint-eslint": "yarn workspace qminder-api build && eslint --ext ts .", "lint-prettier": "prettier --check .", "lint": "yarn lint-eslint && yarn lint-prettier", "format": "prettier --write .", @@ -17,7 +17,7 @@ "prepack": "yarn run build", "build": "yarn workspace qminder-api build", "watch": "yarn workspace qminder-api watch", - "example-new-visitors": "ts-node examples/events/new-visitors.ts" + "example-graphql-events": "yarn workspace qminder-api build && yarn workspace qminder-graphql-events-example start" }, "devDependencies": { "@typescript-eslint/eslint-plugin": "^8.0.0", @@ -26,7 +26,8 @@ "eslint-config-prettier": "9.1.0", "eslint-import-resolver-typescript": "^3.5.3", "eslint-plugin-import": "^2.27.5", - "prettier": "2.8.8" + "prettier": "2.8.8", + "typescript": "5.5.4" }, "workspaces": [ "packages/*" diff --git a/packages/example-graphql-events/README.md b/packages/example-graphql-events/README.md new file mode 100644 index 00000000..780cf215 --- /dev/null +++ b/packages/example-graphql-events/README.md @@ -0,0 +1,11 @@ +# Example of GraphQL events + +This simple example script demonstrates how to consume ticket creation events using the GraphQL subscription API. + +## Usage + +```bash +export API_KEY=XXX +yarn +yarn example-graphql-events +``` diff --git a/packages/example-graphql-events/app.ts b/packages/example-graphql-events/app.ts new file mode 100644 index 00000000..ab597734 --- /dev/null +++ b/packages/example-graphql-events/app.ts @@ -0,0 +1,69 @@ +import { Qminder } from 'qminder-api'; + +interface Location { + id: string; + name: string; +} + +interface Ticket { + id: string; + firstName: string; + lastName: string; +} + +interface TicketCreatedEvent { + createdTickets: Ticket; +} + +async function findFirstLocationId(): Promise { + const result: any = await Qminder.GraphQL.query(`{ + locations { + id + name + } + }`); + + if (result.errors) { + throw new Error( + `Failed to find locations. Errors: ${JSON.stringify(result.errors)}`, + ); + } + + if (result.data.locations.length < 1) { + throw new Error('Account does not have any locations'); + } + + console.log(`Found ${result.data.locations.length} locations`); + return result.data.locations[0]; +} + +async function listenForTickets() { + if (!process.env.API_KEY) { + console.error('Please set API key first by executing "export API_KEY=XXX"'); + console.error( + 'More information: https://developer.qminder.com/reference/overview', + ); + throw new Error('API key is not set'); + } + + Qminder.setKey(process.env.API_KEY); + + console.log('Example of GraphQL events in Qminder'); + + let location = await findFirstLocationId(); + console.log(`Listening for new visitors in: ${location.name}`); + + const observable = Qminder.GraphQL + .subscribe(`subscription { createdTickets(locationId: ${location.id}) { + id + firstName + lastName + } + }`); + + observable.subscribe((event: TicketCreatedEvent) => + console.log(`New visitor: ${JSON.stringify(event.createdTickets)}`), + ); +} + +listenForTickets(); diff --git a/packages/example-graphql-events/package.json b/packages/example-graphql-events/package.json new file mode 100644 index 00000000..67f3a4c1 --- /dev/null +++ b/packages/example-graphql-events/package.json @@ -0,0 +1,17 @@ +{ + "name": "qminder-graphql-events-example", + "version": "1.0.0", + "description": "Example of using GraphQL events", + "main": "app.ts", + "scripts": { + "build": "yarn workspace qminder-api build && tsc -p .", + "start": "yarn build && tsx app.ts", + "example-graphql-events": "yarn start" + }, + "devDependencies": { + "tsx": "^4.19.2", + "typescript": "5.5.4" + }, + "author": "Qminder (https://www.qminder.com)", + "license": "Apache-2.0" +} diff --git a/packages/example-graphql-events/tsconfig.json b/packages/example-graphql-events/tsconfig.json new file mode 100644 index 00000000..c358b23e --- /dev/null +++ b/packages/example-graphql-events/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "module": "es2020", + "noImplicitAny": true, + "removeComments": true, + "preserveConstEnums": true, + "sourceMap": true, + "moduleResolution": "node", + "esModuleInterop": true, + "target": "es2020", + "emitDecoratorMetadata": true, + "allowSyntheticDefaultImports": true, + "experimentalDecorators": true, + "outDir": "build", + "rootDir": "./", + "declaration": true + }, + "include": ["app.ts"], + "files": ["app.ts"] +} diff --git a/yarn.lock b/yarn.lock index 4d26be4c..865d2547 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1290,6 +1290,174 @@ __metadata: languageName: node linkType: hard +"@esbuild/aix-ppc64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/aix-ppc64@npm:0.23.1" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/android-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/android-arm64@npm:0.23.1" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/android-arm@npm:0.23.1" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@esbuild/android-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/android-x64@npm:0.23.1" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/darwin-arm64@npm:0.23.1" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/darwin-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/darwin-x64@npm:0.23.1" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/freebsd-arm64@npm:0.23.1" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/freebsd-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/freebsd-x64@npm:0.23.1" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-arm64@npm:0.23.1" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/linux-arm@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-arm@npm:0.23.1" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-ia32@npm:0.23.1" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/linux-loong64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-loong64@npm:0.23.1" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-mips64el@npm:0.23.1" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"@esbuild/linux-ppc64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-ppc64@npm:0.23.1" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-riscv64@npm:0.23.1" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + +"@esbuild/linux-s390x@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-s390x@npm:0.23.1" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-x64@npm:0.23.1" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/netbsd-x64@npm:0.23.1" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/openbsd-arm64@npm:0.23.1" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/openbsd-x64@npm:0.23.1" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/sunos-x64@npm:0.23.1" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/win32-arm64@npm:0.23.1" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/win32-ia32@npm:0.23.1" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/win32-x64@npm:0.23.1" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": version: 4.4.1 resolution: "@eslint-community/eslint-utils@npm:4.4.1" @@ -3591,6 +3759,89 @@ __metadata: languageName: node linkType: hard +"esbuild@npm:~0.23.0": + version: 0.23.1 + resolution: "esbuild@npm:0.23.1" + dependencies: + "@esbuild/aix-ppc64": "npm:0.23.1" + "@esbuild/android-arm": "npm:0.23.1" + "@esbuild/android-arm64": "npm:0.23.1" + "@esbuild/android-x64": "npm:0.23.1" + "@esbuild/darwin-arm64": "npm:0.23.1" + "@esbuild/darwin-x64": "npm:0.23.1" + "@esbuild/freebsd-arm64": "npm:0.23.1" + "@esbuild/freebsd-x64": "npm:0.23.1" + "@esbuild/linux-arm": "npm:0.23.1" + "@esbuild/linux-arm64": "npm:0.23.1" + "@esbuild/linux-ia32": "npm:0.23.1" + "@esbuild/linux-loong64": "npm:0.23.1" + "@esbuild/linux-mips64el": "npm:0.23.1" + "@esbuild/linux-ppc64": "npm:0.23.1" + "@esbuild/linux-riscv64": "npm:0.23.1" + "@esbuild/linux-s390x": "npm:0.23.1" + "@esbuild/linux-x64": "npm:0.23.1" + "@esbuild/netbsd-x64": "npm:0.23.1" + "@esbuild/openbsd-arm64": "npm:0.23.1" + "@esbuild/openbsd-x64": "npm:0.23.1" + "@esbuild/sunos-x64": "npm:0.23.1" + "@esbuild/win32-arm64": "npm:0.23.1" + "@esbuild/win32-ia32": "npm:0.23.1" + "@esbuild/win32-x64": "npm:0.23.1" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10c0/08c2ed1105cc3c5e3a24a771e35532fe6089dd24a39c10097899072cef4a99f20860e41e9294e000d86380f353b04d8c50af482483d7f69f5208481cce61eec7 + languageName: node + linkType: hard + "escalade@npm:^3.1.1, escalade@npm:^3.2.0": version: 3.2.0 resolution: "escalade@npm:3.2.0" @@ -4097,7 +4348,7 @@ __metadata: languageName: node linkType: hard -"fsevents@npm:^2.3.2": +"fsevents@npm:^2.3.2, fsevents@npm:~2.3.3": version: 2.3.3 resolution: "fsevents@npm:2.3.3" dependencies: @@ -4107,7 +4358,7 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin": +"fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": version: 2.3.3 resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" dependencies: @@ -6512,6 +6763,15 @@ __metadata: languageName: unknown linkType: soft +"qminder-graphql-events-example@workspace:packages/example-graphql-events": + version: 0.0.0-use.local + resolution: "qminder-graphql-events-example@workspace:packages/example-graphql-events" + dependencies: + tsx: "npm:^4.19.2" + typescript: "npm:5.5.4" + languageName: unknown + linkType: soft + "qminder@workspace:.": version: 0.0.0-use.local resolution: "qminder@workspace:." @@ -6523,6 +6783,7 @@ __metadata: eslint-import-resolver-typescript: "npm:^3.5.3" eslint-plugin-import: "npm:^2.27.5" prettier: "npm:2.8.8" + typescript: "npm:5.5.4" languageName: unknown linkType: soft @@ -7491,6 +7752,22 @@ __metadata: languageName: node linkType: hard +"tsx@npm:^4.19.2": + version: 4.19.2 + resolution: "tsx@npm:4.19.2" + dependencies: + esbuild: "npm:~0.23.0" + fsevents: "npm:~2.3.3" + get-tsconfig: "npm:^4.7.5" + dependenciesMeta: + fsevents: + optional: true + bin: + tsx: dist/cli.mjs + checksum: 10c0/63164b889b1d170403e4d8753a6755dec371f220f5ce29a8e88f1f4d6085a784a12d8dc2ee669116611f2c72757ac9beaa3eea5c452796f541bdd2dc11753721 + languageName: node + linkType: hard + "type-check@npm:^0.4.0, type-check@npm:~0.4.0": version: 0.4.0 resolution: "type-check@npm:0.4.0"