diff --git a/.github/workflows/parser-graphql-wrapper.yml b/.github/workflows/parser-graphql-wrapper.yml index f38386856..21d8af51f 100644 --- a/.github/workflows/parser-graphql-wrapper.yml +++ b/.github/workflows/parser-graphql-wrapper.yml @@ -47,7 +47,7 @@ jobs: with: federated-graph-name: pocket-admin-api graph-name: parser - schema-file-path: servers/parser-graphql-wrapper/schema.graphql + schema-file-path: servers/parser-graphql-wrapper/schema-admin.graphql prod-graph-url: https://parser-graphql-wrapper.readitlater.com dev-graph-url: https://parser-graphql-wrapper.getpocket.dev secrets: diff --git a/package.json b/package.json index 975100b4c..db6843ac4 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "@pocket-tools/eslint-config": "workspace:*", "syncpack": "^12.4.0", "tsconfig": "workspace:*", - "turbo": "^2.0.14" + "turbo": "^2.1.0" }, "packageManager": "pnpm@9.7.1", "engines": { diff --git a/packages/apollo-utils/package.json b/packages/apollo-utils/package.json index 392c47b9c..2612c64a9 100644 --- a/packages/apollo-utils/package.json +++ b/packages/apollo-utils/package.json @@ -76,7 +76,7 @@ "@apollo/cache-control-types": "1.0.3", "@apollo/server": "4.10.4", "@apollo/server-plugin-response-cache": "4.1.3", - "@apollo/subgraph": "2.8.4", + "@apollo/subgraph": "2.9.0", "@apollo/utils.keyvadapter": "3.1.0", "@apollo/utils.keyvaluecache": "3.1.0", "@pocket-tools/ts-logger": "workspace:*", @@ -107,7 +107,7 @@ }, "peerDependencies": { "@apollo/server": "4.10.4", - "@apollo/subgraph": "2.8.4", + "@apollo/subgraph": "2.9.0", "@apollo/utils.keyvadapter": "3.1.0", "@apollo/utils.keyvaluecache": "3.1.0", "express": "4.19.2", diff --git a/packages/image-utils/.npmignore b/packages/image-utils/.npmignore new file mode 100644 index 000000000..e254b6528 --- /dev/null +++ b/packages/image-utils/.npmignore @@ -0,0 +1,8 @@ +src +.github +.idea +.prettier* +.eslintrc.js +.tsconfig.js +*.spec.ts +*.integration.ts \ No newline at end of file diff --git a/packages/image-utils/README.md b/packages/image-utils/README.md new file mode 100644 index 000000000..d916c026e --- /dev/null +++ b/packages/image-utils/README.md @@ -0,0 +1,3 @@ +# Image Utils + +We use this repository as a place to keep code we use across our backend services that implement anything to do with image urls diff --git a/packages/image-utils/eslint.config.mjs b/packages/image-utils/eslint.config.mjs new file mode 100644 index 000000000..638ac644e --- /dev/null +++ b/packages/image-utils/eslint.config.mjs @@ -0,0 +1,3 @@ +import packages from '@pocket-tools/eslint-config/packages'; +import tseslint from 'typescript-eslint'; +export default tseslint.config(...packages); diff --git a/packages/image-utils/jest.config.js b/packages/image-utils/jest.config.js new file mode 100644 index 000000000..3dc86cb25 --- /dev/null +++ b/packages/image-utils/jest.config.js @@ -0,0 +1,7 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + testMatch: ['**/?(*.)+(jest|spec).[jt]s?(x)'], + testPathIgnorePatterns: ['/dist/'], + setupFilesAfterEnv: ['jest-extended/all'], +}; diff --git a/packages/image-utils/package.json b/packages/image-utils/package.json new file mode 100644 index 000000000..51feb26ed --- /dev/null +++ b/packages/image-utils/package.json @@ -0,0 +1,91 @@ +{ + "name": "@pocket-tools/image-utils", + "version": "0.0.0-development", + "description": "Utilities for working with image urls", + "keywords": [ + "image" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/Pocket/pocket-monorepo.git" + }, + "license": "Apache-2.0", + "author": "", + "main": "dist/index.js", + "module": "dist/index.mjs", + "types": "dist/index.d.ts", + "files": [ + "dist", + "package.json" + ], + "scripts": { + "build": "tsup src/index.ts --format cjs,esm --dts", + "dev": "pnpm run build --watch", + "format": "eslint --fix", + "lint": "eslint --fix-dry-run", + "semantic-release": "semantic-release", + "test": "jest", + "test:watch": "pnpm run test -- --watch" + }, + "release": { + "branches": [ + "main" + ], + "extends": "semantic-release-monorepo", + "plugins": [ + [ + "@semantic-release/commit-analyzer", + { + "preset": "conventionalcommits", + "parserOpts": { + "noteKeywords": [ + "BREAKING CHANGE", + "BREAKING CHANGES", + "BREAKING" + ] + } + } + ], + [ + "@semantic-release/release-notes-generator", + { + "preset": "conventionalcommits", + "parserOpts": { + "noteKeywords": [ + "BREAKING CHANGE", + "BREAKING CHANGES", + "BREAKING" + ] + }, + "writerOpts": { + "commitsSort": [ + "subject", + "scope" + ] + } + } + ], + "@semantic-release/npm", + "@semantic-release/github" + ] + }, + "dependencies": { + "parse-url": "9.2.0" + }, + "devDependencies": { + "@jest/globals": "29.7.0", + "@pocket-tools/eslint-config": "workspace:*", + "@types/jest": "29.5.12", + "@types/node": "^20.16", + "jest": "29.7.0", + "jest-extended": "4.0.2", + "semantic-release": "24.1.0", + "semantic-release-monorepo": "8.0.2", + "ts-jest": "29.2.4", + "ts-node": "10.9.2", + "tsconfig": "workspace:*", + "tsup": "8.2.4", + "typescript": "5.5.4" + }, + "peerDependencies": {} +} diff --git a/packages/image-utils/src/index.ts b/packages/image-utils/src/index.ts new file mode 100644 index 000000000..04bca77e0 --- /dev/null +++ b/packages/image-utils/src/index.ts @@ -0,0 +1 @@ +export * from './utils'; diff --git a/servers/image-api/src/pocketImageCache/utils.spec.ts b/packages/image-utils/src/utils.spec.ts similarity index 89% rename from servers/image-api/src/pocketImageCache/utils.spec.ts rename to packages/image-utils/src/utils.spec.ts index 5ed532ac5..ed8b50c64 100644 --- a/servers/image-api/src/pocketImageCache/utils.spec.ts +++ b/packages/image-utils/src/utils.spec.ts @@ -1,4 +1,3 @@ -import { NotFoundError } from '@pocket-tools/apollo-utils'; import { getOriginalUrlIfPocketImageCached } from './utils'; describe('getOriginalUrlIfPocketImageCached', () => { @@ -29,8 +28,6 @@ describe('getOriginalUrlIfPocketImageCached', () => { const url = 'https://pocket-image-cache.com/direct?resize=2000w'; expect(() => { getOriginalUrlIfPocketImageCached(url); - }).toThrowError( - new NotFoundError('Pocket image cache url is missing a source url'), - ); + }).toThrow(new Error('Source URL Missing')); }); }); diff --git a/servers/image-api/src/pocketImageCache/utils.ts b/packages/image-utils/src/utils.ts similarity index 93% rename from servers/image-api/src/pocketImageCache/utils.ts rename to packages/image-utils/src/utils.ts index 0265fe587..94125cd8b 100644 --- a/servers/image-api/src/pocketImageCache/utils.ts +++ b/packages/image-utils/src/utils.ts @@ -1,4 +1,3 @@ -import { NotFoundError } from '@pocket-tools/apollo-utils'; import parseUrl from 'parse-url'; //Functions on this page taken from Web Client. @@ -19,7 +18,7 @@ export const getOriginalUrlIfPocketImageCached = (url: string): string => { if (isEncoded) { const urlToUse = extractImageCacheUrl(url); if (!urlToUse) { - throw new NotFoundError('Pocket image cache url is missing a source url'); + throw new Error('Source URL Missing'); } return decodeURIComponent(urlToUse); } diff --git a/packages/image-utils/tsconfig.json b/packages/image-utils/tsconfig.json new file mode 100644 index 000000000..cc4df5007 --- /dev/null +++ b/packages/image-utils/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "tsconfig/library.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "exclude": ["node_modules", "dist"], + "include": ["src/**/*.ts", "src/config"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d563759a1..1ceb00997 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,7 +17,7 @@ importers: devDependencies: '@commitlint/cli': specifier: 19.4.0 - version: 19.4.0(@types/node@22.5.0)(typescript@5.7.0-dev.20240827) + version: 19.4.0(@types/node@22.5.0)(typescript@5.7.0-dev.20240828) '@commitlint/config-conventional': specifier: ^19.2.2 version: 19.2.2 @@ -26,13 +26,13 @@ importers: version: link:packages/eslint-config syncpack: specifier: ^12.4.0 - version: 12.4.0(typescript@5.7.0-dev.20240827) + version: 12.4.0(typescript@5.7.0-dev.20240828) tsconfig: specifier: workspace:* version: link:packages/tsconfig turbo: - specifier: ^2.0.14 - version: 2.0.14 + specifier: ^2.1.0 + version: 2.1.0 infrastructure/account-data-deleter: dependencies: @@ -1690,8 +1690,8 @@ importers: specifier: 4.1.3 version: 4.1.3(@apollo/server@4.10.4(encoding@0.1.13)(graphql@16.8.1))(graphql@16.8.1) '@apollo/subgraph': - specifier: 2.8.4 - version: 2.8.4(graphql@16.8.1) + specifier: 2.9.0 + version: 2.9.0(graphql@16.8.1) '@apollo/utils.keyvadapter': specifier: 3.1.0 version: 3.1.0 @@ -1764,7 +1764,7 @@ importers: version: link:../tsconfig tsup: specifier: 8.2.4 - version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.17.0)(typescript@5.5.4)(yaml@2.5.0) + version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.19.0)(typescript@5.5.4)(yaml@2.5.0) typescript: specifier: 5.5.4 version: 5.5.4 @@ -1801,7 +1801,7 @@ importers: version: link:../tsconfig tsup: specifier: 8.2.4 - version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.17.0)(typescript@5.5.4)(yaml@2.5.0) + version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.19.0)(typescript@5.5.4)(yaml@2.5.0) typescript: specifier: 5.5.4 version: 5.5.4 @@ -1810,19 +1810,19 @@ importers: dependencies: '@eslint/js': specifier: ^9.7.0 - version: 9.9.0 + version: 9.9.1 eslint: specifier: ^9.7.0 - version: 9.9.0(jiti@1.21.6) + version: 9.9.1(jiti@1.21.6) eslint-config-prettier: specifier: ^9.1.0 - version: 9.1.0(eslint@9.9.0(jiti@1.21.6)) + version: 9.1.0(eslint@9.9.1(jiti@1.21.6)) eslint-plugin-package-json: specifier: ^0.15.2 - version: 0.15.2(eslint@9.9.0(jiti@1.21.6))(jsonc-eslint-parser@2.4.0) + version: 0.15.2(eslint@9.9.1(jiti@1.21.6))(jsonc-eslint-parser@2.4.0) eslint-plugin-prettier: specifier: ^5.2.1 - version: 5.2.1(eslint-config-prettier@9.1.0(eslint@9.9.0(jiti@1.21.6)))(eslint@9.9.0(jiti@1.21.6))(prettier@3.3.3) + version: 5.2.1(eslint-config-prettier@9.1.0(eslint@9.9.1(jiti@1.21.6)))(eslint@9.9.1(jiti@1.21.6))(prettier@3.3.3) jsonc-eslint-parser: specifier: ^2.4.0 version: 2.4.0 @@ -1834,7 +1834,7 @@ importers: version: 5.5.4 typescript-eslint: specifier: ^8.2.0 - version: 8.2.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4) + version: 8.3.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.5.4) packages/feature-flags-client: dependencies: @@ -1871,7 +1871,53 @@ importers: version: link:../tsconfig tsup: specifier: 8.2.4 - version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.17.0)(typescript@5.5.4)(yaml@2.5.0) + version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.19.0)(typescript@5.5.4)(yaml@2.5.0) + typescript: + specifier: 5.5.4 + version: 5.5.4 + + packages/image-utils: + dependencies: + parse-url: + specifier: 9.2.0 + version: 9.2.0 + devDependencies: + '@jest/globals': + specifier: 29.7.0 + version: 29.7.0 + '@pocket-tools/eslint-config': + specifier: workspace:* + version: link:../eslint-config + '@types/jest': + specifier: 29.5.12 + version: 29.5.12 + '@types/node': + specifier: ^20.16 + version: 20.16.1 + jest: + specifier: 29.7.0 + version: 29.7.0(@types/node@20.16.1)(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)) + jest-extended: + specifier: 4.0.2 + version: 4.0.2(jest@29.7.0(@types/node@20.16.1)(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4))) + semantic-release: + specifier: 24.1.0 + version: 24.1.0(typescript@5.5.4) + semantic-release-monorepo: + specifier: 8.0.2 + version: 8.0.2(semantic-release@24.1.0(typescript@5.5.4)) + ts-jest: + specifier: 29.2.4 + version: 29.2.4(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(esbuild@0.23.1)(jest@29.7.0(@types/node@20.16.1)(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)))(typescript@5.5.4) + ts-node: + specifier: 10.9.2 + version: 10.9.2(@types/node@20.16.1)(typescript@5.5.4) + tsconfig: + specifier: workspace:* + version: link:../tsconfig + tsup: + specifier: 8.2.4 + version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.19.0)(typescript@5.5.4)(yaml@2.5.0) typescript: specifier: 5.5.4 version: 5.5.4 @@ -1914,7 +1960,7 @@ importers: version: link:../tsconfig tsup: specifier: 8.2.4 - version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.17.0)(typescript@5.5.4)(yaml@2.5.0) + version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.19.0)(typescript@5.5.4)(yaml@2.5.0) typescript: specifier: 5.5.4 version: 5.5.4 @@ -1960,7 +2006,7 @@ importers: version: link:../tsconfig tsup: specifier: 8.2.4 - version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.17.0)(typescript@5.5.4)(yaml@2.5.0) + version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.19.0)(typescript@5.5.4)(yaml@2.5.0) typescript: specifier: 5.5.4 version: 5.5.4 @@ -2003,7 +2049,7 @@ importers: version: link:../tsconfig tsup: specifier: 8.2.4 - version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.17.0)(typescript@5.5.4)(yaml@2.5.0) + version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.19.0)(typescript@5.5.4)(yaml@2.5.0) typescript: specifier: 5.5.4 version: 5.5.4 @@ -2079,7 +2125,7 @@ importers: version: link:../tsconfig tsup: specifier: 8.2.4 - version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.17.0)(typescript@5.5.4)(yaml@2.5.0) + version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.19.0)(typescript@5.5.4)(yaml@2.5.0) typescript: specifier: 5.5.4 version: 5.5.4 @@ -2197,7 +2243,7 @@ importers: version: link:../tsconfig tsup: specifier: 8.2.4 - version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.17.0)(typescript@5.5.4)(yaml@2.5.0) + version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.19.0)(typescript@5.5.4)(yaml@2.5.0) typescript: specifier: 5.5.4 version: 5.5.4 @@ -2246,7 +2292,7 @@ importers: version: link:../tsconfig tsup: specifier: 8.2.4 - version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.17.0)(typescript@5.5.4)(yaml@2.5.0) + version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.19.0)(typescript@5.5.4)(yaml@2.5.0) typescript: specifier: 5.5.4 version: 5.5.4 @@ -2264,7 +2310,7 @@ importers: version: 2.6.3 tsup: specifier: 8.2.4 - version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.17.0)(typescript@5.5.4)(yaml@2.5.0) + version: 8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.19.0)(typescript@5.5.4)(yaml@2.5.0) typescript: specifier: 5.5.4 version: 5.5.4 @@ -2366,8 +2412,8 @@ importers: specifier: 4.10.4 version: 4.10.4(encoding@0.1.13)(graphql@16.8.1) '@apollo/subgraph': - specifier: 2.8.4 - version: 2.8.4(graphql@16.8.1) + specifier: 2.9.0 + version: 2.9.0(graphql@16.8.1) '@aws-sdk/client-dynamodb': specifier: 3.632.0 version: 3.632.0 @@ -2596,8 +2642,8 @@ importers: specifier: 4.10.4 version: 4.10.4(encoding@0.1.13)(graphql@16.8.1) '@apollo/subgraph': - specifier: 2.8.4 - version: 2.8.4(graphql@16.8.1) + specifier: 2.9.0 + version: 2.9.0(graphql@16.8.1) '@govtechsg/passport-openidconnect': specifier: 1.0.2 version: 1.0.2 @@ -2705,8 +2751,8 @@ importers: specifier: 4.10.4 version: 4.10.4(encoding@0.1.13)(graphql@16.8.1) '@apollo/subgraph': - specifier: 2.8.4 - version: 2.8.4(graphql@16.8.1) + specifier: 2.9.0 + version: 2.9.0(graphql@16.8.1) '@apollo/utils.keyvadapter': specifier: 3.1.0 version: 3.1.0 @@ -2716,6 +2762,9 @@ importers: '@pocket-tools/apollo-utils': specifier: workspace:* version: link:../../packages/apollo-utils + '@pocket-tools/image-utils': + specifier: workspace:* + version: link:../../packages/image-utils '@pocket-tools/sentry': specifier: workspace:* version: link:../../packages/sentry @@ -2746,9 +2795,6 @@ importers: keyv: specifier: 4.5.4 version: 4.5.4 - parse-url: - specifier: 9.2.0 - version: 9.2.0 tslib: specifier: 2.6.3 version: 2.6.3 @@ -2799,8 +2845,8 @@ importers: specifier: 4.10.4 version: 4.10.4(encoding@0.1.13)(graphql@16.8.1) '@apollo/subgraph': - specifier: 2.8.4 - version: 2.8.4(graphql@16.8.1) + specifier: 2.9.0 + version: 2.9.0(graphql@16.8.1) '@aws-sdk/client-eventbridge': specifier: 3.632.0 version: 3.632.0 @@ -2956,8 +3002,8 @@ importers: specifier: 4.10.4 version: 4.10.4(encoding@0.1.13)(graphql@16.8.1) '@apollo/subgraph': - specifier: 2.8.4 - version: 2.8.4(graphql@16.8.1) + specifier: 2.9.0 + version: 2.9.0(graphql@16.8.1) '@apollo/utils.keyvadapter': specifier: 3.1.0 version: 3.1.0 @@ -2982,6 +3028,9 @@ importers: '@pocket-tools/feature-flags-client': specifier: workspace:* version: link:../../packages/feature-flags-client + '@pocket-tools/image-utils': + specifier: workspace:* + version: link:../../packages/image-utils '@pocket-tools/int-mask': specifier: workspace:* version: link:../../packages/int-mask @@ -3033,6 +3082,9 @@ importers: luxon: specifier: 3.4.4 version: 3.4.4 + markdown-to-txt: + specifier: 2.0.1 + version: 2.0.1 md5: specifier: 2.3.0 version: 2.3.0 @@ -3186,8 +3238,8 @@ importers: specifier: 4.1.3 version: 4.1.3(@apollo/server@4.10.4(encoding@0.1.13)(graphql@16.8.1))(graphql@16.8.1) '@apollo/subgraph': - specifier: 2.8.4 - version: 2.8.4(graphql@16.8.1) + specifier: 2.9.0 + version: 2.9.0(graphql@16.8.1) '@apollo/utils.keyvadapter': specifier: 3.1.0 version: 3.1.0 @@ -3377,8 +3429,8 @@ importers: specifier: 4.10.4 version: 4.10.4(encoding@0.1.13)(graphql@16.8.1) '@apollo/subgraph': - specifier: 2.8.4 - version: 2.8.4(graphql@16.8.1) + specifier: 2.9.0 + version: 2.9.0(graphql@16.8.1) '@aws-sdk/client-dynamodb': specifier: 3.632.0 version: 3.632.0 @@ -3486,8 +3538,8 @@ importers: specifier: 4.10.4 version: 4.10.4(encoding@0.1.13)(graphql@16.8.1) '@apollo/subgraph': - specifier: 2.8.4 - version: 2.8.4(graphql@16.8.1) + specifier: 2.9.0 + version: 2.9.0(graphql@16.8.1) '@aws-sdk/client-eventbridge': specifier: 3.632.0 version: 3.632.0 @@ -3583,8 +3635,8 @@ importers: specifier: 4.10.4 version: 4.10.4(encoding@0.1.13)(graphql@16.8.1) '@apollo/subgraph': - specifier: 2.8.4 - version: 2.8.4(graphql@16.8.1) + specifier: 2.9.0 + version: 2.9.0(graphql@16.8.1) '@aws-sdk/client-eventbridge': specifier: 3.632.0 version: 3.632.0 @@ -3876,8 +3928,8 @@ packages: peerDependencies: graphql: ^16.5.0 - '@apollo/federation-internals@2.8.4': - resolution: {integrity: sha512-m/vFu5btNfmvxZfe8B1m8jjCN/NxCYctxjdhXgQD4WGbDwtUk59+i7NuVMtX5IfmFMKycwqnbihkv5w2E00XDA==} + '@apollo/federation-internals@2.9.0': + resolution: {integrity: sha512-zvz0nJpfblxAWzphlFtyqUswidIWOf7Vcj4YuPaUlXpOG7VZ0fWyTupPQsj0HeTkAAy3FzCItVHLzn4+I2H/YA==} engines: {node: '>=14.15.0'} peerDependencies: graphql: ^16.5.0 @@ -3904,8 +3956,8 @@ packages: peerDependencies: graphql: ^16.6.0 - '@apollo/subgraph@2.8.4': - resolution: {integrity: sha512-+NMhY2PHrb1C28A3Osns98HWCQ5nlhYv0CSpdSkzY2OOdepaBnzC6btXKZB8J61FaMBmEgL+j2/5uAXJGmS1cQ==} + '@apollo/subgraph@2.9.0': + resolution: {integrity: sha512-FYAOMxMWbAQ/2U/+QYgznBdsyjPiH87wSSJqn6n1dQ80GWIWenZYd49iWy9/y/Z/RTYsA2o8ueAkgHH6AU4psA==} engines: {node: '>=14.15.0'} peerDependencies: graphql: ^16.5.0 @@ -4208,8 +4260,8 @@ packages: resolution: {integrity: sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.25.4': - resolution: {integrity: sha512-NFtZmZsyzDPJnk9Zg3BbTfKKc9UlHYzD0E//p2Z3B9nCwwtJW9T0gVbCz8+fBngnn4zf1Dr3IK8PHQQHq0lDQw==} + '@babel/generator@7.25.5': + resolution: {integrity: sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w==} engines: {node: '>=6.9.0'} '@babel/helper-annotate-as-pure@7.24.7': @@ -4908,16 +4960,16 @@ packages: resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.17.1': - resolution: {integrity: sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==} + '@eslint/config-array@0.18.0': + resolution: {integrity: sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/eslintrc@3.1.0': resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.9.0': - resolution: {integrity: sha512-hhetes6ZHP3BlXLxmd8K2SNgkhNSi+UcecbnwWKwpP7kyi/uC75DJ1lOOBO3xrC4jyojtGE3YxKZPHfk4yrgug==} + '@eslint/js@9.9.1': + resolution: {integrity: sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.4': @@ -5078,8 +5130,8 @@ packages: peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/delegate@10.0.19': - resolution: {integrity: sha512-y4spKkLnngkr+dCatYvqFtq3zumbnyvpMkP5W2Ooy5DnTEUeiPJQ0h5uqi3EHPEDFC+Rs/opvBdOwFOkMObmXg==} + '@graphql-tools/delegate@10.0.21': + resolution: {integrity: sha512-UytyYVvDfLQbCYG1aQo8Vc67c1WhEjzW9ytYKEEqMJSdlwfMCujHmCz7EyH5DNjTAKapDHuQcN5VivKGap/Beg==} engines: {node: '>=16.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 @@ -6016,93 +6068,93 @@ packages: '@redocly/ajv@8.11.0': resolution: {integrity: sha512-9GWx27t7xWhDIR02PA18nzBdLcKQRgc46xNQvjFkrYk4UOmvKhJ/dawwiX0cCOeetN5LcaaiqQbVOWYK62SGHw==} - '@redocly/config@0.9.0': - resolution: {integrity: sha512-rRd0pSiPC68AQGud2VbrHqUov1VHospfcYE2pFYmGYfZhzZfHBSiVaeiTY+CZmrhf5RB9aVdOHRCm25Vb6GFkQ==} + '@redocly/config@0.10.0': + resolution: {integrity: sha512-oFP8SL9qmsJ2QxwvOjI/h87hHMKq8G/RUbTSxF9/r4vbllCxzQ8Tla3xfUO/lGVVO6gZsAIsuJGXhaDagd4msg==} - '@redocly/openapi-core@1.20.1': - resolution: {integrity: sha512-ZbIJRelAAkXuOnKgEyAuzS2Th24ZY4qnJY62ddbAaAn6NworI6BrnoMq/MqkilQWBKhbVTy/XeXc9jWDXLwkRA==} + '@redocly/openapi-core@1.21.1': + resolution: {integrity: sha512-WTsie5b+Ohx2NsmEBVCS5WF24h4XqDpb834ZR4EeE7f+Zjwn34AgaC78HP2xGydi+gFfD4PiqDGgnDPtR5s1OA==} engines: {node: '>=14.19.0', npm: '>=7.0.0'} '@repeaterjs/repeater@3.0.6': resolution: {integrity: sha512-Javneu5lsuhwNCryN+pXH93VPQ8g0dBX7wItHFgYiwQmzE1sVdg5tWHiOgHywzL2W21XQopa7IwIEnNbmeUJYA==} - '@rollup/rollup-android-arm-eabi@4.21.0': - resolution: {integrity: sha512-WTWD8PfoSAJ+qL87lE7votj3syLavxunWhzCnx3XFxFiI/BA/r3X7MUM8dVrH8rb2r4AiO8jJsr3ZjdaftmnfA==} + '@rollup/rollup-android-arm-eabi@4.21.1': + resolution: {integrity: sha512-2thheikVEuU7ZxFXubPDOtspKn1x0yqaYQwvALVtEcvFhMifPADBrgRPyHV0TF3b+9BgvgjgagVyvA/UqPZHmg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.21.0': - resolution: {integrity: sha512-a1sR2zSK1B4eYkiZu17ZUZhmUQcKjk2/j9Me2IDjk1GHW7LB5Z35LEzj9iJch6gtUfsnvZs1ZNyDW2oZSThrkA==} + '@rollup/rollup-android-arm64@4.21.1': + resolution: {integrity: sha512-t1lLYn4V9WgnIFHXy1d2Di/7gyzBWS8G5pQSXdZqfrdCGTwi1VasRMSS81DTYb+avDs/Zz4A6dzERki5oRYz1g==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.21.0': - resolution: {integrity: sha512-zOnKWLgDld/svhKO5PD9ozmL6roy5OQ5T4ThvdYZLpiOhEGY+dp2NwUmxK0Ld91LrbjrvtNAE0ERBwjqhZTRAA==} + '@rollup/rollup-darwin-arm64@4.21.1': + resolution: {integrity: sha512-AH/wNWSEEHvs6t4iJ3RANxW5ZCK3fUnmf0gyMxWCesY1AlUj8jY7GC+rQE4wd3gwmZ9XDOpL0kcFnCjtN7FXlA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.21.0': - resolution: {integrity: sha512-7doS8br0xAkg48SKE2QNtMSFPFUlRdw9+votl27MvT46vo44ATBmdZdGysOevNELmZlfd+NEa0UYOA8f01WSrg==} + '@rollup/rollup-darwin-x64@4.21.1': + resolution: {integrity: sha512-dO0BIz/+5ZdkLZrVgQrDdW7m2RkrLwYTh2YMFG9IpBtlC1x1NPNSXkfczhZieOlOLEqgXOFH3wYHB7PmBtf+Bg==} cpu: [x64] os: [darwin] - '@rollup/rollup-linux-arm-gnueabihf@4.21.0': - resolution: {integrity: sha512-pWJsfQjNWNGsoCq53KjMtwdJDmh/6NubwQcz52aEwLEuvx08bzcy6tOUuawAOncPnxz/3siRtd8hiQ32G1y8VA==} + '@rollup/rollup-linux-arm-gnueabihf@4.21.1': + resolution: {integrity: sha512-sWWgdQ1fq+XKrlda8PsMCfut8caFwZBmhYeoehJ05FdI0YZXk6ZyUjWLrIgbR/VgiGycrFKMMgp7eJ69HOF2pQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.21.0': - resolution: {integrity: sha512-efRIANsz3UHZrnZXuEvxS9LoCOWMGD1rweciD6uJQIx2myN3a8Im1FafZBzh7zk1RJ6oKcR16dU3UPldaKd83w==} + '@rollup/rollup-linux-arm-musleabihf@4.21.1': + resolution: {integrity: sha512-9OIiSuj5EsYQlmwhmFRA0LRO0dRRjdCVZA3hnmZe1rEwRk11Jy3ECGGq3a7RrVEZ0/pCsYWx8jG3IvcrJ6RCew==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.21.0': - resolution: {integrity: sha512-ZrPhydkTVhyeGTW94WJ8pnl1uroqVHM3j3hjdquwAcWnmivjAwOYjTEAuEDeJvGX7xv3Z9GAvrBkEzCgHq9U1w==} + '@rollup/rollup-linux-arm64-gnu@4.21.1': + resolution: {integrity: sha512-0kuAkRK4MeIUbzQYu63NrJmfoUVicajoRAL1bpwdYIYRcs57iyIV9NLcuyDyDXE2GiZCL4uhKSYAnyWpjZkWow==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.21.0': - resolution: {integrity: sha512-cfaupqd+UEFeURmqNP2eEvXqgbSox/LHOyN9/d2pSdV8xTrjdg3NgOFJCtc1vQ/jEke1qD0IejbBfxleBPHnPw==} + '@rollup/rollup-linux-arm64-musl@4.21.1': + resolution: {integrity: sha512-/6dYC9fZtfEY0vozpc5bx1RP4VrtEOhNQGb0HwvYNwXD1BBbwQ5cKIbUVVU7G2d5WRE90NfB922elN8ASXAJEA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.21.0': - resolution: {integrity: sha512-ZKPan1/RvAhrUylwBXC9t7B2hXdpb/ufeu22pG2psV7RN8roOfGurEghw1ySmX/CmDDHNTDDjY3lo9hRlgtaHg==} + '@rollup/rollup-linux-powerpc64le-gnu@4.21.1': + resolution: {integrity: sha512-ltUWy+sHeAh3YZ91NUsV4Xg3uBXAlscQe8ZOXRCVAKLsivGuJsrkawYPUEyCV3DYa9urgJugMLn8Z3Z/6CeyRQ==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.21.0': - resolution: {integrity: sha512-H1eRaCwd5E8eS8leiS+o/NqMdljkcb1d6r2h4fKSsCXQilLKArq6WS7XBLDu80Yz+nMqHVFDquwcVrQmGr28rg==} + '@rollup/rollup-linux-riscv64-gnu@4.21.1': + resolution: {integrity: sha512-BggMndzI7Tlv4/abrgLwa/dxNEMn2gC61DCLrTzw8LkpSKel4o+O+gtjbnkevZ18SKkeN3ihRGPuBxjaetWzWg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.21.0': - resolution: {integrity: sha512-zJ4hA+3b5tu8u7L58CCSI0A9N1vkfwPhWd/puGXwtZlsB5bTkwDNW/+JCU84+3QYmKpLi+XvHdmrlwUwDA6kqw==} + '@rollup/rollup-linux-s390x-gnu@4.21.1': + resolution: {integrity: sha512-z/9rtlGd/OMv+gb1mNSjElasMf9yXusAxnRDrBaYB+eS1shFm6/4/xDH1SAISO5729fFKUkJ88TkGPRUh8WSAA==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.21.0': - resolution: {integrity: sha512-e2hrvElFIh6kW/UNBQK/kzqMNY5mO+67YtEh9OA65RM5IJXYTWiXjX6fjIiPaqOkBthYF1EqgiZ6OXKcQsM0hg==} + '@rollup/rollup-linux-x64-gnu@4.21.1': + resolution: {integrity: sha512-kXQVcWqDcDKw0S2E0TmhlTLlUgAmMVqPrJZR+KpH/1ZaZhLSl23GZpQVmawBQGVhyP5WXIsIQ/zqbDBBYmxm5w==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.21.0': - resolution: {integrity: sha512-1vvmgDdUSebVGXWX2lIcgRebqfQSff0hMEkLJyakQ9JQUbLDkEaMsPTLOmyccyC6IJ/l3FZuJbmrBw/u0A0uCQ==} + '@rollup/rollup-linux-x64-musl@4.21.1': + resolution: {integrity: sha512-CbFv/WMQsSdl+bpX6rVbzR4kAjSSBuDgCqb1l4J68UYsQNalz5wOqLGYj4ZI0thGpyX5kc+LLZ9CL+kpqDovZA==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.21.0': - resolution: {integrity: sha512-s5oFkZ/hFcrlAyBTONFY1TWndfyre1wOMwU+6KCpm/iatybvrRgmZVM+vCFwxmC5ZhdlgfE0N4XorsDpi7/4XQ==} + '@rollup/rollup-win32-arm64-msvc@4.21.1': + resolution: {integrity: sha512-3Q3brDgA86gHXWHklrwdREKIrIbxC0ZgU8lwpj0eEKGBQH+31uPqr0P2v11pn0tSIxHvcdOWxa4j+YvLNx1i6g==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.21.0': - resolution: {integrity: sha512-G9+TEqRnAA6nbpqyUqgTiopmnfgnMkR3kMukFBDsiyy23LZvUCpiUwjTRx6ezYCjJODXrh52rBR9oXvm+Fp5wg==} + '@rollup/rollup-win32-ia32-msvc@4.21.1': + resolution: {integrity: sha512-tNg+jJcKR3Uwe4L0/wY3Ro0H+u3nrb04+tcq1GSYzBEmKLeOQF2emk1whxlzNqb6MMrQ2JOcQEpuuiPLyRcSIw==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.21.0': - resolution: {integrity: sha512-2jsCDZwtQvRhejHLfZ1JY6w6kEuEtfF9nzYsZxzSlNVKDX+DpsDJ+Rbjkm74nvg2rdx0gwBS+IMdvwJuq3S9pQ==} + '@rollup/rollup-win32-x64-msvc@4.21.1': + resolution: {integrity: sha512-xGiIH95H1zU7naUyTKEyOA/I0aexNMUdO9qRv0bLKN3qu25bBdrxZHqA3PTJ24YNN/GdMzG4xkDcd/GvjuhfLg==} cpu: [x64] os: [win32] @@ -6729,8 +6781,8 @@ packages: '@types/stylis@4.2.5': resolution: {integrity: sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==} - '@types/superagent@8.1.8': - resolution: {integrity: sha512-nTqHJ2OTa7PFEpLahzSEEeFeqbMpmcN7OeayiOc7v+xk+/vyTKljRe+o4MPqSnPeRCMvtxuLG+5QqluUVQJOnA==} + '@types/superagent@8.1.9': + resolution: {integrity: sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==} '@types/supertest@6.0.2': resolution: {integrity: sha512-137ypx2lk/wTQbW6An6safu9hXmajAifU/s7szAHLN/FeIm5w7yR0Wkl9fdJMRSHwOn4HLAI0DaB2TOORuhPDg==} @@ -6765,8 +6817,8 @@ packages: '@types/yoga-layout@1.9.2': resolution: {integrity: sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw==} - '@typescript-eslint/eslint-plugin@8.2.0': - resolution: {integrity: sha512-02tJIs655em7fvt9gps/+4k4OsKULYGtLBPJfOsmOq1+3cdClYiF0+d6mHu6qDnTcg88wJBkcPLpQhq7FyDz0A==} + '@typescript-eslint/eslint-plugin@8.3.0': + resolution: {integrity: sha512-FLAIn63G5KH+adZosDYiutqkOkYEx0nvcwNNfJAf+c7Ae/H35qWwTYvPZUKFj5AS+WfHG/WJJfWnDnyNUlp8UA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 @@ -6776,8 +6828,8 @@ packages: typescript: optional: true - '@typescript-eslint/parser@8.2.0': - resolution: {integrity: sha512-j3Di+o0lHgPrb7FxL3fdEy6LJ/j2NE8u+AP/5cQ9SKb+JLH6V6UHDqJ+e0hXBkHP1wn1YDFjYCS9LBQsZDlDEg==} + '@typescript-eslint/parser@8.3.0': + resolution: {integrity: sha512-h53RhVyLu6AtpUzVCYLPhZGL5jzTD9fZL+SYf/+hYOx2bDkyQXztXSc4tbvKYHzfMXExMLiL9CWqJmVz6+78IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -6786,12 +6838,12 @@ packages: typescript: optional: true - '@typescript-eslint/scope-manager@8.2.0': - resolution: {integrity: sha512-OFn80B38yD6WwpoHU2Tz/fTz7CgFqInllBoC3WP+/jLbTb4gGPTy9HBSTsbDWkMdN55XlVU0mMDYAtgvlUspGw==} + '@typescript-eslint/scope-manager@8.3.0': + resolution: {integrity: sha512-mz2X8WcN2nVu5Hodku+IR8GgCOl4C0G/Z1ruaWN4dgec64kDBabuXyPAr+/RgJtumv8EEkqIzf3X2U5DUKB2eg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@8.2.0': - resolution: {integrity: sha512-g1CfXGFMQdT5S+0PSO0fvGXUaiSkl73U1n9LTK5aRAFnPlJ8dLKkXr4AaLFvPedW8lVDoMgLLE3JN98ZZfsj0w==} + '@typescript-eslint/type-utils@8.3.0': + resolution: {integrity: sha512-wrV6qh//nLbfXZQoj32EXKmwHf4b7L+xXLrP3FZ0GOUU72gSvLjeWUl5J5Ue5IwRxIV1TfF73j/eaBapxx99Lg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' @@ -6799,12 +6851,12 @@ packages: typescript: optional: true - '@typescript-eslint/types@8.2.0': - resolution: {integrity: sha512-6a9QSK396YqmiBKPkJtxsgZZZVjYQ6wQ/TlI0C65z7vInaETuC6HAHD98AGLC8DyIPqHytvNuS8bBVvNLKyqvQ==} + '@typescript-eslint/types@8.3.0': + resolution: {integrity: sha512-y6sSEeK+facMaAyixM36dQ5NVXTnKWunfD1Ft4xraYqxP0lC0POJmIaL/mw72CUMqjY9qfyVfXafMeaUj0noWw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.2.0': - resolution: {integrity: sha512-kiG4EDUT4dImplOsbh47B1QnNmXSoUqOjWDvCJw/o8LgfD0yr7k2uy54D5Wm0j4t71Ge1NkynGhpWdS0dEIAUA==} + '@typescript-eslint/typescript-estree@8.3.0': + resolution: {integrity: sha512-Mq7FTHl0R36EmWlCJWojIC1qn/ZWo2YiWYc1XVtasJ7FIgjo0MVv9rZWXEE7IK2CGrtwe1dVOxWwqXUdNgfRCA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' @@ -6812,14 +6864,14 @@ packages: typescript: optional: true - '@typescript-eslint/utils@8.2.0': - resolution: {integrity: sha512-O46eaYKDlV3TvAVDNcoDzd5N550ckSe8G4phko++OCSC1dYIb9LTc3HDGYdWqWIAT5qDUKphO6sd9RrpIJJPfg==} + '@typescript-eslint/utils@8.3.0': + resolution: {integrity: sha512-F77WwqxIi/qGkIGOGXNBLV7nykwfjLsdauRB/DOFPdv6LTF3BHHkBpq81/b5iMPSF055oO2BiivDJV4ChvNtXA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - '@typescript-eslint/visitor-keys@8.2.0': - resolution: {integrity: sha512-sbgsPMW9yLvS7IhCi8IpuK1oBmtbWUNP+hBdwl/I9nzqVsszGnNGti5r9dUtF5RLivHUFFIdRvLiTsPhzSyJ3Q==} + '@typescript-eslint/visitor-keys@8.3.0': + resolution: {integrity: sha512-RmZwrTbQ9QveF15m/Cl28n0LXD6ea2CjkhH5rQ55ewz3H24w+AMCJHPVYaZ8/0HoG8Z3cLLFFycRXxeO2tz9FA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@wesleytodd/openapi@0.3.0': @@ -7114,8 +7166,8 @@ packages: resolution: {integrity: sha512-9GNFMRrEMG5y3Jvv+V4azWvc+qNWdWLTjDdhf/zgMlz8haaaLWv0xeAIWxz9PuWUBawsVxy0zZotjCdR3Xq+2w==} hasBin: true - aws-sdk@2.1681.0: - resolution: {integrity: sha512-oeCr0muJraT+g7ceTMlJcidVayPMfT69EEvDIWMbeBIHqbLOJVtpsF577VZJNEh2Zkj+8DivR69kWdu+Y9JSyQ==} + aws-sdk@2.1683.0: + resolution: {integrity: sha512-uy53mN2oHU0Jx5tkH7qG6h/42DeMAQD5jMi/6294hVgGCa29MK/ZiFIOdkEJNS9tbB03RTabg+5i4c6DxBpG8g==} engines: {node: '>= 10.0.0'} aws-ssl-profiles@1.1.1: @@ -7330,8 +7382,8 @@ packages: camelize@1.0.1: resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} - caniuse-lite@1.0.30001651: - resolution: {integrity: sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==} + caniuse-lite@1.0.30001653: + resolution: {integrity: sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==} capital-case@1.0.4: resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} @@ -7430,8 +7482,8 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} - cjs-module-lexer@1.3.1: - resolution: {integrity: sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==} + cjs-module-lexer@1.4.0: + resolution: {integrity: sha512-N1NGmowPlGBLsOZLPvm48StN04V4YvQRL0i6b7ctrVY3epjP/ct7hFLOItz6pDIvRjwpfPxi52a2UWV2ziir8g==} classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} @@ -8175,8 +8227,8 @@ packages: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} engines: {node: '>=12'} - emoji-regex@10.3.0: - resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} + emoji-regex@10.4.0: + resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -8218,8 +8270,8 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} - env-ci@11.0.0: - resolution: {integrity: sha512-apikxMgkipkgTvMdRT9MNqWx5VLOci79F4VBd7Op/7OPjjoanjdAvn6fglMCCEf/1bAh8eOiuEVCUs4V3qP3nQ==} + env-ci@11.1.0: + resolution: {integrity: sha512-Z8dnwSDbV1XYM9SBF2J0GcNVvmfmfh3a49qddGIROhBoVro6MZVTji15z/sJbQ2ko2ei8n988EU1wzoLU/tF+g==} engines: {node: ^18.17 || >=20.6.1} env-paths@2.2.1: @@ -8363,8 +8415,8 @@ packages: resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.9.0: - resolution: {integrity: sha512-JfiKJrbx0506OEerjK2Y1QlldtBxkAlLxT5OEcRF8uaQ86noDe2k31Vw9rnSWv+MXZHj7OOUV/dA0AhdLFcyvA==} + eslint@9.9.1: + resolution: {integrity: sha512-dHvhrbfr4xFQ9/dq+jcVneZMyRYLjggWjk6RVsIiHsP8Rz6yZ8LvZ//iU4TrZF+SXWG+JkNF2OyiZRvzgRDqMg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -9848,8 +9900,8 @@ packages: jose@4.15.9: resolution: {integrity: sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==} - jose@5.7.0: - resolution: {integrity: sha512-3P9qfTYDVnNn642LCAqIKbTGb9a1TBxZ9ti5zEVEr48aDdflgRjhspWFb6WM4PzAfFbGMJYC4+803v8riCRAKw==} + jose@5.8.0: + resolution: {integrity: sha512-E7CqYpL/t7MMnfGnK/eg416OsFCVUrU/Y3Vwe7QjKhu/BkS1Ms455+2xsqZQVN57/U2MHMBvEb5SrmAZWAIntA==} joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} @@ -10303,6 +10355,9 @@ packages: lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + lodash.unescape@4.0.1: + resolution: {integrity: sha512-DhhGRshNS1aX6s5YdBE3njCCouPgnG29ebyHvImlZzXZf2SHgt+J08DHgytTPnpywNbO1Y8mNUFyQuIDBq2JZg==} + lodash.union@4.6.0: resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} @@ -10426,6 +10481,9 @@ packages: mark.js@8.11.1: resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==} + markdown-to-txt@2.0.1: + resolution: {integrity: sha512-Hsj7KTN8k1gutlLum3vosHwVZGnv8/cbYKWVkUyo/D1rzOYddbDesILebRfOsaVfjIBJank/AVOySBlHAYqfZw==} + marked-terminal@7.1.0: resolution: {integrity: sha512-+pvwa14KZL74MVXjYdPR3nSInhGhNvPce/3mqLVZT2oUvt654sL1XImFuLZ1pkA866IYZ3ikDTOFUIC7XzpZZg==} engines: {node: '>=16.0.0'} @@ -10491,8 +10549,8 @@ packages: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} - micromatch@4.0.7: - resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} mime-db@1.52.0: @@ -11926,8 +11984,8 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - rollup@4.21.0: - resolution: {integrity: sha512-vo+S/lfA2lMS7rZ2Qoubi6I5hwZwzXeUIctILZLbHI+laNtvhhOIon2S1JksA5UEDQ7l3vberd0fxK44lTYjbQ==} + rollup@4.21.1: + resolution: {integrity: sha512-ZnYyKvscThhgd3M5+Qt3pmhO4jIRR5RGzaSovB6Q7rGNrK5cUncrtLmcTTJVSdcKXyZjW8X8MB0JMSuH9bcAJg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -11969,8 +12027,8 @@ packages: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} - safe-stable-stringify@2.4.3: - resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} engines: {node: '>=10'} safer-buffer@2.1.2: @@ -12761,8 +12819,8 @@ packages: typescript: optional: true - tsx@4.17.0: - resolution: {integrity: sha512-eN4mnDA5UMKDt4YZixo9tBioibaMBpoxBkD+rIPAjVmYERSG0/dWEY1CEFuV89CgASlKL499q8AhmkMnnjtOJg==} + tsx@4.19.0: + resolution: {integrity: sha512-bV30kM7bsLZKZIOCHeMNVMJ32/LuJzLVajkQI/qf92J2Qr08ueLQvW00PUZGiuLPP760UINwupgUj8qrSCPUKg==} engines: {node: '>=18.0.0'} hasBin: true @@ -12772,38 +12830,38 @@ packages: tunnel-ssh@4.1.6: resolution: {integrity: sha512-y7+x+T3F3rkx2Zov5Tk9DGfeEBVAdWU3A/91E0Dk5rrZ/VFIlpV2uhhRuaISJUdyG0N+Lcp1fXZMXz+ovPt5vA==} - turbo-darwin-64@2.0.14: - resolution: {integrity: sha512-kwfDmjNwlNfvtrvT29+ZBg5n1Wvxl891bFHchMJyzMoR0HOE9N1NSNdSZb9wG3e7sYNIu4uDkNk+VBEqJW0HzQ==} + turbo-darwin-64@2.1.0: + resolution: {integrity: sha512-gHwpDk2gyB7qZ57gUUwDIS/IkglqEjjVtPZCTxmCRg28Tiwjui0azsLVKrnHP9UZHllozwbi28x8HXLXLEFF1w==} cpu: [x64] os: [darwin] - turbo-darwin-arm64@2.0.14: - resolution: {integrity: sha512-m3LXYEshCx3wc4ZClM6gb01KYpFmtjQ9IBF3A7ofjb6ahux3xlYZJZ3uFCLAGHuvGLuJ3htfiPbwlDPTdknqqw==} + turbo-darwin-arm64@2.1.0: + resolution: {integrity: sha512-GLaqGetNC6eS4eqXgsheLOHic/OcnGCGDi5boVf+TFZTXYH6YE15L4ugZha4xHXCr1KouCLILHh+f8EHEmWylg==} cpu: [arm64] os: [darwin] - turbo-linux-64@2.0.14: - resolution: {integrity: sha512-7vBzCPdoTtR92SNn2JMgj1FlMmyonGmpMaQdgAB1OVYtuQ6NVGoh7/lODfaILqXjpvmFSVbpBIDrKOT6EvcprQ==} + turbo-linux-64@2.1.0: + resolution: {integrity: sha512-VzBOsj7JyGoZtiNZZ6brjnY7UehRnClluw7pwznuLPzClkqOOPMd2jOcgkWxnP/xW4NBmOoFANXXrtvKBD4f2w==} cpu: [x64] os: [linux] - turbo-linux-arm64@2.0.14: - resolution: {integrity: sha512-jwH+c0bfjpBf26K/tdEFatmnYyXwGROjbr6bZmNcL8R+IkGAc/cglL+OToqJnQZTgZvH7uDGbeSyUo7IsHyjuA==} + turbo-linux-arm64@2.1.0: + resolution: {integrity: sha512-St7svJnOO5g4F6R7Z32e10I/0M3e6qpNjEYybXwPNul9NSfnUXeky4WoKaALwqNhyJ7nYemoFpZ1d+i8hFQTHg==} cpu: [arm64] os: [linux] - turbo-windows-64@2.0.14: - resolution: {integrity: sha512-w9/XwkHSzvLjmioo6cl3S1yRfI6swxsV1j1eJwtl66JM4/pn0H2rBa855R0n7hZnmI6H5ywLt/nLt6Ae8RTDmw==} + turbo-windows-64@2.1.0: + resolution: {integrity: sha512-iSobNud2MrJ1SZ1upVPlErT8xexsr0MQtKapdfq6z0M0rBnrDGEq5bUCSScWyGu+O4+glB4br9xkTAkGFqaxqQ==} cpu: [x64] os: [win32] - turbo-windows-arm64@2.0.14: - resolution: {integrity: sha512-XaQlyYk+Rf4xS5XWCo8XCMIpssgGGy8blzLfolN6YBp4baElIWMlkLZHDbGyiFmCbNf9I9gJI64XGRG+LVyyjA==} + turbo-windows-arm64@2.1.0: + resolution: {integrity: sha512-d61jN4rjE5PnUfF66GKrKoj8S8Ql4FGXzFFzZz4kjsHpZZzCTtqlzPZBmd1byzGYhDPTorTqG3G1USohbdyohA==} cpu: [arm64] os: [win32] - turbo@2.0.14: - resolution: {integrity: sha512-00JjdCMD/cpsjP0Izkjcm8Oaor5yUCfDwODtaLb+WyblyadkaDEisGhy3Dbd5az9n+5iLSPiUgf+WjPbns6MRg==} + turbo@2.1.0: + resolution: {integrity: sha512-A969/LO/sPHKlapIarY2VVzqQ5JnnW2/1kksZlnMEpsRD6gwOELvVL+ozfMiO7av9RILt3UeN02L17efr6HUCA==} hasBin: true turndown@7.2.0: @@ -12878,8 +12936,8 @@ packages: typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typescript-eslint@8.2.0: - resolution: {integrity: sha512-DmnqaPcML0xYwUzgNbM1XaKXpEb7BShYf2P1tkUmmcl8hyeG7Pj08Er7R9bNy6AufabywzJcOybQAtnD/c9DGw==} + typescript-eslint@8.3.0: + resolution: {integrity: sha512-EvWjwWLwwKDIJuBjk2I6UkV8KEQcwZ0VM10nR1rIunRDIP67QJTZAHBXTX0HW/oI1H10YESF8yWie8fRQxjvFA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' @@ -12897,8 +12955,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - typescript@5.7.0-dev.20240827: - resolution: {integrity: sha512-qNwNQBg18O4Z5RRGb07O562OpDlAVlytNcKfqcx8JQRJcs3p/KLHXjr0FbUbJ3SKoxA2vaQ3Zt89YLWHuCXzUw==} + typescript@5.7.0-dev.20240828: + resolution: {integrity: sha512-ErCxPl/V/LAmiULX17il/1qONClDF5dKH3A7ltOVj6Rsj+fSSXYiimnDAZShs7iFfMpo87oWv97hjkX7sG1edg==} engines: {node: '>=14.17'} hasBin: true @@ -13428,7 +13486,7 @@ snapshots: transitivePeerDependencies: - encoding - '@apollo/federation-internals@2.8.4(graphql@16.8.1)': + '@apollo/federation-internals@2.9.0(graphql@16.8.1)': dependencies: '@types/uuid': 9.0.8 chalk: 4.1.2 @@ -13498,10 +13556,10 @@ snapshots: - encoding - supports-color - '@apollo/subgraph@2.8.4(graphql@16.8.1)': + '@apollo/subgraph@2.9.0(graphql@16.8.1)': dependencies: '@apollo/cache-control-types': 1.0.3(graphql@16.8.1) - '@apollo/federation-internals': 2.8.4(graphql@16.8.1) + '@apollo/federation-internals': 2.9.0(graphql@16.8.1) graphql: 16.8.1 '@apollo/usage-reporting-protobuf@4.1.1': @@ -13577,7 +13635,7 @@ snapshots: '@ardatan/relay-compiler@12.0.0(encoding@0.1.13)(graphql@16.8.1)': dependencies: '@babel/core': 7.25.2 - '@babel/generator': 7.25.4 + '@babel/generator': 7.25.5 '@babel/parser': 7.25.4 '@babel/runtime': 7.25.4 '@babel/traverse': 7.25.4 @@ -14455,7 +14513,7 @@ snapshots: dependencies: '@ampproject/remapping': 2.3.0 '@babel/code-frame': 7.24.7 - '@babel/generator': 7.25.4 + '@babel/generator': 7.25.5 '@babel/helper-compilation-targets': 7.25.2 '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2) '@babel/helpers': 7.25.0 @@ -14473,12 +14531,12 @@ snapshots: '@babel/generator@7.24.7': dependencies: - '@babel/types': 7.24.7 + '@babel/types': 7.25.4 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 - '@babel/generator@7.25.4': + '@babel/generator@7.25.5': dependencies: '@babel/types': 7.25.4 '@jridgewell/gen-mapping': 0.3.5 @@ -14837,7 +14895,7 @@ snapshots: dependencies: '@babel/code-frame': 7.24.7 '@babel/parser': 7.25.4 - '@babel/types': 7.24.7 + '@babel/types': 7.25.4 '@babel/template@7.25.0': dependencies: @@ -14848,7 +14906,7 @@ snapshots: '@babel/traverse@7.25.4': dependencies: '@babel/code-frame': 7.24.7 - '@babel/generator': 7.25.4 + '@babel/generator': 7.25.5 '@babel/parser': 7.25.4 '@babel/template': 7.25.0 '@babel/types': 7.25.4 @@ -15078,11 +15136,11 @@ snapshots: dependencies: commander: 12.1.0 - '@commitlint/cli@19.4.0(@types/node@22.5.0)(typescript@5.7.0-dev.20240827)': + '@commitlint/cli@19.4.0(@types/node@22.5.0)(typescript@5.7.0-dev.20240828)': dependencies: '@commitlint/format': 19.3.0 '@commitlint/lint': 19.2.2 - '@commitlint/load': 19.4.0(@types/node@22.5.0)(typescript@5.7.0-dev.20240827) + '@commitlint/load': 19.4.0(@types/node@22.5.0)(typescript@5.7.0-dev.20240828) '@commitlint/read': 19.4.0 '@commitlint/types': 19.0.3 execa: 8.0.1 @@ -15129,15 +15187,15 @@ snapshots: '@commitlint/rules': 19.0.3 '@commitlint/types': 19.0.3 - '@commitlint/load@19.4.0(@types/node@22.5.0)(typescript@5.7.0-dev.20240827)': + '@commitlint/load@19.4.0(@types/node@22.5.0)(typescript@5.7.0-dev.20240828)': dependencies: '@commitlint/config-validator': 19.0.3 '@commitlint/execute-rule': 19.0.0 '@commitlint/resolve-extends': 19.1.0 '@commitlint/types': 19.0.3 chalk: 5.3.0 - cosmiconfig: 9.0.0(typescript@5.7.0-dev.20240827) - cosmiconfig-typescript-loader: 5.0.0(@types/node@22.5.0)(cosmiconfig@9.0.0(typescript@5.7.0-dev.20240827))(typescript@5.7.0-dev.20240827) + cosmiconfig: 9.0.0(typescript@5.7.0-dev.20240828) + cosmiconfig-typescript-loader: 5.0.0(@types/node@22.5.0)(cosmiconfig@9.0.0(typescript@5.7.0-dev.20240828))(typescript@5.7.0-dev.20240828) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 @@ -15303,14 +15361,14 @@ snapshots: '@esbuild/win32-x64@0.23.1': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@9.9.0(jiti@1.21.6))': + '@eslint-community/eslint-utils@4.4.0(eslint@9.9.1(jiti@1.21.6))': dependencies: - eslint: 9.9.0(jiti@1.21.6) + eslint: 9.9.1(jiti@1.21.6) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.11.0': {} - '@eslint/config-array@0.17.1': + '@eslint/config-array@0.18.0': dependencies: '@eslint/object-schema': 2.1.4 debug: 4.3.6(supports-color@5.5.0) @@ -15332,7 +15390,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.9.0': {} + '@eslint/js@9.9.1': {} '@eslint/object-schema@2.1.4': {} @@ -15455,7 +15513,7 @@ snapshots: '@graphql-codegen/cli@5.0.2(@parcel/watcher@2.4.1)(@types/node@20.16.1)(encoding@0.1.13)(enquirer@2.4.1)(graphql@16.8.1)(typescript@5.5.4)': dependencies: - '@babel/generator': 7.25.4 + '@babel/generator': 7.25.5 '@babel/template': 7.25.0 '@babel/types': 7.25.4 '@graphql-codegen/client-preset': 4.3.3(encoding@0.1.13)(graphql@16.8.1) @@ -15484,7 +15542,7 @@ snapshots: json-to-pretty-yaml: 1.2.2 listr2: 4.0.5(enquirer@2.4.1) log-symbols: 4.1.0 - micromatch: 4.0.7 + micromatch: 4.0.8 shell-quote: 1.8.1 string-env-interpolation: 1.0.1 ts-log: 2.2.5 @@ -15655,7 +15713,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@graphql-tools/delegate@10.0.19(graphql@16.8.1)': + '@graphql-tools/delegate@10.0.21(graphql@16.8.1)': dependencies: '@graphql-tools/batch-execute': 9.0.4(graphql@16.8.1) '@graphql-tools/executor': 1.3.1(graphql@16.8.1) @@ -15725,7 +15783,7 @@ snapshots: '@graphql-tools/utils': 10.5.4(graphql@16.8.1) graphql: 16.8.1 is-glob: 4.0.3 - micromatch: 4.0.7 + micromatch: 4.0.8 tslib: 2.6.3 unixify: 1.0.0 transitivePeerDependencies: @@ -15821,7 +15879,7 @@ snapshots: graphql-request: 6.1.0(encoding@0.1.13)(graphql@16.8.1) http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.5 - jose: 5.7.0 + jose: 5.8.0 js-yaml: 4.1.0 lodash: 4.17.21 scuid: 1.1.0 @@ -15863,7 +15921,7 @@ snapshots: '@graphql-tools/url-loader@8.0.2(@types/node@20.16.1)(encoding@0.1.13)(graphql@16.8.1)': dependencies: '@ardatan/sync-fetch': 0.0.1(encoding@0.1.13) - '@graphql-tools/delegate': 10.0.19(graphql@16.8.1) + '@graphql-tools/delegate': 10.0.21(graphql@16.8.1) '@graphql-tools/executor-graphql-ws': 1.2.0(graphql@16.8.1) '@graphql-tools/executor-http': 1.1.6(@types/node@20.16.1)(graphql@16.8.1) '@graphql-tools/executor-legacy-ws': 1.1.0(graphql@16.8.1) @@ -15898,7 +15956,7 @@ snapshots: '@graphql-tools/wrap@10.0.5(graphql@16.8.1)': dependencies: - '@graphql-tools/delegate': 10.0.19(graphql@16.8.1) + '@graphql-tools/delegate': 10.0.21(graphql@16.8.1) '@graphql-tools/schema': 10.0.6(graphql@16.8.1) '@graphql-tools/utils': 10.5.4(graphql@16.8.1) graphql: 16.8.1 @@ -16106,7 +16164,7 @@ snapshots: jest-util: 29.7.0 jest-validate: 29.7.0 jest-watcher: 29.7.0 - micromatch: 4.0.7 + micromatch: 4.0.8 pretty-format: 29.7.0 slash: 3.0.0 strip-ansi: 6.0.1 @@ -16217,7 +16275,7 @@ snapshots: jest-haste-map: 29.7.0 jest-regex-util: 29.6.3 jest-util: 29.7.0 - micromatch: 4.0.7 + micromatch: 4.0.8 pirates: 4.0.6 slash: 3.0.0 write-file-atomic: 4.0.2 @@ -16836,7 +16894,7 @@ snapshots: dependencies: detect-libc: 1.0.3 is-glob: 4.0.3 - micromatch: 4.0.7 + micromatch: 4.0.8 node-addon-api: 7.1.1 optionalDependencies: '@parcel/watcher-android-arm64': 2.4.1 @@ -17067,12 +17125,12 @@ snapshots: require-from-string: 2.0.2 uri-js: 4.4.1 - '@redocly/config@0.9.0': {} + '@redocly/config@0.10.0': {} - '@redocly/openapi-core@1.20.1(encoding@0.1.13)': + '@redocly/openapi-core@1.21.1(encoding@0.1.13)': dependencies: '@redocly/ajv': 8.11.0 - '@redocly/config': 0.9.0 + '@redocly/config': 0.10.0 colorette: 1.4.0 https-proxy-agent: 7.0.5 js-levenshtein: 1.1.6 @@ -17088,52 +17146,52 @@ snapshots: '@repeaterjs/repeater@3.0.6': {} - '@rollup/rollup-android-arm-eabi@4.21.0': + '@rollup/rollup-android-arm-eabi@4.21.1': optional: true - '@rollup/rollup-android-arm64@4.21.0': + '@rollup/rollup-android-arm64@4.21.1': optional: true - '@rollup/rollup-darwin-arm64@4.21.0': + '@rollup/rollup-darwin-arm64@4.21.1': optional: true - '@rollup/rollup-darwin-x64@4.21.0': + '@rollup/rollup-darwin-x64@4.21.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.21.0': + '@rollup/rollup-linux-arm-gnueabihf@4.21.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.21.0': + '@rollup/rollup-linux-arm-musleabihf@4.21.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.21.0': + '@rollup/rollup-linux-arm64-gnu@4.21.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.21.0': + '@rollup/rollup-linux-arm64-musl@4.21.1': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.21.0': + '@rollup/rollup-linux-powerpc64le-gnu@4.21.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.21.0': + '@rollup/rollup-linux-riscv64-gnu@4.21.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.21.0': + '@rollup/rollup-linux-s390x-gnu@4.21.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.21.0': + '@rollup/rollup-linux-x64-gnu@4.21.1': optional: true - '@rollup/rollup-linux-x64-musl@4.21.0': + '@rollup/rollup-linux-x64-musl@4.21.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.21.0': + '@rollup/rollup-win32-arm64-msvc@4.21.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.21.0': + '@rollup/rollup-win32-ia32-msvc@4.21.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.21.0': + '@rollup/rollup-win32-x64-msvc@4.21.1': optional: true '@sec-ant/readable-stream@0.4.1': {} @@ -17147,7 +17205,7 @@ snapshots: debug: 4.3.6(supports-color@5.5.0) import-from-esm: 1.3.4 lodash-es: 4.17.21 - micromatch: 4.0.7 + micromatch: 4.0.8 semantic-release: 24.1.0(typescript@5.5.4) transitivePeerDependencies: - supports-color @@ -17720,7 +17778,7 @@ snapshots: mime-types: 2.1.35 mkdirp: 3.0.1 semver: 7.6.3 - tsx: 4.17.0 + tsx: 4.19.0 transitivePeerDependencies: - commander - encoding @@ -18066,7 +18124,7 @@ snapshots: '@types/stylis@4.2.5': {} - '@types/superagent@8.1.8': + '@types/superagent@8.1.9': dependencies: '@types/cookiejar': 2.1.5 '@types/methods': 1.1.4 @@ -18076,7 +18134,7 @@ snapshots: '@types/supertest@6.0.2': dependencies: '@types/methods': 1.1.4 - '@types/superagent': 8.1.8 + '@types/superagent': 8.1.9 '@types/tough-cookie@4.0.5': optional: true @@ -18106,15 +18164,15 @@ snapshots: '@types/yoga-layout@1.9.2': {} - '@typescript-eslint/eslint-plugin@8.2.0(@typescript-eslint/parser@8.2.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4))(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)': + '@typescript-eslint/eslint-plugin@8.3.0(@typescript-eslint/parser@8.3.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.5.4))(eslint@9.9.1(jiti@1.21.6))(typescript@5.5.4)': dependencies: '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 8.2.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4) - '@typescript-eslint/scope-manager': 8.2.0 - '@typescript-eslint/type-utils': 8.2.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4) - '@typescript-eslint/utils': 8.2.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4) - '@typescript-eslint/visitor-keys': 8.2.0 - eslint: 9.9.0(jiti@1.21.6) + '@typescript-eslint/parser': 8.3.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.5.4) + '@typescript-eslint/scope-manager': 8.3.0 + '@typescript-eslint/type-utils': 8.3.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.5.4) + '@typescript-eslint/utils': 8.3.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.5.4) + '@typescript-eslint/visitor-keys': 8.3.0 + eslint: 9.9.1(jiti@1.21.6) graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 @@ -18124,28 +18182,28 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.2.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)': + '@typescript-eslint/parser@8.3.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.5.4)': dependencies: - '@typescript-eslint/scope-manager': 8.2.0 - '@typescript-eslint/types': 8.2.0 - '@typescript-eslint/typescript-estree': 8.2.0(typescript@5.5.4) - '@typescript-eslint/visitor-keys': 8.2.0 + '@typescript-eslint/scope-manager': 8.3.0 + '@typescript-eslint/types': 8.3.0 + '@typescript-eslint/typescript-estree': 8.3.0(typescript@5.5.4) + '@typescript-eslint/visitor-keys': 8.3.0 debug: 4.3.6(supports-color@5.5.0) - eslint: 9.9.0(jiti@1.21.6) + eslint: 9.9.1(jiti@1.21.6) optionalDependencies: typescript: 5.5.4 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.2.0': + '@typescript-eslint/scope-manager@8.3.0': dependencies: - '@typescript-eslint/types': 8.2.0 - '@typescript-eslint/visitor-keys': 8.2.0 + '@typescript-eslint/types': 8.3.0 + '@typescript-eslint/visitor-keys': 8.3.0 - '@typescript-eslint/type-utils@8.2.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)': + '@typescript-eslint/type-utils@8.3.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.5.4)': dependencies: - '@typescript-eslint/typescript-estree': 8.2.0(typescript@5.5.4) - '@typescript-eslint/utils': 8.2.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4) + '@typescript-eslint/typescript-estree': 8.3.0(typescript@5.5.4) + '@typescript-eslint/utils': 8.3.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.5.4) debug: 4.3.6(supports-color@5.5.0) ts-api-utils: 1.3.0(typescript@5.5.4) optionalDependencies: @@ -18154,14 +18212,14 @@ snapshots: - eslint - supports-color - '@typescript-eslint/types@8.2.0': {} + '@typescript-eslint/types@8.3.0': {} - '@typescript-eslint/typescript-estree@8.2.0(typescript@5.5.4)': + '@typescript-eslint/typescript-estree@8.3.0(typescript@5.5.4)': dependencies: - '@typescript-eslint/types': 8.2.0 - '@typescript-eslint/visitor-keys': 8.2.0 + '@typescript-eslint/types': 8.3.0 + '@typescript-eslint/visitor-keys': 8.3.0 debug: 4.3.6(supports-color@5.5.0) - globby: 11.1.0 + fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.3 @@ -18171,20 +18229,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.2.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)': + '@typescript-eslint/utils@8.3.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.5.4)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.0(jiti@1.21.6)) - '@typescript-eslint/scope-manager': 8.2.0 - '@typescript-eslint/types': 8.2.0 - '@typescript-eslint/typescript-estree': 8.2.0(typescript@5.5.4) - eslint: 9.9.0(jiti@1.21.6) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.1(jiti@1.21.6)) + '@typescript-eslint/scope-manager': 8.3.0 + '@typescript-eslint/types': 8.3.0 + '@typescript-eslint/typescript-estree': 8.3.0(typescript@5.5.4) + eslint: 9.9.1(jiti@1.21.6) transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/visitor-keys@8.2.0': + '@typescript-eslint/visitor-keys@8.3.0': dependencies: - '@typescript-eslint/types': 8.2.0 + '@typescript-eslint/types': 8.3.0 eslint-visitor-keys: 3.4.3 '@wesleytodd/openapi@0.3.0(core-js@3.38.1)(encoding@0.1.13)(enzyme@3.11.0)(mobx@6.13.1)(openapi-types@12.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@6.1.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': @@ -18527,12 +18585,12 @@ snapshots: aws-lambda@1.0.7: dependencies: - aws-sdk: 2.1681.0 + aws-sdk: 2.1683.0 commander: 3.0.2 js-yaml: 3.14.1 watchpack: 2.4.2 - aws-sdk@2.1681.0: + aws-sdk@2.1683.0: dependencies: buffer: 4.9.2 events: 1.1.1 @@ -18734,7 +18792,7 @@ snapshots: browserslist@4.23.3: dependencies: - caniuse-lite: 1.0.30001651 + caniuse-lite: 1.0.30001653 electron-to-chromium: 1.5.13 node-releases: 2.0.18 update-browserslist-db: 1.1.0(browserslist@4.23.3) @@ -18849,7 +18907,7 @@ snapshots: camelize@1.0.1: {} - caniuse-lite@1.0.30001651: {} + caniuse-lite@1.0.30001653: {} capital-case@1.0.4: dependencies: @@ -19030,7 +19088,7 @@ snapshots: ci-info@3.9.0: {} - cjs-module-lexer@1.3.1: {} + cjs-module-lexer@1.4.0: {} classnames@2.5.1: {} @@ -19372,12 +19430,12 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 - cosmiconfig-typescript-loader@5.0.0(@types/node@22.5.0)(cosmiconfig@9.0.0(typescript@5.7.0-dev.20240827))(typescript@5.7.0-dev.20240827): + cosmiconfig-typescript-loader@5.0.0(@types/node@22.5.0)(cosmiconfig@9.0.0(typescript@5.7.0-dev.20240828))(typescript@5.7.0-dev.20240828): dependencies: '@types/node': 22.5.0 - cosmiconfig: 9.0.0(typescript@5.7.0-dev.20240827) + cosmiconfig: 9.0.0(typescript@5.7.0-dev.20240828) jiti: 1.21.6 - typescript: 5.7.0-dev.20240827 + typescript: 5.7.0-dev.20240828 cosmiconfig@8.3.6(typescript@5.5.4): dependencies: @@ -19397,14 +19455,14 @@ snapshots: optionalDependencies: typescript: 5.5.4 - cosmiconfig@9.0.0(typescript@5.7.0-dev.20240827): + cosmiconfig@9.0.0(typescript@5.7.0-dev.20240828): dependencies: env-paths: 2.2.1 import-fresh: 3.3.0 js-yaml: 4.1.0 parse-json: 5.2.0 optionalDependencies: - typescript: 5.7.0-dev.20240827 + typescript: 5.7.0-dev.20240828 cpu-features@0.0.2: dependencies: @@ -19747,7 +19805,7 @@ snapshots: dependencies: semver: 7.6.3 shelljs: 0.8.5 - typescript: 5.7.0-dev.20240827 + typescript: 5.7.0-dev.20240828 dreamopt@0.8.0: dependencies: @@ -19812,7 +19870,7 @@ snapshots: emittery@0.13.1: {} - emoji-regex@10.3.0: {} + emoji-regex@10.4.0: {} emoji-regex@8.0.0: {} @@ -19849,7 +19907,7 @@ snapshots: entities@4.5.0: {} - env-ci@11.0.0: + env-ci@11.1.0: dependencies: execa: 8.0.1 java-properties: 1.0.2 @@ -20054,15 +20112,15 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-prettier@9.1.0(eslint@9.9.0(jiti@1.21.6)): + eslint-config-prettier@9.1.0(eslint@9.9.1(jiti@1.21.6)): dependencies: - eslint: 9.9.0(jiti@1.21.6) + eslint: 9.9.1(jiti@1.21.6) - eslint-plugin-package-json@0.15.2(eslint@9.9.0(jiti@1.21.6))(jsonc-eslint-parser@2.4.0): + eslint-plugin-package-json@0.15.2(eslint@9.9.1(jiti@1.21.6))(jsonc-eslint-parser@2.4.0): dependencies: detect-indent: 6.1.0 detect-newline: 3.1.0 - eslint: 9.9.0(jiti@1.21.6) + eslint: 9.9.1(jiti@1.21.6) jsonc-eslint-parser: 2.4.0 package-json-validator: 0.6.5 semver: 7.6.3 @@ -20070,14 +20128,14 @@ snapshots: sort-package-json: 1.57.0 validate-npm-package-name: 5.0.1 - eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@9.9.0(jiti@1.21.6)))(eslint@9.9.0(jiti@1.21.6))(prettier@3.3.3): + eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@9.9.1(jiti@1.21.6)))(eslint@9.9.1(jiti@1.21.6))(prettier@3.3.3): dependencies: - eslint: 9.9.0(jiti@1.21.6) + eslint: 9.9.1(jiti@1.21.6) prettier: 3.3.3 prettier-linter-helpers: 1.0.0 synckit: 0.9.1 optionalDependencies: - eslint-config-prettier: 9.1.0(eslint@9.9.0(jiti@1.21.6)) + eslint-config-prettier: 9.1.0(eslint@9.9.1(jiti@1.21.6)) eslint-scope@8.0.2: dependencies: @@ -20088,13 +20146,13 @@ snapshots: eslint-visitor-keys@4.0.0: {} - eslint@9.9.0(jiti@1.21.6): + eslint@9.9.1(jiti@1.21.6): dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.0(jiti@1.21.6)) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.1(jiti@1.21.6)) '@eslint-community/regexpp': 4.11.0 - '@eslint/config-array': 0.17.1 + '@eslint/config-array': 0.18.0 '@eslint/eslintrc': 3.1.0 - '@eslint/js': 9.9.0 + '@eslint/js': 9.9.1 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.3.0 '@nodelib/fs.walk': 1.2.8 @@ -20339,7 +20397,7 @@ snapshots: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.7 + micromatch: 4.0.8 fast-json-patch@3.1.1: {} @@ -21173,14 +21231,14 @@ snapshots: dependencies: acorn: 8.12.1 acorn-import-attributes: 1.9.5(acorn@8.12.1) - cjs-module-lexer: 1.3.1 + cjs-module-lexer: 1.4.0 module-details-from-path: 1.0.3 import-in-the-middle@1.7.1: dependencies: acorn: 8.12.1 acorn-import-assertions: 1.9.0(acorn@8.12.1) - cjs-module-lexer: 1.3.1 + cjs-module-lexer: 1.4.0 module-details-from-path: 1.0.3 optional: true @@ -21689,7 +21747,7 @@ snapshots: jest-runner: 29.7.0 jest-util: 29.7.0 jest-validate: 29.7.0 - micromatch: 4.0.7 + micromatch: 4.0.8 parse-json: 5.2.0 pretty-format: 29.7.0 slash: 3.0.0 @@ -21749,7 +21807,7 @@ snapshots: jest-regex-util: 29.6.3 jest-util: 29.7.0 jest-worker: 29.7.0 - micromatch: 4.0.7 + micromatch: 4.0.8 walker: 1.0.8 optionalDependencies: fsevents: 2.3.3 @@ -21773,7 +21831,7 @@ snapshots: '@types/stack-utils': 2.0.3 chalk: 4.1.2 graceful-fs: 4.2.11 - micromatch: 4.0.7 + micromatch: 4.0.8 pretty-format: 29.7.0 slash: 3.0.0 stack-utils: 2.0.6 @@ -21850,7 +21908,7 @@ snapshots: '@jest/types': 29.6.3 '@types/node': 20.16.1 chalk: 4.1.2 - cjs-module-lexer: 1.3.1 + cjs-module-lexer: 1.4.0 collect-v8-coverage: 1.0.2 glob: 7.2.3 graceful-fs: 4.2.11 @@ -21869,7 +21927,7 @@ snapshots: jest-snapshot@29.7.0: dependencies: '@babel/core': 7.25.2 - '@babel/generator': 7.25.4 + '@babel/generator': 7.25.5 '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.25.2) '@babel/plugin-syntax-typescript': 7.25.4(@babel/core@7.25.2) '@babel/types': 7.25.4 @@ -21953,7 +22011,7 @@ snapshots: jose@4.15.9: {} - jose@5.7.0: {} + jose@5.8.0: {} joycon@3.1.1: {} @@ -22235,7 +22293,7 @@ snapshots: dotenv-expand: 11.0.6 git-diff: 2.0.6 kysely: 0.27.3 - micromatch: 4.0.7 + micromatch: 4.0.8 minimist: 1.2.8 optionalDependencies: mysql2: 3.10.3 @@ -22391,6 +22449,8 @@ snapshots: lodash.startcase@4.4.0: {} + lodash.unescape@4.0.1: {} + lodash.union@4.6.0: {} lodash.uniq@4.5.0: {} @@ -22434,7 +22494,7 @@ snapshots: '@types/triple-beam': 1.3.5 fecha: 4.2.3 ms: 2.1.3 - safe-stable-stringify: 2.4.3 + safe-stable-stringify: 2.5.0 triple-beam: 1.4.1 loglevel@1.9.1: {} @@ -22553,6 +22613,12 @@ snapshots: mark.js@8.11.1: {} + markdown-to-txt@2.0.1: + dependencies: + lodash.escape: 4.0.1 + lodash.unescape: 4.0.1 + marked: 4.3.0 + marked-terminal@7.1.0(marked@12.0.2): dependencies: ansi-escapes: 7.0.0 @@ -22610,7 +22676,7 @@ snapshots: methods@1.1.2: {} - micromatch@4.0.7: + micromatch@4.0.8: dependencies: braces: 3.0.3 picomatch: 2.3.1 @@ -22849,7 +22915,7 @@ snapshots: node-abi@3.67.0: dependencies: - semver: 7.6.2 + semver: 7.6.3 node-abort-controller@3.1.1: {} @@ -23459,13 +23525,13 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-load-config@6.0.1(jiti@1.21.6)(postcss@8.4.38)(tsx@4.17.0)(yaml@2.5.0): + postcss-load-config@6.0.1(jiti@1.21.6)(postcss@8.4.38)(tsx@4.19.0)(yaml@2.5.0): dependencies: lilconfig: 3.1.2 optionalDependencies: jiti: 1.21.6 postcss: 8.4.38 - tsx: 4.17.0 + tsx: 4.19.0 yaml: 2.5.0 postcss-value-parser@4.2.0: {} @@ -23824,7 +23890,7 @@ snapshots: redoc@2.1.5(core-js@3.38.1)(encoding@0.1.13)(enzyme@3.11.0)(mobx@6.13.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@6.1.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1)): dependencies: '@cfaester/enzyme-adapter-react-18': 0.8.0(enzyme@3.11.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@redocly/openapi-core': 1.20.1(encoding@0.1.13) + '@redocly/openapi-core': 1.21.1(encoding@0.1.13) classnames: 2.5.1 core-js: 3.38.1 decko: 1.2.0 @@ -23980,26 +24046,26 @@ snapshots: dependencies: glob: 7.2.3 - rollup@4.21.0: + rollup@4.21.1: dependencies: '@types/estree': 1.0.5 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.21.0 - '@rollup/rollup-android-arm64': 4.21.0 - '@rollup/rollup-darwin-arm64': 4.21.0 - '@rollup/rollup-darwin-x64': 4.21.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.21.0 - '@rollup/rollup-linux-arm-musleabihf': 4.21.0 - '@rollup/rollup-linux-arm64-gnu': 4.21.0 - '@rollup/rollup-linux-arm64-musl': 4.21.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.21.0 - '@rollup/rollup-linux-riscv64-gnu': 4.21.0 - '@rollup/rollup-linux-s390x-gnu': 4.21.0 - '@rollup/rollup-linux-x64-gnu': 4.21.0 - '@rollup/rollup-linux-x64-musl': 4.21.0 - '@rollup/rollup-win32-arm64-msvc': 4.21.0 - '@rollup/rollup-win32-ia32-msvc': 4.21.0 - '@rollup/rollup-win32-x64-msvc': 4.21.0 + '@rollup/rollup-android-arm-eabi': 4.21.1 + '@rollup/rollup-android-arm64': 4.21.1 + '@rollup/rollup-darwin-arm64': 4.21.1 + '@rollup/rollup-darwin-x64': 4.21.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.21.1 + '@rollup/rollup-linux-arm-musleabihf': 4.21.1 + '@rollup/rollup-linux-arm64-gnu': 4.21.1 + '@rollup/rollup-linux-arm64-musl': 4.21.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.21.1 + '@rollup/rollup-linux-riscv64-gnu': 4.21.1 + '@rollup/rollup-linux-s390x-gnu': 4.21.1 + '@rollup/rollup-linux-x64-gnu': 4.21.1 + '@rollup/rollup-linux-x64-musl': 4.21.1 + '@rollup/rollup-win32-arm64-msvc': 4.21.1 + '@rollup/rollup-win32-ia32-msvc': 4.21.1 + '@rollup/rollup-win32-x64-msvc': 4.21.1 fsevents: 2.3.3 router@1.3.8: @@ -24050,7 +24116,7 @@ snapshots: es-errors: 1.3.0 is-regex: 1.1.4 - safe-stable-stringify@2.4.3: {} + safe-stable-stringify@2.5.0: {} safer-buffer@2.1.2: {} @@ -24108,7 +24174,7 @@ snapshots: aggregate-error: 5.0.0 cosmiconfig: 9.0.0(typescript@5.5.4) debug: 4.3.6(supports-color@5.5.0) - env-ci: 11.0.0 + env-ci: 11.1.0 execa: 9.3.1 figures: 6.1.0 find-versions: 6.0.0 @@ -24120,7 +24186,7 @@ snapshots: lodash-es: 4.17.21 marked: 12.0.2 marked-terminal: 7.1.0(marked@12.0.2) - micromatch: 4.0.7 + micromatch: 4.0.8 p-each-series: 3.0.0 p-reduce: 3.0.0 read-package-up: 11.0.0 @@ -24519,7 +24585,7 @@ snapshots: string-width@7.2.0: dependencies: - emoji-regex: 10.3.0 + emoji-regex: 10.4.0 get-east-asian-width: 1.2.0 strip-ansi: 7.1.0 @@ -24707,13 +24773,13 @@ snapshots: '@pkgr/core': 0.1.1 tslib: 2.6.3 - syncpack@12.4.0(typescript@5.7.0-dev.20240827): + syncpack@12.4.0(typescript@5.7.0-dev.20240828): dependencies: '@effect/schema': 0.69.0(effect@3.5.7) chalk: 5.3.0 chalk-template: 1.1.0 commander: 12.1.0 - cosmiconfig: 9.0.0(typescript@5.7.0-dev.20240827) + cosmiconfig: 9.0.0(typescript@5.7.0-dev.20240828) effect: 3.5.7 enquirer: 2.4.1 fast-check: 3.20.0 @@ -24939,7 +25005,7 @@ snapshots: tsscmp@1.0.6: {} - tsup@8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.17.0)(typescript@5.5.4)(yaml@2.5.0): + tsup@8.2.4(jiti@1.21.6)(postcss@8.4.38)(tsx@4.19.0)(typescript@5.5.4)(yaml@2.5.0): dependencies: bundle-require: 5.0.0(esbuild@0.23.1) cac: 6.7.14 @@ -24951,9 +25017,9 @@ snapshots: globby: 11.1.0 joycon: 3.1.1 picocolors: 1.0.1 - postcss-load-config: 6.0.1(jiti@1.21.6)(postcss@8.4.38)(tsx@4.17.0)(yaml@2.5.0) + postcss-load-config: 6.0.1(jiti@1.21.6)(postcss@8.4.38)(tsx@4.19.0)(yaml@2.5.0) resolve-from: 5.0.0 - rollup: 4.21.0 + rollup: 4.21.1 source-map: 0.8.0-beta.0 sucrase: 3.35.0 tree-kill: 1.2.2 @@ -24966,7 +25032,7 @@ snapshots: - tsx - yaml - tsx@4.17.0: + tsx@4.19.0: dependencies: esbuild: 0.23.1 get-tsconfig: 4.7.6 @@ -24985,32 +25051,32 @@ snapshots: transitivePeerDependencies: - supports-color - turbo-darwin-64@2.0.14: + turbo-darwin-64@2.1.0: optional: true - turbo-darwin-arm64@2.0.14: + turbo-darwin-arm64@2.1.0: optional: true - turbo-linux-64@2.0.14: + turbo-linux-64@2.1.0: optional: true - turbo-linux-arm64@2.0.14: + turbo-linux-arm64@2.1.0: optional: true - turbo-windows-64@2.0.14: + turbo-windows-64@2.1.0: optional: true - turbo-windows-arm64@2.0.14: + turbo-windows-arm64@2.1.0: optional: true - turbo@2.0.14: + turbo@2.1.0: optionalDependencies: - turbo-darwin-64: 2.0.14 - turbo-darwin-arm64: 2.0.14 - turbo-linux-64: 2.0.14 - turbo-linux-arm64: 2.0.14 - turbo-windows-64: 2.0.14 - turbo-windows-arm64: 2.0.14 + turbo-darwin-64: 2.1.0 + turbo-darwin-arm64: 2.1.0 + turbo-linux-64: 2.1.0 + turbo-linux-arm64: 2.1.0 + turbo-windows-64: 2.1.0 + turbo-windows-arm64: 2.1.0 turndown@7.2.0: dependencies: @@ -25081,11 +25147,11 @@ snapshots: typedarray@0.0.6: {} - typescript-eslint@8.2.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4): + typescript-eslint@8.3.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.5.4): dependencies: - '@typescript-eslint/eslint-plugin': 8.2.0(@typescript-eslint/parser@8.2.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4))(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4) - '@typescript-eslint/parser': 8.2.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4) - '@typescript-eslint/utils': 8.2.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4) + '@typescript-eslint/eslint-plugin': 8.3.0(@typescript-eslint/parser@8.3.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.5.4))(eslint@9.9.1(jiti@1.21.6))(typescript@5.5.4) + '@typescript-eslint/parser': 8.3.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.5.4) + '@typescript-eslint/utils': 8.3.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.5.4) optionalDependencies: typescript: 5.5.4 transitivePeerDependencies: @@ -25096,7 +25162,7 @@ snapshots: typescript@5.5.4: {} - typescript@5.7.0-dev.20240827: {} + typescript@5.7.0-dev.20240828: {} ua-parser-js@1.0.38: {} @@ -25466,7 +25532,7 @@ snapshots: logform: 2.6.1 one-time: 1.0.0 readable-stream: 3.6.2 - safe-stable-stringify: 2.4.3 + safe-stable-stringify: 2.5.0 stack-trace: 0.0.10 triple-beam: 1.4.1 winston-transport: 4.7.1 @@ -25514,7 +25580,7 @@ snapshots: xml2js@0.6.2: dependencies: - sax: 1.2.1 + sax: 1.4.1 xmlbuilder: 11.0.1 xmlbuilder@11.0.1: {} diff --git a/servers/annotations-api/package.json b/servers/annotations-api/package.json index 7f72efac0..71f4735e3 100644 --- a/servers/annotations-api/package.json +++ b/servers/annotations-api/package.json @@ -27,7 +27,7 @@ "@apollo/cache-control-types": "1.0.3", "@apollo/datasource-rest": "^6.2.2", "@apollo/server": "4.10.4", - "@apollo/subgraph": "2.8.4", + "@apollo/subgraph": "2.9.0", "@aws-sdk/client-dynamodb": "3.632.0", "@aws-sdk/client-sqs": "3.632.0", "@aws-sdk/lib-dynamodb": "3.632.0", diff --git a/servers/client-api/.env.example b/servers/client-api/.env.example index 30fc17bc8..cafa86774 100644 --- a/servers/client-api/.env.example +++ b/servers/client-api/.env.example @@ -1,4 +1,7 @@ +REDIS_ENDPOINT=localhost:6379 +REDIS_PROTOCOL=redis +APP_ENVIRONMENT=local APOLLO_KEY=API_KEY_HERE -APOLLO_GRAPH_REF=pocket-client-api@development +APOLLO_GRAPH_REF=pocket-client-api@current PORT=4050 -OTLP_COLLECTOR_HOST=host.docker.internal \ No newline at end of file +OTLP_COLLECTOR_HOST=localhost \ No newline at end of file diff --git a/servers/client-api/Dockerfile b/servers/client-api/Dockerfile index c6bedfe34..f87cddf23 100644 --- a/servers/client-api/Dockerfile +++ b/servers/client-api/Dockerfile @@ -1,4 +1,4 @@ -FROM ghcr.io/apollographql/router:v1.52.1@sha256:b16b1cb64f88ceb3485f5e524ade1b4c4a2039a2b1be851be122e79b9d5a6ded +FROM ghcr.io/apollographql/router:v1.53.0@sha256:cfa48711d26bcc7b0320c990f6bf9d135914e1ce34c93d7f2d6ccc5f8314ee1f USER root diff --git a/servers/client-api/README.md b/servers/client-api/README.md index d8aece3cf..9d33c56ee 100644 --- a/servers/client-api/README.md +++ b/servers/client-api/README.md @@ -12,7 +12,8 @@ ## Commands - `docker build -t router .` builds the router image with the tag `router` for local testing. -- `rover dev --supergraph-config supergraph.yaml --router-config router.yaml` to run the Router locally without Docker (using [Rover]). You'll need to update the `supergraph.yaml` file to point at the local versions of your subgraphs. **Make sure to set the required environment variables ahead of time!** +- `dotenv rover dev --supergraph-config ./config/supergraph.yaml --router-config ./config/router.yaml` to run the Router locally without Docker (using [Rover]). You'll need to update the `supergraph.yaml` file to point at the local versions of your subgraphs. **Make sure to set the required environment variables ahead of time!** +- Alternatively you can use the prod or dev graph if you have an api key set like: `dotenv rover dev --graph-ref pocket-client-api@current --router-config ./config/router.yaml` and override it like `dotenv rover dev --graph-ref pocket-client-api@current --router-config ./config/router.yaml --name parser-graphql-wrapper --url http://localhost:4001`. `rover dev --name parser-graphql-wrapper --url http://localhost:4001` can also be ran in a seperate terminal window anytime after the first dev command is ran. - `docker run -it --env APOLLO_KEY --env APOLLO_GRAPH_REF -p4000:4000 router` runs the same router image you'll run in production. You can now query the router at `http://localhost:4000`. - Make sure to set the env vars `APOLLO_KEY` and `APOLLO_GRAPH_REF` first - You can alternatively create a file (e.g., `.env`) and run `docker run -it --env-file .env -v $(pwd)/config/router.yaml:/config/router.yaml -v $(pwd)/rhai:/dist/rhai -p4050:4050 router --dev --config /config/router.yaml`. **Make sure not to check the `.env` file into source control!** This will enable hot reloading and dev mode but use the production schemas. diff --git a/servers/client-api/config/router.yaml b/servers/client-api/config/router.yaml index c078c1212..4f78029ad 100644 --- a/servers/client-api/config/router.yaml +++ b/servers/client-api/config/router.yaml @@ -6,7 +6,7 @@ supergraph: query_planning: cache: redis: - urls: ['rediss-cluster://${env.REDIS_ENDPOINT}'] + urls: ['${env.REDIS_PROTOCOL:-rediss-cluster}://${env.REDIS_ENDPOINT}'] ttl: 48h # optional, by default no expiration include_subgraph_errors: all: true # Propagate errors from all subgraphs @@ -80,5 +80,5 @@ apq: router: cache: redis: - urls: ['rediss-cluster://${env.REDIS_ENDPOINT}'] + urls: ['${env.REDIS_PROTOCOL:-rediss-cluster}://${env.REDIS_ENDPOINT}'] ttl: 24h # optional, by default no expiration diff --git a/servers/client-api/config/supergraph.yaml b/servers/client-api/config/supergraph.yaml index 0b073a840..6340b4894 100644 --- a/servers/client-api/config/supergraph.yaml +++ b/servers/client-api/config/supergraph.yaml @@ -1,10 +1,76 @@ -federation_version: =2.4.7 +federation_version: =2.7.0 subgraphs: - products: + # Pocket Monorepo + annotations-api: + routing_url: https://annotations-api.readitlater.com + # schema: + # subgraph_url: https://annotations-api.readitlater.com + schema: # Schema downloaded from GraphOS registry, does not poll for updates + graphref: pocket-client-api@current + subgraph: annotations-api + featureflags: + routing_url: https://featureflags.readitlater.com/graphql + schema: + subgraph_url: https://featureflags.readitlater.com/graphql + image-api: + routing_url: https://image-api.readitlater.com + schema: + subgraph_url: https://image-api.readitlater.com + list-api: + routing_url: https://list-api.readitlater.com + schema: + subgraph_url: https://list-api.readitlater.com + parser: + #routing_url: https://parser-graphql-wrapper.readitlater.com + #schema: + # subgraph_url: https://parser-graphql-wrapper.readitlater.com routing_url: http://localhost:4001 schema: subgraph_url: http://localhost:4001 - users: - routing_url: http://localhost:4002 + shareable-lists-api: + routing_url: https://shareablelistsapi.readitlater.com + schema: + subgraph_url: https://shareablelistsapi.readitlater.com + shares-api: + routing_url: https://shares-api.readitlater.com + schema: + subgraph_url: https://shares-api.readitlater.com + user: + routing_url: https://user-api.readitlater.com + schema: + subgraph_url: https://user-api.readitlater.com + user-list-search: + routing_url: https://user-list-search.readitlater.com/graphql + schema: + subgraph_url: https://user-list-search.readitlater.com/graphql + + # # Content Monorepo + collection: + routing_url: https://collection-api.readitlater.com + # schema: + # subgraph_url: https://collection-api.readitlater.com + schema: # Schema downloaded from GraphOS registry, does not poll for updates + graphref: pocket-client-api@current + subgraph: collection + curated-corpus: + routing_url: https://curated-corpus-api.readitlater.com + # schema: + # subgraph_url: https://curated-corpus-api.readitlater.com + schema: # Schema downloaded from GraphOS registry, does not poll for updates + graphref: pocket-client-api@current + subgraph: curated-corpus + # curation-tools: + # routing_url: https://curation-tools-api.readitlater.com + # schema: + # subgraph_url: https://curation-tools-api.readitlater.com + recommendation-api: + routing_url: https://recommendation-api.readitlater.com/ schema: - subgraph_url: http://localhost:4002 + subgraph_url: https://recommendation-api.readitlater.com/ + syndication: + routing_url: https://syndication-api-wrapper.readitlater.com/ + # schema: + # subgraph_url: https://syndication-api-wrapper.readitlater.com/ + schema: # Schema downloaded from GraphOS registry, does not poll for updates + graphref: pocket-client-api@current + subgraph: syndication \ No newline at end of file diff --git a/servers/feature-flags/package.json b/servers/feature-flags/package.json index c2ae5f455..f7afeb326 100644 --- a/servers/feature-flags/package.json +++ b/servers/feature-flags/package.json @@ -22,7 +22,7 @@ }, "dependencies": { "@apollo/server": "4.10.4", - "@apollo/subgraph": "2.8.4", + "@apollo/subgraph": "2.9.0", "@govtechsg/passport-openidconnect": "1.0.2", "@pocket-tools/apollo-utils": "workspace:*", "@pocket-tools/sentry": "workspace:*", diff --git a/servers/image-api/package.json b/servers/image-api/package.json index 27953279f..2065e17ea 100644 --- a/servers/image-api/package.json +++ b/servers/image-api/package.json @@ -23,10 +23,11 @@ }, "dependencies": { "@apollo/server": "4.10.4", - "@apollo/subgraph": "2.8.4", + "@apollo/subgraph": "2.9.0", "@apollo/utils.keyvadapter": "3.1.0", "@keyv/redis": "2.8.5", "@pocket-tools/apollo-utils": "workspace:*", + "@pocket-tools/image-utils": "workspace:*", "@pocket-tools/sentry": "workspace:*", "@pocket-tools/ts-logger": "workspace:*", "@sentry/node": "8.26.0", @@ -37,7 +38,6 @@ "graphql": "16.8.1", "graphql-tag": "2.12.6", "keyv": "4.5.4", - "parse-url": "9.2.0", "tslib": "2.6.3" }, "devDependencies": { diff --git a/servers/image-api/src/resolvers/index.ts b/servers/image-api/src/resolvers/index.ts index 33974f2f1..14e6d1fce 100644 --- a/servers/image-api/src/resolvers/index.ts +++ b/servers/image-api/src/resolvers/index.ts @@ -1,6 +1,6 @@ import { IContext } from '../server/context'; import { Image, CachedImageInput, CachedImage } from '../types'; -import { getOriginalUrlIfPocketImageCached } from '../pocketImageCache/utils'; +import { getOriginalUrlIfPocketImageCached } from '@pocket-tools/image-utils'; import { getPocketImageCachePath } from '../pocketImageCache'; import config from '../config'; diff --git a/servers/list-api/package.json b/servers/list-api/package.json index f366576c4..5604d3a58 100644 --- a/servers/list-api/package.json +++ b/servers/list-api/package.json @@ -21,7 +21,7 @@ }, "dependencies": { "@apollo/server": "4.10.4", - "@apollo/subgraph": "2.8.4", + "@apollo/subgraph": "2.9.0", "@aws-sdk/client-eventbridge": "3.632.0", "@aws-sdk/client-kinesis": "3.632.0", "@aws-sdk/client-sqs": "3.632.0", diff --git a/servers/parser-graphql-wrapper/package.json b/servers/parser-graphql-wrapper/package.json index 4917ca019..78b3068f1 100644 --- a/servers/parser-graphql-wrapper/package.json +++ b/servers/parser-graphql-wrapper/package.json @@ -22,7 +22,7 @@ "@apollo/cache-control-types": "1.0.3", "@apollo/datasource-rest": "^6.2.2", "@apollo/server": "4.10.4", - "@apollo/subgraph": "2.8.4", + "@apollo/subgraph": "2.9.0", "@apollo/utils.keyvadapter": "3.1.0", "@apollo/utils.keyvaluecache": "3.1.0", "@aws-sdk/client-dynamodb": "3.632.0", @@ -31,6 +31,7 @@ "@keyv/redis": "2.8.5", "@pocket-tools/apollo-utils": "workspace:*", "@pocket-tools/feature-flags-client": "workspace:*", + "@pocket-tools/image-utils": "workspace:*", "@pocket-tools/int-mask": "workspace:*", "@pocket-tools/sentry": "workspace:*", "@pocket-tools/ts-logger": "workspace:*", @@ -48,6 +49,7 @@ "kysely": "0.27.3", "lodash": "4.17.21", "luxon": "3.4.4", + "markdown-to-txt": "2.0.1", "md5": "2.3.0", "mysql2": "3.10.3", "open-graph-scraper": "6.5.2", @@ -79,4 +81,4 @@ "tsconfig": "workspace:*", "typescript": "5.5.4" } -} +} \ No newline at end of file diff --git a/servers/parser-graphql-wrapper/schema-admin.graphql b/servers/parser-graphql-wrapper/schema-admin.graphql new file mode 100644 index 000000000..49ec9020e --- /dev/null +++ b/servers/parser-graphql-wrapper/schema-admin.graphql @@ -0,0 +1,556 @@ +extend schema + @link( + url: "https://specs.apollo.dev/federation/v2.0" + import: [ + "@key" + "@shareable" + "@requires" + "@external" + "@tag" + "@inaccessible" + ] + ) +"A String representing a date in the format of `yyyy-MM-dd HH:mm:ss`" +scalar DateString +""" +ISOString scalar - all datetimes fields are Typescript Date objects on this server & +returned as ISO-8601 encoded date strings (e.g. ISOString scalars) to GraphQL clients. +See Section 5.6 of the RFC 3339 profile of the ISO 8601 standard: https://www.ietf.org/rfc/rfc3339.txt. +""" +scalar ISOString + +""" +A string formatted with CommonMark markdown, +plus the strikethrough extension from GFM. +This Scalar is for documentation purposes; otherwise +not treated differently from String in the API. +""" +scalar Markdown + +"A String in the format of a url." +scalar Url +scalar ValidUrl + +enum CacheControlScope { + PUBLIC + PRIVATE +} + +""" +We need to manually implement cacheControl in the schema for now +https://stackoverflow.com/questions/52922080/how-to-implement-caching-on-apollo-server-hapi-graphql +https://github.com/apollographql/federation/issues/356 +""" +directive @cacheControl( + maxAge: Int + scope: CacheControlScope +) on FIELD_DEFINITION | OBJECT | INTERFACE + +""" +The heart of Pocket +A url and meta data related to it. +""" +type Item + @key(fields: "givenUrl") + @key(fields: "itemId") + @cacheControl(maxAge: 86400) { + "A server generated unique id for this item. Item's whose normalUrl are the same will have the same item_id. Most likely numeric, but to ensure future proofing this can be treated as a String in apps." + itemId: String! + "A server generated unique id for this item based on itemId" + id: ID! + "A server generated unique reader slug for this item based on itemId" + readerSlug: String! + """ + A normalized value of the givenUrl. + It will look like a url but is not guaranteed to be a valid url, just a unique string that is used to eliminate common duplicates. + Item's that share a normal_url should be considered the same item. For example https://getpocket.com and http://getpocket.com will be considered the same since they both normalize to http://getpocket.com + This is technically the true identity of an item, since this is what the backend uses to tell if two items are the same. + However, for the clients to use this, they would all have to ship an implementation of the normalization function that the backend has exactly. + And even if it did that, some items, some of the earliest saves, use a legacy normalize function and the client would have no way to know when to use which normalizing function. + """ + normalUrl: String! + "If available, the url to an AMP version of this article" + ampUrl: Url + """ + Provides short url for the given_url in the format: https://pocket.co/. + marked as beta because it's not ready yet for large client request. + """ + shortUrl: Url @tag(name: "beta") + "List of Authors involved with this article" + authors: [Author] + "The domain, such as 'getpocket.com' of the resolved_url" + domain: String + "Additional information about the item domain, when present, use this for displaying the domain name" + domainMetadata: DomainMetadata + "The string encoding code of this item's web page" + encoding: String + "A snippet of text from the article" + excerpt: String + "0=no images, 1=contains images, 2=is an image" + hasImage: Imageness + "0=no videos, 1=contains video, 2=is a video" + hasVideo: Videoness + "Array of images within an article" + images: [Image] + "true if the item is an article" + isArticle: Boolean + "true if the item is an index / home page, rather than a specific single piece of content" + isIndex: Boolean + "The mime type of this item's web page" + mimeType: String + "The item id of the resolved_url" + resolvedId: String + "If the givenUrl redirects (once or many times), this is the final url. Otherwise, same as givenUrl" + resolvedUrl: Url + "The title as determined by the parser." + title: String + "The page's / publisher's preferred thumbnail image" + topImageUrl: Url @deprecated(reason: "use the topImage object") + "The page's / publisher's preferred thumbnail image" + topImage: Image + "Array of videos within the item If the item is a video, this will likely just contain one video" + videos: [Video] + "Number of words in the article" + wordCount: Int + "The date the parser resolved this item" + dateResolved: DateString + "The date the article was published" + datePublished: DateString + "The detected language of the article" + language: String + "How long it will take to read the article (TODO in what time unit? and by what calculation?)" + timeToRead: Int + "Estimated time to listen to the article, in seconds" + listenDuration: Int + """ + The url as provided by the user when saving. Only http or https schemes allowed. + + CAUTION: this value will *likely* (but not always) change depending on which query is used. + itemByItemId will return the normalUrl value here (which is a bug?). itemByUrl will return + the URL value passed in to the query. As if that weren't complicated enough, sometimes + normalUrl and givenUrl are the same (but not usually). + """ + givenUrl: Url! + "Indicates that the item was stored via a different search_hash (using the old method), we'll need to look up a different id" + hasOldDupes: Boolean @deprecated(reason: "Most new items use a new hash") + "The primary database id of the domain this article is from" + domainId: String @deprecated(reason: "Use a domain as the identifier instead") + "If a the domainId is a subdomain this is the primary domain id" + originDomainId: String + @deprecated(reason: "Use a domain as the identifier instead") + "The http response code of the given url" + responseCode: Int @deprecated(reason: "Clients should not use this") + "The length in bytes of the content" + contentLength: Int @deprecated(reason: "Clients should not use this") + "Indicates if the text of the url is a redirect to another url" + innerDomainRedirect: Boolean + @deprecated(reason: "Clients should not use this") + "Indicates if the url requires a login" + loginRequired: Boolean @deprecated(reason: "Clients should not use this") + "Indicates if the parser used fallback methods" + usedFallback: Int @deprecated(reason: "Clients should not use this") + "Date this item was first parsed in Pocket" + timeFirstParsed: DateString @deprecated(reason: "Clients should not use this") + "The resolved url, but ran through the normalized function" + resolvedNormalUrl: Url @deprecated(reason: "Use the resolved url instead") + """ + The pocket HTML string of the article. + Note: Web and Android as of 3/4/2022 use the Article field, any improvements made + within MArticle for parsing will not be reflected in the article field. + When that happens, the clients will work to move to MArticle. + """ + article: String + + "If the url is an Article, the text in SSML format for speaking, i.e. Listen" + ssml: String @tag(name: "beta") + + "The Marticle format of the article, used by clients for native article view." + marticle: [MarticleComponent!] + + "The client preview/display logic for this url" + preview: PocketMetadata +} + +type ArticleMarkdown { + text: String! + images: [MarkdownImagePosition!] +} + +type MarkdownImagePosition { + index: Int! + position: Int! + """ + Fallback is to use the images field in the Item entity + """ + src: String +} + +""" +Metadata from a domain, originally populated from ClearBit +""" +type DomainMetadata @cacheControl(maxAge: 86400) { + "The name of the domain (e.g., The New York Times)" + name: String + "Url for the logo image" + logo: Url + "Url for the greyscale logo image" + logoGreyscale: Url +} + +""" +An image, typically a thumbnail or article view image for an Item +""" +type Image @cacheControl(maxAge: 86400) @key(fields: "url") { + "Absolute url to the image" + url: Url! + "A caption or description of the image" + caption: String + "A credit for the image, typically who the image belongs to / created by" + credit: String + "If known, the height of the image in px" + height: Int @shareable + "The id for placing within an Article View. Item.article will have placeholders of
where X is this id. Apps can download those images as needed and populate them in their article view." + imageId: Int! + "Absolute url to the image" + src: String! @deprecated(reason: "use url property moving forward") + "If known, the width of the image in px" + width: Int @shareable + "If the image is also a link, the destination url" + targetUrl: String +} + +enum Imageness { + "No images (v3 value is 0)" + NO_IMAGES + "Contains images (v3 value is 1)" + HAS_IMAGES + "Is an image (v3 value is 2)" + IS_IMAGE +} + +""" +A Video, typically within an Article View of an Item or if the Item is a video itself. +""" +type Video @cacheControl(maxAge: 86400) { + "If known, the height of the video in px" + height: Int + "Absolute url to the video" + src: String! + "The type of video" + type: VideoType! + "The video's id within the service defined by type" + vid: String + "The id of the video within Article View. Item.article will have placeholders of
where X is this id. Apps can download those images as needed and populate them in their article view." + videoId: Int! + "If known, the width of the video in px" + width: Int + "If known, the length of the video in seconds" + length: Int +} + +enum VideoType { + "Youtube (v3 value is 1)" + YOUTUBE + "Vimeo Link (v3 value is 2)" + VIMEO_LINK + "Vimeo Moogaloop (v3 value is 3)" + VIMEO_MOOGALOOP + "video iframe (v3 value is 4)" + VIMEO_IFRAME + "html5 (v3 value is 5)" + HTML5 + "Flash (v3 value is 6)" + FLASH + "iframe (v3 value is 7)" + IFRAME + "Brightcove (v3 value is 8)" + BRIGHTCOVE +} + +enum Videoness { + "No videos (v3 value is 0)" + NO_VIDEOS + "Contains videos (v3 value is 1)" + HAS_VIDEOS + "Is a video (v3 value is 2)" + IS_VIDEO +} + +union MarticleComponent = + | MarticleText + | Image + | MarticleDivider + | MarticleTable + | MarticleHeading + | MarticleCodeBlock + | Video + | MarticleBulletedList + | MarticleNumberedList + | MarticleBlockquote + | UnMarseable + +""" +Represents content that could not be parsed into a valid Marticle* component. +""" +type UnMarseable { + "The html that could not be parsed into a Marticle* component." + html: String! +} + +""" +A section of the article's text content, in markdown. +A subset of gfm is supported. See README.md for more information. +""" +type MarticleText { + "Markdown text content. Typically, a paragraph." + content: Markdown! +} + +type MarticleDivider { + "Always '---'; provided for convenience if building a markdown string" + content: Markdown! +} + +""" +Content in a table. +""" +type MarticleTable { + "Raw HTML representation of the table." + html: String! +} + +""" +A heading in an article, with markdown formatting. +""" +type MarticleHeading { + "Heading text, in markdown." + content: Markdown! + "Heading level. Restricted to values 1-6." + level: Int! +} + +""" +A pre formatted text in the HTML content. +""" +type MarticleCodeBlock { + "Content of a pre tag" + text: String! + "Assuming the codeblock was a programming language, this field is used to identify it." + language: Int +} + +interface ListElement { + "Row in a list." + content: Markdown! + "Zero-indexed level, for handling nested lists." + level: Int! +} + +""" +Row in a bulleted (unordered list) +""" +type BulletedListElement implements ListElement { + "Row in a list." + content: Markdown! + "Zero-indexed level, for handling nested lists." + level: Int! +} + +type NumberedListElement implements ListElement { + "Row in a list" + content: Markdown! + "Zero-indexed level, for handling nested lists." + level: Int! + "Numeric index. If a nested item, the index is zero-indexed from the first child." + index: Int! +} + +""" +Content in a bulleted (unordered) list. +""" +type MarticleBulletedList { + rows: [BulletedListElement!]! +} + +""" +Content in a bulleted (unordered) list. +""" +type MarticleNumberedList { + rows: [NumberedListElement!]! +} + +""" +Content of a blockquote +""" +type MarticleBlockquote { + "Markdown text content." + content: Markdown! +} + +""" +Information about an Author of an article or some content +""" +type Author @cacheControl(maxAge: 86400) { + "Unique id for that Author" + id: ID! + "Display name" + name: String + "A url to that Author's site" + url: String +} + +type Query { + """ + Look up Item info by a url. + """ + getItemByUrl(url: String!): Item + @cacheControl(maxAge: 86400) + @deprecated(reason: "Use itemByUrl instead") + + """ + Look up Item info by a url. + """ + itemByUrl(url: String!): Item @cacheControl(maxAge: 86400) + + """ + Resolve Reader View links which might point to SavedItems that do not + exist, aren't in the Pocket User's list, or are requested by a logged-out + user (or user without a Pocket Account). + Fetches data which clients can use to generate an appropriate fallback view + that allows users to preview the content and access the original source site. + """ + readerSlug(slug: ID!): ReaderViewResult! +} + +type Mutation { + """ + Refresh an Item's article content. + """ + refreshItemArticle(url: String!): Item! +} + +extend type CorpusItem @key(fields: "url") { + """ + Provides short url for the given_url in the format: https://pocket.co/. + marked as beta because it's not ready yet for large client request. + """ + shortUrl: Url @tag(name: "beta") + url: Url! @external + """ + Time to read in minutes. Is nullable. + """ + timeToRead: Int +} +extend type Collection @key(fields: "slug") { + """ + Provides short url for the given_url in the format: https://pocket.co/. + marked as beta because it's not ready yet for large client request. + """ + shortUrl: Url @tag(name: "beta") + slug: String! @external +} + +""" +Result for resolving a getpocket.com/read/ link. +""" +type ReaderViewResult @key(fields: "slug") { + slug: ID! + fallbackPage: ReaderFallback +} + +""" +Metadata of an Item in Pocket for preview purposes, +or an ItemNotFound result if the record does not exist. +""" +union ReaderFallback = ReaderInterstitial | ItemNotFound + +enum PocketMetadataSource { + POCKET_PARSER + OPENGRAPH + OEMBED +} + +interface PocketMetadata { + id: ID! + image: Image + excerpt: String + title: String + authors: [Author!] + domain: DomainMetadata + datePublished: ISOString + url: Url! + source: PocketMetadataSource! + item: Item +} + +type ItemSummary implements PocketMetadata { + id: ID! + image: Image + excerpt: String + title: String + authors: [Author!] + domain: DomainMetadata + datePublished: ISOString + url: Url! + source: PocketMetadataSource! + item: Item +} + +enum OEmbedType { + RICH + VIDEO + PHOTO + LINK +} + +type OEmbed implements PocketMetadata { + id: ID! + image: Image + excerpt: String + title: String + authors: [Author!] + domain: DomainMetadata + datePublished: ISOString + url: Url! + source: PocketMetadataSource! + item: Item + htmlEmbed: String + type: OEmbedType +} + +""" +Card preview data for Items resolved from reader view +(getpocket.com/read/) links. + +Should be used to create a view if Reader Mode cannot +be rendered (e.g. the link is visited by an anonymous +Pocket user, or a Pocket User that does not have the +underlying Item in their Saves). Due to legal obligations +we can only display Reader Mode for SavedItems. +""" +type ReaderInterstitial { + itemCard: PocketMetadata +} + +type ItemNotFound { + message: String +} + +type PocketShare @key(fields: "targetUrl") { + targetUrl: ValidUrl! + preview: PocketMetadata +} + +""" +A node in a CorpusSearchConnection result +""" +type CorpusSearchNode @key(fields: "url") { + """ + For federation only + """ + url: Url! @inaccessible + """ + The preview of the search result + """ + preview: PocketMetadata! +} diff --git a/servers/parser-graphql-wrapper/schema.graphql b/servers/parser-graphql-wrapper/schema.graphql index 4f4c38e6c..8fb79f361 100644 --- a/servers/parser-graphql-wrapper/schema.graphql +++ b/servers/parser-graphql-wrapper/schema.graphql @@ -19,6 +19,11 @@ See Section 5.6 of the RFC 3339 profile of the ISO 8601 standard: https://www.ie """ scalar ISOString +""" +A date in the YYYY-MM-DD format. +""" +scalar Date + """ A string formatted with CommonMark markdown, plus the strikethrough extension from GFM. @@ -167,8 +172,20 @@ type Item "The Marticle format of the article, used by clients for native article view." marticle: [MarticleComponent!] - "The client preview/display logic for this url" + "The client preview/display logic for this url. The requires for each object should be kept in sync with the sub objects requires field." preview: PocketMetadata + @requires( + fields: "syndicatedArticle { title excerpt mainImage publishedAt authorNames publisherUrl publisher { logo name } } collection { title excerpt publishedAt authors { name } imageUrl } corpusItem { title excerpt datePublished publisher image { url } }" + ) + + "If the item is a syndicated article, then the syndication information" + syndicatedArticle: SyndicatedArticle @external + + "If the item is a collection, then the collection information" + collection: Collection @external + + "If the item is in the Pocket Corpus, then the corpus information" + corpusItem: CorpusItem @external } type ArticleMarkdown { @@ -440,7 +457,50 @@ extend type CorpusItem @key(fields: "url") { Time to read in minutes. Is nullable. """ timeToRead: Int + + """ + The title of the Approved Item. + """ + title: String! @external + """ + The excerpt of the Approved Item. + """ + excerpt: String! @external + """ + The publication date for this story. + """ + datePublished: Date @external + """ + The name of the online publication that published this story. + """ + publisher: String! @external + """ + The image for this item's accompanying picture. + """ + image: Image! @external + + """ + The author names and sort orders associated with this CorpusItem. + """ + authors: [CorpusItemAuthor!]! @external + + """ + The preview of the search result + """ + preview: PocketMetadata! + @requires( + fields: "title excerpt datePublished publisher image { url } authors { name sortOrder }" + ) +} + +""" +An author associated with a CorpusItem. +""" +type CorpusItemAuthor @external { + name: String! + sortOrder: Int! } + extend type Collection @key(fields: "slug") { """ Provides short url for the given_url in the format: https://pocket.co/. @@ -448,6 +508,21 @@ extend type Collection @key(fields: "slug") { """ shortUrl: Url @tag(name: "beta") slug: String! @external + title: String! @external + authors: [CollectionAuthor!]! @external + excerpt: Markdown @external + publishedAt: DateString @external + imageUrl: Url @external + + """ + The preview of the collection + """ + preview: PocketMetadata! + @requires(fields: "title excerpt publishedAt authors { name } imageUrl") +} + +extend type CollectionAuthor @external { + name: String! } """ @@ -468,6 +543,9 @@ enum PocketMetadataSource { POCKET_PARSER OPENGRAPH OEMBED + CURATED_CORPUS + COLLECTION + SYNDICATION } interface PocketMetadata { @@ -524,7 +602,7 @@ Card preview data for Items resolved from reader view Should be used to create a view if Reader Mode cannot be rendered (e.g. the link is visited by an anonymous -Pocket user, or a Pocket User that does not have the +Pocket user, or a Pocket User that does not have the underlying Item in their Saves). Due to legal obligations we can only display Reader Mode for SavedItems. """ @@ -541,10 +619,57 @@ type PocketShare @key(fields: "targetUrl") { preview: PocketMetadata } -"""A node in a CorpusSearchConnection result""" -type CorpusSearchNode @key (fields: "url") { - """For federation only""" +""" +A node in a CorpusSearchConnection result +""" +type CorpusSearchNode @key(fields: "url") { + """ + For federation only + """ url: Url! @inaccessible - """The preview of the search result""" + """ + The preview of the search result + """ + preview: PocketMetadata! +} + +extend type SyndicatedArticle @key(fields: "slug") { + "Slug that pocket uses for this article in the url" + slug: String + + "Title of syndicated article" + title: String! @external + "Array of author names in string format" + authorNames: [String]! @external + + "AWSDateTime — Format: YYYY-MM-DDThh:mm:ss.sssZ" + publishedAt: String! @external + + "Primary image to use in surfacing this content" + mainImage: String @external + + "Excerpt " + excerpt: String @external + + "The canonical publisher URL. Automatically set at time of creation but can be changed by editor." + publisherUrl: String! @external + + "The manually set publisher information for this article" + publisher: Publisher @external + + """ + The preview of the syndicated article + """ preview: PocketMetadata! + @requires( + fields: "title excerpt mainImage publishedAt authorNames publisherUrl publisher { logo name }" + ) } + + +extend type Publisher @external { + "Square logo to use for the publisher" + logo: String + "Name of the publisher of the article" + name: String +} \ No newline at end of file diff --git a/servers/parser-graphql-wrapper/src/__generated__/resolvers-types.ts b/servers/parser-graphql-wrapper/src/__generated__/resolvers-types.ts index 0c55866a8..2cc12f427 100644 --- a/servers/parser-graphql-wrapper/src/__generated__/resolvers-types.ts +++ b/servers/parser-graphql-wrapper/src/__generated__/resolvers-types.ts @@ -20,6 +20,8 @@ export type Scalars = { Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } + /** A date in the YYYY-MM-DD format. */ + Date: { input: any; output: any; } /** A String representing a date in the format of `yyyy-MM-dd HH:mm:ss` */ DateString: { input: any; output: any; } /** @@ -74,16 +76,40 @@ export enum CacheControlScope { export type Collection = { __typename?: 'Collection'; + authors: Array; + excerpt?: Maybe; + imageUrl?: Maybe; + /** The preview of the collection */ + preview: PocketMetadata; + publishedAt?: Maybe; /** * Provides short url for the given_url in the format: https://pocket.co/. * marked as beta because it's not ready yet for large client request. */ shortUrl?: Maybe; slug: Scalars['String']['output']; + title: Scalars['String']['output']; +}; + +export type CollectionAuthor = { + __typename?: 'CollectionAuthor'; + name: Scalars['String']['output']; }; export type CorpusItem = { __typename?: 'CorpusItem'; + /** The author names and sort orders associated with this CorpusItem. */ + authors: Array; + /** The publication date for this story. */ + datePublished?: Maybe; + /** The excerpt of the Approved Item. */ + excerpt: Scalars['String']['output']; + /** The image for this item's accompanying picture. */ + image: Image; + /** The preview of the search result */ + preview: PocketMetadata; + /** The name of the online publication that published this story. */ + publisher: Scalars['String']['output']; /** * Provides short url for the given_url in the format: https://pocket.co/. * marked as beta because it's not ready yet for large client request. @@ -91,9 +117,18 @@ export type CorpusItem = { shortUrl?: Maybe; /** Time to read in minutes. Is nullable. */ timeToRead?: Maybe; + /** The title of the Approved Item. */ + title: Scalars['String']['output']; url: Scalars['Url']['output']; }; +/** An author associated with a CorpusItem. */ +export type CorpusItemAuthor = { + __typename?: 'CorpusItemAuthor'; + name: Scalars['String']['output']; + sortOrder: Scalars['Int']['output']; +}; + /** A node in a CorpusSearchConnection result */ export type CorpusSearchNode = { __typename?: 'CorpusSearchNode'; @@ -164,11 +199,15 @@ export type Item = { article?: Maybe; /** List of Authors involved with this article */ authors?: Maybe>>; + /** If the item is a collection, then the collection information */ + collection?: Maybe; /** * The length in bytes of the content * @deprecated Clients should not use this */ contentLength?: Maybe; + /** If the item is in the Pocket Corpus, then the corpus information */ + corpusItem?: Maybe; /** The date the article was published */ datePublished?: Maybe; /** The date the parser resolved this item */ @@ -246,7 +285,7 @@ export type Item = { * @deprecated Use a domain as the identifier instead */ originDomainId?: Maybe; - /** The client preview/display logic for this url */ + /** The client preview/display logic for this url. The requires for each object should be kept in sync with the sub objects requires field. */ preview?: Maybe; /** A server generated unique reader slug for this item based on itemId */ readerSlug: Scalars['String']['output']; @@ -271,6 +310,8 @@ export type Item = { shortUrl?: Maybe; /** If the url is an Article, the text in SSML format for speaking, i.e. Listen */ ssml?: Maybe; + /** If the item is a syndicated article, then the syndication information */ + syndicatedArticle?: Maybe; /** * Date this item was first parsed in Pocket * @deprecated Clients should not use this @@ -452,9 +493,12 @@ export type PocketMetadata = { }; export enum PocketMetadataSource { + Collection = 'COLLECTION', + CuratedCorpus = 'CURATED_CORPUS', Oembed = 'OEMBED', Opengraph = 'OPENGRAPH', - PocketParser = 'POCKET_PARSER' + PocketParser = 'POCKET_PARSER', + Syndication = 'SYNDICATION' } export type PocketShare = { @@ -463,6 +507,14 @@ export type PocketShare = { targetUrl: Scalars['ValidUrl']['output']; }; +export type Publisher = { + __typename?: 'Publisher'; + /** Square logo to use for the publisher */ + logo?: Maybe; + /** Name of the publisher of the article */ + name?: Maybe; +}; + export type Query = { __typename?: 'Query'; /** @@ -525,6 +577,28 @@ export type ReaderViewResult = { slug: Scalars['ID']['output']; }; +export type SyndicatedArticle = { + __typename?: 'SyndicatedArticle'; + /** Array of author names in string format */ + authorNames: Array>; + /** Excerpt */ + excerpt?: Maybe; + /** Primary image to use in surfacing this content */ + mainImage?: Maybe; + /** The preview of the syndicated article */ + preview: PocketMetadata; + /** AWSDateTime — Format: YYYY-MM-DDThh:mm:ss.sssZ */ + publishedAt: Scalars['String']['output']; + /** The manually set publisher information for this article */ + publisher?: Maybe; + /** The canonical publisher URL. Automatically set at time of creation but can be changed by editor. */ + publisherUrl: Scalars['String']['output']; + /** Slug that pocket uses for this article in the url */ + slug?: Maybe; + /** Title of syndicated article */ + title: Scalars['String']['output']; +}; + /** Represents content that could not be parsed into a valid Marticle* component. */ export type UnMarseable = { __typename?: 'UnMarseable'; @@ -679,15 +753,18 @@ export type ResolversTypes = ResolversObject<{ BulletedListElement: ResolverTypeWrapper; Int: ResolverTypeWrapper; CacheControlScope: CacheControlScope; - Collection: ResolverTypeWrapper; - CorpusItem: ResolverTypeWrapper; + Collection: ResolverTypeWrapper & { preview: ResolversTypes['PocketMetadata'] }>; + CollectionAuthor: ResolverTypeWrapper; + CorpusItem: ResolverTypeWrapper & { preview: ResolversTypes['PocketMetadata'] }>; + CorpusItemAuthor: ResolverTypeWrapper; CorpusSearchNode: ResolverTypeWrapper & { preview: ResolversTypes['PocketMetadata'] }>; + Date: ResolverTypeWrapper; DateString: ResolverTypeWrapper; DomainMetadata: ResolverTypeWrapper; ISOString: ResolverTypeWrapper; Image: ResolverTypeWrapper; Imageness: Imageness; - Item: ResolverTypeWrapper & { marticle?: Maybe>, preview?: Maybe }>; + Item: ResolverTypeWrapper & { collection?: Maybe, corpusItem?: Maybe, marticle?: Maybe>, preview?: Maybe, syndicatedArticle?: Maybe }>; Boolean: ResolverTypeWrapper; ItemNotFound: ResolverTypeWrapper; ItemSummary: ResolverTypeWrapper & { item?: Maybe }>; @@ -710,10 +787,12 @@ export type ResolversTypes = ResolversObject<{ PocketMetadata: ResolverTypeWrapper['PocketMetadata']>; PocketMetadataSource: PocketMetadataSource; PocketShare: ResolverTypeWrapper & { preview?: Maybe }>; + Publisher: ResolverTypeWrapper; Query: ResolverTypeWrapper<{}>; ReaderFallback: ResolverTypeWrapper['ReaderFallback']>; ReaderInterstitial: ResolverTypeWrapper & { itemCard?: Maybe }>; ReaderViewResult: ResolverTypeWrapper & { fallbackPage?: Maybe }>; + SyndicatedArticle: ResolverTypeWrapper & { preview: ResolversTypes['PocketMetadata'] }>; UnMarseable: ResolverTypeWrapper; Url: ResolverTypeWrapper; ValidUrl: ResolverTypeWrapper; @@ -730,14 +809,17 @@ export type ResolversParentTypes = ResolversObject<{ ID: Scalars['ID']['output']; BulletedListElement: BulletedListElement; Int: Scalars['Int']['output']; - Collection: Collection; - CorpusItem: CorpusItem; + Collection: Omit & { preview: ResolversParentTypes['PocketMetadata'] }; + CollectionAuthor: CollectionAuthor; + CorpusItem: Omit & { preview: ResolversParentTypes['PocketMetadata'] }; + CorpusItemAuthor: CorpusItemAuthor; CorpusSearchNode: Omit & { preview: ResolversParentTypes['PocketMetadata'] }; + Date: Scalars['Date']['output']; DateString: Scalars['DateString']['output']; DomainMetadata: DomainMetadata; ISOString: Scalars['ISOString']['output']; Image: Image; - Item: Omit & { marticle?: Maybe>, preview?: Maybe }; + Item: Omit & { collection?: Maybe, corpusItem?: Maybe, marticle?: Maybe>, preview?: Maybe, syndicatedArticle?: Maybe }; Boolean: Scalars['Boolean']['output']; ItemNotFound: ItemNotFound; ItemSummary: Omit & { item?: Maybe }; @@ -758,10 +840,12 @@ export type ResolversParentTypes = ResolversObject<{ OEmbed: Omit & { item?: Maybe }; PocketMetadata: ResolversInterfaceTypes['PocketMetadata']; PocketShare: Omit & { preview?: Maybe }; + Publisher: Publisher; Query: {}; ReaderFallback: ResolversUnionTypes['ReaderFallback']; ReaderInterstitial: Omit & { itemCard?: Maybe }; ReaderViewResult: Omit & { fallbackPage?: Maybe }; + SyndicatedArticle: Omit & { preview: ResolversParentTypes['PocketMetadata'] }; UnMarseable: UnMarseable; Url: Scalars['Url']['output']; ValidUrl: Scalars['ValidUrl']['output']; @@ -796,16 +880,40 @@ export type BulletedListElementResolvers = ResolversObject<{ __resolveReference?: ReferenceResolver, { __typename: 'Collection' } & GraphQLRecursivePick, ContextType>; + + + + preview?: Resolver & GraphQLRecursivePick, ContextType>; + shortUrl?: Resolver, { __typename: 'Collection' } & GraphQLRecursivePick, ContextType>; + + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type CollectionAuthorResolvers = ResolversObject<{ + name?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }>; export type CorpusItemResolvers = ResolversObject<{ __resolveReference?: ReferenceResolver, { __typename: 'CorpusItem' } & GraphQLRecursivePick, ContextType>; + + + + + preview?: Resolver & GraphQLRecursivePick, ContextType>; + shortUrl?: Resolver, { __typename: 'CorpusItem' } & GraphQLRecursivePick, ContextType>; timeToRead?: Resolver, { __typename: 'CorpusItem' } & GraphQLRecursivePick, ContextType>; + + __isTypeOf?: IsTypeOfResolverFn; +}>; + +export type CorpusItemAuthorResolvers = ResolversObject<{ + name?: Resolver; + sortOrder?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }>; @@ -816,6 +924,10 @@ export type CorpusSearchNodeResolvers; }>; +export interface DateScalarConfig extends GraphQLScalarTypeConfig { + name: 'Date'; +} + export interface DateStringScalarConfig extends GraphQLScalarTypeConfig { name: 'DateString'; } @@ -846,50 +958,53 @@ export type ImageResolvers = ResolversObject<{ __resolveReference?: ReferenceResolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; - ampUrl?: Resolver, ParentType, ContextType>; - article?: Resolver, ParentType, ContextType>; - authors?: Resolver>>, ParentType, ContextType>; - contentLength?: Resolver, ParentType, ContextType>; - datePublished?: Resolver, ParentType, ContextType>; - dateResolved?: Resolver, ParentType, ContextType>; - domain?: Resolver, ParentType, ContextType>; - domainId?: Resolver, ParentType, ContextType>; - domainMetadata?: Resolver, ParentType, ContextType>; - encoding?: Resolver, ParentType, ContextType>; - excerpt?: Resolver, ParentType, ContextType>; - givenUrl?: Resolver; - hasImage?: Resolver, ParentType, ContextType>; - hasOldDupes?: Resolver, ParentType, ContextType>; - hasVideo?: Resolver, ParentType, ContextType>; - id?: Resolver; - images?: Resolver>>, ParentType, ContextType>; - innerDomainRedirect?: Resolver, ParentType, ContextType>; - isArticle?: Resolver, ParentType, ContextType>; - isIndex?: Resolver, ParentType, ContextType>; - itemId?: Resolver; - language?: Resolver, ParentType, ContextType>; - listenDuration?: Resolver, ParentType, ContextType>; - loginRequired?: Resolver, ParentType, ContextType>; - marticle?: Resolver>, ParentType, ContextType>; - mimeType?: Resolver, ParentType, ContextType>; - normalUrl?: Resolver; - originDomainId?: Resolver, ParentType, ContextType>; - preview?: Resolver, ParentType, ContextType>; - readerSlug?: Resolver; - resolvedId?: Resolver, ParentType, ContextType>; - resolvedNormalUrl?: Resolver, ParentType, ContextType>; - resolvedUrl?: Resolver, ParentType, ContextType>; - responseCode?: Resolver, ParentType, ContextType>; - shortUrl?: Resolver, ParentType, ContextType>; - ssml?: Resolver, ParentType, ContextType>; - timeFirstParsed?: Resolver, ParentType, ContextType>; - timeToRead?: Resolver, ParentType, ContextType>; - title?: Resolver, ParentType, ContextType>; - topImage?: Resolver, ParentType, ContextType>; - topImageUrl?: Resolver, ParentType, ContextType>; - usedFallback?: Resolver, ParentType, ContextType>; - videos?: Resolver>>, ParentType, ContextType>; - wordCount?: Resolver, ParentType, ContextType>; + ampUrl?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + article?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + authors?: Resolver>>, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + + contentLength?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + + datePublished?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + dateResolved?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + domain?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + domainId?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + domainMetadata?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + encoding?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + excerpt?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + givenUrl?: Resolver | GraphQLRecursivePick), ContextType>; + hasImage?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + hasOldDupes?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + hasVideo?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + id?: Resolver | GraphQLRecursivePick), ContextType>; + images?: Resolver>>, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + innerDomainRedirect?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + isArticle?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + isIndex?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + itemId?: Resolver | GraphQLRecursivePick), ContextType>; + language?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + listenDuration?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + loginRequired?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + marticle?: Resolver>, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + mimeType?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + normalUrl?: Resolver | GraphQLRecursivePick), ContextType>; + originDomainId?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + preview?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick) & GraphQLRecursivePick, ContextType>; + readerSlug?: Resolver | GraphQLRecursivePick), ContextType>; + resolvedId?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + resolvedNormalUrl?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + resolvedUrl?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + responseCode?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + shortUrl?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + ssml?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + + timeFirstParsed?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + timeToRead?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + title?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + topImage?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + topImageUrl?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + usedFallback?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + videos?: Resolver>>, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + wordCount?: Resolver, { __typename: 'Item' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; __isTypeOf?: IsTypeOfResolverFn; }>; @@ -1023,6 +1138,12 @@ export type PocketShareResolvers; }>; +export type PublisherResolvers = ResolversObject<{ + logo?: Resolver, ParentType, ContextType>; + name?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + export type QueryResolvers = ResolversObject<{ getItemByUrl?: Resolver, ParentType, ContextType, RequireFields>; itemByUrl?: Resolver, ParentType, ContextType, RequireFields>; @@ -1045,6 +1166,20 @@ export type ReaderViewResultResolvers; }>; +export type SyndicatedArticleResolvers = ResolversObject<{ + __resolveReference?: ReferenceResolver, { __typename: 'SyndicatedArticle' } & GraphQLRecursivePick, ContextType>; + + + + preview?: Resolver & GraphQLRecursivePick, ContextType>; + + + + slug?: Resolver, { __typename: 'SyndicatedArticle' } & GraphQLRecursivePick, ContextType>; + + __isTypeOf?: IsTypeOfResolverFn; +}>; + export type UnMarseableResolvers = ResolversObject<{ html?: Resolver; __isTypeOf?: IsTypeOfResolverFn; @@ -1074,8 +1209,11 @@ export type Resolvers = ResolversObject<{ Author?: AuthorResolvers; BulletedListElement?: BulletedListElementResolvers; Collection?: CollectionResolvers; + CollectionAuthor?: CollectionAuthorResolvers; CorpusItem?: CorpusItemResolvers; + CorpusItemAuthor?: CorpusItemAuthorResolvers; CorpusSearchNode?: CorpusSearchNodeResolvers; + Date?: GraphQLScalarType; DateString?: GraphQLScalarType; DomainMetadata?: DomainMetadataResolvers; ISOString?: GraphQLScalarType; @@ -1100,10 +1238,12 @@ export type Resolvers = ResolversObject<{ OEmbed?: OEmbedResolvers; PocketMetadata?: PocketMetadataResolvers; PocketShare?: PocketShareResolvers; + Publisher?: PublisherResolvers; Query?: QueryResolvers; ReaderFallback?: ReaderFallbackResolvers; ReaderInterstitial?: ReaderInterstitialResolvers; ReaderViewResult?: ReaderViewResultResolvers; + SyndicatedArticle?: SyndicatedArticleResolvers; UnMarseable?: UnMarseableResolvers; Url?: GraphQLScalarType; ValidUrl?: GraphQLScalarType; diff --git a/servers/parser-graphql-wrapper/src/apollo/resolvers.ts b/servers/parser-graphql-wrapper/src/apollo/resolvers.ts index 0f084cf6d..451dbfde9 100644 --- a/servers/parser-graphql-wrapper/src/apollo/resolvers.ts +++ b/servers/parser-graphql-wrapper/src/apollo/resolvers.ts @@ -8,7 +8,14 @@ import { import { SSMLModel } from '../models/SSMLModel'; import { fallbackPage } from '../readerView'; import { PocketDefaultScalars } from '@pocket-tools/apollo-utils'; -import { Item, Resolvers, Videoness } from '../__generated__/resolvers-types'; +import { + Collection, + CorpusItem, + Item, + Resolvers, + SyndicatedArticle, + Videoness, +} from '../__generated__/resolvers-types'; import { BoolStringParam, MediaTypeParam } from '../datasources/ParserAPI'; import { extractSlugFromReadUrl, @@ -27,6 +34,11 @@ export const resolvers: Resolvers = { item, context, false, + { + syndicatedArticle: item.syndicatedArticle, + collection: item.collection, + corpusItem: item.corpusItem, + }, ); return { url: representation.url, @@ -47,7 +59,7 @@ export const resolvers: Resolvers = { } if ('givenUrl' in item) { - return itemFromUrl(item.givenUrl, context); + return { ...item, ...(await itemFromUrl(item.givenUrl, context)) }; } else if ('itemId' in item) { const itemLoaderType = await context.dataLoaders.itemIdLoader.load( item.itemId, @@ -55,10 +67,11 @@ export const resolvers: Resolvers = { if (!itemLoaderType.url) { throw new Error(`No url found for itemId: ${item.itemId}`); } - return itemFromUrl(itemLoaderType.url, context); + return { ...item, ...(await itemFromUrl(itemLoaderType.url, context)) }; } }, - article: async (parent, args, { dataSources }, info) => { + article: async (uncastParent, args, { dataSources }, info) => { + const parent = uncastParent as Item; if (parent.article) { // Use the parent resolver for article content if available // (e.g. via refreshArticle mutation), otherwise load the article @@ -78,7 +91,8 @@ export const resolvers: Resolvers = { return item.article || null; }, - marticle: async (parent, args, { dataSources }, info) => { + marticle: async (uncastParent, args, { dataSources }, info) => { + const parent = uncastParent as Item; // Note: When the Web & Android teams switch to MArticle, make all the parser article call use // MediaTypeParam.AS_COMMENTS and add back this optimization: // @@ -106,12 +120,13 @@ export const resolvers: Resolvers = { : ([] as MarticleElement[]); }, ssml: async (parent, args, { dataSources }, info) => { - if (!parent.article && parent.isArticle) { + const castParent = parent as Item; + if (!castParent.article && castParent.isArticle) { // If the field was requested via refreshArticle we need to clear the cache before we request data const clearCache = isInResolverChain('refreshItemArticle', info.path); - parent.article = ( + castParent.article = ( await dataSources.parserAPI.getItemData( - parent.givenUrl, + castParent.givenUrl, { videos: MediaTypeParam.DIV_TAG, images: MediaTypeParam.DIV_TAG, @@ -121,12 +136,14 @@ export const resolvers: Resolvers = { ) ).article; } - if (!parent.article) { + if (!castParent.article) { return null; } - return SSMLModel.generateSSML(parent); + return SSMLModel.generateSSML(parent as Item); }, - shortUrl: async (parent, args, context) => { + shortUrl: async (uncastParent, args, context) => { + const parent = uncastParent as Item; + // If the givenUrl is already a short share url, or there is a // short url key on the parent from a previous step, return the // same value to avoid another db trip @@ -147,11 +164,16 @@ export const resolvers: Resolvers = { const clearCache = isInResolverChain('refreshItemArticle', info.path); const preview = await context.dataSources.pocketMetadataModel.derivePocketMetadata( - parent, + parent as Item, context, clearCache, + { + syndicatedArticle: parent.syndicatedArticle as SyndicatedArticle, + collection: parent.collection as Collection, + corpusItem: parent.corpusItem as CorpusItem, + }, ); - return { ...preview, item: parent }; + return { ...preview, item: parent as Item }; }, }, MarticleComponent: { @@ -210,6 +232,18 @@ export const resolvers: Resolvers = { return null; } }, + preview: async (parent, _, context) => { + const item = await context.dataSources.parserAPI.getItemData(parent.url); + + const preview = + await context.dataSources.pocketMetadataModel.derivePocketMetadata( + item, + context, + false, + { corpusItem: parent as CorpusItem }, + ); + return { ...preview, item }; + }, }, Collection: { shortUrl: async ({ slug }, args, { dataSources, dataLoaders }) => { @@ -227,6 +261,36 @@ export const resolvers: Resolvers = { givenUrl: item.givenUrl, }); }, + preview: async (parent, args, context) => { + const item = await context.dataSources.parserAPI.getItemData( + `${config.shortUrl.collectionUrl}/${parent.slug}`, + ); + + const preview = + await context.dataSources.pocketMetadataModel.derivePocketMetadata( + item, + context, + false, + { collection: parent as Collection }, + ); + return { ...preview, item }; + }, + }, + SyndicatedArticle: { + preview: async (parent, args, context) => { + const item = await context.dataSources.parserAPI.getItemData( + `${config.shortUrl.syndicationUrl}/${parent.slug}`, + ); + + const preview = + await context.dataSources.pocketMetadataModel.derivePocketMetadata( + item, + context, + false, + { syndicatedArticle: parent as SyndicatedArticle }, + ); + return { ...preview, item }; + }, }, PocketMetadata: { __resolveType(parent) { diff --git a/servers/parser-graphql-wrapper/src/config/index.ts b/servers/parser-graphql-wrapper/src/config/index.ts index c4ba041ba..014c0ea45 100644 --- a/servers/parser-graphql-wrapper/src/config/index.ts +++ b/servers/parser-graphql-wrapper/src/config/index.ts @@ -58,6 +58,8 @@ export default { 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ123456789_', collectionUrl: process.env.COLLECTIONS_URL || 'https://getpocket.com/collections', + syndicationUrl: + process.env.SYNDICATION_URL || 'https://getpocket.com/explore/item', }, mysql: { host: process.env.DB_HOST || 'localhost', diff --git a/servers/parser-graphql-wrapper/src/models/PocketMetadataModel.ts b/servers/parser-graphql-wrapper/src/models/PocketMetadataModel.ts index 21cd50db5..4aba10aba 100644 --- a/servers/parser-graphql-wrapper/src/models/PocketMetadataModel.ts +++ b/servers/parser-graphql-wrapper/src/models/PocketMetadataModel.ts @@ -3,6 +3,9 @@ import { PocketMetadataSource, PocketMetadata, ItemSummary, + SyndicatedArticle, + CorpusItem, + Collection, } from '../__generated__/resolvers-types'; import config from '../config'; import { DateTime } from 'luxon'; @@ -12,6 +15,8 @@ import { PocketMetadataEntity, } from '../databases/pocketMetadataStore'; import md5 from 'md5'; +import { getOriginalUrlIfPocketImageCached } from '@pocket-tools/image-utils'; +import markdownToTxt from 'markdown-to-txt'; export interface IPocketMetadataDataSource { matcher: RegExp; @@ -36,25 +41,34 @@ export class PocketMetadataModel { item: Item, context: IContext, refresh: boolean, + extraData: { + corpusItem?: CorpusItem; + syndicatedArticle?: SyndicatedArticle; + collection?: Collection; + } = {}, ): Promise { + const { syndicatedArticle, collection, corpusItem } = extraData; const url = item.givenUrl; // the url we are going to key everything on. - const fallbackParserPocketMetadata: ItemSummary = { - id: item.id, - image: item.topImage ?? item.images?.[0], - excerpt: item.excerpt, - title: item.title ?? item.givenUrl, - authors: item.authors, - domain: item.domainMetadata, - datePublished: item.datePublished - ? DateTime.fromSQL(item.datePublished, { - zone: config.mysql.tz, - }).toJSDate() - : null, - url: url, - source: PocketMetadataSource.PocketParser, - __typename: 'ItemSummary', - }; + const syndicatedArticlePocketMetadata = this.transformSyndicatedArticle( + item, + syndicatedArticle, + ); + if (syndicatedArticlePocketMetadata) { + return syndicatedArticlePocketMetadata; + } + + const collectionPocketMetadata = this.transformCollection(item, collection); + if (collectionPocketMetadata) { + return collectionPocketMetadata; + } + + const corpusItemMetadata = this.transformCorpusItem(item, corpusItem); + if (corpusItemMetadata) { + return corpusItemMetadata; + } + + const fallbackParserPocketMetadata = this.transformParserFallback(item); // First we filter to our sources. // We do this first because some sources could be behind a feature flag or not enabled // We also only store other data sources beyond our parser in the datastore, \ @@ -172,4 +186,173 @@ export class PocketMetadataModel { return res == null ? null : this.fromEntity(res); } + + /** + * + * @param item Item object from the Graph + * @param collection Collection object from the graph + * @returns ItemSummary data to be shown to the user + */ + transformCollection( + item: Item, + collection: Collection, + ): ItemSummary | undefined { + if (!collection) { + return; + } + const imageUrl = getOriginalUrlIfPocketImageCached(collection.imageUrl); + return { + id: item.id, + image: { + url: imageUrl, + imageId: 0, + src: imageUrl, + }, + excerpt: markdownToTxt(collection.excerpt), + title: collection.title, + authors: collection.authors.map((author, index) => { + return { + name: author.name, + id: index.toFixed(), + }; + }), + domain: { + logo: 'https://getpocket.com/favicon.ico', + name: 'Pocket', + }, + datePublished: collection.publishedAt + ? DateTime.fromISO(collection.publishedAt).toJSDate() + : item.datePublished + ? DateTime.fromSQL(item.datePublished, { + zone: config.mysql.tz, + }).toJSDate() + : null, + url: item.givenUrl, + source: PocketMetadataSource.Collection, + __typename: 'ItemSummary', + }; + } + + /** + * + * @param item Item object from the Graph + * @param syndicatedArticle Syndication object from the graph + * @returns ItemSummary data to be shown to the user + */ + transformSyndicatedArticle( + item: Item, + syndicatedArticle?: SyndicatedArticle, + ): ItemSummary | undefined { + if (!syndicatedArticle) { + return; + } + const imageUrl = getOriginalUrlIfPocketImageCached( + syndicatedArticle.mainImage, + ); + + return { + id: item.id, + image: { + url: imageUrl, + imageId: 0, + src: imageUrl, + }, + excerpt: syndicatedArticle.excerpt, + title: syndicatedArticle.title, + authors: syndicatedArticle.authorNames.map((author, index) => { + return { + name: author, + id: index.toFixed(), + }; + }), + domain: { + logo: syndicatedArticle.publisher.logo, + name: syndicatedArticle.publisher.name, + }, + datePublished: syndicatedArticle.publishedAt + ? DateTime.fromISO(syndicatedArticle.publishedAt).toJSDate() + : item.datePublished + ? DateTime.fromSQL(item.datePublished, { + zone: config.mysql.tz, + }).toJSDate() + : null, + url: item.givenUrl, + source: PocketMetadataSource.Syndication, + __typename: 'ItemSummary', + }; + } + + /** + * + * @param item Item object from the Graph + * @param syndicatedArticle Syndication object from the graph + * @returns ItemSummary data to be shown to the user + */ + transformCorpusItem( + item: Item, + corpusItem?: CorpusItem, + ): ItemSummary | undefined { + if (!corpusItem) { + return; + } + const imageUrl = getOriginalUrlIfPocketImageCached(corpusItem.image.url); + + return { + id: item.id, + image: { + url: imageUrl, + imageId: 0, + src: imageUrl, + }, + excerpt: corpusItem.excerpt, + title: corpusItem.title, + authors: corpusItem.authors + .map((author) => { + return { + name: author.name, + id: author.sortOrder.toFixed(), + }; + }) + .sort((author1, author2) => + author1.id < author2.id ? -1 : author1.id > author2.id ? 1 : 0, + ), + domain: { + name: corpusItem.publisher, + }, + datePublished: corpusItem.datePublished + ? DateTime.fromISO(corpusItem.datePublished).toJSDate() + : item.datePublished + ? DateTime.fromSQL(item.datePublished, { + zone: config.mysql.tz, + }).toJSDate() + : null, + url: item.givenUrl, + source: PocketMetadataSource.CuratedCorpus, + __typename: 'ItemSummary', + }; + } + + /** + * Transforms the item into ItemSummary + * @param item The item that we need to transform + * @returns + */ + transformParserFallback(item: Item): ItemSummary | undefined { + return { + id: item.id, + image: item.topImage ?? item.images?.[0], + excerpt: item.excerpt, + title: item.title ?? item.givenUrl, + authors: item.authors, + domain: item.domainMetadata, + datePublished: item.datePublished + ? DateTime.fromSQL(item.datePublished, { + zone: config.mysql.tz, + }).toJSDate() + : null, + url: item.givenUrl, + source: PocketMetadataSource.PocketParser, + __typename: 'ItemSummary', + }; + } } diff --git a/servers/parser-graphql-wrapper/src/test/queries/preview.integration.ts.bak b/servers/parser-graphql-wrapper/src/test/queries/preview.integration.ts.bak new file mode 100644 index 000000000..06451fa50 --- /dev/null +++ b/servers/parser-graphql-wrapper/src/test/queries/preview.integration.ts.bak @@ -0,0 +1,170 @@ +// import { cleanAll, restore } from 'nock'; +// import { getRedis } from '../../cache'; +// import { startServer } from '../../apollo/server'; +// import { ApolloServer } from '@apollo/server'; +// import request from 'supertest'; +// import { print } from 'graphql'; +// import { gql } from 'graphql-tag'; +// import { IContext } from '../../apollo/context'; +// import { Application } from 'express'; +// import { IntMask } from '@pocket-tools/int-mask'; +// import { nockResponseForParser } from '../utils/parserResponse'; +// import { Kysely } from 'kysely'; +// import { DB } from '../../__generated__/readitlab'; +// import { conn as readitlabInit } from '../../databases/readitlab'; +// import { conn as sharesInit } from '../../databases/readitlaShares'; +// import { clearDynamoDB, dynamoClient } from '../../datasources/dynamoClient'; +// import { PocketMetadataSource } from '../../__generated__/resolvers-types'; + +// //TODO: Sync with @kschelonka on how we can test this best. For now I manually tested locally and in dev. +// describe.skip('preview', () => { +// let app: Application; +// let server: ApolloServer; +// let graphQLUrl: string; +// let readitlabDB: Kysely; + +// const GET_PREVIEW = gql` +// query display($representations: [_Any!]!) { +// _entities(representations: $representations) { +// ... on Item { +// preview { +// ... on PocketMetadata { +// source +// id +// title +// image { +// url +// src +// } +// excerpt +// authors { +// id +// } +// domain { +// name +// logo +// } +// datePublished +// url +// item { +// id +// } +// } +// } +// } +// } +// } +// `; + +// const testUrl = 'https://getpocket.com/collections/testing'; + +// const item = { +// item_id: 123, +// search_hash: '123455sdf', +// normal_url: testUrl, +// resolved_id: 123, +// has_old_dupes: 0, +// }; + +// const parserItemId = '123'; + +// const defaultExpected = { +// id: 'encodedId_202cb962ac59075b964b07152d234b70', +// image: null, +// excerpt: null, +// authors: null, +// domain: { logo: null, name: 'getpocket.com' }, +// datePublished: '2022-06-29T20:14:49.000Z', +// url: testUrl, +// item: { +// id: 'encodedId_202cb962ac59075b964b07152d234b70', +// }, +// }; + +// beforeAll(async () => { +// ({ app, server, url: graphQLUrl } = await startServer(0)); +// readitlabDB = readitlabInit(); +// await readitlabDB.deleteFrom('items_resolver').execute(); + +// //Create a seed item +// await readitlabDB.insertInto('items_resolver').values([item]).execute(); +// }); + +// beforeEach(async () => { +// jest.resetAllMocks(); +// jest.restoreAllMocks(); +// jest.spyOn(IntMask, 'decode').mockReturnValueOnce(123); +// jest.spyOn(IntMask, 'encode').mockReturnValueOnce('encodedId'); +// // flush the redis cache +// await getRedis().clear(); +// await clearDynamoDB(dynamoClient()); +// }); + +// afterAll(async () => { +// await server.stop(); +// await getRedis().disconnect(); +// cleanAll(); +// restore(); +// await readitlabDB.destroy(); +// await sharesInit().destroy(); +// jest.restoreAllMocks(); +// }); + +// it.each([ +// { +// parserData: {}, +// collection: { +// __typename: 'Collection', +// title: 'Super cool collection', +// excerpt: 'The collection', +// publishedAt: '2028-01-01', +// authors: [{ name: 'Billy Joel' }], +// imageUrl: 'https://thecoolimage.com', +// }, +// syndicatedArticle: undefined, +// corpusItem: undefined, +// expected: { +// title: 'Super cool collection', +// source: PocketMetadataSource.Collection, +// }, +// }, +// ])( +// 'should return opengraph display data if enabled', +// async ({ +// parserData, +// collection, +// syndicatedArticle, +// corpusItem, +// expected, +// }) => { +// nockResponseForParser(testUrl, { +// data: { +// item_id: parserItemId, +// given_url: testUrl, +// normal_url: testUrl, +// title: 'parser test', +// authors: [], +// images: [], +// videos: [], +// resolved_id: '16822', +// excerpt: null, +// domainMetadata: null, +// topImageUrl: null, +// // override the default +// ...parserData, +// }, +// }); +// const variables = { +// representations: [ +// { __typename: 'Item', collection, syndicatedArticle, corpusItem }, +// ], +// }; +// const res = await request(app) +// .post(graphQLUrl) +// .send({ query: print(GET_PREVIEW), variables }); +// expect(res.body.data).toEqual({ +// itemByUrl: { preview: { ...defaultExpected, ...expected } }, +// }); +// }, +// ); +// }); diff --git a/servers/shareable-lists-api/package.json b/servers/shareable-lists-api/package.json index 8ec9b116c..a6902c01c 100644 --- a/servers/shareable-lists-api/package.json +++ b/servers/shareable-lists-api/package.json @@ -35,7 +35,7 @@ "dependencies": { "@apollo/server": "4.10.4", "@apollo/server-plugin-response-cache": "4.1.3", - "@apollo/subgraph": "2.8.4", + "@apollo/subgraph": "2.9.0", "@apollo/utils.keyvadapter": "3.1.0", "@apollo/utils.keyvaluecache": "3.1.0", "@aws-sdk/client-eventbridge": "3.632.0", diff --git a/servers/shares-api/package.json b/servers/shares-api/package.json index 24548a477..b917cab60 100644 --- a/servers/shares-api/package.json +++ b/servers/shares-api/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@apollo/server": "4.10.4", - "@apollo/subgraph": "2.8.4", + "@apollo/subgraph": "2.9.0", "@aws-sdk/client-dynamodb": "3.632.0", "@aws-sdk/client-eventbridge": "3.632.0", "@aws-sdk/lib-dynamodb": "3.632.0", diff --git a/servers/user-api/package.json b/servers/user-api/package.json index 3ea52c730..a0b09a53f 100644 --- a/servers/user-api/package.json +++ b/servers/user-api/package.json @@ -19,7 +19,7 @@ }, "dependencies": { "@apollo/server": "4.10.4", - "@apollo/subgraph": "2.8.4", + "@apollo/subgraph": "2.9.0", "@aws-sdk/client-eventbridge": "3.632.0", "@pocket-tools/apollo-utils": "workspace:*", "@pocket-tools/int-mask": "workspace:*", diff --git a/servers/user-list-search/package.json b/servers/user-list-search/package.json index f91688bc9..b998d6229 100644 --- a/servers/user-list-search/package.json +++ b/servers/user-list-search/package.json @@ -22,7 +22,7 @@ }, "dependencies": { "@apollo/server": "4.10.4", - "@apollo/subgraph": "2.8.4", + "@apollo/subgraph": "2.9.0", "@aws-sdk/client-eventbridge": "3.632.0", "@aws-sdk/client-sqs": "3.632.0", "@elastic/elasticsearch": "^8.14.0", diff --git a/turbo.json b/turbo.json index aca88aac1..2497965e2 100644 --- a/turbo.json +++ b/turbo.json @@ -6,7 +6,23 @@ ".env", ".env.example" ], - "globalEnv": ["NODE_ENV", "GITHUB_TOKEN", "NPM_TOKEN", "GH_TOKEN"], + "globalEnv": [ + "NODE_ENV", + "GITHUB_TOKEN", + "NPM_TOKEN", + "GH_TOKEN", + "PARSER_BASE_ENDPOINT", + "PARSER_DATA_PATH", + "LOG_LEVEL", + "CHARACTER_MAP", + "POSITION_MAP", + "MD5_RANDOMIZER", + "LETTER_INDEX", + "SALT_1", + "SALT_2", + "UNLEASH_ENDPOINT", + "UNLEASH_KEY" + ], "tasks": { "build": { "dependsOn": ["^build"],