diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 206e3a04d8..3fd4fbb415 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -63,6 +63,9 @@ jobs: - name: Install Playwright Browsers run: ./node_modules/.bin/playwright install --with-deps + - name: Build the website + run: pnpm build + - name: Run end-to-end tests run: ./node_modules/.bin/playwright test @@ -72,3 +75,6 @@ jobs: name: playwright-report path: playwright-report/ retention-days: 30 + + # - uses: valeriangalliat/action-sshd-cloudflared@v1 + # if: failure() diff --git a/package.json b/package.json index bc69a6cf49..ef1b0a4112 100644 --- a/package.json +++ b/package.json @@ -15,10 +15,11 @@ "lint:docs": "eslint --ignore-path .gitignore src/pages/learn --format stylish", "lint:docs:ci": "eslint --ignore-path .gitignore src/pages/learn --format eslint-formatter-github", "postbuild": "next-sitemap", - "prebuild": "tsx scripts/get-github-info && tsx scripts/sync-landing-schema/src/index.ts", + "prebuild": "tsx scripts/get-github-info && node scripts/sync-landing-schema && node scripts/sync-working-groups", "start": "next start", "test": "playwright test && pnpm test:unit", "test:e2e": "playwright test", + "test:show-report": "playwright show-report", "test:ui": "playwright test --ui", "test:unit": "node --import=tsx --test 'src/**/*.test.tsx'", "validate:snippets": "node scripts/validate-snippets.js" diff --git a/playwright.config.ts b/playwright.config.ts index 1d32e2a082..7424479740 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -27,13 +27,7 @@ export default defineConfig({ channel: "chromium", ...(process.env.CI ? { - args: [ - "--enable-gpu", - "--use-gl=angle", - "--use-angle=gl-egl", - "--ignore-gpu-blocklist", - "--enable-unsafe-swiftshader", - ], + args: ["--enable-gpu"], } : {}), }, @@ -41,7 +35,7 @@ export default defineConfig({ ], webServer: { - command: "pnpm dev", + command: process.env.CI ? "pnpm start" : "pnpm dev", url: "http://localhost:3000", reuseExistingServer: !process.env.CI, }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ae2663fb51..f0f6fca1bc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -323,6 +323,12 @@ importers: specifier: ^3.2.0 version: 3.2.0(graphql@16.10.0) + scripts/sync-working-groups: + dependencies: + arktype: + specifier: ^2.1.27 + version: 2.1.27 + packages: '@alloc/quick-lru@5.2.0': @@ -345,6 +351,12 @@ packages: peerDependencies: graphql: '*' + '@ark/schema@0.55.0': + resolution: {integrity: sha512-IlSIc0FmLKTDGr4I/FzNHauMn0MADA6bCjT1wauu4k6MyxhC1R9gz0olNpIRvK7lGGDwtc/VO0RUDNvVQW5WFg==} + + '@ark/util@0.55.0': + resolution: {integrity: sha512-aWFNK7aqSvqFtVsl1xmbTjGbg91uqtJV7Za76YGNEwIO4qLjMfyY8flmmbhooYMuqPCO2jyxu8hve943D+w3bA==} + '@asamuzakjp/css-color@3.2.0': resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} @@ -2640,6 +2652,12 @@ packages: aria-query@5.3.0: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + arkregex@0.0.3: + resolution: {integrity: sha512-bU21QJOJEFJK+BPNgv+5bVXkvRxyAvgnon75D92newgHxkBJTgiFwQxusyViYyJkETsddPlHyspshDQcCzmkNg==} + + arktype@2.1.27: + resolution: {integrity: sha512-enctOHxI4SULBv/TDtCVi5M8oLd4J5SVlPUblXDzSsOYQNMzmVbUosGBnJuZDKmFlN5Ie0/QVEuTE+Z5X1UhsQ==} + array-buffer-byte-length@1.0.2: resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} @@ -6616,6 +6634,12 @@ snapshots: transitivePeerDependencies: - encoding + '@ark/schema@0.55.0': + dependencies: + '@ark/util': 0.55.0 + + '@ark/util@0.55.0': {} + '@asamuzakjp/css-color@3.2.0': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) @@ -9322,6 +9346,16 @@ snapshots: dependencies: dequal: 2.0.3 + arkregex@0.0.3: + dependencies: + '@ark/util': 0.55.0 + + arktype@2.1.27: + dependencies: + '@ark/schema': 0.55.0 + '@ark/util': 0.55.0 + arkregex: 0.0.3 + array-buffer-byte-length@1.0.2: dependencies: call-bound: 1.0.4 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4745f21d75..7996ce9d6a 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,4 @@ packages: - "." - "scripts/sync-landing-schema" + - "scripts/sync-working-groups" diff --git a/scripts/get-github-info/github-stats.json b/scripts/get-github-info/github-stats.json index c2bcf3c790..575c2e84fa 100644 --- a/scripts/get-github-info/github-stats.json +++ b/scripts/get-github-info/github-stats.json @@ -1,19 +1,19 @@ { "altair-graphql/altair": { "hasCommitsInLast3Months": false, - "stars": 5355, + "stars": 5361, "formattedStars": "5k", "license": "MIT License", "lastRelease": "2025-10-28T22:43:22Z", - "formattedLastRelease": "1 week ago" + "formattedLastRelease": "2 weeks ago" }, "apache/apisix": { "hasCommitsInLast3Months": false, - "stars": 15805, + "stars": 15866, "formattedStars": "16k", "license": "Apache License 2.0", "lastRelease": "2025-10-16T07:54:57Z", - "formattedLastRelease": "3 weeks ago" + "formattedLastRelease": "1 month ago" }, "apollographql/apollo-studio-community": { "hasCommitsInLast3Months": false, @@ -25,19 +25,19 @@ }, "ChilliCream/hotchocolate": { "hasCommitsInLast3Months": false, - "stars": 5614, + "stars": 5621, "formattedStars": "6k", "license": "MIT License", - "lastRelease": "2025-10-31T07:44:48Z", - "formattedLastRelease": "6 days ago" + "lastRelease": "2025-11-18T21:41:46Z", + "formattedLastRelease": "5 minutes ago" }, "dgraph-io/dgraph": { "hasCommitsInLast3Months": false, - "stars": 21328, + "stars": 21350, "formattedStars": "21k", "license": "Apache License 2.0", "lastRelease": "2025-10-07T20:50:36Z", - "formattedLastRelease": "4 weeks ago" + "formattedLastRelease": "1 month ago" }, "yahoo/elide": { "hasCommitsInLast3Months": false, @@ -57,31 +57,31 @@ }, "hasura/graphql-engine": { "hasCommitsInLast3Months": false, - "stars": 31797, + "stars": 31815, "formattedStars": "32k", "license": "Apache License 2.0", "lastRelease": "2025-10-14T15:20:38Z", - "formattedLastRelease": "3 weeks ago" + "formattedLastRelease": "1 month ago" }, "graphql-hive/platform": { "hasCommitsInLast3Months": false, - "stars": 466, - "formattedStars": "466", + "stars": 469, + "formattedStars": "469", "license": "MIT License", - "lastRelease": "2025-10-30T07:47:41Z", - "formattedLastRelease": "1 week ago" + "lastRelease": "2025-11-18T10:07:16Z", + "formattedLastRelease": "11 hours ago" }, "Kong/insomnia": { "hasCommitsInLast3Months": false, - "stars": 37475, - "formattedStars": "37k", + "stars": 37563, + "formattedStars": "38k", "license": "Apache License 2.0", - "lastRelease": "2025-11-03T13:06:45Z", - "formattedLastRelease": "2 days ago" + "lastRelease": "2025-11-14T09:22:34Z", + "formattedLastRelease": "4 days ago" }, "postmanlabs/postman-app-support": { "hasCommitsInLast3Months": false, - "stars": 5970, + "stars": 5973, "formattedStars": "6k", "license": "Unknown", "lastRelease": "", @@ -97,11 +97,11 @@ }, "TykTechnologies/tyk": { "hasCommitsInLast3Months": false, - "stars": 10466, + "stars": 10484, "formattedStars": "10k", "license": "Other", "lastRelease": "2025-10-24T18:32:20Z", - "formattedLastRelease": "1 week ago" + "formattedLastRelease": "3 weeks ago" }, "twinlogix/typetta": { "hasCommitsInLast3Months": false, @@ -113,11 +113,11 @@ }, "webiny/webiny-js": { "hasCommitsInLast3Months": false, - "stars": 7879, + "stars": 7890, "formattedStars": "8k", "license": "Other", "lastRelease": "2025-09-16T08:29:00Z", - "formattedLastRelease": "1 month ago" + "formattedLastRelease": "2 months ago" }, "ballerina-platform/module-ballerina-graphql": { "hasCommitsInLast3Months": false, @@ -125,79 +125,23 @@ "formattedStars": "139", "license": "Apache License 2.0", "lastRelease": "2025-11-06T10:54:08Z", - "formattedLastRelease": "14 minutes ago" - }, - "graphql-dotnet/graphql-client": { - "hasCommitsInLast3Months": false, - "stars": 644, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2024-05-21T07:06:30Z", - "formattedLastRelease": "1 year ago" - }, - "bkniffler/graphql-net-client": { - "hasCommitsInLast3Months": false, - "stars": 94, - "formattedStars": "94", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "linq2graphql/linq2graphql.client": { - "hasCommitsInLast3Months": false, - "stars": 8, - "formattedStars": "8", - "license": "MIT License", - "lastRelease": "2025-11-06T09:24:10Z", - "formattedLastRelease": "1 hour ago" - }, - "sahb1239/SAHB.GraphQLClient": { - "hasCommitsInLast3Months": false, - "stars": 44, - "formattedStars": "44", - "license": "MIT License", - "lastRelease": "2020-05-17T10:50:58Z", - "formattedLastRelease": "5 years ago" - }, - "byme8/ZeroQL": { - "hasCommitsInLast3Months": false, - "stars": 312, - "formattedStars": "312", - "license": "MIT License", - "lastRelease": "2025-10-14T11:58:44Z", - "formattedLastRelease": "3 weeks ago" - }, - "EntityGraphQL/EntityGraphQL": { - "hasCommitsInLast3Months": false, - "stars": 446, - "formattedStars": "446", - "license": "MIT License", - "lastRelease": "2025-09-16T00:35:14Z", - "formattedLastRelease": "1 month ago" - }, - "graphql-dotnet/graphql-dotnet": { - "hasCommitsInLast3Months": false, - "stars": 5974, - "formattedStars": "6k", - "license": "MIT License", - "lastRelease": "2025-10-23T21:34:31Z", "formattedLastRelease": "1 week ago" }, - "chkimes/graphql-net": { + "microsoft/cppgraphqlgen": { "hasCommitsInLast3Months": false, - "stars": 888, - "formattedStars": "1k", + "stars": 344, + "formattedStars": "344", "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" + "lastRelease": "2024-12-10T17:25:31Z", + "formattedLastRelease": "11 months ago" }, - "rivantsov/ngraphql": { + "graphql/libgraphqlparser": { "hasCommitsInLast3Months": false, - "stars": 47, - "formattedStars": "47", + "stars": 1101, + "formattedStars": "1k", "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" + "lastRelease": "2017-10-16T21:47:42Z", + "formattedLastRelease": "8 years ago" }, "graphql-dotnet/graphql-client": { "hasCommitsInLast3Months": false, @@ -220,8 +164,8 @@ "stars": 8, "formattedStars": "8", "license": "MIT License", - "lastRelease": "2025-10-07T07:20:37Z", - "formattedLastRelease": "2 weeks ago" + "lastRelease": "2025-11-14T07:39:17Z", + "formattedLastRelease": "4 days ago" }, "sahb1239/SAHB.GraphQLClient": { "hasCommitsInLast3Months": false, @@ -237,23 +181,23 @@ "formattedStars": "312", "license": "MIT License", "lastRelease": "2025-10-14T11:58:44Z", - "formattedLastRelease": "1 week ago" + "formattedLastRelease": "1 month ago" }, "EntityGraphQL/EntityGraphQL": { "hasCommitsInLast3Months": false, - "stars": 446, - "formattedStars": "446", + "stars": 448, + "formattedStars": "448", "license": "MIT License", "lastRelease": "2025-09-16T00:35:14Z", - "formattedLastRelease": "1 month ago" + "formattedLastRelease": "2 months ago" }, "graphql-dotnet/graphql-dotnet": { "hasCommitsInLast3Months": false, - "stars": 5971, + "stars": 5977, "formattedStars": "6k", "license": "MIT License", - "lastRelease": "2025-10-23T21:34:31Z", - "formattedLastRelease": "3 days ago" + "lastRelease": "2025-11-17T17:57:35Z", + "formattedLastRelease": "1 day ago" }, "chkimes/graphql-net": { "hasCommitsInLast3Months": false, @@ -265,20 +209,12 @@ }, "rivantsov/ngraphql": { "hasCommitsInLast3Months": false, - "stars": 46, - "formattedStars": "46", + "stars": 47, + "formattedStars": "47", "license": "MIT License", "lastRelease": "", "formattedLastRelease": "" }, - "graphql/libgraphqlparser": { - "hasCommitsInLast3Months": false, - "stars": 1100, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2017-10-16T21:47:42Z", - "formattedLastRelease": "8 years ago" - }, "oliyh/re-graph": { "hasCommitsInLast3Months": false, "stars": 466, @@ -305,7 +241,7 @@ }, "walmartlabs/lacinia": { "hasCommitsInLast3Months": false, - "stars": 1842, + "stars": 1844, "formattedStars": "2k", "license": "Other", "lastRelease": "", @@ -337,11 +273,11 @@ }, "absinthe-graphql/absinthe": { "hasCommitsInLast3Months": false, - "stars": 4368, + "stars": 4369, "formattedStars": "4k", "license": "Other", - "lastRelease": "2025-10-30T13:52:04Z", - "formattedLastRelease": "6 days ago" + "lastRelease": "2025-11-06T13:26:50Z", + "formattedLastRelease": "1 week ago" }, "graphql-elixir/graphql": { "hasCommitsInLast3Months": false, @@ -377,31 +313,31 @@ }, "zino-app/graphql-flutter": { "hasCommitsInLast3Months": false, - "stars": 3268, + "stars": 3269, "formattedStars": "3k", "license": "MIT License", "lastRelease": "2025-10-21T16:42:55Z", - "formattedLastRelease": "2 weeks ago" + "formattedLastRelease": "4 weeks ago" }, "Khan/genqlient": { "hasCommitsInLast3Months": false, - "stars": 1258, + "stars": 1265, "formattedStars": "1k", "license": "MIT License", "lastRelease": "2025-05-18T19:09:08Z", - "formattedLastRelease": "5 months ago" + "formattedLastRelease": "6 months ago" }, "hasura/go-graphql-client": { "hasCommitsInLast3Months": false, - "stars": 452, - "formattedStars": "452", + "stars": 455, + "formattedStars": "455", "license": "MIT License", "lastRelease": "2025-11-05T06:45:53Z", - "formattedLastRelease": "1 day ago" + "formattedLastRelease": "1 week ago" }, "shurcooL/graphql": { "hasCommitsInLast3Months": false, - "stars": 728, + "stars": 727, "formattedStars": "1k", "license": "MIT License", "lastRelease": "", @@ -415,21 +351,13 @@ "lastRelease": "2018-05-31T14:28:32Z", "formattedLastRelease": "7 years ago" }, - "dosco/graphjin": { - "hasCommitsInLast3Months": false, - "stars": 2997, - "formattedStars": "3k", - "license": "Apache License 2.0", - "lastRelease": "2025-09-18T06:22:50Z", - "formattedLastRelease": "1 month ago" - }, "99designs/gqlgen": { "hasCommitsInLast3Months": false, - "stars": 10575, + "stars": 10583, "formattedStars": "11k", "license": "MIT License", - "lastRelease": "2025-09-25T23:00:54Z", - "formattedLastRelease": "1 month ago" + "lastRelease": "2025-11-11T02:05:44Z", + "formattedLastRelease": "1 week ago" }, "andrewwphillips/eggql": { "hasCommitsInLast3Months": false, @@ -449,15 +377,15 @@ }, "graph-gophers/graphql-go": { "hasCommitsInLast3Months": false, - "stars": 4733, + "stars": 4739, "formattedStars": "5k", "license": "BSD 2-Clause \"Simplified\" License", "lastRelease": "2025-09-09T11:37:07Z", - "formattedLastRelease": "1 month ago" + "formattedLastRelease": "2 months ago" }, "graphql-go/graphql": { "hasCommitsInLast3Months": false, - "stars": 10124, + "stars": 10129, "formattedStars": "10k", "license": "MIT License", "lastRelease": "2023-04-10T18:20:23Z", @@ -484,16 +412,16 @@ "stars": 790, "formattedStars": "1k", "license": "MIT License", - "lastRelease": "2025-10-31T00:41:38Z", - "formattedLastRelease": "6 days ago" + "lastRelease": "2025-11-17T08:37:55Z", + "formattedLastRelease": "1 day ago" }, "dosco/graphjin": { "hasCommitsInLast3Months": false, - "stars": 3000, + "stars": 3002, "formattedStars": "3k", "license": "Apache License 2.0", "lastRelease": "2025-11-05T07:51:12Z", - "formattedLastRelease": "1 day ago" + "formattedLastRelease": "1 week ago" }, "grails/gorm-graphql": { "hasCommitsInLast3Months": false, @@ -513,8 +441,8 @@ }, "morpheusgraphql/morpheus-graphql": { "hasCommitsInLast3Months": false, - "stars": 417, - "formattedStars": "417", + "stars": 418, + "formattedStars": "418", "license": "MIT License", "lastRelease": "2024-06-10T08:34:35Z", "formattedLastRelease": "1 year ago" @@ -537,19 +465,19 @@ }, "apollographql/apollo-kotlin": { "hasCommitsInLast3Months": false, - "stars": 3918, + "stars": 3927, "formattedStars": "4k", "license": "MIT License", - "lastRelease": "2025-08-21T15:31:08Z", - "formattedLastRelease": "2 months ago" + "lastRelease": "2025-11-13T17:33:51Z", + "formattedLastRelease": "5 days ago" }, "ExpediaGroup/graphql-kotlin": { "hasCommitsInLast3Months": false, - "stars": 1789, + "stars": 1795, "formattedStars": "2k", "license": "Apache License 2.0", "lastRelease": "2025-06-16T17:02:18Z", - "formattedLastRelease": "4 months ago" + "formattedLastRelease": "5 months ago" }, "americanexpress/nodes": { "hasCommitsInLast3Months": false, @@ -569,7 +497,7 @@ }, "graphql-java-kickstart/graphql-spring-boot": { "hasCommitsInLast3Months": false, - "stars": 1514, + "stars": 1513, "formattedStars": "2k", "license": "MIT License", "lastRelease": "2023-12-07T11:07:47Z", @@ -577,24 +505,24 @@ }, "graphql-java/graphql-java": { "hasCommitsInLast3Months": false, - "stars": 6224, + "stars": 6226, "formattedStars": "6k", "license": "MIT License", - "lastRelease": "2025-10-12T21:04:23Z", - "formattedLastRelease": "3 weeks ago" + "lastRelease": "2025-11-10T01:21:35Z", + "formattedLastRelease": "1 week ago" }, "babyfish-ct/jimmer": { "hasCommitsInLast3Months": false, - "stars": 1538, + "stars": 1552, "formattedStars": "2k", "license": "Apache License 2.0", - "lastRelease": "2025-11-04T23:19:50Z", + "lastRelease": "2025-11-17T08:58:28Z", "formattedLastRelease": "1 day ago" }, "aPureBase/KGraphQL": { "hasCommitsInLast3Months": false, - "stars": 307, - "formattedStars": "307", + "stars": 308, + "formattedStars": "308", "license": "MIT License", "lastRelease": "2023-01-27T10:09:55Z", "formattedLastRelease": "2 years ago" @@ -609,19 +537,19 @@ }, "netflix/dgs-framework": { "hasCommitsInLast3Months": false, - "stars": 3270, + "stars": 3275, "formattedStars": "3k", "license": "Apache License 2.0", - "lastRelease": "2025-10-29T17:28:56Z", + "lastRelease": "2025-11-08T16:22:51Z", "formattedLastRelease": "1 week ago" }, "spring-projects/spring-graphql": { "hasCommitsInLast3Months": false, - "stars": 1576, + "stars": 1578, "formattedStars": "2k", "license": "Apache License 2.0", - "lastRelease": "2025-11-04T08:35:52Z", - "formattedLastRelease": "2 days ago" + "lastRelease": "2025-11-18T10:05:26Z", + "formattedLastRelease": "11 hours ago" }, "graphql-java-generator/graphql-gradle-plugin-project": { "hasCommitsInLast3Months": false, @@ -633,19 +561,19 @@ }, "apollographql/apollo-client": { "hasCommitsInLast3Months": false, - "stars": 19663, + "stars": 19672, "formattedStars": "20k", "license": "MIT License", - "lastRelease": "2025-10-31T17:11:18Z", - "formattedLastRelease": "5 days ago" + "lastRelease": "2025-11-17T21:21:55Z", + "formattedLastRelease": "1 day ago" }, "aws-amplify/amplify-js": { "hasCommitsInLast3Months": false, - "stars": 9560, + "stars": 9565, "formattedStars": "10k", "license": "Apache License 2.0", - "lastRelease": "2025-09-29T15:51:39Z", - "formattedLastRelease": "1 month ago" + "lastRelease": "2025-11-06T13:36:19Z", + "formattedLastRelease": "1 week ago" }, "Houfeng/gq-loader": { "hasCommitsInLast3Months": false, @@ -657,11 +585,11 @@ }, "gqty-dev/gqty": { "hasCommitsInLast3Months": false, - "stars": 1030, + "stars": 1031, "formattedStars": "1k", "license": "MIT License", "lastRelease": "2025-10-26T19:29:38Z", - "formattedLastRelease": "1 week ago" + "formattedLastRelease": "3 weeks ago" }, "grafoojs/grafoo": { "hasCommitsInLast3Months": false, @@ -685,19 +613,19 @@ "formattedStars": "2k", "license": "Other", "lastRelease": "2025-01-08T18:45:52Z", - "formattedLastRelease": "9 months ago" + "formattedLastRelease": "10 months ago" }, "graphql/graphql-http": { "hasCommitsInLast3Months": false, - "stars": 355, - "formattedStars": "355", + "stars": 357, + "formattedStars": "357", "license": "MIT License", "lastRelease": "2025-01-17T14:16:52Z", - "formattedLastRelease": "9 months ago" + "formattedLastRelease": "10 months ago" }, "jasonkuhrt/graphql-request": { "hasCommitsInLast3Months": false, - "stars": 6068, + "stars": 6075, "formattedStars": "6k", "license": "MIT License", "lastRelease": "2020-05-29T13:00:56Z", @@ -705,31 +633,31 @@ }, "enisdenjo/graphql-sse": { "hasCommitsInLast3Months": false, - "stars": 434, - "formattedStars": "434", + "stars": 435, + "formattedStars": "435", "license": "MIT License", "lastRelease": "2025-10-22T16:19:40Z", - "formattedLastRelease": "2 weeks ago" + "formattedLastRelease": "3 weeks ago" }, "babyfish-ct/graphql-ts-client": { "hasCommitsInLast3Months": false, - "stars": 149, - "formattedStars": "149", + "stars": 150, + "formattedStars": "150", "license": "MIT License", "lastRelease": "2023-12-14T03:06:21Z", "formattedLastRelease": "1 year ago" }, "enisdenjo/graphql-ws": { "hasCommitsInLast3Months": false, - "stars": 1840, + "stars": 1842, "formattedStars": "2k", "license": "MIT License", "lastRelease": "2025-07-14T12:15:37Z", - "formattedLastRelease": "3 months ago" + "formattedLastRelease": "4 months ago" }, "hasura/graphqurl": { "hasCommitsInLast3Months": false, - "stars": 3375, + "stars": 3376, "formattedStars": "3k", "license": "Apache License 2.0", "lastRelease": "", @@ -753,7 +681,7 @@ }, "facebook/relay": { "hasCommitsInLast3Months": false, - "stars": 18878, + "stars": 18887, "formattedStars": "19k", "license": "MIT License", "lastRelease": "2025-08-06T23:45:00Z", @@ -761,7 +689,7 @@ }, "FormidableLabs/urql": { "hasCommitsInLast3Months": false, - "stars": 8890, + "stars": 8893, "formattedStars": "9k", "license": "MIT License", "lastRelease": "2025-08-29T08:06:41Z", @@ -769,83 +697,67 @@ }, "apollographql/apollo-server": { "hasCommitsInLast3Months": false, - "stars": 13917, + "stars": 13924, "formattedStars": "14k", "license": "MIT License", "lastRelease": "2025-10-28T15:47:16Z", - "formattedLastRelease": "1 week ago" + "formattedLastRelease": "3 weeks ago" }, "graphql/graphql-js": { "hasCommitsInLast3Months": false, - "stars": 20271, + "stars": 20270, "formattedStars": "20k", "license": "MIT License", "lastRelease": "2025-11-01T14:18:53Z", - "formattedLastRelease": "4 days ago" + "formattedLastRelease": "2 weeks ago" }, "dotansimha/graphql-yoga": { "hasCommitsInLast3Months": false, - "stars": 8447, + "stars": 8452, "formattedStars": "8k", "license": "MIT License", - "lastRelease": "2025-11-04T15:51:36Z", - "formattedLastRelease": "1 day ago" + "lastRelease": "2025-11-07T02:09:51Z", + "formattedLastRelease": "1 week ago" }, "mercurius-js/mercurius": { "hasCommitsInLast3Months": false, - "stars": 2450, + "stars": 2456, "formattedStars": "2k", "license": "MIT License", - "lastRelease": "2025-10-10T09:11:58Z", - "formattedLastRelease": "3 weeks ago" + "lastRelease": "2025-11-13T14:12:18Z", + "formattedLastRelease": "5 days ago" }, "getcronit/pylon": { "hasCommitsInLast3Months": false, - "stars": 342, - "formattedStars": "342", + "stars": 343, + "formattedStars": "343", "license": "Apache License 2.0", "lastRelease": "2025-10-01T08:35:15Z", "formattedLastRelease": "1 month ago" }, - "neomatrixcode/Diana.jl": { - "hasCommitsInLast3Months": false, - "stars": 117, - "formattedStars": "117", - "license": "MIT License", - "lastRelease": "2022-08-16T03:22:22Z", - "formattedLastRelease": "3 years ago" - }, - "DeloitteDigitalAPAC/GraphQLClient.jl": { - "hasCommitsInLast3Months": false, - "stars": 47, - "formattedStars": "47", - "license": "Other", - "lastRelease": "2022-10-26T16:48:16Z", - "formattedLastRelease": "3 years ago" - }, "networkimprov/brangr": { "hasCommitsInLast3Months": false, - "stars": 4, - "formattedStars": "4", + "stars": 5, + "formattedStars": "5", "license": "Mozilla Public License 2.0", "lastRelease": "2023-06-02T09:20:18Z", "formattedLastRelease": "2 years ago" }, "hayes/giraphql": { "hasCommitsInLast3Months": false, - "stars": 2547, + "stars": 2553, "formattedStars": "3k", "license": "ISC License", - "lastRelease": "2025-10-20T17:43:11Z", - "formattedLastRelease": "2 weeks ago" + "lastRelease": "2025-11-10T01:29:18Z", + "formattedLastRelease": "1 week ago" }, "graphql/graphiql": { "hasCommitsInLast3Months": false, - "stars": 16687, + "stars": 16706, "formattedStars": "17k", "license": "MIT License", "lastRelease": "2025-11-01T22:30:04Z", - "formattedLastRelease": "4 days ago" + "formattedLastRelease": "2 weeks ago" }, "Urigo/graphql-cli": { "hasCommitsInLast3Months": false, @@ -857,11 +769,11 @@ }, "dotansimha/graphql-code-generator": { "hasCommitsInLast3Months": false, - "stars": 11170, + "stars": 11175, "formattedStars": "11k", "license": "MIT License", - "lastRelease": "2025-10-30T14:30:07Z", - "formattedLastRelease": "6 days ago" + "lastRelease": "2025-11-13T15:19:33Z", + "formattedLastRelease": "5 days ago" }, "kamilkisiela/graphql-config": { "hasCommitsInLast3Months": false, @@ -873,7 +785,7 @@ }, "dimaMachina/graphql-eslint/": { "hasCommitsInLast3Months": false, - "stars": 831, + "stars": 830, "formattedStars": "1k", "license": "MIT License", "lastRelease": "2025-03-26T14:11:23Z", @@ -881,11 +793,11 @@ }, "kamilkisiela/graphql-inspector": { "hasCommitsInLast3Months": false, - "stars": 1726, + "stars": 1727, "formattedStars": "2k", "license": "MIT License", - "lastRelease": "2024-12-09T13:34:14Z", - "formattedLastRelease": "10 months ago" + "lastRelease": "2025-11-15T02:42:13Z", + "formattedLastRelease": "3 days ago" }, "graphql/graphql-language-service": { "hasCommitsInLast3Months": false, @@ -905,11 +817,11 @@ }, "Urigo/graphql-mesh": { "hasCommitsInLast3Months": false, - "stars": 3450, + "stars": 3459, "formattedStars": "3k", "license": "MIT License", - "lastRelease": "2025-11-05T20:58:23Z", - "formattedLastRelease": "14 hours ago" + "lastRelease": "2025-11-07T23:26:14Z", + "formattedLastRelease": "1 week ago" }, "maticzav/graphql-middleware": { "hasCommitsInLast3Months": false, @@ -921,7 +833,7 @@ }, "Urigo/graphql-modules": { "hasCommitsInLast3Months": false, - "stars": 1329, + "stars": 1328, "formattedStars": "1k", "license": "MIT License", "lastRelease": "2025-02-19T10:43:37Z", @@ -929,15 +841,15 @@ }, "Urigo/graphql-scalars": { "hasCommitsInLast3Months": false, - "stars": 1924, + "stars": 1925, "formattedStars": "2k", "license": "MIT License", "lastRelease": "2025-10-14T23:00:24Z", - "formattedLastRelease": "3 weeks ago" + "formattedLastRelease": "1 month ago" }, "maticzav/graphql-shield": { "hasCommitsInLast3Months": false, - "stars": 3569, + "stars": 3573, "formattedStars": "4k", "license": "MIT License", "lastRelease": "2022-11-22T19:08:37Z", @@ -948,8 +860,8 @@ "stars": 5420, "formattedStars": "5k", "license": "MIT License", - "lastRelease": "2025-11-04T15:42:44Z", - "formattedLastRelease": "1 day ago" + "lastRelease": "2025-11-12T10:07:43Z", + "formattedLastRelease": "6 days ago" }, "anvilco/graphql-introspection-tools": { "hasCommitsInLast3Months": false, @@ -961,7 +873,7 @@ }, "graphile/postgraphile": { "hasCommitsInLast3Months": false, - "stars": 12837, + "stars": 12852, "formattedStars": "13k", "license": "Other", "lastRelease": "2023-10-05T16:27:00Z", @@ -969,20 +881,36 @@ }, "Urigo/SOFA": { "hasCommitsInLast3Months": false, - "stars": 1110, + "stars": 1111, "formattedStars": "1k", "license": "MIT License", "lastRelease": "2024-12-16T10:06:41Z", - "formattedLastRelease": "10 months ago" + "formattedLastRelease": "11 months ago" }, "anvilco/spectaql": { "hasCommitsInLast3Months": false, - "stars": 1189, + "stars": 1203, "formattedStars": "1k", "license": "MIT License", "lastRelease": "", "formattedLastRelease": "" }, + "neomatrixcode/Diana.jl": { + "hasCommitsInLast3Months": false, + "stars": 117, + "formattedStars": "117", + "license": "MIT License", + "lastRelease": "2022-08-16T03:22:22Z", + "formattedLastRelease": "3 years ago" + }, + "DeloitteDigitalAPAC/GraphQLClient.jl": { + "hasCommitsInLast3Months": false, + "stars": 47, + "formattedStars": "47", + "license": "Other", + "lastRelease": "2022-10-26T16:48:16Z", + "formattedLastRelease": "3 years ago" + }, "andreas/ocaml-graphql-server": { "hasCommitsInLast3Months": false, "stars": 621, @@ -1001,11 +929,11 @@ }, "api-platform/api-platform": { "hasCommitsInLast3Months": false, - "stars": 9041, + "stars": 9045, "formattedStars": "9k", "license": "MIT License", "lastRelease": "2025-03-11T16:15:41Z", - "formattedLastRelease": "7 months ago" + "formattedLastRelease": "8 months ago" }, "GatoGraphQL/GatoGraphQL": { "hasCommitsInLast3Months": false, @@ -1013,7 +941,7 @@ "formattedStars": "376", "license": "GNU General Public License v2.0", "lastRelease": "2025-10-17T15:10:13Z", - "formattedLastRelease": "2 weeks ago" + "formattedLastRelease": "1 month ago" }, "infinityloop-dev/graphpinator": { "hasCommitsInLast3Months": false, @@ -1029,15 +957,15 @@ "formattedStars": "16", "license": "MIT License", "lastRelease": "2025-10-11T09:19:14Z", - "formattedLastRelease": "3 weeks ago" + "formattedLastRelease": "1 month ago" }, "webonyx/graphql-php": { "hasCommitsInLast3Months": false, - "stars": 4696, + "stars": 4700, "formattedStars": "5k", "license": "MIT License", "lastRelease": "2025-10-25T09:34:10Z", - "formattedLastRelease": "1 week ago" + "formattedLastRelease": "3 weeks ago" }, "ivome/graphql-relay-php": { "hasCommitsInLast3Months": false, @@ -1053,7 +981,7 @@ "formattedStars": "1k", "license": "MIT License", "lastRelease": "2025-10-31T08:00:22Z", - "formattedLastRelease": "6 days ago" + "formattedLastRelease": "2 weeks ago" }, "thecodingmachine/graphqlite": { "hasCommitsInLast3Months": false, @@ -1069,7 +997,7 @@ "formattedStars": "3k", "license": "MIT License", "lastRelease": "2025-09-11T08:07:50Z", - "formattedLastRelease": "1 month ago" + "formattedLastRelease": "2 months ago" }, "railt/railt": { "hasCommitsInLast3Months": false, @@ -1097,23 +1025,23 @@ }, "wp-graphql/wp-graphql": { "hasCommitsInLast3Months": false, - "stars": 3757, + "stars": 3759, "formattedStars": "4k", "license": "GNU General Public License v3.0", "lastRelease": "2025-10-30T16:56:08Z", - "formattedLastRelease": "6 days ago" + "formattedLastRelease": "2 weeks ago" }, "mirumee/ariadne-codegen": { "hasCommitsInLast3Months": false, - "stars": 359, - "formattedStars": "359", + "stars": 361, + "formattedStars": "361", "license": "BSD 3-Clause \"New\" or \"Revised\" License", "lastRelease": "2025-10-13T06:38:02Z", - "formattedLastRelease": "3 weeks ago" + "formattedLastRelease": "1 month ago" }, "graphql-python/gql": { "hasCommitsInLast3Months": false, - "stars": 1645, + "stars": 1649, "formattedStars": "2k", "license": "MIT License", "lastRelease": "2025-09-05T14:22:54Z", @@ -1129,8 +1057,8 @@ }, "prisma-labs/python-graphql-client": { "hasCommitsInLast3Months": false, - "stars": 156, - "formattedStars": "156", + "stars": 157, + "formattedStars": "157", "license": "MIT License", "lastRelease": "", "formattedLastRelease": "" @@ -1161,11 +1089,11 @@ }, "mirumee/ariadne": { "hasCommitsInLast3Months": false, - "stars": 2306, + "stars": 2307, "formattedStars": "2k", "license": "BSD 3-Clause \"New\" or \"Revised\" License", "lastRelease": "2025-04-18T08:27:47Z", - "formattedLastRelease": "6 months ago" + "formattedLastRelease": "7 months ago" }, "yefeza/django-graphbox": { "hasCommitsInLast3Months": false, @@ -1185,19 +1113,19 @@ }, "graphql-python/graphene": { "hasCommitsInLast3Months": false, - "stars": 8233, + "stars": 8238, "formattedStars": "8k", "license": "MIT License", "lastRelease": "2024-11-09T20:43:58Z", - "formattedLastRelease": "11 months ago" + "formattedLastRelease": "1 year ago" }, "strawberry-graphql/strawberry": { "hasCommitsInLast3Months": false, - "stars": 4457, + "stars": 4467, "formattedStars": "4k", "license": "MIT License", - "lastRelease": "2025-11-05T19:14:26Z", - "formattedLastRelease": "15 hours ago" + "lastRelease": "2025-11-18T18:05:57Z", + "formattedLastRelease": "3 hours ago" }, "tartiflette/tartiflette": { "hasCommitsInLast3Months": false, @@ -1205,7 +1133,7 @@ "formattedStars": "1k", "license": "MIT License", "lastRelease": "2021-11-15T11:05:03Z", - "formattedLastRelease": "3 years ago" + "formattedLastRelease": "4 years ago" }, "ropensci/ghql": { "hasCommitsInLast3Months": false, @@ -1213,7 +1141,7 @@ "formattedStars": "149", "license": "Other", "lastRelease": "2025-09-08T08:41:00Z", - "formattedLastRelease": "1 month ago" + "formattedLastRelease": "2 months ago" }, "ohler55/agoo": { "hasCommitsInLast3Months": false, @@ -1225,11 +1153,11 @@ }, "rmosolgo/graphql-ruby": { "hasCommitsInLast3Months": false, - "stars": 5427, + "stars": 5428, "formattedStars": "5k", "license": "MIT License", "lastRelease": "2025-07-19T17:15:49Z", - "formattedLastRelease": "3 months ago" + "formattedLastRelease": "4 months ago" }, "virtualshield/rails-graphql": { "hasCommitsInLast3Months": false, @@ -1253,11 +1181,19 @@ "formattedStars": "51", "license": "MIT License", "lastRelease": "2025-06-07T14:31:10Z", + "formattedLastRelease": "5 months ago" + }, + "ghostdogpr/caliban": { + "hasCommitsInLast3Months": false, + "stars": 975, + "formattedStars": "1k", + "license": "Apache License 2.0", + "lastRelease": "2025-07-14T00:24:20Z", "formattedLastRelease": "4 months ago" }, "async-graphql/async-graphql": { "hasCommitsInLast3Months": false, - "stars": 3585, + "stars": 3588, "formattedStars": "4k", "license": "Apache License 2.0", "lastRelease": "", @@ -1265,19 +1201,19 @@ }, "graphql-rust/juniper": { "hasCommitsInLast3Months": false, - "stars": 5899, + "stars": 5911, "formattedStars": "6k", "license": "Other", "lastRelease": "2025-09-08T23:23:40Z", - "formattedLastRelease": "1 month ago" + "formattedLastRelease": "2 months ago" }, - "ghostdogpr/caliban": { + "apollographql/router": { "hasCommitsInLast3Months": false, - "stars": 975, + "stars": 938, "formattedStars": "1k", - "license": "Apache License 2.0", - "lastRelease": "2025-07-14T00:24:20Z", - "formattedLastRelease": "3 months ago" + "license": "Other", + "lastRelease": "2025-11-11T14:49:10Z", + "formattedLastRelease": "1 week ago" }, "sangria-graphql/sangria": { "hasCommitsInLast3Months": false, @@ -1285,15 +1221,71 @@ "formattedStars": "2k", "license": "Apache License 2.0", "lastRelease": "2025-10-20T11:40:30Z", - "formattedLastRelease": "2 weeks ago" + "formattedLastRelease": "4 weeks ago" + }, + "eerimoq/gqt": { + "hasCommitsInLast3Months": false, + "stars": 470, + "formattedStars": "470", + "license": "MIT License", + "lastRelease": "", + "formattedLastRelease": "" + }, + "Escape-Technologies/graphql-armor": { + "hasCommitsInLast3Months": false, + "stars": 553, + "formattedStars": "1k", + "license": "MIT License", + "lastRelease": "2025-08-22T13:32:40Z", + "formattedLastRelease": "2 months ago" + }, + "ldebruijn/graphql-protect": { + "hasCommitsInLast3Months": false, + "stars": 34, + "formattedStars": "34", + "license": "MIT License", + "lastRelease": "2025-09-09T20:03:39Z", + "formattedLastRelease": "2 months ago" + }, + "graphql-hive/gateway": { + "hasCommitsInLast3Months": false, + "stars": 68, + "formattedStars": "68", + "license": "MIT License", + "lastRelease": "2025-11-11T14:50:09Z", + "formattedLastRelease": "1 week ago" + }, + "microcks/microcks": { + "hasCommitsInLast3Months": false, + "stars": 1746, + "formattedStars": "2k", + "license": "Apache License 2.0", + "lastRelease": "2025-10-25T15:08:00Z", + "formattedLastRelease": "3 weeks ago" + }, + "glideapps/quicktype": { + "hasCommitsInLast3Months": false, + "stars": 13438, + "formattedStars": "13k", + "license": "Apache License 2.0", + "lastRelease": "", + "formattedLastRelease": "" + }, + "schemathesis/schemathesis": { + "hasCommitsInLast3Months": false, + "stars": 2852, + "formattedStars": "3k", + "license": "MIT License", + "lastRelease": "2025-11-18T17:07:09Z", + "formattedLastRelease": "4 hours ago" }, "apollographql/apollo-ios": { "hasCommitsInLast3Months": false, - "stars": 4005, + "stars": 4008, "formattedStars": "4k", "license": "MIT License", "lastRelease": "2025-11-05T23:30:57Z", - "formattedLastRelease": "11 hours ago" + "formattedLastRelease": "1 week ago" }, "nerdsupremacist/Graphaello": { "hasCommitsInLast3Months": false, @@ -1313,7 +1305,7 @@ }, "maticzav/swift-graphql": { "hasCommitsInLast3Months": false, - "stars": 619, + "stars": 621, "formattedStars": "1k", "license": "MIT License", "lastRelease": "2024-05-06T20:00:06Z", @@ -1335,76 +1327,12 @@ "lastRelease": "2021-05-17T12:51:10Z", "formattedLastRelease": "4 years ago" }, - "apollographql/router": { - "hasCommitsInLast3Months": false, - "stars": 936, - "formattedStars": "1k", - "license": "Other", - "lastRelease": "2025-11-04T16:58:39Z", - "formattedLastRelease": "1 day ago" - }, - "eerimoq/gqt": { - "hasCommitsInLast3Months": false, - "stars": 471, - "formattedStars": "471", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "Escape-Technologies/graphql-armor": { - "hasCommitsInLast3Months": false, - "stars": 550, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2025-08-22T13:32:40Z", - "formattedLastRelease": "2 months ago" - }, - "ldebruijn/graphql-protect": { - "hasCommitsInLast3Months": false, - "stars": 34, - "formattedStars": "34", - "license": "MIT License", - "lastRelease": "2025-09-09T20:03:39Z", - "formattedLastRelease": "1 month ago" - }, - "graphql-hive/gateway": { - "hasCommitsInLast3Months": false, - "stars": 65, - "formattedStars": "65", - "license": "MIT License", - "lastRelease": "2025-11-01T14:42:06Z", - "formattedLastRelease": "4 days ago" - }, - "microcks/microcks": { - "hasCommitsInLast3Months": false, - "stars": 1733, - "formattedStars": "2k", - "license": "Apache License 2.0", - "lastRelease": "2025-10-25T15:08:00Z", - "formattedLastRelease": "1 week ago" - }, - "glideapps/quicktype": { - "hasCommitsInLast3Months": false, - "stars": 13414, - "formattedStars": "13k", - "license": "Apache License 2.0", - "lastRelease": "", - "formattedLastRelease": "" - }, - "schemathesis/schemathesis": { - "hasCommitsInLast3Months": false, - "stars": 2828, - "formattedStars": "3k", - "license": "MIT License", - "lastRelease": "2025-11-06T00:26:15Z", - "formattedLastRelease": "10 hours ago" - }, "wundergraph/cosmo": { "hasCommitsInLast3Months": false, - "stars": 1111, + "stars": 1115, "formattedStars": "1k", "license": "Apache License 2.0", - "lastRelease": "2025-10-31T01:22:40Z", - "formattedLastRelease": "6 days ago" + "lastRelease": "2025-11-17T21:18:03Z", + "formattedLastRelease": "1 day ago" } -} +} \ No newline at end of file diff --git a/scripts/get-github-info/last-success.isodate b/scripts/get-github-info/last-success.isodate index 8cd7883166..27b775b3c9 100644 --- a/scripts/get-github-info/last-success.isodate +++ b/scripts/get-github-info/last-success.isodate @@ -1 +1 @@ -2025-11-06T11:11:00.490Z +2025-11-18T21:48:50.765Z \ No newline at end of file diff --git a/scripts/sync-working-groups/package.json b/scripts/sync-working-groups/package.json new file mode 100644 index 0000000000..b470821c56 --- /dev/null +++ b/scripts/sync-working-groups/package.json @@ -0,0 +1,12 @@ +{ + "name": "@graphql-website/sync-working-groups", + "private": true, + "type": "module", + "main": "./sync-working-groups.ts", + "scripts": { + "start": "node ./sync-working-groups.ts" + }, + "dependencies": { + "arktype": "^2.1.27" + } +} diff --git a/scripts/sync-working-groups/sync-working-groups.ts b/scripts/sync-working-groups/sync-working-groups.ts new file mode 100644 index 0000000000..7756734ff3 --- /dev/null +++ b/scripts/sync-working-groups/sync-working-groups.ts @@ -0,0 +1,216 @@ +#!/usr/bin/env node + +import { readFile, writeFile } from "node:fs/promises" +import { type } from "arktype" + +const CALENDAR_ID = + "linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com" +const API_KEY = process.env.GOOGLE_CALENDAR_API_KEY +const OUTPUT_FILE = new URL("./working-group-events.ndjson", import.meta.url) +const DAYS_BACK = 30 +const DAYS_TO_KEEP = 90 +const DAYS_AHEAD = 30 + +const Instant = type({ + "dateTime?": "string", + "date?": "string", // full day events have just date +}) + .pipe((value): string => { + if (value.dateTime) return value.dateTime + if (value.date) return `${value.date}T00:00:00Z` + throw new Error("Instant is missing date/dateTime") + }) + .to("string.date") + +const calendarEventSchema = type({ + id: "string", + "summary?": "string", + "status?": "string", + "description?": "string", + "location?": "string", + start: Instant, + end: Instant, + htmlLink: "string.url", + updated: "string", +}) + +const responseSchema = type({ + items: calendarEventSchema.array(), + "nextSyncToken?": "string", + "nextPageToken?": "string", +}) + +export type WorkingGroupMeeting = + typeof calendarEventSchema.inferIntrospectableOut + +async function main() { + if (!API_KEY) { + console.warn( + "GOOGLE_CALENDAR_API_KEY is not set, skipping sync (using existing file)", + ) + return + } + + const now = new Date() + const existingMeetings = await readExistingMeetings() + console.log(`Found ${existingMeetings.length} existing event(s) in file`) + + const lastMeetingStart = existingMeetings.at(-1)?.start ?? null + const cutoffDate = new Date( + now.getTime() - DAYS_TO_KEEP * 24 * 60 * 60 * 1000, + ) + + const searchParams = new URLSearchParams({ + key: API_KEY, + singleEvents: "true", + }) + + const timeMin = + lastMeetingStart !== null && lastMeetingStart !== undefined + ? new Date(Math.min(Date.parse(lastMeetingStart), now.getTime())) + : new Date(now.getTime() - DAYS_BACK * 24 * 60 * 60 * 1000) + + const timeMax = new Date(now.getTime() + DAYS_AHEAD * 24 * 60 * 60 * 1000) + searchParams.set("timeMin", timeMin.toISOString()) + searchParams.set("timeMax", timeMax.toISOString()) + searchParams.set("orderBy", "startTime") + console.log( + `\nSyncing from: ${timeMin.toLocaleDateString()} (${timeMin.toISOString()})`, + ) + console.log( + `Limiting to before: ${timeMax.toLocaleDateString()} (${timeMax.toISOString()})`, + ) + + const endpoint = new URL( + `calendars/${encodeURIComponent(CALENDAR_ID)}/events?${searchParams}`, + "https://www.googleapis.com/calendar/v3/", + ) + + console.log(`Fetching events for calendar: ${CALENDAR_ID}`) + + const response = await fetch(endpoint) + const body = await response.json() + + if (!response.ok) { + const errorDetails = body.error?.message || response.statusText + throw new Error( + `Calendar API request failed: ${response.status} ${errorDetails}`, + ) + } + + const payload = responseSchema.assert(body) + + let newMeetings = payload.items + .filter(event => event.status !== "cancelled") + .map(event => calendarEventSchema.out.assert(event)) + + if (payload.nextPageToken) { + let pageToken: string | undefined = payload.nextPageToken + while (pageToken) { + const pageParams = new URLSearchParams(searchParams) + pageParams.set("pageToken", pageToken) + const pageEndpoint = new URL( + `${encodeURIComponent(CALENDAR_ID)}/events?${pageParams}`, + "https://www.googleapis.com/calendar/v3/calendars/", + ) + const pageResponse = await fetch(pageEndpoint) + const pageBody = await pageResponse.json() + if (!pageResponse.ok) { + throw new Error(`Page fetch failed: ${pageResponse.status}`) + } + const pagePayload = responseSchema.assert(pageBody) + newMeetings = [ + ...newMeetings, + ...pagePayload.items + .filter(event => event.status !== "cancelled") + .map(event => calendarEventSchema.out.assert(event)), + ] + pageToken = pagePayload.nextPageToken + } + } + + const newIds = new Set(newMeetings.map(meeting => meeting.id)) + const existingIds = new Set(existingMeetings.map(meeting => meeting.id)) + const newCount = Array.from(newIds).filter(id => !existingIds.has(id)).length + console.log( + `Fetched ${newMeetings.length} event(s) from API (${newCount} new)`, + ) + + const allMeetings = mergeMeetings(existingMeetings, newMeetings) + const netChange = allMeetings.length - existingMeetings.length + + if (netChange > 0) { + console.log(`Added ${netChange} new event(s)`) + } else if (netChange < 0) { + console.log(`Removed ${Math.abs(netChange)} event(s)`) + } + const cutoffDateStr = cutoffDate.toISOString().split("T")[0] + const futureLimit = new Date(now.getTime() + DAYS_AHEAD * 24 * 60 * 60 * 1000) + const futureLimitStr = futureLimit.toISOString().split("T")[0] + const filteredMeetings = allMeetings.filter(meeting => { + const startDate = meeting.start.split("T")[0] + return startDate >= cutoffDateStr && startDate <= futureLimitStr + }) + + console.log( + `Keeping events from ${cutoffDate.toLocaleDateString()} onwards (${DAYS_TO_KEEP} days)`, + ) + console.log( + `Filtered to ${filteredMeetings.length} event(s) after removing old entries`, + ) + + const sortedMeetings = filteredMeetings.sort((a, b) => + a.start.localeCompare(b.start), + ) + + const ndjson = sortedMeetings.map(event => JSON.stringify(event)).join("\n") + const content = sortedMeetings.length > 0 ? `${ndjson}\n` : "" + await writeFile(OUTPUT_FILE, content, "utf8") + + console.log( + `Saved ${sortedMeetings.length} event(s) (${newCount} new) to ${OUTPUT_FILE.pathname}`, + ) +} + +async function readExistingMeetings(): Promise { + try { + const content = await readFile(OUTPUT_FILE, "utf8") + return content + .trim() + .split("\n") + .filter(line => line.trim()) + .map(line => calendarEventSchema.out.assert(JSON.parse(line))) + } catch (error: any) { + if (error.code === "ENOENT") { + return [] + } + throw error + } +} + +function mergeMeetings( + existing: WorkingGroupMeeting[], + incoming: WorkingGroupMeeting[], +): WorkingGroupMeeting[] { + const byId = new Map() + + for (const meeting of existing) { + byId.set(meeting.id, meeting) + } + + for (const meeting of incoming) { + const existing = byId.get(meeting.id) + if (!existing || meeting.updated > existing.updated) { + byId.set(meeting.id, meeting) + } + } + + return Array.from(byId.values()) +} + +try { + await main() +} catch (error: unknown) { + console.error(error) + process.exit(1) +} diff --git a/scripts/sync-working-groups/working-group-events.ndjson b/scripts/sync-working-groups/working-group-events.ndjson new file mode 100644 index 0000000000..cfbbde9d70 --- /dev/null +++ b/scripts/sync-working-groups/working-group-events.ndjson @@ -0,0 +1,33 @@ +{"kind":"calendar#event","etag":"\"3524923598591262\"","id":"s9agipg1r702pfngano7pol2h5_20251023T160000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=czlhZ2lwZzFyNzAycGZuZ2Fubzdwb2wyaDVfMjAyNTEwMjNUMTYwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2024-01-12T09:56:07.000Z","updated":"2025-11-06T20:43:19.295Z","summary":"Composite schemas WG - Weekly 4","description":"The weekly "secondary" meeting of the composite schemas WG: https://github.com/graphql/composite-schemas-wg

Meeting password is "composite"

Live notes are at https://docs.google.com/document/d/1hJO6U7daYvcNcQ3FBKnh3v4R256ers6M8IGyqRpY_kE/edit?usp=sharing","location":"https://zoom.us/j/91078840351","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-10-23T12:00:00-04:00","end":"2025-10-23T13:00:00-04:00","recurringEventId":"s9agipg1r702pfngano7pol2h5","originalStartTime":{"dateTime":"2025-10-23T12:00:00-04:00","timeZone":"Europe/Berlin"},"iCalUID":"s9agipg1r702pfngano7pol2h5@google.com","sequence":1,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3524923550687710\"","id":"4igp67o2j2nkso49c1d6nbv040_20251023T170000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=NGlncDY3bzJqMm5rc280OWMxZDZuYnYwNDBfMjAyNTEwMjNUMTcwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2025-04-15T10:29:33.000Z","updated":"2025-11-06T20:42:55.343Z","summary":"GraphQL OTel WG","description":"Zoom password: otel
 
https://github.com/graphql/otel-wg","location":"https://zoom.us/j/93594710848?pwd=meEB8rd5g69r5DF8zFaL8VIWO2Il1v.1","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-10-23T13:00:00-04:00","end":"2025-10-23T14:00:00-04:00","recurringEventId":"4igp67o2j2nkso49c1d6nbv040","originalStartTime":{"dateTime":"2025-10-23T13:00:00-04:00","timeZone":"America/Los_Angeles"},"iCalUID":"4igp67o2j2nkso49c1d6nbv040@google.com","sequence":0,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3524923696926750\"","id":"56uko3hh68be4q73tttdicg7l2_20251023T173000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=NTZ1a28zaGg2OGJlNHE3M3R0dGRpY2c3bDJfMjAyNTEwMjNUMTczMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2025-10-16T15:10:58.000Z","updated":"2025-11-06T20:44:08.463Z","summary":"GraphQL AI Working Group","description":"Sign up and view agenda at https://github.com/graphql/ai-wg


Zoom password: aiwg","location":"https://zoom.us/j/92302442188","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-10-23T13:30:00-04:00","end":"2025-10-23T14:30:00-04:00","recurringEventId":"56uko3hh68be4q73tttdicg7l2","originalStartTime":{"dateTime":"2025-10-23T13:30:00-04:00","timeZone":"America/New_York"},"transparency":"transparent","iCalUID":"56uko3hh68be4q73tttdicg7l2@google.com","sequence":0,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3517067971709790\"","id":"f7cvs5ala9jtt147l3mik2mlvl_20251027T150000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=ZjdjdnM1YWxhOWp0dDE0N2wzbWlrMm1sdmxfMjAyNTEwMjdUMTUwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2024-01-29T15:14:17.000Z","updated":"2025-09-22T09:39:45.854Z","summary":"Conference & Community Committee Meeting - Fortnightly Recurring","description":"\nYou have been invited to a recurring meeting for GraphQL Foundation\n\nWeekly Sync and Coordination Meeting for Conference Committee participants. Notes Document: https://docs.google.com/document/d/19-alP5jywnXzgN_1zYLBTRWh-4CaXzGakEZdTBFwNAc/edit\n\nWays to join meeting:\n\n1. Join from PC, Mac, iPad, or Android\n\nhttps://zoom-lfx.platform.linuxfoundation.org/meeting/96286151238?password=ff267735-efbd-4be4-a89c-b927b596190a\n\n2. Join via audio\n\nOne tap mobile:\nUS: +12532158782,,96286151238# or +13462487799,,96286151238\n\nOr dial:\nUS: +1 253 215 8782 or +1 346 248 7799 or +1 669 900 6833 or +1 301 715 8592 or +1 312 626 6799 or +1 646 374 8656 or 877 369 0926 (Toll Free) or 855 880 1246 (Toll Free)\nCanada: +1 647 374 4685 or +1 647 558 0588 or +1 778 907 2071 or +1 204 272 7920 or +1 438 809 7799 or +1 587 328 1099 or 855 703 8985 (Toll Free)\n\nMeeting ID: 96286151238\n\nMeeting Passcode: 986182\n\n\nInternational numbers: https://zoom.us/u/alwnPIaVT\n","location":"https://zoom-lfx.platform.linuxfoundation.org/meeting/96286151238?password=ff267735-efbd-4be4-a89c-b927b596190a","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-10-27T11:00:00-04:00","end":"2025-10-27T12:00:00-04:00","recurringEventId":"f7cvs5ala9jtt147l3mik2mlvl","originalStartTime":{"dateTime":"2025-10-27T11:00:00-04:00","timeZone":"America/New_York"},"iCalUID":"f7cvs5ala9jtt147l3mik2mlvl@google.com","sequence":2,"guestsCanInviteOthers":false,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3526415457310878\"","id":"5lk8stcvmomgh5n4o8766f7nt4_20251029T170000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=NWxrOHN0Y3Ztb21naDVuNG84NzY2ZjdudDRfMjAyNTEwMjlUMTcwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2021-02-02T17:29:31.000Z","updated":"2025-11-15T11:55:28.655Z","summary":"GraphQL.js Working Group meeting","description":"https://zoom.us/j/96871026087\nPassword: graphqljs\n\nPlease note these meetings are recorded and posted to https://youtube.graphql.org\n\nTo join, please open a PR and add yourself to the meeting agenda: https://github.com/graphql/graphql-js-wg/tree/main/agendas\n\nYou must have completed the (free) GraphQL Specification Membership Agreement prior to joining.","location":"https://zoom.us/j/96871026087?pwd=aHhrNWJIUDFoQXNDdTNzUzBkRTJ0QT09 (password: graphqljs)","creator":{"email":"bwarner@linuxfoundation.org"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-10-29T13:00:00-04:00","end":"2025-10-29T14:00:00-04:00","recurringEventId":"5lk8stcvmomgh5n4o8766f7nt4_R20240228T170000","originalStartTime":{"dateTime":"2025-10-29T13:00:00-04:00","timeZone":"UTC"},"iCalUID":"5lk8stcvmomgh5n4o8766f7nt4_R20240228T170000@google.com","sequence":0,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3526415626368510\"","id":"2pcpvfmbi9720g997rtddc907j_20251029T190000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=MnBjcHZmbWJpOTcyMGc5OTdydGRkYzkwN2pfMjAyNTEwMjlUMTkwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2023-07-21T21:19:53.000Z","updated":"2025-11-15T11:56:53.184Z","summary":"Client Controlled Nullability WG","location":"https://zoom.us/j/95723407712?pwd=ZHhQakxqd1JlTnZJNTJXdlN3UFdQUT09","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-10-29T15:00:00-04:00","end":"2025-10-29T16:00:00-04:00","recurringEventId":"2pcpvfmbi9720g997rtddc907j","originalStartTime":{"dateTime":"2025-10-29T15:00:00-04:00","timeZone":"UTC"},"iCalUID":"2pcpvfmbi9720g997rtddc907j@google.com","sequence":2,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3526826931784574\"","id":"q3qul35gpekign7gc8cvr6bap1_20251030T130000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=cTNxdWwzNWdwZWtpZ243Z2M4Y3ZyNmJhcDFfMjAyNTEwMzBUMTMwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2023-12-08T21:20:13.000Z","updated":"2025-11-17T21:04:25.892Z","summary":"Marketing & Content Subcommittee Meeting","location":"https://zoom-lfx.platform.linuxfoundation.org/meeting/91228653788?password=0745533d-9a7a-42bb-8c72-3b823f679384","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-10-30T09:00:00-04:00","end":"2025-10-30T10:00:00-04:00","recurringEventId":"q3qul35gpekign7gc8cvr6bap1_R20251030T130000","originalStartTime":{"dateTime":"2025-10-30T09:00:00-04:00","timeZone":"America/New_York"},"iCalUID":"q3qul35gpekign7gc8cvr6bap1_R20251030T130000@google.com","sequence":1,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3524923616454910\"","id":"pag44b4o3k87r90laj5vf5t67v_20251030T180000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=cGFnNDRiNG8zazg3cjkwbGFqNXZmNXQ2N3ZfMjAyNTEwMzBUMTgwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2023-12-04T10:48:14.000Z","updated":"2025-11-06T20:43:28.227Z","summary":"GraphQL-over-HTTP WG","description":"Zoom password: httpwg","location":"https://zoom.us/j/92781382543","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-10-30T14:00:00-04:00","end":"2025-10-30T15:00:00-04:00","recurringEventId":"pag44b4o3k87r90laj5vf5t67v","originalStartTime":{"dateTime":"2025-10-30T14:00:00-04:00","timeZone":"America/Los_Angeles"},"iCalUID":"pag44b4o3k87r90laj5vf5t67v@google.com","sequence":3,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3468081203314000\"","id":"op4181cbuekphecnfnuh384lek_20251106T170000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=b3A0MTgxY2J1ZWtwaGVjbmZudWgzODRsZWtfMjAyNTExMDZUMTcwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2024-01-12T09:52:53.000Z","updated":"2024-12-12T21:56:41.657Z","summary":"Composite schemas WG - Primary","description":"The main monthly meeting of the composite schemas WG: https://github.com/graphql/composite-schemas-wg

Meeting password is \"composite\"

Live notes are at https://docs.google.com/document/d/1hJO6U7daYvcNcQ3FBKnh3v4R256ers6M8IGyqRpY_kE/edit?usp=sharing","location":"https://zoom.us/j/91078840351","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-11-06T12:00:00-05:00","end":"2025-11-06T13:00:00-05:00","recurringEventId":"op4181cbuekphecnfnuh384lek","originalStartTime":{"dateTime":"2025-11-06T12:00:00-05:00","timeZone":"Europe/Berlin"},"iCalUID":"op4181cbuekphecnfnuh384lek@google.com","sequence":1,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3468081261828000\"","id":"1alpt1iidn6gfs1j7c7723qf7c_20251106T183000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=MWFscHQxaWlkbjZnZnMxajdjNzcyM3FmN2NfMjAyNTExMDZUMTgzMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2023-12-07T13:57:52.000Z","updated":"2024-12-12T21:57:10.914Z","summary":"GraphQL Primary WG","description":"Password: graphqlwg
 
Notes: https://docs.google.com/document/d/1q-sT4k8-c0tcDYJ8CxPZkJ8UY4Nhk3HbKsRxosu_7YE/edit?usp=sharing","location":"https://zoom.us/j/593263740","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-11-06T13:30:00-05:00","end":"2025-11-06T15:00:00-05:00","recurringEventId":"1alpt1iidn6gfs1j7c7723qf7c_R20240404T173000","originalStartTime":{"dateTime":"2025-11-06T13:30:00-05:00","timeZone":"America/Los_Angeles"},"iCalUID":"1alpt1iidn6gfs1j7c7723qf7c_R20240404T173000@google.com","sequence":0,"guestsCanInviteOthers":false,"guestsCanSeeOtherGuests":false,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3517067971709790\"","id":"f7cvs5ala9jtt147l3mik2mlvl_20251110T160000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=ZjdjdnM1YWxhOWp0dDE0N2wzbWlrMm1sdmxfMjAyNTExMTBUMTYwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2024-01-29T15:14:17.000Z","updated":"2025-09-22T09:39:45.854Z","summary":"Conference & Community Committee Meeting - Fortnightly Recurring","description":"\nYou have been invited to a recurring meeting for GraphQL Foundation\n\nWeekly Sync and Coordination Meeting for Conference Committee participants. Notes Document: https://docs.google.com/document/d/19-alP5jywnXzgN_1zYLBTRWh-4CaXzGakEZdTBFwNAc/edit\n\nWays to join meeting:\n\n1. Join from PC, Mac, iPad, or Android\n\nhttps://zoom-lfx.platform.linuxfoundation.org/meeting/96286151238?password=ff267735-efbd-4be4-a89c-b927b596190a\n\n2. Join via audio\n\nOne tap mobile:\nUS: +12532158782,,96286151238# or +13462487799,,96286151238\n\nOr dial:\nUS: +1 253 215 8782 or +1 346 248 7799 or +1 669 900 6833 or +1 301 715 8592 or +1 312 626 6799 or +1 646 374 8656 or 877 369 0926 (Toll Free) or 855 880 1246 (Toll Free)\nCanada: +1 647 374 4685 or +1 647 558 0588 or +1 778 907 2071 or +1 204 272 7920 or +1 438 809 7799 or +1 587 328 1099 or 855 703 8985 (Toll Free)\n\nMeeting ID: 96286151238\n\nMeeting Passcode: 986182\n\n\nInternational numbers: https://zoom.us/u/alwnPIaVT\n","location":"https://zoom-lfx.platform.linuxfoundation.org/meeting/96286151238?password=ff267735-efbd-4be4-a89c-b927b596190a","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-11-10T11:00:00-05:00","end":"2025-11-10T12:00:00-05:00","recurringEventId":"f7cvs5ala9jtt147l3mik2mlvl","originalStartTime":{"dateTime":"2025-11-10T11:00:00-05:00","timeZone":"America/New_York"},"iCalUID":"f7cvs5ala9jtt147l3mik2mlvl@google.com","sequence":2,"guestsCanInviteOthers":false,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3367247718456000\"","id":"4svb2ppg9lloos2qmqmp5i57o4_20251111T170000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=NHN2YjJwcGc5bGxvb3MycW1xbXA1aTU3bzRfMjAyNTExMTFUMTcwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2020-04-02T01:41:08.000Z","updated":"2023-05-09T09:17:39.228Z","summary":"GraphiQL Working Group","description":"Meeting password: graphiql

https://github.com/graphql/graphiql/blob/master/working-group/agendas

Please be aware that these calls are recorded and/or live streamed.
","location":"https://zoom.us/j/760146252","creator":{"email":"bwarner@linuxfoundation.org"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation","self":true},"start":"2025-11-11T12:00:00-05:00","end":"2025-11-11T14:00:00-05:00","recurringEventId":"4svb2ppg9lloos2qmqmp5i57o4_R20230509T160000","originalStartTime":{"dateTime":"2025-11-11T12:00:00-05:00","timeZone":"America/New_York"},"iCalUID":"4svb2ppg9lloos2qmqmp5i57o4_R20230509T160000@google.com","sequence":0,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3440167444944000\"","id":"8hn563rseadaj3kchtvul2966p_20251113T000000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=OGhuNTYzcnNlYWRhajNrY2h0dnVsMjk2NnBfMjAyNTExMTNUMDAwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2022-09-14T16:22:12.000Z","updated":"2024-07-04T09:02:02.472Z","summary":"WG APAC","description":"GraphQL Foundation is inviting you to a scheduled Zoom meeting.

Join Zoom Meeting
https://zoom.us/j/593263740


","location":"https://zoom.us/j/593263740","creator":{"email":"lee@leebyron.com","displayName":"Lee Byron"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-11-12T19:00:00-05:00","end":"2025-11-12T20:00:00-05:00","recurringEventId":"8hn563rseadaj3kchtvul2966p_R20240710T230000","originalStartTime":{"dateTime":"2025-11-12T19:00:00-05:00","timeZone":"America/New_York"},"iCalUID":"8hn563rseadaj3kchtvul2966p_R20240710T230000@google.com","sequence":2,"extendedProperties":{"shared":{"zmMeetingNum":"92300060973"}},"eventType":"default"} +{"kind":"calendar#event","etag":"\"3526826931784574\"","id":"q3qul35gpekign7gc8cvr6bap1_20251113T140000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=cTNxdWwzNWdwZWtpZ243Z2M4Y3ZyNmJhcDFfMjAyNTExMTNUMTQwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2023-12-08T21:20:13.000Z","updated":"2025-11-17T21:04:25.892Z","summary":"Marketing & Content Subcommittee Meeting","location":"https://zoom-lfx.platform.linuxfoundation.org/meeting/91228653788?password=0745533d-9a7a-42bb-8c72-3b823f679384","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-11-13T09:00:00-05:00","end":"2025-11-13T10:00:00-05:00","recurringEventId":"q3qul35gpekign7gc8cvr6bap1_R20251030T130000","originalStartTime":{"dateTime":"2025-11-13T09:00:00-05:00","timeZone":"America/New_York"},"iCalUID":"q3qul35gpekign7gc8cvr6bap1_R20251030T130000@google.com","sequence":1,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3512629578532638\"","id":"1ae8m39lvqtigc4ao1p670g8il_20251113T160000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=MWFlOG0zOWx2cXRpZ2M0YW8xcDY3MGc4aWxfMjAyNTExMTNUMTYwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2025-02-04T14:14:16.000Z","updated":"2025-08-27T17:13:09.266Z","summary":"GraphQL Community WG","description":"Meeting password: community

https://github.com/graphql/community-wg/tree/main/agendas

Please be aware that meetings are recorded and/or live-streamed.","location":"https://zoom.us/j/93104287544","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-11-13T11:00:00-05:00","end":"2025-11-13T12:00:00-05:00","recurringEventId":"1ae8m39lvqtigc4ao1p670g8il_R20250313T150000","originalStartTime":{"dateTime":"2025-11-13T11:00:00-05:00","timeZone":"America/Los_Angeles"},"iCalUID":"1ae8m39lvqtigc4ao1p670g8il_R20250313T150000@google.com","sequence":1,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3462003293658000\"","id":"lvqspfdh491rrdmvl7k1mruqd8_20251113T170000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=bHZxc3BmZGg0OTFycmRtdmw3azFtcnVxZDhfMjAyNTExMTNUMTcwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2024-01-12T09:56:35.000Z","updated":"2024-11-07T17:47:26.829Z","summary":"Composite schemas WG - Weekly 2","description":"The weekly "secondary" meeting of the composite schemas WG: https://github.com/graphql/composite-schemas-wg

Meeting password is "composite"

Live notes are at https://docs.google.com/document/d/1hJO6U7daYvcNcQ3FBKnh3v4R256ers6M8IGyqRpY_kE/edit?usp=sharing","location":"https://zoom.us/j/91078840351","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-11-13T12:00:00-05:00","end":"2025-11-13T13:00:00-05:00","recurringEventId":"lvqspfdh491rrdmvl7k1mruqd8","originalStartTime":{"dateTime":"2025-11-13T12:00:00-05:00","timeZone":"Europe/Berlin"},"iCalUID":"lvqspfdh491rrdmvl7k1mruqd8@google.com","sequence":1,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3516415120288286\"","id":"h9erafl4rc1jjor9i6akokm5ec_20251120T160000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=aDllcmFmbDRyYzFqam9yOWk2YWtva201ZWNfMjAyNTExMjBUMTYwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2023-12-08T21:32:03.000Z","updated":"2025-09-18T14:59:20.144Z","summary":"GraphQL Governing Board Meeting","creator":{"email":"jburson@linuxfoundation.org"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-11-20T11:00:00-05:00","end":"2025-11-20T12:00:00-05:00","recurringEventId":"h9erafl4rc1jjor9i6akokm5ec","originalStartTime":{"dateTime":"2025-11-20T11:00:00-05:00","timeZone":"America/New_York"},"iCalUID":"h9erafl4rc1jjor9i6akokm5ec@google.com","sequence":3,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3462003372886000\"","id":"kkc5tt01ovrjv8fki1lo31g5hj_20251120T170000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=a2tjNXR0MDFvdnJqdjhma2kxbG8zMWc1aGpfMjAyNTExMjBUMTcwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2024-01-12T09:55:37.000Z","updated":"2024-11-07T17:48:06.443Z","summary":"Composite schemas WG - Weekly 3","description":"The weekly \"secondary\" meeting of the composite schemas WG: https://github.com/graphql/composite-schemas-wg

Meeting password is \"composite\"

Live notes are at https://docs.google.com/document/d/1hJO6U7daYvcNcQ3FBKnh3v4R256ers6M8IGyqRpY_kE/edit?usp=sharing","location":"https://zoom.us/j/91078840351","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-11-20T12:00:00-05:00","end":"2025-11-20T13:00:00-05:00","recurringEventId":"kkc5tt01ovrjv8fki1lo31g5hj","originalStartTime":{"dateTime":"2025-11-20T12:00:00-05:00","timeZone":"Europe/Berlin"},"iCalUID":"kkc5tt01ovrjv8fki1lo31g5hj@google.com","sequence":1,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3500694996844990\"","id":"2ffd8o32sh77kd3mtccrtg887n_20251120T183000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=MmZmZDhvMzJzaDc3a2QzbXRjY3J0Zzg4N25fMjAyNTExMjBUMTgzMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2025-05-01T19:23:48.000Z","updated":"2025-06-19T15:38:18.422Z","summary":"GraphQL WG - Secondary (EU)","description":"Zoom password: graphqlwg","location":"https://zoom.us/j/593263740","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-11-20T13:30:00-05:00","end":"2025-11-20T15:00:00-05:00","recurringEventId":"2ffd8o32sh77kd3mtccrtg887n","originalStartTime":{"dateTime":"2025-11-20T13:30:00-05:00","timeZone":"America/Los_Angeles"},"iCalUID":"2ffd8o32sh77kd3mtccrtg887n@google.com","sequence":0,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3524923696926750\"","id":"56uko3hh68be4q73tttdicg7l2_20251127T183000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=NTZ1a28zaGg2OGJlNHE3M3R0dGRpY2c3bDJfMjAyNTExMjdUMTgzMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2025-10-16T15:10:58.000Z","updated":"2025-11-06T20:44:08.463Z","summary":"GraphQL AI Working Group","description":"Sign up and view agenda at https://github.com/graphql/ai-wg


Zoom password: aiwg","location":"https://zoom.us/j/92302442188","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-11-20T13:30:00-05:00","end":"2025-11-20T14:30:00-05:00","recurringEventId":"56uko3hh68be4q73tttdicg7l2","originalStartTime":{"dateTime":"2025-11-27T13:30:00-05:00","timeZone":"America/New_York"},"transparency":"transparent","iCalUID":"56uko3hh68be4q73tttdicg7l2@google.com","sequence":1,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3517067971709790\"","id":"f7cvs5ala9jtt147l3mik2mlvl_20251124T160000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=ZjdjdnM1YWxhOWp0dDE0N2wzbWlrMm1sdmxfMjAyNTExMjRUMTYwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2024-01-29T15:14:17.000Z","updated":"2025-09-22T09:39:45.854Z","summary":"Conference & Community Committee Meeting - Fortnightly Recurring","description":"\nYou have been invited to a recurring meeting for GraphQL Foundation\n\nWeekly Sync and Coordination Meeting for Conference Committee participants. Notes Document: https://docs.google.com/document/d/19-alP5jywnXzgN_1zYLBTRWh-4CaXzGakEZdTBFwNAc/edit\n\nWays to join meeting:\n\n1. Join from PC, Mac, iPad, or Android\n\nhttps://zoom-lfx.platform.linuxfoundation.org/meeting/96286151238?password=ff267735-efbd-4be4-a89c-b927b596190a\n\n2. Join via audio\n\nOne tap mobile:\nUS: +12532158782,,96286151238# or +13462487799,,96286151238\n\nOr dial:\nUS: +1 253 215 8782 or +1 346 248 7799 or +1 669 900 6833 or +1 301 715 8592 or +1 312 626 6799 or +1 646 374 8656 or 877 369 0926 (Toll Free) or 855 880 1246 (Toll Free)\nCanada: +1 647 374 4685 or +1 647 558 0588 or +1 778 907 2071 or +1 204 272 7920 or +1 438 809 7799 or +1 587 328 1099 or 855 703 8985 (Toll Free)\n\nMeeting ID: 96286151238\n\nMeeting Passcode: 986182\n\n\nInternational numbers: https://zoom.us/u/alwnPIaVT\n","location":"https://zoom-lfx.platform.linuxfoundation.org/meeting/96286151238?password=ff267735-efbd-4be4-a89c-b927b596190a","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-11-24T11:00:00-05:00","end":"2025-11-24T12:00:00-05:00","recurringEventId":"f7cvs5ala9jtt147l3mik2mlvl","originalStartTime":{"dateTime":"2025-11-24T11:00:00-05:00","timeZone":"America/New_York"},"iCalUID":"f7cvs5ala9jtt147l3mik2mlvl@google.com","sequence":2,"guestsCanInviteOthers":false,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3468081203314000\"","id":"op4181cbuekphecnfnuh384lek_20251204T170000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=b3A0MTgxY2J1ZWtwaGVjbmZudWgzODRsZWtfMjAyNTEyMDRUMTcwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2024-01-12T09:52:53.000Z","updated":"2024-12-12T21:56:41.657Z","summary":"Composite schemas WG - Primary","description":"The main monthly meeting of the composite schemas WG: https://github.com/graphql/composite-schemas-wg

Meeting password is \"composite\"

Live notes are at https://docs.google.com/document/d/1hJO6U7daYvcNcQ3FBKnh3v4R256ers6M8IGyqRpY_kE/edit?usp=sharing","location":"https://zoom.us/j/91078840351","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-12-04T12:00:00-05:00","end":"2025-12-04T13:00:00-05:00","recurringEventId":"op4181cbuekphecnfnuh384lek","originalStartTime":{"dateTime":"2025-12-04T12:00:00-05:00","timeZone":"Europe/Berlin"},"iCalUID":"op4181cbuekphecnfnuh384lek@google.com","sequence":1,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3468081261828000\"","id":"1alpt1iidn6gfs1j7c7723qf7c_20251204T183000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=MWFscHQxaWlkbjZnZnMxajdjNzcyM3FmN2NfMjAyNTEyMDRUMTgzMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2023-12-07T13:57:52.000Z","updated":"2024-12-12T21:57:10.914Z","summary":"GraphQL Primary WG","description":"Password: graphqlwg
 
Notes: https://docs.google.com/document/d/1q-sT4k8-c0tcDYJ8CxPZkJ8UY4Nhk3HbKsRxosu_7YE/edit?usp=sharing","location":"https://zoom.us/j/593263740","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-12-04T13:30:00-05:00","end":"2025-12-04T15:00:00-05:00","recurringEventId":"1alpt1iidn6gfs1j7c7723qf7c_R20240404T173000","originalStartTime":{"dateTime":"2025-12-04T13:30:00-05:00","timeZone":"America/Los_Angeles"},"iCalUID":"1alpt1iidn6gfs1j7c7723qf7c_R20240404T173000@google.com","sequence":0,"guestsCanInviteOthers":false,"guestsCanSeeOtherGuests":false,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3517067971709790\"","id":"f7cvs5ala9jtt147l3mik2mlvl_20251208T160000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=ZjdjdnM1YWxhOWp0dDE0N2wzbWlrMm1sdmxfMjAyNTEyMDhUMTYwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2024-01-29T15:14:17.000Z","updated":"2025-09-22T09:39:45.854Z","summary":"Conference & Community Committee Meeting - Fortnightly Recurring","description":"\nYou have been invited to a recurring meeting for GraphQL Foundation\n\nWeekly Sync and Coordination Meeting for Conference Committee participants. Notes Document: https://docs.google.com/document/d/19-alP5jywnXzgN_1zYLBTRWh-4CaXzGakEZdTBFwNAc/edit\n\nWays to join meeting:\n\n1. Join from PC, Mac, iPad, or Android\n\nhttps://zoom-lfx.platform.linuxfoundation.org/meeting/96286151238?password=ff267735-efbd-4be4-a89c-b927b596190a\n\n2. Join via audio\n\nOne tap mobile:\nUS: +12532158782,,96286151238# or +13462487799,,96286151238\n\nOr dial:\nUS: +1 253 215 8782 or +1 346 248 7799 or +1 669 900 6833 or +1 301 715 8592 or +1 312 626 6799 or +1 646 374 8656 or 877 369 0926 (Toll Free) or 855 880 1246 (Toll Free)\nCanada: +1 647 374 4685 or +1 647 558 0588 or +1 778 907 2071 or +1 204 272 7920 or +1 438 809 7799 or +1 587 328 1099 or 855 703 8985 (Toll Free)\n\nMeeting ID: 96286151238\n\nMeeting Passcode: 986182\n\n\nInternational numbers: https://zoom.us/u/alwnPIaVT\n","location":"https://zoom-lfx.platform.linuxfoundation.org/meeting/96286151238?password=ff267735-efbd-4be4-a89c-b927b596190a","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-12-08T11:00:00-05:00","end":"2025-12-08T12:00:00-05:00","recurringEventId":"f7cvs5ala9jtt147l3mik2mlvl","originalStartTime":{"dateTime":"2025-12-08T11:00:00-05:00","timeZone":"America/New_York"},"iCalUID":"f7cvs5ala9jtt147l3mik2mlvl@google.com","sequence":2,"guestsCanInviteOthers":false,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3367247718456000\"","id":"4svb2ppg9lloos2qmqmp5i57o4_20251209T170000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=NHN2YjJwcGc5bGxvb3MycW1xbXA1aTU3bzRfMjAyNTEyMDlUMTcwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2020-04-02T01:41:08.000Z","updated":"2023-05-09T09:17:39.228Z","summary":"GraphiQL Working Group","description":"Meeting password: graphiql

https://github.com/graphql/graphiql/blob/master/working-group/agendas

Please be aware that these calls are recorded and/or live streamed.
","location":"https://zoom.us/j/760146252","creator":{"email":"bwarner@linuxfoundation.org"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation","self":true},"start":"2025-12-09T12:00:00-05:00","end":"2025-12-09T14:00:00-05:00","recurringEventId":"4svb2ppg9lloos2qmqmp5i57o4_R20230509T160000","originalStartTime":{"dateTime":"2025-12-09T12:00:00-05:00","timeZone":"America/New_York"},"iCalUID":"4svb2ppg9lloos2qmqmp5i57o4_R20230509T160000@google.com","sequence":0,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3440167444944000\"","id":"8hn563rseadaj3kchtvul2966p_20251211T000000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=OGhuNTYzcnNlYWRhajNrY2h0dnVsMjk2NnBfMjAyNTEyMTFUMDAwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2022-09-14T16:22:12.000Z","updated":"2024-07-04T09:02:02.472Z","summary":"WG APAC","description":"GraphQL Foundation is inviting you to a scheduled Zoom meeting.

Join Zoom Meeting
https://zoom.us/j/593263740


","location":"https://zoom.us/j/593263740","creator":{"email":"lee@leebyron.com","displayName":"Lee Byron"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-12-10T19:00:00-05:00","end":"2025-12-10T20:00:00-05:00","recurringEventId":"8hn563rseadaj3kchtvul2966p_R20240710T230000","originalStartTime":{"dateTime":"2025-12-10T19:00:00-05:00","timeZone":"America/New_York"},"iCalUID":"8hn563rseadaj3kchtvul2966p_R20240710T230000@google.com","sequence":2,"extendedProperties":{"shared":{"zmMeetingNum":"92300060973"}},"eventType":"default"} +{"kind":"calendar#event","etag":"\"3526826931784574\"","id":"q3qul35gpekign7gc8cvr6bap1_20251211T140000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=cTNxdWwzNWdwZWtpZ243Z2M4Y3ZyNmJhcDFfMjAyNTEyMTFUMTQwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2023-12-08T21:20:13.000Z","updated":"2025-11-17T21:04:25.892Z","summary":"Marketing & Content Subcommittee Meeting","location":"https://zoom-lfx.platform.linuxfoundation.org/meeting/91228653788?password=0745533d-9a7a-42bb-8c72-3b823f679384","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-12-11T09:00:00-05:00","end":"2025-12-11T10:00:00-05:00","recurringEventId":"q3qul35gpekign7gc8cvr6bap1_R20251030T130000","originalStartTime":{"dateTime":"2025-12-11T09:00:00-05:00","timeZone":"America/New_York"},"iCalUID":"q3qul35gpekign7gc8cvr6bap1_R20251030T130000@google.com","sequence":1,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3512629578532638\"","id":"1ae8m39lvqtigc4ao1p670g8il_20251211T160000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=MWFlOG0zOWx2cXRpZ2M0YW8xcDY3MGc4aWxfMjAyNTEyMTFUMTYwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2025-02-04T14:14:16.000Z","updated":"2025-08-27T17:13:09.266Z","summary":"GraphQL Community WG","description":"Meeting password: community

https://github.com/graphql/community-wg/tree/main/agendas

Please be aware that meetings are recorded and/or live-streamed.","location":"https://zoom.us/j/93104287544","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-12-11T11:00:00-05:00","end":"2025-12-11T12:00:00-05:00","recurringEventId":"1ae8m39lvqtigc4ao1p670g8il_R20250313T150000","originalStartTime":{"dateTime":"2025-12-11T11:00:00-05:00","timeZone":"America/Los_Angeles"},"iCalUID":"1ae8m39lvqtigc4ao1p670g8il_R20250313T150000@google.com","sequence":1,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3462003293658000\"","id":"lvqspfdh491rrdmvl7k1mruqd8_20251211T170000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=bHZxc3BmZGg0OTFycmRtdmw3azFtcnVxZDhfMjAyNTEyMTFUMTcwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2024-01-12T09:56:35.000Z","updated":"2024-11-07T17:47:26.829Z","summary":"Composite schemas WG - Weekly 2","description":"The weekly "secondary" meeting of the composite schemas WG: https://github.com/graphql/composite-schemas-wg

Meeting password is "composite"

Live notes are at https://docs.google.com/document/d/1hJO6U7daYvcNcQ3FBKnh3v4R256ers6M8IGyqRpY_kE/edit?usp=sharing","location":"https://zoom.us/j/91078840351","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-12-11T12:00:00-05:00","end":"2025-12-11T13:00:00-05:00","recurringEventId":"lvqspfdh491rrdmvl7k1mruqd8","originalStartTime":{"dateTime":"2025-12-11T12:00:00-05:00","timeZone":"Europe/Berlin"},"iCalUID":"lvqspfdh491rrdmvl7k1mruqd8@google.com","sequence":1,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3524923696926750\"","id":"56uko3hh68be4q73tttdicg7l2_20251225T183000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=NTZ1a28zaGg2OGJlNHE3M3R0dGRpY2c3bDJfMjAyNTEyMjVUMTgzMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2025-10-16T15:10:58.000Z","updated":"2025-11-06T20:44:08.463Z","summary":"GraphQL AI Working Group","description":"Sign up and view agenda at https://github.com/graphql/ai-wg


Zoom password: aiwg","location":"https://zoom.us/j/92302442188","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-12-11T13:30:00-05:00","end":"2025-12-11T14:30:00-05:00","recurringEventId":"56uko3hh68be4q73tttdicg7l2","originalStartTime":{"dateTime":"2025-12-25T13:30:00-05:00","timeZone":"America/New_York"},"transparency":"transparent","iCalUID":"56uko3hh68be4q73tttdicg7l2@google.com","sequence":1,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3516415120288286\"","id":"h9erafl4rc1jjor9i6akokm5ec_20251218T160000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=aDllcmFmbDRyYzFqam9yOWk2YWtva201ZWNfMjAyNTEyMThUMTYwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2023-12-08T21:32:03.000Z","updated":"2025-09-18T14:59:20.144Z","summary":"GraphQL Governing Board Meeting","creator":{"email":"jburson@linuxfoundation.org"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-12-18T11:00:00-05:00","end":"2025-12-18T12:00:00-05:00","recurringEventId":"h9erafl4rc1jjor9i6akokm5ec","originalStartTime":{"dateTime":"2025-12-18T11:00:00-05:00","timeZone":"America/New_York"},"iCalUID":"h9erafl4rc1jjor9i6akokm5ec@google.com","sequence":3,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3462003372886000\"","id":"kkc5tt01ovrjv8fki1lo31g5hj_20251218T170000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=a2tjNXR0MDFvdnJqdjhma2kxbG8zMWc1aGpfMjAyNTEyMThUMTcwMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2024-01-12T09:55:37.000Z","updated":"2024-11-07T17:48:06.443Z","summary":"Composite schemas WG - Weekly 3","description":"The weekly \"secondary\" meeting of the composite schemas WG: https://github.com/graphql/composite-schemas-wg

Meeting password is \"composite\"

Live notes are at https://docs.google.com/document/d/1hJO6U7daYvcNcQ3FBKnh3v4R256ers6M8IGyqRpY_kE/edit?usp=sharing","location":"https://zoom.us/j/91078840351","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-12-18T12:00:00-05:00","end":"2025-12-18T13:00:00-05:00","recurringEventId":"kkc5tt01ovrjv8fki1lo31g5hj","originalStartTime":{"dateTime":"2025-12-18T12:00:00-05:00","timeZone":"Europe/Berlin"},"iCalUID":"kkc5tt01ovrjv8fki1lo31g5hj@google.com","sequence":1,"eventType":"default"} +{"kind":"calendar#event","etag":"\"3500694996844990\"","id":"2ffd8o32sh77kd3mtccrtg887n_20251218T183000Z","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=MmZmZDhvMzJzaDc3a2QzbXRjY3J0Zzg4N25fMjAyNTEyMThUMTgzMDAwWiBsaW51eGZvdW5kYXRpb24ub3JnX2lrNzl0OXV1ajJwMzJpM3IyMDNkZ3Y1bW84QGc","created":"2025-05-01T19:23:48.000Z","updated":"2025-06-19T15:38:18.422Z","summary":"GraphQL WG - Secondary (EU)","description":"Zoom password: graphqlwg","location":"https://zoom.us/j/593263740","creator":{"email":"benjie@graphile.com"},"organizer":{"email":"linuxfoundation.org_ik79t9uuj2p32i3r203dgv5mo8@group.calendar.google.com","displayName":"GraphQL Foundation - Public","self":true},"start":"2025-12-18T13:30:00-05:00","end":"2025-12-18T15:00:00-05:00","recurringEventId":"2ffd8o32sh77kd3mtccrtg887n","originalStartTime":{"dateTime":"2025-12-18T13:30:00-05:00","timeZone":"America/Los_Angeles"},"iCalUID":"2ffd8o32sh77kd3mtccrtg887n@google.com","sequence":0,"eventType":"default"} diff --git a/src/app/(main)/community/events/event-card.tsx b/src/app/(main)/community/events/event-card.tsx index 346bdee5bc..6042a89644 100644 --- a/src/app/(main)/community/events/event-card.tsx +++ b/src/app/(main)/community/events/event-card.tsx @@ -55,8 +55,8 @@ export interface EventCardProps { city: ReactNode name: ReactNode meta?: ReactNode - official?: boolean kind: "meetup" | "conference" | "working-group" + className?: string } export function EventCard({ @@ -65,8 +65,8 @@ export function EventCard({ city, name, meta, - official, kind, + className, }: EventCardProps) { const dateLabel = formatDateLabel(date) const parsedDate = normaliseDate(date) @@ -74,9 +74,8 @@ export function EventCard({ - {kind} - {meta ? ( - {meta} - ) : ( - Official GraphQL Local + {kind.replace("-", " ")} + {!!meta && ( + + {meta} + )} @@ -121,7 +128,15 @@ export function EventCard({
{parsedDate ? ( - + ) : ( {dateLabel} )} diff --git a/src/app/(main)/community/events/event-filter-tag.tsx b/src/app/(main)/community/events/event-filter-tag.tsx index 9b1ebc398f..911f5f4fd1 100644 --- a/src/app/(main)/community/events/event-filter-tag.tsx +++ b/src/app/(main)/community/events/event-filter-tag.tsx @@ -15,24 +15,27 @@ export interface EventFilterTagProps kind: EventKind checked: boolean onChange: (event: React.ChangeEvent) => void + disabled?: boolean } export function EventFilterTag({ kind, checked, onChange, + disabled, ...rest }: EventFilterTagProps) { return ( + Subscribe to Events RSS + RSS Feed + + ) +} diff --git a/test/e2e/community-events.spec.ts b/test/e2e/community-events.spec.ts index e0bd7e632c..dfa9ec7e77 100644 --- a/test/e2e/community-events.spec.ts +++ b/test/e2e/community-events.spec.ts @@ -1,4 +1,4 @@ -import { test, expect } from "@playwright/test" +import { test, expect, type Locator } from "@playwright/test" test.beforeEach(async ({ page }) => { await page.goto("/community/events") @@ -43,7 +43,7 @@ test("map matches screenshot", async ({ page }) => { await expect(mapContainer.locator("canvas").first()).toHaveScreenshot( "meetups-map.png", - { timeout: 30_000 }, + { timeout: 30_000, maxDiffPixelRatio: 0.015 }, ) }) @@ -138,3 +138,210 @@ test("map tooltip appears on marker hover", async ({ page }) => { await expect(tooltip).toHaveText("London GraphQL", { timeout: 5000 }) await expect(tooltip).toBeVisible() }) + +test("event type filters hide cards and lock the last active tag", async ({ + page, +}) => { + // TODO: @hasparus figure out why this fails only on CI + if (process.env.CI) test.skip() + + const pastEventsSection = page + .locator("section") + .filter({ + has: page.getByRole("heading", { + level: 2, + name: /Past events & meetups/i, + }), + }) + .first() + + await pastEventsSection.scrollIntoViewIfNeeded() + + const filterGroup = pastEventsSection.getByRole("group", { + name: "Event type", + }) + + await expect(filterGroup).toBeVisible() + const conferenceFilter = filterGroup.getByRole("checkbox", { + name: /conference/i, + }) + const meetupFilter = filterGroup.getByRole("checkbox", { name: /meetup/i }) + const workingGroupFilter = filterGroup.getByRole("checkbox", { + name: /working group/i, + }) + const conferenceChip = filterGroup + .locator("label") + .filter({ hasText: /conference/i }) + .first() + const meetupChip = filterGroup + .locator("label") + .filter({ hasText: /meetup/i }) + .first() + const workingGroupChip = filterGroup + .locator("label") + .filter({ hasText: /working group/i }) + .first() + + const tagBadge = (tag: RegExp) => + pastEventsSection.locator("a span:has(.Tag--bg)").filter({ hasText: tag }) + + const filterDefinitions = [ + { + kind: "conference", + filterName: /conference/i, + badgeText: /^conference$/i, + chip: conferenceChip, + filter: conferenceFilter, + }, + { + kind: "meetup", + filterName: /meetup/i, + badgeText: /^meetup$/i, + chip: meetupChip, + filter: meetupFilter, + }, + { + kind: "working group", + filterName: /working group/i, + badgeText: /^working group$/i, + chip: workingGroupChip, + filter: workingGroupFilter, + }, + ] as const + + type FilterDefinition = (typeof filterDefinitions)[number] + type ActiveFilter = FilterDefinition & { badges: Locator } + + const activeFilters: ActiveFilter[] = [] + const toggleableFilters: ActiveFilter[] = [] + + for (const definition of filterDefinitions) { + const badgeLocator = tagBadge(definition.badgeText) + if ((await definition.filter.count()) === 0) continue + const filterDefinition = { ...definition, badges: badgeLocator } + activeFilters.push(filterDefinition) + if (await definition.filter.isEnabled()) { + toggleableFilters.push(filterDefinition) + } + } + + expect(activeFilters.length).toBeGreaterThan(0) + + for (const activeFilter of activeFilters) { + await expect(activeFilter.badges.first()).toBeVisible() + } + + if (toggleableFilters.length === 0) { + return + } + + for (const activeFilter of toggleableFilters) { + await activeFilter.chip.click() + await expect(activeFilter.filter).not.toBeChecked() + await expect(activeFilter.badges).toHaveCount(0) + await activeFilter.chip.click() + await expect(activeFilter.filter).toBeChecked() + await expect(activeFilter.badges.first()).toBeVisible() + } + + if (toggleableFilters.length < 2) { + return + } + + const [lockedFilter, ...filtersToToggle] = toggleableFilters + + for (const filter of filtersToToggle) { + await filter.chip.click() + await expect(filter.filter).not.toBeChecked() + } + + await expect(lockedFilter.filter).toBeChecked() + await expect(lockedFilter.filter).toBeDisabled() + await expect(lockedFilter.badges.first()).toBeVisible() + + for (const filter of filtersToToggle) { + await filter.chip.click() + await expect(filter.filter).toBeChecked() + } + + await expect(lockedFilter.filter).toBeEnabled() +}) + +test("upcoming and past sections only show events on the correct side of now", async ({ + page, +}) => { + // TODO: @hasparus figure out why this fails only on CI + if (process.env.CI) test.skip() + + const upcomingSection = page + .locator("section") + .filter({ + has: page.getByRole("heading", { level: 2, name: /Upcoming events/i }), + }) + .first() + const pastEventsSection = page + .locator("section") + .filter({ + has: page.getByRole("heading", { + level: 2, + name: /Past events & meetups/i, + }), + }) + .first() + + await Promise.all([ + upcomingSection.scrollIntoViewIfNeeded(), + pastEventsSection.scrollIntoViewIfNeeded(), + ]) + + await expect(upcomingSection).toBeVisible() + await expect(pastEventsSection).toBeVisible() + + const now = Date.now() + + const readSectionDates = async (section: Locator) => { + const entries = await section.locator("a time").evaluateAll(elements => + elements.map(element => ({ + iso: element.getAttribute("datetime") ?? "", + text: element.textContent?.trim() ?? "", + })), + ) + return entries + } + + const upcomingDates = await readSectionDates(upcomingSection) + expect(upcomingDates.length).toBeGreaterThan(0) + upcomingDates.forEach(({ iso, text }) => { + expect( + iso.length, + `${text} is missing a datetime attribute`, + ).toBeGreaterThan(0) + const timestamp = Date.parse(iso) + expect( + Number.isNaN(timestamp), + `${text} carries an invalid datetime attribute: ${iso}`, + ).toBe(false) + expect( + timestamp, + `${text} should be in the future but resolved to ${iso}`, + ).toBeGreaterThanOrEqual(now) + }) + + const pastDates = await readSectionDates(pastEventsSection) + expect(pastDates.length).toBeGreaterThan(0) + pastDates.forEach(({ iso, text }) => { + expect( + iso.length, + `${text} is missing a datetime attribute`, + ).toBeGreaterThan(0) + const timestamp = Date.parse(iso) + expect( + Number.isNaN(timestamp), + `${text} carries an invalid datetime attribute: ${iso}`, + ).toBe(false) + expect( + timestamp, + `${text} should be in the past but resolved to ${iso}`, + ).toBeLessThan(now) + }) +})