diff --git a/infrastructure/braze-content-proxy/src/main.ts b/infrastructure/braze-content-proxy/src/main.ts index ee9dd75c7..1cecc7606 100644 --- a/infrastructure/braze-content-proxy/src/main.ts +++ b/infrastructure/braze-content-proxy/src/main.ts @@ -1,10 +1,5 @@ import { Construct } from 'constructs'; -import { - App, - DataTerraformRemoteState, - S3Backend, - TerraformStack, -} from 'cdktf'; +import { App, S3Backend, TerraformStack } from 'cdktf'; import { provider as awsProvider, dataAwsCallerIdentity, @@ -15,10 +10,7 @@ import { wafv2IpSet, } from '@cdktf/provider-aws'; import { config } from './config'; -import { - PocketALBApplication, - PocketPagerDuty, -} from '@pocket-tools/terraform-modules'; +import { PocketALBApplication } from '@pocket-tools/terraform-modules'; import { provider as localProvider } from '@cdktf/provider-local'; import { provider as nullProvider } from '@cdktf/provider-null'; import { provider as pagerDutyProvider } from '@cdktf/provider-pagerduty'; @@ -52,7 +44,6 @@ class BrazeContentProxy extends TerraformStack { ); this.createPocketAlbApplication({ - pagerDuty: this.createPagerDuty(), secretsManagerKmsAlias: this.getSecretsManagerKmsAlias(), snsTopic: this.getCodeDeploySnsTopic(), region, @@ -150,57 +141,15 @@ class BrazeContentProxy extends TerraformStack { }); } - /** - * Create PagerDuty service for alerts - * @private - */ - private createPagerDuty() { - // don't create any pagerduty resources if in dev - if (config.isDev) { - return undefined; - } - - const incidentManagement = new DataTerraformRemoteState( - this, - 'incident_management', - { - organization: 'Pocket', - workspaces: { - name: 'incident-management', - }, - }, - ); - - return new PocketPagerDuty(this, 'pagerduty', { - prefix: config.prefix, - service: { - // This is a Tier 2 service and as such only raises non-critical alarms. - criticalEscalationPolicyId: incidentManagement - .get('policy_default_non_critical_id') - .toString(), - nonCriticalEscalationPolicyId: incidentManagement - .get('policy_default_non_critical_id') - .toString(), - }, - }); - } - private createPocketAlbApplication(dependencies: { - pagerDuty: PocketPagerDuty; region: dataAwsRegion.DataAwsRegion; caller: dataAwsCallerIdentity.DataAwsCallerIdentity; secretsManagerKmsAlias: dataAwsKmsAlias.DataAwsKmsAlias; snsTopic: dataAwsSnsTopic.DataAwsSnsTopic; wafAcl: wafv2WebAcl.Wafv2WebAcl; }): PocketALBApplication { - const { - pagerDuty, - region, - caller, - secretsManagerKmsAlias, - snsTopic, - wafAcl, - } = dependencies; + const { region, caller, secretsManagerKmsAlias, snsTopic, wafAcl } = + dependencies; return new PocketALBApplication(this, 'application', { internal: false, @@ -242,18 +191,6 @@ class BrazeContentProxy extends TerraformStack { }, ], }, - { - name: 'xray-daemon', - containerImage: 'public.ecr.aws/xray/aws-xray-daemon:latest', - portMappings: [ - { - hostPort: 2000, - containerPort: 2000, - protocol: 'udp', - }, - ], - command: ['--region', 'us-east-1', '--local-mode'], - }, ], codeDeploy: { useCodeDeploy: true, @@ -324,7 +261,7 @@ class BrazeContentProxy extends TerraformStack { threshold: 25, evaluationPeriods: 4, period: 300, - actions: config.isDev ? [] : [pagerDuty.snsNonCriticalAlarmTopic.arn], + actions: config.isDev ? [] : [snsTopic.arn], }, }, }); diff --git a/packages/apollo-utils/package.json b/packages/apollo-utils/package.json index d0e9c385a..392c47b9c 100644 --- a/packages/apollo-utils/package.json +++ b/packages/apollo-utils/package.json @@ -25,6 +25,7 @@ "dev": "pnpm run build --watch", "format": "eslint --fix", "lint": "eslint --fix-dry-run", + "presemantic-release": "pnpm run build", "semantic-release": "semantic-release", "test": "jest", "test:watch": "pnpm run test -- --watch" @@ -113,4 +114,4 @@ "graphql": "16.8.1", "graphql-tag": "2.12.6" } -} +} \ No newline at end of file diff --git a/packages/lambda-secrets/package.json b/packages/lambda-secrets/package.json index 7e2499f6a..e9852b42d 100644 --- a/packages/lambda-secrets/package.json +++ b/packages/lambda-secrets/package.json @@ -24,6 +24,7 @@ "dev": "pnpm run build --watch", "format": "eslint --fix", "lint": "eslint --fix-dry-run", + "presemantic-release": "pnpm run build", "semantic-release": "semantic-release" }, "release": { @@ -86,4 +87,4 @@ "tsup": "8.2.4", "typescript": "5.5.4" } -} +} \ No newline at end of file diff --git a/packages/terraform-modules/package.json b/packages/terraform-modules/package.json index bb43ebcc1..25fd240cd 100644 --- a/packages/terraform-modules/package.json +++ b/packages/terraform-modules/package.json @@ -20,6 +20,7 @@ "example:synth": "cdktf synth", "format": "eslint --fix", "lint": "eslint --fix-dry-run", + "presemantic-release": "pnpm run build", "semantic-release": "semantic-release", "test": "jest --ci --maxWorkers=4 --logHeapUsage", "test:watch": "npm test -- --watch --watch-extensions ts -R min --watch-files src" @@ -94,4 +95,4 @@ "tsup": "8.2.4", "typescript": "5.5.4" } -} +} \ No newline at end of file diff --git a/packages/tracing/package.json b/packages/tracing/package.json index feae6cc51..6186a7454 100644 --- a/packages/tracing/package.json +++ b/packages/tracing/package.json @@ -19,6 +19,7 @@ "dev": "pnpm run build --watch", "format": "eslint --fix", "lint": "eslint --fix-dry-run", + "presemantic-release": "pnpm run build", "semantic-release": "semantic-release" }, "release": { @@ -105,4 +106,4 @@ "tsup": "8.2.4", "typescript": "5.5.4" } -} +} \ No newline at end of file diff --git a/packages/ts-logger/package.json b/packages/ts-logger/package.json index 1804a68ff..b659279df 100644 --- a/packages/ts-logger/package.json +++ b/packages/ts-logger/package.json @@ -21,6 +21,7 @@ "dev": "pnpm run build --watch", "format": "eslint --fix", "lint": "eslint --fix-dry-run", + "presemantic-release": "pnpm run build", "semantic-release": "semantic-release", "test": "jest", "test:watch": "pnpm run test -- --watch" @@ -86,4 +87,4 @@ "tsup": "8.2.4", "typescript": "5.5.4" } -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 10e4c2437..d563759a1 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.20240822) + version: 19.4.0(@types/node@22.5.0)(typescript@5.7.0-dev.20240827) '@commitlint/config-conventional': specifier: ^19.2.2 version: 19.2.2 @@ -26,7 +26,7 @@ importers: version: link:packages/eslint-config syncpack: specifier: ^12.4.0 - version: 12.4.0(typescript@5.7.0-dev.20240822) + version: 12.4.0(typescript@5.7.0-dev.20240827) tsconfig: specifier: workspace:* version: link:packages/tsconfig @@ -2501,6 +2501,9 @@ importers: '@apollo/client': specifier: 3.7.17 version: 3.7.17(graphql-ws@5.16.0(graphql@16.8.1))(graphql@16.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@graphql-typed-document-node/core': + specifier: 3.2.0 + version: 3.2.0(graphql@16.8.1) '@pocket-tools/sentry': specifier: workspace:* version: link:../../packages/sentry @@ -2510,9 +2513,6 @@ importers: '@sentry/node': specifier: 8.26.0 version: 8.26.0 - aws-xray-sdk-express: - specifier: 3.5.1 - version: 3.5.1(aws-xray-sdk-core@3.9.0) cross-fetch: specifier: 4.0.0 version: 4.0.0(encoding@0.1.13) @@ -2529,12 +2529,30 @@ importers: specifier: 2.6.3 version: 2.6.3 devDependencies: + '@graphql-codegen/add': + specifier: 5.0.3 + version: 5.0.3(graphql@16.8.1) + '@graphql-codegen/cli': + specifier: 5.0.2 + version: 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) + '@graphql-codegen/typed-document-node': + specifier: 5.0.9 + version: 5.0.9(encoding@0.1.13)(graphql@16.8.1) + '@graphql-codegen/typescript': + specifier: 4.0.9 + version: 4.0.9(encoding@0.1.13)(graphql@16.8.1) + '@graphql-codegen/typescript-operations': + specifier: 4.2.3 + version: 4.2.3(encoding@0.1.13)(graphql@16.8.1) '@jest/globals': specifier: 29.7.0 version: 29.7.0 '@pocket-tools/eslint-config': specifier: workspace:* version: link:../../packages/eslint-config + '@types/express': + specifier: 4.17.21 + version: 4.17.21 '@types/jest': specifier: 29.5.12 version: 29.5.12 @@ -6327,10 +6345,6 @@ packages: resolution: {integrity: sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==} engines: {node: '>=16.0.0'} - '@smithy/service-error-classification@2.1.5': - resolution: {integrity: sha512-uBDTIBBEdAQryvHdc5W8sS5YX7RQzF683XrHePVdFmAgKiMofU15FLSM0/HU03hKTnazdNRFa0YHS7+ArwoUSQ==} - engines: {node: '>=14.0.0'} - '@smithy/service-error-classification@3.0.3': resolution: {integrity: sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==} engines: {node: '>=16.0.0'} @@ -6347,10 +6361,6 @@ packages: resolution: {integrity: sha512-pDbtxs8WOhJLJSeaF/eAbPgXg4VVYFlRcL/zoNYA5WbG3wBL06CHtBSg53ppkttDpAJ/hdiede+xApip1CwSLw==} engines: {node: '>=16.0.0'} - '@smithy/types@2.12.0': - resolution: {integrity: sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==} - engines: {node: '>=14.0.0'} - '@smithy/types@3.3.0': resolution: {integrity: sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==} engines: {node: '>=16.0.0'} @@ -6493,9 +6503,6 @@ packages: '@types/chance@1.1.6': resolution: {integrity: sha512-V+pm3stv1Mvz8fSKJJod6CglNGVqEQ6OyuqitoDkWywEODM/eJd1eSuIp9xt6DrX8BWZ2eDSIzbw1tPCUTvGbQ==} - '@types/cls-hooked@4.3.8': - resolution: {integrity: sha512-tf/7H883gFA6MPlWI15EQtfNZ+oPL0gLKkOlx9UHFrun1fC/FkuyNBpTKq1B5E3T4fbvjId6WifHUdSGsMMuPg==} - '@types/connect@3.4.36': resolution: {integrity: sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==} @@ -7080,10 +7087,6 @@ packages: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} - async-hook-jl@1.7.6: - resolution: {integrity: sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg==} - engines: {node: ^4.7 || >=6.9 || >=7.3} - async-retry@1.3.3: resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} @@ -7099,9 +7102,6 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - atomic-batcher@1.0.2: - resolution: {integrity: sha512-EFGCRj4kLX1dHv1cDzTk+xbjBFj1GnJDpui52YmEcxxHHEWjYyT6l51U7n6WQ28osZH4S9gSybxe56Vm7vB61Q==} - auto-bind@4.0.0: resolution: {integrity: sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ==} engines: {node: '>=8'} @@ -7122,16 +7122,6 @@ packages: resolution: {integrity: sha512-+H+kuK34PfMaI9PNU/NSjBKL5hh/KDM9J72kwYeYEm0A8B1AC4fuCy3qsjnA7lxklgyXsB68yn8Z2xoZEjgwCQ==} engines: {node: '>= 6.0.0'} - aws-xray-sdk-core@3.9.0: - resolution: {integrity: sha512-YKzOVse7m6PCO/Uf3y3zhkWqPo5uUIU1Iin/hvL+Lpr2gFxCbNR88pkARAW2LyjvkwlcwLvx7TEoNV3SJYa4yg==} - engines: {node: '>= 14.x'} - - aws-xray-sdk-express@3.5.1: - resolution: {integrity: sha512-Qcu9rYDJttaOVqm+cljq5ZrqEbQicynGcW07ZYbuVeCWXfr41/nk/5ocW0zyOHqofMLafIhHjxMiNAGxnc3uMA==} - engines: {node: '>= 14.x'} - peerDependencies: - aws-xray-sdk-core: ^3.5.1 - aws4@1.13.1: resolution: {integrity: sha512-u5w79Rd7SU4JaIlA/zFqG+gOiuq25q5VLyZ8E+ijJeILuTxVzZgp2CaGw/UTw6pXYN9XMO9yiqj/nEHmhTG5CA==} @@ -7520,10 +7510,6 @@ packages: resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} engines: {node: '>=0.8'} - cls-hooked@4.2.2: - resolution: {integrity: sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==} - engines: {node: ^4.7 || >=6.9 || >=7.3 || >=8.2.1} - clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -8185,9 +8171,6 @@ packages: elliptic@6.5.7: resolution: {integrity: sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==} - emitter-listener@1.1.2: - resolution: {integrity: sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==} - emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} engines: {node: '>=12'} @@ -12306,9 +12289,6 @@ packages: resolution: {integrity: sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - stack-chain@1.3.7: - resolution: {integrity: sha512-D8cWtWVdIe/jBA7v5p5Hwl5yOSOrmZPWDPe2KxQ5UAGD+nxbxU0lKXA4h85Ta6+qgdKVL3vUxsbIZjc1kBG7ug==} - stack-trace@0.0.10: resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} @@ -12917,8 +12897,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - typescript@5.7.0-dev.20240822: - resolution: {integrity: sha512-JL60efPDEbshbweVXX18Ic5g+9iVbf2Nc3xh3eBGbLjrt5+x6KZzB3c2d+J5PoqOzPjbFATCT2FQ3W8vEGOXTg==} + typescript@5.7.0-dev.20240827: + resolution: {integrity: sha512-qNwNQBg18O4Z5RRGb07O562OpDlAVlytNcKfqcx8JQRJcs3p/KLHXjr0FbUbJ3SKoxA2vaQ3Zt89YLWHuCXzUw==} engines: {node: '>=14.17'} hasBin: true @@ -15098,11 +15078,11 @@ snapshots: dependencies: commander: 12.1.0 - '@commitlint/cli@19.4.0(@types/node@22.5.0)(typescript@5.7.0-dev.20240822)': + '@commitlint/cli@19.4.0(@types/node@22.5.0)(typescript@5.7.0-dev.20240827)': 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.20240822) + '@commitlint/load': 19.4.0(@types/node@22.5.0)(typescript@5.7.0-dev.20240827) '@commitlint/read': 19.4.0 '@commitlint/types': 19.0.3 execa: 8.0.1 @@ -15149,15 +15129,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.20240822)': + '@commitlint/load@19.4.0(@types/node@22.5.0)(typescript@5.7.0-dev.20240827)': 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.20240822) - cosmiconfig-typescript-loader: 5.0.0(@types/node@22.5.0)(cosmiconfig@9.0.0(typescript@5.7.0-dev.20240822))(typescript@5.7.0-dev.20240822) + 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) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 @@ -17573,10 +17553,6 @@ snapshots: '@smithy/types': 3.3.0 tslib: 2.6.3 - '@smithy/service-error-classification@2.1.5': - dependencies: - '@smithy/types': 2.12.0 - '@smithy/service-error-classification@3.0.3': dependencies: '@smithy/types': 3.3.0 @@ -17606,10 +17582,6 @@ snapshots: '@smithy/util-stream': 3.1.3 tslib: 2.6.3 - '@smithy/types@2.12.0': - dependencies: - tslib: 2.6.3 - '@smithy/types@3.3.0': dependencies: tslib: 2.6.3 @@ -17818,10 +17790,6 @@ snapshots: '@types/chance@1.1.6': {} - '@types/cls-hooked@4.3.8': - dependencies: - '@types/node': 20.16.1 - '@types/connect@3.4.36': dependencies: '@types/node': 20.16.1 @@ -18537,10 +18505,6 @@ snapshots: astral-regex@2.0.0: {} - async-hook-jl@1.7.6: - dependencies: - stack-chain: 1.3.7 - async-retry@1.3.3: dependencies: retry: 0.13.1 @@ -18555,8 +18519,6 @@ snapshots: asynckit@0.4.0: {} - atomic-batcher@1.0.2: {} - auto-bind@4.0.0: {} available-typed-arrays@1.0.7: @@ -18585,20 +18547,6 @@ snapshots: aws-ssl-profiles@1.1.1: {} - aws-xray-sdk-core@3.9.0: - dependencies: - '@aws-sdk/types': 3.609.0 - '@smithy/service-error-classification': 2.1.5 - '@types/cls-hooked': 4.3.8 - atomic-batcher: 1.0.2 - cls-hooked: 4.2.2 - semver: 7.6.3 - - aws-xray-sdk-express@3.5.1(aws-xray-sdk-core@3.9.0): - dependencies: - '@types/express': 4.17.21 - aws-xray-sdk-core: 3.9.0 - aws4@1.13.1: {} axios-retry@4.4.0(axios@1.7.4): @@ -19164,12 +19112,6 @@ snapshots: clone@2.1.2: {} - cls-hooked@4.2.2: - dependencies: - async-hook-jl: 1.7.6 - emitter-listener: 1.1.2 - semver: 5.7.2 - clsx@2.1.1: {} cluster-key-slot@1.1.2: {} @@ -19430,12 +19372,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.20240822))(typescript@5.7.0-dev.20240822): + 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): dependencies: '@types/node': 22.5.0 - cosmiconfig: 9.0.0(typescript@5.7.0-dev.20240822) + cosmiconfig: 9.0.0(typescript@5.7.0-dev.20240827) jiti: 1.21.6 - typescript: 5.7.0-dev.20240822 + typescript: 5.7.0-dev.20240827 cosmiconfig@8.3.6(typescript@5.5.4): dependencies: @@ -19455,14 +19397,14 @@ snapshots: optionalDependencies: typescript: 5.5.4 - cosmiconfig@9.0.0(typescript@5.7.0-dev.20240822): + cosmiconfig@9.0.0(typescript@5.7.0-dev.20240827): 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.20240822 + typescript: 5.7.0-dev.20240827 cpu-features@0.0.2: dependencies: @@ -19805,7 +19747,7 @@ snapshots: dependencies: semver: 7.6.3 shelljs: 0.8.5 - typescript: 5.7.0-dev.20240822 + typescript: 5.7.0-dev.20240827 dreamopt@0.8.0: dependencies: @@ -19868,10 +19810,6 @@ snapshots: minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - emitter-listener@1.1.2: - dependencies: - shimmer: 1.2.1 - emittery@0.13.1: {} emoji-regex@10.3.0: {} @@ -24505,8 +24443,6 @@ snapshots: dependencies: minipass: 7.1.2 - stack-chain@1.3.7: {} - stack-trace@0.0.10: {} stack-utils@2.0.6: @@ -24771,13 +24707,13 @@ snapshots: '@pkgr/core': 0.1.1 tslib: 2.6.3 - syncpack@12.4.0(typescript@5.7.0-dev.20240822): + syncpack@12.4.0(typescript@5.7.0-dev.20240827): 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.20240822) + cosmiconfig: 9.0.0(typescript@5.7.0-dev.20240827) effect: 3.5.7 enquirer: 2.4.1 fast-check: 3.20.0 @@ -25160,7 +25096,7 @@ snapshots: typescript@5.5.4: {} - typescript@5.7.0-dev.20240822: {} + typescript@5.7.0-dev.20240827: {} ua-parser-js@1.0.38: {} diff --git a/servers/braze-content-proxy/codegen.ts b/servers/braze-content-proxy/codegen.ts new file mode 100644 index 000000000..eb08ba8e1 --- /dev/null +++ b/servers/braze-content-proxy/codegen.ts @@ -0,0 +1,33 @@ +import { CodegenConfig } from '@graphql-codegen/cli'; + +const config: CodegenConfig = { + schema: 'https://client-api.getpocket.com', + documents: ['src/graphql/**/*.graphql'], + generates: { + './src/generated/graphql/types.ts': { + plugins: [ + //generated types do not conform to ts/lint rules, disable them for these files + { + add: { + content: '// THIS FILE IS GENERATED, DO NOT EDIT!', + }, + }, + { + add: { + content: '/* tslint:disable */', + }, + }, + { + add: { + content: '/* eslint-disable */', + }, + }, + 'typescript', + 'typescript-operations', + 'typed-document-node', + ], + }, + }, +}; + +export default config; diff --git a/servers/braze-content-proxy/package.json b/servers/braze-content-proxy/package.json index 698ad0f13..b15ccecee 100644 --- a/servers/braze-content-proxy/package.json +++ b/servers/braze-content-proxy/package.json @@ -7,18 +7,19 @@ "dev": "npm run build && npm run watch", "format": "eslint --fix", "lint": "eslint --fix-dry-run", + "prebuild": "graphql-codegen", "start": "node dist/main.js", "test": "jest \"\\.spec\\.ts\"", "test-integrations": "jest \"\\.integration\\.ts\" --runInBand", "test:watch": "npm test -- --watchAll", - "watch": "tsc -w & nodemon" + "watch": "tsc -w --preserveWatchOutput & nodemon --config ../../nodemon.json" }, "dependencies": { "@apollo/client": "3.7.17", + "@graphql-typed-document-node/core": "3.2.0", "@pocket-tools/sentry": "workspace:*", "@pocket-tools/ts-logger": "workspace:*", "@sentry/node": "8.26.0", - "aws-xray-sdk-express": "3.5.1", "cross-fetch": "4.0.0", "dataloader": "2.2.2", "express": "4.19.2", @@ -26,8 +27,14 @@ "tslib": "2.6.3" }, "devDependencies": { + "@graphql-codegen/add": "5.0.3", + "@graphql-codegen/cli": "5.0.2", + "@graphql-codegen/typed-document-node": "5.0.9", + "@graphql-codegen/typescript": "4.0.9", + "@graphql-codegen/typescript-operations": "4.2.3", "@jest/globals": "29.7.0", "@pocket-tools/eslint-config": "workspace:*", + "@types/express": "4.17.21", "@types/jest": "29.5.12", "@types/node": "^20.16", "@types/supertest": "^6.0.2", diff --git a/servers/braze-content-proxy/src/generated/graphql/types.ts b/servers/braze-content-proxy/src/generated/graphql/types.ts new file mode 100644 index 000000000..a7cfad378 --- /dev/null +++ b/servers/braze-content-proxy/src/generated/graphql/types.ts @@ -0,0 +1,3818 @@ +// THIS FILE IS GENERATED, DO NOT EDIT! +/* tslint:disable */ +/* eslint-disable */ +import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +export type Maybe = T | null; +export type InputMaybe = Maybe; +export type Exact = { [K in keyof T]: T[K] }; +export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; +export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; +export type MakeEmpty = { [_ in K]?: never }; +export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: { input: string; output: string; } + String: { input: string; output: string; } + Boolean: { input: boolean; output: boolean; } + Int: { input: number; output: number; } + Float: { input: number; output: number; } + Date: { input: any; output: any; } + DateString: { input: any; output: any; } + FunctionalBoostValue: { input: any; output: any; } + HtmlString: { input: any; output: any; } + ISOString: { input: any; output: any; } + Markdown: { input: any; output: any; } + Max300CharString: { input: any; output: any; } + NonNegativeInt: { input: any; output: any; } + Timestamp: { input: any; output: any; } + Url: { input: any; output: any; } + ValidUrl: { input: any; output: any; } +}; + +/** + * Input data for adding multiple items to a list. + * Appends to the end of the list. + */ +export type AddItemInput = { + authors?: InputMaybe; + excerpt?: InputMaybe; + imageUrl?: InputMaybe; + itemId: Scalars['ID']['input']; + note?: InputMaybe; + publisher?: InputMaybe; + title?: InputMaybe; + url: Scalars['Url']['input']; +}; + +export type AdvancedSearchFilters = { + contentType?: InputMaybe; + domain?: InputMaybe; + isFavorite?: InputMaybe; + status?: InputMaybe; + /** + * Include only items with the following tags (exact) + * in search results (OR combination) + */ + tags?: InputMaybe>; + title?: InputMaybe; +}; + +/** Valid grade values for CorpusItem (public graph) and ApprovedItem (admin graph) */ +export enum ApprovedItemGrade { + A = 'A', + B = 'B', + C = 'C' +} + +export type ArticleMarkdown = { + __typename?: 'ArticleMarkdown'; + images?: Maybe>; + text: Scalars['String']['output']; +}; + +/** + * The status of the syndicated article + * TODO: rename to SyndicatedArticle status and move to schema-shared.graphql + * (requires client changes) + */ +export enum ArticleStatus { + Active = 'ACTIVE', + Draft = 'DRAFT', + Expired = 'EXPIRED' +} + +/** Information about an Author of an article or some content */ +export type Author = { + __typename?: 'Author'; + /** Unique id for that Author */ + id: Scalars['ID']['output']; + /** Display name */ + name?: Maybe; + /** A url to that Author's site */ + url?: Maybe; +}; + +export type BaseError = { + message: Scalars['String']['output']; + path: Scalars['String']['output']; +}; + +/** Input object for creating and deleting highlights using bulk mutation. */ +export type BatchWriteHighlightsInput = { + create?: InputMaybe>; + delete?: InputMaybe>; +}; + +/** + * Result object for bulk create/delete highlights mutation. + * Mutation is atomic -- if there is a response, all operations + * were successful. + * + * The corresponding result array will be empty, but present, if there + * were no requests for created/deleted. + */ +export type BatchWriteHighlightsResult = { + __typename?: 'BatchWriteHighlightsResult'; + created: Array; + deleted: Array; +}; + +/** Row in a bulleted (unordered list) */ +export type BulletedListElement = ListElement & { + __typename?: 'BulletedListElement'; + /** Row in a list. */ + content: Scalars['Markdown']['output']; + /** Zero-indexed level, for handling nested lists. */ + level: Scalars['Int']['output']; +}; + +/** + * Apollo Server @cacheControl directive caching behavior either for a single field, or for all fields that + * return a particular type + */ +export enum CacheControlScope { + Private = 'PRIVATE', + Public = 'PUBLIC' +} + +/** A requested image that is cached and has the requested image parameters */ +export type CachedImage = { + __typename?: 'CachedImage'; + /** Height of the cached image */ + height?: Maybe; + /** Id of the image that matches the ID from the requested options */ + id: Scalars['ID']['output']; + /** URL of the cached image */ + url?: Maybe; + /** Width of the cached image */ + width?: Maybe; +}; + +/** Set of parameters that will be used to change an image */ +export type CachedImageInput = { + /** File type of the requested image */ + fileType?: InputMaybe; + /** Height of the image */ + height?: InputMaybe; + /** Id of the image in the returned result set */ + id: Scalars['ID']['input']; + /** Quality of the image in whole percentage, 100 = full, quality 50 = half quality */ + qualityPercentage?: InputMaybe; + /** Width of the image */ + width?: InputMaybe; +}; + +export type Collection = { + __typename?: 'Collection'; + IABChildCategory?: Maybe; + /** + * We will never return child categories in this type, so there's no need to + * specify `IABParentCategory` here. The basic `IABCategory` is sufficient. + */ + IABParentCategory?: Maybe; + authors: Array; + curationCategory?: Maybe; + excerpt?: Maybe; + externalId: Scalars['ID']['output']; + imageUrl?: Maybe; + intro?: Maybe; + labels?: Maybe>>; + /** + * note that language is *not* being used as locale - only to specify the + * language of the collection. + */ + language: CollectionLanguage; + partnership?: Maybe; + 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']; + status: CollectionStatus; + stories: Array; + title: Scalars['String']['output']; +}; + +export type CollectionAuthor = { + __typename?: 'CollectionAuthor'; + active: Scalars['Boolean']['output']; + bio?: Maybe; + externalId: Scalars['ID']['output']; + imageUrl?: Maybe; + name: Scalars['String']['output']; + slug?: Maybe; +}; + +/** valid language codes for collections */ +export enum CollectionLanguage { + /** German */ + De = 'DE', + /** English */ + En = 'EN' +} + +/** + * If a collection was made in partnership with an external company, this + * entity will hold all required info about that partnership. + */ +export type CollectionPartnership = { + __typename?: 'CollectionPartnership'; + blurb: Scalars['Markdown']['output']; + externalId: Scalars['String']['output']; + imageUrl: Scalars['Url']['output']; + name: Scalars['String']['output']; + type: CollectionPartnershipType; + url: Scalars['Url']['output']; +}; + +/** Type and enums related to Collections made in partnership with a company. */ +export enum CollectionPartnershipType { + Partnered = 'PARTNERED', + Sponsored = 'SPONSORED' +} + +export enum CollectionStatus { + Archived = 'ARCHIVED', + Draft = 'DRAFT', + Published = 'PUBLISHED', + Review = 'REVIEW' +} + +export type CollectionStory = { + __typename?: 'CollectionStory'; + authors: Array; + excerpt: Scalars['Markdown']['output']; + externalId: Scalars['ID']['output']; + /** if True, the story is provided by a partner and should be displayed as such */ + fromPartner: Scalars['Boolean']['output']; + imageUrl?: Maybe; + item?: Maybe; + publisher?: Maybe; + sortOrder?: Maybe; + title: Scalars['String']['output']; + url: Scalars['Url']['output']; +}; + +export type CollectionStoryAuthor = { + __typename?: 'CollectionStoryAuthor'; + name: Scalars['String']['output']; + sortOrder: Scalars['Int']['output']; +}; + +export type CollectionsFiltersInput = { + /** If provided, will return all collections that match at least one of the labels. */ + labels?: InputMaybe>>; + /** If not provided, or if an unsupported language is requested, defaults to `en` */ + language?: InputMaybe; +}; + +export type CollectionsResult = { + __typename?: 'CollectionsResult'; + collections: Array; + pagination: Pagination; +}; + +/** Content type classification for a corpus item */ +export enum CorpusContentType { + Article = 'ARTICLE', + Collection = 'COLLECTION', + Video = 'VIDEO' +} + +/** + * Represents an item that is in the Corpus and its associated manually edited metadata. + * TODO: CorpusItem to implement PocketResource when it becomes available. + */ +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 quality grade associated with this CorpusItem. */ + grade?: Maybe; + /** The GUID that is stored on an approved corpus item */ + id: Scalars['ID']['output']; + /** The image for this item's accompanying picture. */ + image: Image; + /** The image URL for this item's accompanying picture. */ + imageUrl: Scalars['Url']['output']; + /** What language this item is in. This is a two-letter code, for example, 'EN' for English. */ + language: CorpusLanguage; + /** The name of the online publication that published this story. */ + publisher: Scalars['String']['output']; + /** The user's saved item, from the Corpus Item, if the corpus item was saved to the user's saves */ + savedItem?: 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; + /** If the Corpus Item is pocket owned with a specific type, this is the associated object (Collection or SyndicatedArticle). */ + target?: Maybe; + /** Time to read in minutes. Is nullable. */ + timeToRead?: Maybe; + /** The title of the Approved Item. */ + title: Scalars['String']['output']; + /** The topic associated with this CorpusItem. */ + topic?: Maybe; + /** The URL of the Approved Item. */ + url: Scalars['Url']['output']; +}; + +/** An author associated with a CorpusItem. */ +export type CorpusItemAuthor = { + __typename?: 'CorpusItemAuthor'; + name: Scalars['String']['output']; + sortOrder: Scalars['Int']['output']; +}; + +/** Valid language codes for curated corpus items. */ +export enum CorpusLanguage { + /** German */ + De = 'DE', + /** English */ + En = 'EN', + /** Spanish */ + Es = 'ES', + /** French */ + Fr = 'FR', + /** Italian */ + It = 'IT' +} + +export type CorpusRecommendation = { + __typename?: 'CorpusRecommendation'; + /** Content meta data. */ + corpusItem: CorpusItem; + /** Clients should include this id in the `corpus_recommendation` Snowplow entity for impression, content_open, and engagement events related to this recommendation. This id is different across users, across requests, and across corpus items. The recommendation-api service associates metadata with this id to join and aggregate recommendations in our data warehouse. */ + id: Scalars['ID']['output']; + /** Reason why this CorpusItem is recommended to the user, or null if no reason is available. */ + reason?: Maybe; + /** + * Firefox clients require an integer id. Other clients should use `id` instead of this field. tileId uniquely identifies the ScheduledSurface, CorpusItem, and scheduled_date. tileId is greater than 0 and less than 2^53 to fit in a Javascript number (64-bit IEEE 754 float). The field type is a Float because a GraphQL Int is limited to 32 bit. + * @deprecated Only to be used by Firefox. Other clients should use `id`. We plan to also migrate Firefox New Tab to use CorpusRecommendation.id instead of tileId to track recommendation telemetry. + */ + tileId: Scalars['Float']['output']; +}; + +/** Paginated corpus search result connection */ +export type CorpusSearchConnection = { + __typename?: 'CorpusSearchConnection'; + edges: Array; + pageInfo: PageInfo; + totalCount: Scalars['Int']['output']; +}; + +/** An edge in a CorpusSearchConnection result */ +export type CorpusSearchEdge = { + __typename?: 'CorpusSearchEdge'; + cursor: Scalars['String']['output']; + node: CorpusSearchNode; +}; + +/** Fields that can be searched using query strings */ +export enum CorpusSearchFields { + /** Search all possible fields */ + All = 'ALL', + /** + * (Default) Search the fields which relate to the content + * of the resource (title, article, excerpt, extracted content) + * rather than the metadata (publisher). + */ + AllContentful = 'ALL_CONTENTFUL', + /** Search terms in excerpt fields */ + Excerpt = 'EXCERPT', + /** Search terms in parsed, extracted content fields */ + ExtractedContent = 'EXTRACTED_CONTENT', + /** Search terms in publisher fields */ + Publisher = 'PUBLISHER', + /** Search terms in title fields */ + Title = 'TITLE' +} + +/** Filters to refine corpus search results. */ +export type CorpusSearchFilters = { + /** When the content was added to Pocket's corpus */ + addedDateRange?: InputMaybe; + /** The author's name */ + author?: InputMaybe; + /** + * Filter to limit the result set to specific content types. + * Multiple types are combined with OR. + * Can use this to search collections only. + */ + contentType?: InputMaybe>; + /** Set to true to exclude collections from the results. */ + excludeCollections?: InputMaybe; + /** Set to true to exclude ML-generated recommendations from the results. */ + excludeML?: InputMaybe; + /** The language of the corpus to search (letter code) */ + language: CorpusLanguage; + /** + * Filter for when an article was published. Can provide + * upper/lower bounds with 'before' or 'after', or use both + * both to create a time range. + */ + publishedDateRange?: InputMaybe; + /** + * The publisher's name. This is an exact match for filtering. + * To use publisher in search, use the publisher field in the query + * string. + */ + publisher?: InputMaybe; + /** + * The topic (use getTopics query to retrieve valid topics). + * Multiple topics are combined with OR. + */ + topic?: InputMaybe>; +}; + +/** + * Highlighted snippets from fields in the search results + * so clients can show users where the query matches are. + * Each field, if available, contains an array of html text + * snippets that contain a match to the search term. + * The matching text is wrapped in tags, e.g. + * ["Hiss at vacuum cleaner if it fits i sits"] + */ +export type CorpusSearchHighlights = { + __typename?: 'CorpusSearchHighlights'; + excerpt?: Maybe>>; + fullText?: Maybe>>; + publisher?: Maybe>>; + title?: Maybe>>; +}; + +/** A node in a CorpusSearchConnection result */ +export type CorpusSearchNode = { + __typename?: 'CorpusSearchNode'; + /** The preview of the search result */ + preview: PocketMetadata; + /** Search highlights */ + searchHighlights?: Maybe; +}; + +/** A search query for the corpus */ +export type CorpusSearchQueryString = { + /** + * A specific field to search on (e.g. title), + * or ALL to search all available text content fields. + * If missing, defaults to 'ALL_CONTENTFUL' + */ + field?: InputMaybe; + /** The query string to search. */ + query: Scalars['String']['input']; +}; + +/** Sort scheme for Corpus Search. Defaults to showing most relevant results first. */ +export type CorpusSearchSort = { + sortBy: CorpusSearchSortBy; + sortOrder?: InputMaybe; +}; + +/** Sortable properties for Corpus Search */ +export enum CorpusSearchSortBy { + /** When the content was added to the corpus */ + DateAddedToCorpus = 'DATE_ADDED_TO_CORPUS', + /** + * When the content was originally published + * (Note: this data is sparse/nullable) + */ + DatePublished = 'DATE_PUBLISHED', + /** Relevance score computed by search algorithm */ + Relevance = 'RELEVANCE' +} + +/** This is the same as Slate but in this type all recommendations are backed by CorpusItems. This means that the editorial team has editorial control over the items served by this endpoint. */ +export type CorpusSlate = { + __typename?: 'CorpusSlate'; + /** The display headline for the slate. Surface context may be required to render determine what to display. This will depend on if we connect the copy to the Surface, SlateExperiment, or Slate. */ + headline: Scalars['String']['output']; + /** UUID */ + id: Scalars['ID']['output']; + /** Link to a page where the user can explore more recommendations similar to this slate, or null if no link is provided. */ + moreLink?: Maybe; + /** Indicates the main type of reason why recommendations are included in this slate, or null if none is available. */ + recommendationReasonType?: Maybe; + /** Recommendations for the current request context. */ + recommendations: Array; + /** A smaller, secondary headline that can be displayed to provide additional context on the slate. */ + subheadline?: Maybe; + /** utm_source value that can be set on the url by the caller to attribute the recommendations. */ + utmSource?: Maybe; +}; + + +/** This is the same as Slate but in this type all recommendations are backed by CorpusItems. This means that the editorial team has editorial control over the items served by this endpoint. */ +export type CorpusSlateRecommendationsArgs = { + count?: InputMaybe; +}; + +/** A collection of slates. */ +export type CorpusSlateLineup = { + __typename?: 'CorpusSlateLineup'; + /** UUID */ + id: Scalars['ID']['output']; + /** Slates. */ + slates: Array; +}; + + +/** A collection of slates. */ +export type CorpusSlateLineupSlatesArgs = { + count?: InputMaybe; +}; + +/** + * TODO: Make this type implement PocketResource when available. + * https://getpocket.atlassian.net/wiki/spaces/PE/pages/2771714049/The+Future+of+Item + */ +export type CorpusTarget = Collection | SyndicatedArticle; + +/** Input for creating a new User-highlighted passage on a SavedItem. */ +export type CreateHighlightByUrlInput = { + /** + * Optionally, a client-generated UUID to identify the highlight. + * If one is not passed, it will be created. Must be in UUID format, + * or will fail generation. Will not overwrite existing data if there + * is an ID collision. + */ + id?: InputMaybe; + /** Optional note generated by User */ + note?: InputMaybe; + /** + * Patch string generated by 'DiffMatchPatch' library, serialized + * into text via `patch_toText` method. + * Format is similar to UniDiff but is character-based. + * The patched text depends on version. For example, the version 2 + * patch surrounds the highlighted text portion with a pair of + * sentinel tags: '' + * Reference: https://github.com/google/diff-match-patch + */ + patch: Scalars['String']['input']; + /** + * The full text of the highlighted passage. Used as a fallback for + * rendering highlight if the patch fails. + */ + quote: Scalars['String']['input']; + /** The url of the Item that should be annotated in the User's list */ + url: Scalars['ValidUrl']['input']; + /** Annotation data version */ + version: Scalars['Int']['input']; +}; + +/** Input for creating a new User-highlighted passage on a SavedItem. */ +export type CreateHighlightInput = { + /** + * Optionally, a client-generated UUID to identify the highlight. + * If one is not passed, it will be created. Must be in UUID format, + * or will fail generation. Will not overwrite existing data if there + * is an ID collision. + */ + id?: InputMaybe; + /** The ID of the Item that should be annotated in the User's list */ + itemId: Scalars['ID']['input']; + /** Optional note generated by User */ + note?: InputMaybe; + /** + * Patch string generated by 'DiffMatchPatch' library, serialized + * into text via `patch_toText` method. + * Format is similar to UniDiff but is character-based. + * The patched text depends on version. For example, the version 2 + * patch surrounds the highlighted text portion with a pair of + * sentinel tags: '' + * Reference: https://github.com/google/diff-match-patch + */ + patch: Scalars['String']['input']; + /** + * The full text of the highlighted passage. Used as a fallback for + * rendering highlight if the patch fails. + */ + quote: Scalars['String']['input']; + /** Annotation data version */ + version: Scalars['Int']['input']; +}; + +/** Input data for creating a Shareable List. */ +export type CreateShareableListInput = { + description?: InputMaybe; + listItemNoteVisibility?: InputMaybe; + title: Scalars['String']['input']; +}; + +/** Input data for creating a Shareable List Item. */ +export type CreateShareableListItemInput = { + authors?: InputMaybe; + excerpt?: InputMaybe; + imageUrl?: InputMaybe; + itemId: Scalars['ID']['input']; + listExternalId: Scalars['ID']['input']; + note?: InputMaybe; + publisher?: InputMaybe; + sortOrder: Scalars['Int']['input']; + title?: InputMaybe; + url: Scalars['Url']['input']; +}; + +/** Input data for creating a Shareable List Item during Shareable List creation. */ +export type CreateShareableListItemWithList = { + authors?: InputMaybe; + excerpt?: InputMaybe; + imageUrl?: InputMaybe; + itemId: Scalars['ID']['input']; + note?: InputMaybe; + publisher?: InputMaybe; + sortOrder: Scalars['Int']['input']; + title?: InputMaybe; + url: Scalars['Url']['input']; +}; + +/** This type represents the information we need on a curated item. */ +export type CuratedInfo = { + __typename?: 'CuratedInfo'; + excerpt?: Maybe; + /** The image for this item's accompanying picture. */ + image?: Maybe; + imageSrc?: Maybe; + title?: Maybe; +}; + +export type CurationCategory = { + __typename?: 'CurationCategory'; + externalId: Scalars['ID']['output']; + name: Scalars['String']['output']; + slug: Scalars['String']['output']; +}; + +/** + * Filter to get documents added/published before or after a date, + * or provide both for a range of [after, before) + * Before is exclusive, after is inclusive. + */ +export type DateFilter = { + /** Inclusive date -- results must be at or after than this time. */ + after?: InputMaybe; + /** Exclusive date -- results must be exclusively before this time. */ + before?: InputMaybe; +}; + +export type DeleteSavedItemTagsInput = { + /** The id of the SavedItem from which to delete a Tag association */ + savedItemId: Scalars['ID']['input']; + /** The ids of the Tag to disassociate from the SavedItem */ + tagIds: Array; +}; + +/** Metadata from a domain, originally populated from ClearBit */ +export type DomainMetadata = { + __typename?: 'DomainMetadata'; + /** Url for the logo image */ + logo?: Maybe; + /** Url for the greyscale logo image */ + logoGreyscale?: Maybe; + /** The name of the domain (e.g., The New York Times) */ + name?: Maybe; +}; + +/** The reason a user web session is being expired. */ +export enum ExpireUserWebSessionReason { + /** Expire web session upon logging out. */ + Logout = 'LOGOUT', + /** Expire web session on account password change. */ + PasswordChanged = 'PASSWORD_CHANGED' +} + +/** Input field to boost the score of an elasticsearch document based on a specific field and value */ +export type FunctionalBoostField = { + /** A float number to boost the score by */ + factor: Scalars['Float']['input']; + /** Field to evaluate for boosting */ + field: Scalars['String']['input']; + /** The mathematical operation to use for boosting */ + operation: SearchFunctionalBoostOperation; + /** Field value to evaluate */ + value: Scalars['FunctionalBoostValue']['input']; +}; + +/** A User-highlighted passage on a SavedItem */ +export type Highlight = { + __typename?: 'Highlight'; + /** When the Highlight was created */ + _createdAt: Scalars['Timestamp']['output']; + /** When the highlight was last updated */ + _updatedAt: Scalars['Timestamp']['output']; + /** The ID for this Highlight annotation */ + id: Scalars['ID']['output']; + /** Highlight Note associated with this Highlight */ + note?: Maybe; + /** + * Patch string generated by 'DiffMatchPatch' library, serialized + * into text via `patch_toText` method. Use `patch_fromText` to + * deserialize into an object that can be used by the DiffMatchPatch + * library. Format is similar to UniDiff but is character-based. + * The patched text depends on version. For example, the version 2 + * patch surrounds the highlighted text portion with a pair of + * sentinel tags: '' + * Reference: https://github.com/google/diff-match-patch + */ + patch: Scalars['String']['output']; + /** + * The full text of the highlighted passage. Used as a fallback for + * rendering highlight if the patch fails. + */ + quote: Scalars['String']['output']; + /** Version number for highlight data specification */ + version: Scalars['Int']['output']; +}; + +export type HighlightNote = { + __typename?: 'HighlightNote'; + /** When the HighlightNote was created */ + _createdAt: Scalars['Timestamp']['output']; + /** When the HighlightNote was last updated */ + _updatedAt: Scalars['Timestamp']['output']; + /** User entered text */ + text: Scalars['String']['output']; +}; + +/** Interactive Advertising Bureau Category - these are used on clients to serve relevant ads */ +export type IabCategory = { + __typename?: 'IABCategory'; + externalId: Scalars['String']['output']; + name: Scalars['String']['output']; + slug: Scalars['String']['output']; +}; + +export type IabParentCategory = { + __typename?: 'IABParentCategory'; + children: Array; + externalId: Scalars['String']['output']; + name: Scalars['String']['output']; + slug: Scalars['String']['output']; +}; + +/** An image that is keyed on URL */ +export type Image = { + __typename?: 'Image'; + /** Query to get a cached and modified set of images based on the image from the original url, images will be matched by the client assigned id value */ + cachedImages?: Maybe>>; + /** A caption or description of the image */ + caption?: Maybe; + /** A credit for the image, typically who the image belongs to / created by */ + credit?: Maybe; + /** The determined height of the image at the url */ + height?: Maybe; + /** 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: Scalars['Int']['output']; + /** + * Absolute url to the image + * @deprecated use url property moving forward + */ + src: Scalars['String']['output']; + /** If the image is also a link, the destination url */ + targetUrl?: Maybe; + /** The url of the image */ + url: Scalars['Url']['output']; + /** The determined width of the image at the url */ + width?: Maybe; +}; + + +/** An image that is keyed on URL */ +export type ImageCachedImagesArgs = { + imageOptions: Array; +}; + +/** The image file type */ +export enum ImageFileType { + Jpeg = 'JPEG', + Png = 'PNG', + Webp = 'WEBP' +} + +export enum Imageness { + /** Contains images (v3 value is 1) */ + HasImages = 'HAS_IMAGES', + /** Is an image (v3 value is 2) */ + IsImage = 'IS_IMAGE', + /** No images (v3 value is 0) */ + NoImages = 'NO_IMAGES' +} + +/** + * The heart of Pocket + * A url and meta data related to it. + */ +export type Item = { + __typename?: 'Item'; + /** If available, the url to an AMP version of this article */ + ampUrl?: Maybe; + /** + * 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?: Maybe; + /** List of Authors involved with this article */ + authors?: Maybe>>; + /** If the item is a collection allow them to get 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 corpus allow the item to reference it. Exposing curated info for consistent UX */ + corpusItem?: Maybe; + /** The date the article was published */ + datePublished?: Maybe; + /** The date the parser resolved this item */ + dateResolved?: Maybe; + /** The domain, such as 'getpocket.com' of the resolved_url */ + domain?: Maybe; + /** + * The primary database id of the domain this article is from + * @deprecated Use a domain as the identifier instead + */ + domainId?: Maybe; + /** Additional information about the item domain, when present, use this for displaying the domain name */ + domainMetadata?: Maybe; + /** The string encoding code of this item's web page */ + encoding?: Maybe; + /** A snippet of text from the article */ + excerpt?: Maybe; + /** key field to identify the Item entity in the Parser service */ + givenUrl: Scalars['Url']['output']; + /** 0=no images, 1=contains images, 2=is an image */ + hasImage?: Maybe; + /** + * Indicates that the item was stored via a different search_hash (using the old method), we'll need to look up a different id + * @deprecated Most new items use a new hash + */ + hasOldDupes?: Maybe; + /** 0=no videos, 1=contains video, 2=is a video */ + hasVideo?: Maybe; + /** Keyword highlights from search */ + highlights?: Maybe; + /** A server generated unique id for this item based on itemId */ + id: Scalars['ID']['output']; + /** Array of images within an article */ + images?: Maybe>>; + /** + * Indicates if the text of the url is a redirect to another url + * @deprecated Clients should not use this + */ + innerDomainRedirect?: Maybe; + /** true if the item is an article */ + isArticle?: Maybe; + /** true if the item is an index / home page, rather than a specific single piece of content */ + isIndex?: Maybe; + /** + * The Item entity is owned by the Parser service. + * We only extend it in this service to make this service's schema valid. + * The key for this entity is the 'itemId' + */ + itemId: Scalars['String']['output']; + /** The detected language of the article */ + language?: Maybe; + /** Estimated time to listen to the article, in seconds */ + listenDuration?: Maybe; + /** + * Indicates if the url requires a login + * @deprecated Clients should not use this + */ + loginRequired?: Maybe; + /** The Marticle format of the article, used by clients for native article view. */ + marticle?: Maybe>; + /** The mime type of this item's web page */ + mimeType?: Maybe; + /** + * 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: Scalars['String']['output']; + /** + * If a the domainId is a subdomain this is the primary domain id + * @deprecated Use a domain as the identifier instead + */ + originDomainId?: Maybe; + /** The client preview/display logic for this url */ + preview?: Maybe; + /** A server generated unique reader slug for this item based on itemId */ + readerSlug: Scalars['String']['output']; + /** Recommend similar articles to show in the bottom of an article. */ + relatedAfterArticle: Array; + /** Recommend similar articles after saving. */ + relatedAfterCreate: Array; + /** The item id of the resolved_url */ + resolvedId?: Maybe; + /** + * The resolved url, but ran through the normalized function + * @deprecated Use the resolved url instead + */ + resolvedNormalUrl?: Maybe; + /** If the givenUrl redirects (once or many times), this is the final url. Otherwise, same as givenUrl */ + resolvedUrl?: Maybe; + /** + * The http response code of the given url + * @deprecated Clients should not use this + */ + responseCode?: Maybe; + /** Helper property to identify if the given item is in the user's list */ + savedItem?: 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; + /** If the url is an Article, the text in SSML format for speaking, i.e. Listen */ + ssml?: Maybe; + /** If the item has a syndicated counterpart the syndication information */ + syndicatedArticle?: Maybe; + /** + * Date this item was first parsed in Pocket + * @deprecated Clients should not use this + */ + timeFirstParsed?: Maybe; + /** How long it will take to read the article (TODO in what time unit? and by what calculation?) */ + timeToRead?: Maybe; + /** The title as determined by the parser. */ + title?: Maybe; + /** The page's / publisher's preferred thumbnail image */ + topImage?: Maybe; + /** + * The page's / publisher's preferred thumbnail image + * @deprecated use the topImage object + */ + topImageUrl?: Maybe; + /** + * Indicates if the parser used fallback methods + * @deprecated Clients should not use this + */ + usedFallback?: Maybe; + /** Array of videos within the item If the item is a video, this will likely just contain one video */ + videos?: Maybe>>; + /** Number of words in the article */ + wordCount?: Maybe; +}; + + +/** + * The heart of Pocket + * A url and meta data related to it. + */ +export type ItemRelatedAfterArticleArgs = { + count?: InputMaybe; +}; + + +/** + * The heart of Pocket + * A url and meta data related to it. + */ +export type ItemRelatedAfterCreateArgs = { + count?: InputMaybe; +}; + +/** Elasticsearch highlights */ +export type ItemHighlights = { + __typename?: 'ItemHighlights'; + full_text?: Maybe>>; + tags?: Maybe>>; + title?: Maybe>>; + url?: Maybe>>; +}; + +export type ItemNotFound = { + __typename?: 'ItemNotFound'; + message?: Maybe; +}; + +/** Union type for items that may or may not be processed */ +export type ItemResult = Item | PendingItem; + +export type ItemSummary = PocketMetadata & { + __typename?: 'ItemSummary'; + authors?: Maybe>; + datePublished?: Maybe; + domain?: Maybe; + excerpt?: Maybe; + id: Scalars['ID']['output']; + image?: Maybe; + item?: Maybe; + source: PocketMetadataSource; + title?: Maybe; + url: Scalars['Url']['output']; +}; + +/** A label used to mark and categorize an Entity (e.g. Collection). */ +export type Label = { + __typename?: 'Label'; + externalId: Scalars['ID']['output']; + name: Scalars['String']['output']; +}; + +/** Web link */ +export type Link = { + __typename?: 'Link'; + /** The link text displayed to the user. */ + text: Scalars['String']['output']; + /** The URL to send the user to when clicking on the link. */ + url: Scalars['Url']['output']; +}; + +export type ListElement = { + /** Row in a list. */ + content: Scalars['Markdown']['output']; + /** Zero-indexed level, for handling nested lists. */ + level: Scalars['Int']['output']; +}; + +/** The Connection type for ListItem */ +export type ListItemConnection = { + __typename?: 'ListItemConnection'; + /** A list of edges. */ + edges?: Maybe>; + /** Information to aid in pagination. */ + pageInfo: PageInfo; + /** Identifies the total count of SavedItems in the connection. */ + totalCount: Scalars['Int']['output']; +}; + +/** An Edge in a Connection */ +export type ListItemEdge = { + __typename?: 'ListItemEdge'; + /** A cursor for use in pagination. */ + cursor: Scalars['String']['output']; + /** The ListItem at the end of the edge. */ + node: ShareableListItem; +}; + +export type MarkdownImagePosition = { + __typename?: 'MarkdownImagePosition'; + index: Scalars['Int']['output']; + position: Scalars['Int']['output']; + /** Fallback is to use the images field in the Item entity */ + src?: Maybe; +}; + +/** Content of a blockquote */ +export type MarticleBlockquote = { + __typename?: 'MarticleBlockquote'; + /** Markdown text content. */ + content: Scalars['Markdown']['output']; +}; + +/** Content in a bulleted (unordered) list. */ +export type MarticleBulletedList = { + __typename?: 'MarticleBulletedList'; + rows: Array; +}; + +/** A pre formatted text in the HTML content. */ +export type MarticleCodeBlock = { + __typename?: 'MarticleCodeBlock'; + /** Assuming the codeblock was a programming language, this field is used to identify it. */ + language?: Maybe; + /** Content of a pre tag */ + text: Scalars['String']['output']; +}; + +export type MarticleComponent = Image | MarticleBlockquote | MarticleBulletedList | MarticleCodeBlock | MarticleDivider | MarticleHeading | MarticleNumberedList | MarticleTable | MarticleText | UnMarseable | Video; + +export type MarticleDivider = { + __typename?: 'MarticleDivider'; + /** Always '---'; provided for convenience if building a markdown string */ + content: Scalars['Markdown']['output']; +}; + +/** A heading in an article, with markdown formatting. */ +export type MarticleHeading = { + __typename?: 'MarticleHeading'; + /** Heading text, in markdown. */ + content: Scalars['Markdown']['output']; + /** Heading level. Restricted to values 1-6. */ + level: Scalars['Int']['output']; +}; + +/** Content in a bulleted (unordered) list. */ +export type MarticleNumberedList = { + __typename?: 'MarticleNumberedList'; + rows: Array; +}; + +/** Content in a table. */ +export type MarticleTable = { + __typename?: 'MarticleTable'; + /** Raw HTML representation of the table. */ + html: Scalars['String']['output']; +}; + +/** + * A section of the article's text content, in markdown. + * A subset of gfm is supported. See README.md for more information. + */ +export type MarticleText = { + __typename?: 'MarticleText'; + /** Markdown text content. Typically, a paragraph. */ + content: Scalars['Markdown']['output']; +}; + +/** Default Mutation Type */ +export type Mutation = { + __typename?: 'Mutation'; + /** + * Attach share context to a Pocket Share. If a context already exists + * on the Pocket Share, it will be overrwritten. Session ID via the `guid` + * field on the JWT is used to determine ownership of a share. + * That means users may only edit share links created in the same + * session (intended to be a post-share add, not something returned to + * later). It also lets us attribute ownership to anonymous/logged-out + * users. + * Null values in provided context will not overrwrite existing values + * if there are any, but but empty values will (e.g. empty string, empty array). + * Attempting to update a nonexistent share or a share that is not owned + * by the session user will return ShareNotFound. + */ + addShareContext?: Maybe; + /** Add a batch of items to an existing shareable list. */ + addToShareableList: ShareableList; + /** + * Make requests to create and delete highlights in a single batch. + * Mutation is atomic -- if there is a response, all operations were successful. + */ + batchWriteHighlights: BatchWriteHighlightsResult; + /** Remove all tags associated to a SavedItem (included for v3 proxy). */ + clearTags?: Maybe; + /** Add a batch of items to an existing shareable list. */ + createAndAddToShareableList?: Maybe; + /** Create new highlight annotation(s). Returns the data for the created Highlight object. */ + createHighlightByUrl: Highlight; + /** Create new highlight note. Returns the data for the created Highlight note. */ + createSavedItemHighlightNote?: Maybe; + /** Create new highlight annotation(s). Returns the data for the created Highlight object(s). */ + createSavedItemHighlights: Array; + /** + * Add tags to the savedItems + * Inputs a list of SavedItemTagsInput(ie. savedItemId and the list of tagName) + * Returns the list of `SavedItem` for which the tags were added + */ + createSavedItemTags: Array; + /** + * Create a Pocket Share for a provided target URL, optionally + * with additional share context. + */ + createShareLink?: Maybe; + /** + * Creates a Shareable List. Takes in an optional listItemData parameter to create a ShareableListItem + * along with a ShareableList. + */ + createShareableList?: Maybe; + /** Creates a Shareable List Item. */ + createShareableListItem?: Maybe; + /** + * Deletes a SavedItem from the users list. Returns ID of the + * deleted SavedItem + */ + deleteSavedItem: Scalars['ID']['output']; + /** Delete a highlight by its ID. */ + deleteSavedItemHighlight: Scalars['ID']['output']; + /** Delete a highlight note by the Highlight ID. */ + deleteSavedItemHighlightNote: Scalars['ID']['output']; + /** + * Delete one or more tags from one or more SavedItems. + * Note that if this operation results in a Tag having no associations + * to a SavedItem, the Tag object will be deleted. + */ + deleteSavedItemTags: Array; + /** Deletes a Shareable List. */ + deleteShareableList: ShareableList; + /** Deletes a Shareable List Item. HIDDEN Lists cannot have their items deleted. */ + deleteShareableListItem: ShareableListItem; + /** + * Deletes a Tag object. This is deletes the Tag and all SavedItem associations + * (removes the Tag from all SavedItems). Returns ID of the deleted Tag. + */ + deleteTag: Scalars['ID']['output']; + /** + * Delete a tag entity identified by name (rather than ID), to support v3 proxy. + * Disassociates this tag from all SavedItems. + */ + deleteTagByName?: Maybe; + /** Deletes user information and their pocket data for the given pocket userId. Returns pocket userId. */ + deleteUser: Scalars['ID']['output']; + /** + * Deletes user information and their pocket data for the given firefox account ID. + * Returns firefox account ID sent as the query parameter with the request. + */ + deleteUserByFxaId: Scalars['ID']['output']; + /** + * Expires a user's web session tokens by firefox account ID. + * Called by fxa-webhook proxy. Need to supply a reason why to expire user web session. + * Returns the user ID. + */ + expireUserWebSessionByFxaId: Scalars['ID']['output']; + /** + * temporary mutation for apple user migration. + * called by fxa-webhook proxy to update the fxaId and email of the user. + * Returns the pocket userId on success + * Note: requires `transfersub` to be set in the header. + */ + migrateAppleUser: Scalars['ID']['output']; + /** + * 'Re-add' a SavedItem by id. Unarchives and undeletes the SavedItem + * as applicable, and refreshes the "createdAt" timestamp. + */ + reAddById?: Maybe; + /** Refresh an Item's article content. */ + refreshItemArticle: Item; + /** + * Removes specific tags associated to a SavedItem, + * referenced by name, to support v3 proxy. + */ + removeTagsByName?: Maybe; + /** Rename a tag identified by name (rather than ID), to support v3 proxy. */ + renameTagByName?: Maybe; + /** + * Replaces the old tags associated with the savedItem to the new tag list + * given in the entry + * To remove all Tags from a SavedItem, use `updateSavedItemRemoveTags`. + * Note: if there is a new tag name in the SavedItemTagsInput, then the tag record will be created + * Inputs a list of SavedItemTagsInput(ie. savedItemId and list of tag names) + * Returns the SavedItem for which the tags have been modified. + * @deprecated use saveBatchUpdateTags + */ + replaceSavedItemTags: Array; + /** Replace specific tags associated to a SavedItem, to support v3 proxy. */ + replaceTags?: Maybe; + /** Archives PocketSaves */ + saveArchive?: Maybe; + /** + * Batch update the Tags associated with a Save + * by adding new tags and deleting existing tags. + * Maximum of 150 operations (adds/deletes) per request. + */ + saveBatchUpdateTags: SaveWriteMutationPayload; + /** + * Favorites PocketSaves + * Accepts a list of PocketSave Ids that we want to favorite. + */ + saveFavorite?: Maybe; + /** + * Save search to potentially appear in recentSearches response. + * Requires premium account (otherwise will send ForbiddenError). + */ + saveSearch?: Maybe; + /** Unarchives PocketSaves */ + saveUnArchive?: Maybe; + /** + * Unfavorites PocketSaves + * Accepts a list of PocketSave Ids that we want to unfavorite. + */ + saveUnFavorite?: Maybe; + /** + * Creates a new Save; if the Save already exists (either in List or Archive), "re-add" it. + * "Re-adding" unarchives and undeletes the Save as applicable, and refreshes the "createdAt" + * timestamp. + */ + saveUpsert: SaveWriteMutationPayload; + /** Archive a SavedItem (identified by URL) */ + savedItemArchive?: Maybe; + /** 'Soft-delete' a SavedItem (identified by URL) */ + savedItemDelete?: Maybe; + /** Favorite a SavedItem (identified by URL) */ + savedItemFavorite?: Maybe; + /** Associate Tag(s) with a Save */ + savedItemTag?: Maybe; + /** Unarchive a SavedItem (identified by URL) */ + savedItemUnArchive?: Maybe; + /** + * Undo the 'soft-delete' operation on a SavedItem (identified by URL). + * Does not restore tags. Does not restore SavedItems that have been + * 'hard-deleted' (record removed from the database entirely). + */ + savedItemUnDelete?: Maybe; + /** 'Unfavorite' a 'favorite' SavedItem (identified by URL) */ + savedItemUnFavorite?: Maybe; + /** + * Update the title display of a Saved Item, retrieved by URL. + * This is user-save specific (does not update the metadata saved by the parser) + * Clients should ensure the input fits in the utf8mb3 character set (BMP only, + * which means no emoji) to avoid being rejected by the database. + * In the future this will be more permissive. + */ + savedItemUpdateTitle?: Maybe; + /** + * Update an existing highlight annotation, by its ID. + * If the given highlight ID does not exist, will return error data + * and the highlight will not be created. + */ + updateHighlight: Highlight; + /** Archives a SavedItem */ + updateSavedItemArchive: SavedItem; + /** Favorites a SavedItem */ + updateSavedItemFavorite: SavedItem; + /** + * Update an existing highlight annotation, by its ID. + * If the given highlight ID does not exist, will return error data + * and the highlight will not be created. + * Note that if an ID is passed to the optional ID field in CreateHighlightInput, + * it will be ignored, as this mutation does not allow updating the ID. + * @deprecated use updateHighlight + */ + updateSavedItemHighlight: Highlight; + /** + * Update an existing highlight note, by its ID. + * If the given highlight ID does not exist, will return error data + * and the note will not be updated. + */ + updateSavedItemHighlightNote?: Maybe; + /** + * Removes all Tag associations from a SavedItem. Returns the + * SavedItem that had its Tag associations cleared. + * Note that if this operation results in a Tag having no associations + * to a SavedItem, the Tag object will be deleted. + * @deprecated use saveBatchUpdateTags + */ + updateSavedItemRemoveTags: SavedItem; + /** + * Set the Tags that are associated with a SavedItem. + * Will replace any existing Tag associations on the SavedItem. + * To remove all Tags from a SavedItem, use `updateSavedItemRemoveTags`. + * @deprecated use saveBatchUpdateTags + */ + updateSavedItemTags: SavedItem; + /** + * Update the title display of a Saved Item, retrieved by ID. + * This is user-save specific (does not update the metadata saved by the parser). + * Clients should ensure the input fits in the utf8mb3 character set (BMP only, + * which means no emoji) to avoid being rejected by the database. + * In the future this will be more permissive. + */ + updateSavedItemTitle?: Maybe; + /** Unarchives a SavedItem */ + updateSavedItemUnArchive: SavedItem; + /** Undo the delete operation for a SavedItem */ + updateSavedItemUnDelete: SavedItem; + /** Unfavorites a SavedItem */ + updateSavedItemUnFavorite: SavedItem; + /** Updates a Shareable List. Cannot make a list public. */ + updateShareableList: ShareableList; + /** Updates a single Shareable List Item. */ + updateShareableListItem: ShareableListItem; + /** Updates an array of Shareable List Items (sortOrder). */ + updateShareableListItems: Array; + /** + * Updates a Tag (renames the tag), and returns the updated Tag. + * If a Tag with the updated name already exists in the database, will + * associate that Tag to all relevant SavedItems rather than creating + * a duplicate Tag object. + */ + updateTag: Tag; + /** + * update the email of the user for the given pocket userId. Request is made by + * an authenticated user, and the userID is inferred from the request headers `userid`. + */ + updateUserEmail: User; + /** + * update the email of the user for the given firefox account ID. Request + * is made by a backend service. The `userid` in the headers should match + * the FxA ID or else an authentication error will be thrown. + */ + updateUserEmailByFxaId: User; + /** Updates user preferences for content recommendations across Pocket. */ + updateUserRecommendationPreferences: UserRecommendationPreferences; + /** + * Updates a SavedItem, undeletes and unarchives it, bringing it to the top of the user's list, if it exists + * and creates it if it doesn't. + */ + upsertSavedItem: SavedItem; +}; + + +/** Default Mutation Type */ +export type MutationAddShareContextArgs = { + context: ShareContextInput; + slug: Scalars['ID']['input']; +}; + + +/** Default Mutation Type */ +export type MutationAddToShareableListArgs = { + items: Array; + listExternalId: Scalars['ID']['input']; +}; + + +/** Default Mutation Type */ +export type MutationBatchWriteHighlightsArgs = { + input?: InputMaybe; +}; + + +/** Default Mutation Type */ +export type MutationClearTagsArgs = { + savedItem: SavedItemRef; + timestamp?: InputMaybe; +}; + + +/** Default Mutation Type */ +export type MutationCreateAndAddToShareableListArgs = { + itemData: Array; + listData: CreateShareableListInput; +}; + + +/** Default Mutation Type */ +export type MutationCreateHighlightByUrlArgs = { + input: CreateHighlightByUrlInput; +}; + + +/** Default Mutation Type */ +export type MutationCreateSavedItemHighlightNoteArgs = { + id: Scalars['ID']['input']; + input: Scalars['String']['input']; +}; + + +/** Default Mutation Type */ +export type MutationCreateSavedItemHighlightsArgs = { + input: Array; +}; + + +/** Default Mutation Type */ +export type MutationCreateSavedItemTagsArgs = { + input: Array; + timestamp?: InputMaybe; +}; + + +/** Default Mutation Type */ +export type MutationCreateShareLinkArgs = { + context?: InputMaybe; + target: Scalars['ValidUrl']['input']; +}; + + +/** Default Mutation Type */ +export type MutationCreateShareableListArgs = { + listData: CreateShareableListInput; + listItemData?: InputMaybe; +}; + + +/** Default Mutation Type */ +export type MutationCreateShareableListItemArgs = { + data: CreateShareableListItemInput; +}; + + +/** Default Mutation Type */ +export type MutationDeleteSavedItemArgs = { + id: Scalars['ID']['input']; + timestamp?: InputMaybe; +}; + + +/** Default Mutation Type */ +export type MutationDeleteSavedItemHighlightArgs = { + id: Scalars['ID']['input']; +}; + + +/** Default Mutation Type */ +export type MutationDeleteSavedItemHighlightNoteArgs = { + id: Scalars['ID']['input']; +}; + + +/** Default Mutation Type */ +export type MutationDeleteSavedItemTagsArgs = { + input: Array; +}; + + +/** Default Mutation Type */ +export type MutationDeleteShareableListArgs = { + externalId: Scalars['ID']['input']; +}; + + +/** Default Mutation Type */ +export type MutationDeleteShareableListItemArgs = { + externalId: Scalars['ID']['input']; +}; + + +/** Default Mutation Type */ +export type MutationDeleteTagArgs = { + id: Scalars['ID']['input']; +}; + + +/** Default Mutation Type */ +export type MutationDeleteTagByNameArgs = { + tagName: Scalars['String']['input']; + timestamp?: InputMaybe; +}; + + +/** Default Mutation Type */ +export type MutationDeleteUserByFxaIdArgs = { + id: Scalars['ID']['input']; +}; + + +/** Default Mutation Type */ +export type MutationExpireUserWebSessionByFxaIdArgs = { + id: Scalars['ID']['input']; + reason: ExpireUserWebSessionReason; +}; + + +/** Default Mutation Type */ +export type MutationMigrateAppleUserArgs = { + email: Scalars['String']['input']; + fxaId: Scalars['ID']['input']; +}; + + +/** Default Mutation Type */ +export type MutationReAddByIdArgs = { + id: Scalars['ID']['input']; + timestamp: Scalars['ISOString']['input']; +}; + + +/** Default Mutation Type */ +export type MutationRefreshItemArticleArgs = { + url: Scalars['String']['input']; +}; + + +/** Default Mutation Type */ +export type MutationRemoveTagsByNameArgs = { + savedItem: SavedItemRef; + tagNames: Array; + timestamp?: InputMaybe; +}; + + +/** Default Mutation Type */ +export type MutationRenameTagByNameArgs = { + newName: Scalars['String']['input']; + oldName: Scalars['String']['input']; + timestamp?: InputMaybe; +}; + + +/** Default Mutation Type */ +export type MutationReplaceSavedItemTagsArgs = { + input: Array; + timestamp?: InputMaybe; +}; + + +/** Default Mutation Type */ +export type MutationReplaceTagsArgs = { + savedItem: SavedItemRef; + tagNames: Array; + timestamp?: InputMaybe; +}; + + +/** Default Mutation Type */ +export type MutationSaveArchiveArgs = { + id: Array; + timestamp: Scalars['ISOString']['input']; +}; + + +/** Default Mutation Type */ +export type MutationSaveBatchUpdateTagsArgs = { + input: Array; + timestamp: Scalars['ISOString']['input']; +}; + + +/** Default Mutation Type */ +export type MutationSaveFavoriteArgs = { + id: Array; + timestamp: Scalars['ISOString']['input']; +}; + + +/** Default Mutation Type */ +export type MutationSaveSearchArgs = { + search: RecentSearchInput; +}; + + +/** Default Mutation Type */ +export type MutationSaveUnArchiveArgs = { + id: Array; + timestamp: Scalars['ISOString']['input']; +}; + + +/** Default Mutation Type */ +export type MutationSaveUnFavoriteArgs = { + id: Array; + timestamp: Scalars['ISOString']['input']; +}; + + +/** Default Mutation Type */ +export type MutationSaveUpsertArgs = { + input: Array; + timestamp: Scalars['ISOString']['input']; +}; + + +/** Default Mutation Type */ +export type MutationSavedItemArchiveArgs = { + givenUrl: Scalars['Url']['input']; + timestamp: Scalars['ISOString']['input']; +}; + + +/** Default Mutation Type */ +export type MutationSavedItemDeleteArgs = { + givenUrl: Scalars['Url']['input']; + timestamp: Scalars['ISOString']['input']; +}; + + +/** Default Mutation Type */ +export type MutationSavedItemFavoriteArgs = { + givenUrl: Scalars['Url']['input']; + timestamp: Scalars['ISOString']['input']; +}; + + +/** Default Mutation Type */ +export type MutationSavedItemTagArgs = { + input: SavedItemTagInput; + timestamp: Scalars['ISOString']['input']; +}; + + +/** Default Mutation Type */ +export type MutationSavedItemUnArchiveArgs = { + givenUrl: Scalars['Url']['input']; + timestamp: Scalars['ISOString']['input']; +}; + + +/** Default Mutation Type */ +export type MutationSavedItemUnDeleteArgs = { + givenUrl: Scalars['Url']['input']; + timestamp: Scalars['ISOString']['input']; +}; + + +/** Default Mutation Type */ +export type MutationSavedItemUnFavoriteArgs = { + givenUrl: Scalars['Url']['input']; + timestamp: Scalars['ISOString']['input']; +}; + + +/** Default Mutation Type */ +export type MutationSavedItemUpdateTitleArgs = { + givenUrl: Scalars['Url']['input']; + timestamp: Scalars['ISOString']['input']; + title: Scalars['String']['input']; +}; + + +/** Default Mutation Type */ +export type MutationUpdateHighlightArgs = { + id: Scalars['ID']['input']; + input: UpdateHighlightInput; +}; + + +/** Default Mutation Type */ +export type MutationUpdateSavedItemArchiveArgs = { + id: Scalars['ID']['input']; + timestamp?: InputMaybe; +}; + + +/** Default Mutation Type */ +export type MutationUpdateSavedItemFavoriteArgs = { + id: Scalars['ID']['input']; + timestamp?: InputMaybe; +}; + + +/** Default Mutation Type */ +export type MutationUpdateSavedItemHighlightArgs = { + id: Scalars['ID']['input']; + input: CreateHighlightInput; +}; + + +/** Default Mutation Type */ +export type MutationUpdateSavedItemHighlightNoteArgs = { + id: Scalars['ID']['input']; + input: Scalars['String']['input']; +}; + + +/** Default Mutation Type */ +export type MutationUpdateSavedItemRemoveTagsArgs = { + savedItemId?: InputMaybe; + timestamp?: InputMaybe; +}; + + +/** Default Mutation Type */ +export type MutationUpdateSavedItemTagsArgs = { + input: SavedItemTagUpdateInput; +}; + + +/** Default Mutation Type */ +export type MutationUpdateSavedItemTitleArgs = { + id: Scalars['ID']['input']; + timestamp: Scalars['ISOString']['input']; + title: Scalars['String']['input']; +}; + + +/** Default Mutation Type */ +export type MutationUpdateSavedItemUnArchiveArgs = { + id: Scalars['ID']['input']; + timestamp?: InputMaybe; +}; + + +/** Default Mutation Type */ +export type MutationUpdateSavedItemUnDeleteArgs = { + id: Scalars['ID']['input']; + timestamp?: InputMaybe; +}; + + +/** Default Mutation Type */ +export type MutationUpdateSavedItemUnFavoriteArgs = { + id: Scalars['ID']['input']; + timestamp?: InputMaybe; +}; + + +/** Default Mutation Type */ +export type MutationUpdateShareableListArgs = { + data: UpdateShareableListInput; +}; + + +/** Default Mutation Type */ +export type MutationUpdateShareableListItemArgs = { + data: UpdateShareableListItemInput; +}; + + +/** Default Mutation Type */ +export type MutationUpdateShareableListItemsArgs = { + data: Array; +}; + + +/** Default Mutation Type */ +export type MutationUpdateTagArgs = { + input: TagUpdateInput; +}; + + +/** Default Mutation Type */ +export type MutationUpdateUserEmailArgs = { + email: Scalars['String']['input']; +}; + + +/** Default Mutation Type */ +export type MutationUpdateUserEmailByFxaIdArgs = { + email: Scalars['String']['input']; + id: Scalars['ID']['input']; +}; + + +/** Default Mutation Type */ +export type MutationUpdateUserRecommendationPreferencesArgs = { + input: UpdateUserRecommendationPreferencesInput; +}; + + +/** Default Mutation Type */ +export type MutationUpsertSavedItemArgs = { + input: SavedItemUpsertInput; +}; + +export type NotFound = BaseError & { + __typename?: 'NotFound'; + key?: Maybe; + message: Scalars['String']['output']; + path: Scalars['String']['output']; + value?: Maybe; +}; + +export type NumberedListElement = ListElement & { + __typename?: 'NumberedListElement'; + /** Row in a list */ + content: Scalars['Markdown']['output']; + /** Numeric index. If a nested item, the index is zero-indexed from the first child. */ + index: Scalars['Int']['output']; + /** Zero-indexed level, for handling nested lists. */ + level: Scalars['Int']['output']; +}; + +export type OEmbed = PocketMetadata & { + __typename?: 'OEmbed'; + authors?: Maybe>; + datePublished?: Maybe; + domain?: Maybe; + excerpt?: Maybe; + htmlEmbed?: Maybe; + id: Scalars['ID']['output']; + image?: Maybe; + item?: Maybe; + source: PocketMetadataSource; + title?: Maybe; + type?: Maybe; + url: Scalars['Url']['output']; +}; + +export enum OEmbedType { + Link = 'LINK', + Photo = 'PHOTO', + Rich = 'RICH', + Video = 'VIDEO' +} + +/** Input for offset-pagination (internal backend use only). */ +export type OffsetPaginationInput = { + /** Defaults to 30 */ + limit?: InputMaybe; + /** Defaults to 0 */ + offset?: InputMaybe; +}; + +/** Information about pagination in a connection. */ +export type PageInfo = { + __typename?: 'PageInfo'; + /** When paginating forwards, the cursor to continue. */ + endCursor?: Maybe; + /** When paginating forwards, are there more items? */ + hasNextPage: Scalars['Boolean']['output']; + /** When paginating backwards, are there more items? */ + hasPreviousPage: Scalars['Boolean']['output']; + /** When paginating backwards, the cursor to continue. */ + startCursor?: Maybe; +}; + +/** + * Represents a type of page for /explore + * Deprecated for SlateLineups + */ +export enum PageType { + EditorialCollection = 'editorial_collection', + TopicPage = 'topic_page' +} + +export type Pagination = { + __typename?: 'Pagination'; + currentPage: Scalars['Int']['output']; + perPage: Scalars['Int']['output']; + totalPages: Scalars['Int']['output']; + totalResults: Scalars['Int']['output']; +}; + +/** + * Pagination request. To determine which edges to return, the connection + * evaluates the `before` and `after` cursors (if given) to filter the + * edges, then evaluates `first`/`last` to slice the edges (only include a + * value for either `first` or `last`, not both). If all fields are null, + * by default will return a page with the first 30 elements. + */ +export type PaginationInput = { + /** + * Returns the elements in the list that come after the specified cursor. + * The specified cursor is not included in the result. + */ + after?: InputMaybe; + /** + * Returns the elements in the list that come before the specified cursor. + * The specified cursor is not included in the result. + */ + before?: InputMaybe; + /** + * Returns the first _n_ elements from the list. Must be a non-negative integer. + * If `first` contains a value, `last` should be null/omitted in the input. + */ + first?: InputMaybe; + /** + * Returns the last _n_ elements from the list. Must be a non-negative integer. + * If `last` contains a value, `first` should be null/omitted in the input. + */ + last?: InputMaybe; +}; + +export type PendingItem = { + __typename?: 'PendingItem'; + /** + * URL of the item that the user gave for the SavedItem + * that is pending processing by parser + */ + itemId: Scalars['String']['output']; + status?: Maybe; + url: Scalars['Url']['output']; +}; + +export enum PendingItemStatus { + Resolved = 'RESOLVED', + Unresolved = 'UNRESOLVED' +} + +export type PocketMetadata = { + authors?: Maybe>; + datePublished?: Maybe; + domain?: Maybe; + excerpt?: Maybe; + id: Scalars['ID']['output']; + image?: Maybe; + item?: Maybe; + source: PocketMetadataSource; + title?: Maybe; + url: Scalars['Url']['output']; +}; + +export enum PocketMetadataSource { + Oembed = 'OEMBED', + Opengraph = 'OPENGRAPH', + PocketParser = 'POCKET_PARSER' +} + +/** + * New Pocket Save Type, replacing SavedItem. + * + * Represents a Pocket Item that a user has saved to their list. + * (Said otherways, indicates a saved url to a users list and associated user specific information.) + */ +export type PocketSave = { + __typename?: 'PocketSave'; + /** Indicates if the PocketSave is archived. */ + archived: Scalars['Boolean']['output']; + /** Timestamp that the PocketSave became archived, null if not archived. */ + archivedAt?: Maybe; + /** Unix timestamp of when the PocketSave was created. */ + createdAt: Scalars['ISOString']['output']; + /** Unix timestamp of when the entity was deleted. */ + deletedAt?: Maybe; + /** Indicates if the PocketSave is favorited. */ + favorite: Scalars['Boolean']['output']; + /** Timestamp that the PocketSave became favorited, null if not favorited. */ + favoritedAt?: Maybe; + /** The url the user gave (as opposed to normalized URLs). */ + givenUrl: Scalars['String']['output']; + /** Surrogate primary key. */ + id: Scalars['ID']['output']; + /** + * Link to the underlying Pocket Item for the URL. + * Temporary until resource field is added. Will hopefully + * make it easier for clients to adopt. + * @deprecated use resource + */ + item: ItemResult; + /** The status of this PocketSave; Marked for review for possible removal. */ + status?: Maybe; + /** The Suggested Tags associated with this PocketSave, if the user is not premium or there are none, this will be empty. */ + suggestedTags?: Maybe>; + /** The Tags associated with this PocketSave. */ + tags?: Maybe>; + /** The title of the Resource; defaults to the URL. */ + title: Scalars['String']['output']; + /** Unix timestamp of when the PocketSave was last updated, if any property on the PocketSave is modified this timestamp is set to the modified time. */ + updatedAt?: Maybe; +}; + +/** Enum to specify the PocketSave Status (mapped to integers in data store). */ +export enum PocketSaveStatus { + Archived = 'ARCHIVED', + Deleted = 'DELETED', + Hidden = 'HIDDEN', + Unread = 'UNREAD' +} + +export type PocketShare = { + __typename?: 'PocketShare'; + context?: Maybe; + createdAt: Scalars['ISOString']['output']; + preview?: Maybe; + shareUrl: Scalars['ValidUrl']['output']; + slug: Scalars['ID']['output']; + targetUrl: Scalars['ValidUrl']['output']; +}; + +export enum PremiumFeature { + /** Feature where you get an ad-free experience */ + AdFree = 'AD_FREE', + /** Feature where you can highlight articles */ + Annotations = 'ANNOTATIONS', + /** Feature where pocket saves permanent copies of all your saves */ + PermanentLibrary = 'PERMANENT_LIBRARY', + /** Feature where pocket's search is enhanced */ + PremiumSearch = 'PREMIUM_SEARCH', + /** Feature where pocket suggests tags */ + SuggestedTags = 'SUGGESTED_TAGS' +} + +export enum PremiumStatus { + /** + * User has premium and its active + * NOTE: User will still show as active if they turn off auto-renew or have otherwise canceled but the expiration date hasn't hit yet + */ + Active = 'ACTIVE', + /** User has had premium, but it is expired */ + Expired = 'EXPIRED', + /** User has never had premium */ + Never = 'NEVER' +} + +/** The publisher that the curation team set for the syndicated article */ +export type Publisher = { + __typename?: 'Publisher'; + /** Whether or not to show the article appeared on domain */ + appearedOnDomain: Scalars['Boolean']['output']; + /** The article call to action to show if selected */ + articleCta?: Maybe; + /** Whether or not to attribute the publisher to the article */ + attributeCanonicalToPublisher: Scalars['Boolean']['output']; + /** Square logo to use for the publisher */ + logo?: Maybe; + /** Wide logo to use for the publisher */ + logoWide?: Maybe; + /** Black wide based logo to use for the publisher */ + logoWideBlack?: Maybe; + /** Name of the publisher of the article */ + name?: Maybe; + /** The name to show to the article in recommendations */ + recommendationName?: Maybe; + /** Whether or not to show an article call to action */ + showArticleCta: Scalars['Boolean']['output']; + /** Whether or not to show the authors of the article */ + showAuthors: Scalars['Boolean']['output']; + /** Whether or not to show publisher recomendations */ + showPublisherRecommendations?: Maybe; + /** Url of the publisher */ + url?: Maybe; +}; + +/** + * The call to action to show on a SyndicatedArticle for a specific publisher + * TODO: rename to SyndicatedPublisherArticle and move to schema-shared.graphql + * (requires client changes) + */ +export type PublisherArticleCta = { + __typename?: 'PublisherArticleCta'; + /** The lead in text to show */ + leadIn?: Maybe; + /** The text to show */ + text?: Maybe; + /** The url to link to */ + url?: Maybe; +}; + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type Query = { + __typename?: 'Query'; + /** Retrieves a Collection by the given slug. The Collection must be published. */ + collectionBySlug?: Maybe; + /** + * Retrieves a Collection by the given slug. The Collection must be published. + * @deprecated Use collectionBySlug instead + */ + getCollectionBySlug?: Maybe; + /** Retrieves a paged set of published Collections. */ + getCollections: CollectionsResult; + /** + * Look up Item info by a url. + * @deprecated Use itemByUrl instead + */ + getItemByUrl?: Maybe; + /** + * Request a specific `Slate` by id + * @deprecated Please use queries specific to the surface ex. setMomentSlate. If a named query for your surface does not yet exit please reach out to the Data Products team and they will happily provide you with a named query. + */ + getSlate: Slate; + /** + * Request a specific `SlateLineup` by id + * @deprecated Please use queries specific to the surface ex. setMomentSlate. If a named query for your surface does not yet exit please reach out to the Data Products team and they will happily provide you with a named query. + */ + getSlateLineup: SlateLineup; + /** + * Look up SyndicatedArticle by a slug. + * @deprecated use syndicatedArticleBySlug instead + */ + getSyndicatedArticleBySlug?: Maybe; + /** + * Returns a list of unleash toggles that are enabled for a given context. + * + * For more details on this check out https://docs.google.com/document/d/1dYS81h-DbQEWNLtK-ajLTylw454S32llPXUyBmDd5mU/edit# and https://getpocket.atlassian.net/wiki/spaces/PE/pages/1191444582/Feature+Flags+-+Unleash + * + * ~ For each of the enabled unleash toggles (via https://featureflags.readitlater.com/api/client/features or an unleash sdk) + * ~ Check if the toggle is assigned/enabled for the provided {.context} + * ~ Add an {UnleashAssignment} representing it to this list + * ~ If no toggles are found, return an empty list + * @deprecated use unleashAssignments instead + */ + getUnleashAssignments?: Maybe; + /** Get ranked corpus slates and recommendations to deliver a unified Home experience. */ + homeSlateLineup: CorpusSlateLineup; + /** Look up Item info by a url. */ + itemByUrl?: Maybe; + /** + * List all available topics that we have recommendations for. + * @deprecated Use `getSlateLineup` with a specific SlateLineup instead. + */ + listTopics: Array; + /** Get a slate of ranked recommendations for the Firefox New Tab. Currently supports the Italy, France, and Spain markets. */ + newTabSlate: CorpusSlate; + /** + * 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: ReaderViewResult; + /** List all topics that the user can express a preference for. */ + recommendationPreferenceTopics: Array; + scheduledSurface: ScheduledSurface; + /** Search Pocket's corpus of recommendations and collections. */ + searchCorpus?: Maybe; + /** + * Resolve data for a Shared link, or return a Not Found + * message if the share does not exist. + */ + shareSlug?: Maybe; + /** + * Looks up and returns a Shareable List with a given external ID for a given user. + * (the user ID will be coming through with the headers) + */ + shareableList?: Maybe; + /** Returns a publicly-shared Shareable List. Note: this query does not require user authentication. */ + shareableListPublic?: Maybe; + /** + * Looks up and returns an array of Shareable Lists for a given user ID for a given user. + * (the user ID will be coming through with the headers) + */ + shareableLists: Array; + /** Determines if the userid passed in the headers has access to the pilot program. */ + shareableListsPilotUser: Scalars['Boolean']['output']; + /** This is a future improvement, not needed now. */ + surface: Surface; + /** Look up the SyndicatedArticle by a slug */ + syndicatedArticleBySlug?: Maybe; + /** + * Returns a list of unleash toggles that are enabled for a given context. + * + * For more details on this check out https://docs.google.com/document/d/1dYS81h-DbQEWNLtK-ajLTylw454S32llPXUyBmDd5mU/edit# and https://getpocket.atlassian.net/wiki/spaces/PE/pages/1191444582/Feature+Flags+-+Unleash + * + * ~ For each of the enabled unleash toggles (via https://featureflags.readitlater.com/api/client/features or an unleash sdk) + * ~ Check if the toggle is assigned/enabled for the provided {.context} + * ~ Add an {UnleashAssignment} representing it to this list + * ~ If no toggles are found, return an empty list + */ + unleashAssignments?: Maybe; + /** Get a user entity for an authenticated client */ + user?: Maybe; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QueryCollectionBySlugArgs = { + slug: Scalars['String']['input']; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QueryGetCollectionBySlugArgs = { + slug: Scalars['String']['input']; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QueryGetCollectionsArgs = { + filters?: InputMaybe; + page?: InputMaybe; + perPage?: InputMaybe; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QueryGetItemByUrlArgs = { + url: Scalars['String']['input']; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QueryGetSlateArgs = { + recommendationCount?: InputMaybe; + slateId: Scalars['String']['input']; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QueryGetSlateLineupArgs = { + recommendationCount?: InputMaybe; + slateCount?: InputMaybe; + slateLineupId: Scalars['String']['input']; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QueryGetSyndicatedArticleBySlugArgs = { + slug: Scalars['String']['input']; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QueryGetUnleashAssignmentsArgs = { + context: UnleashContext; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QueryHomeSlateLineupArgs = { + locale?: Scalars['String']['input']; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QueryItemByUrlArgs = { + url: Scalars['String']['input']; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QueryNewTabSlateArgs = { + enableRankingByRegion?: InputMaybe; + locale: Scalars['String']['input']; + region?: InputMaybe; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QueryReaderSlugArgs = { + slug: Scalars['ID']['input']; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QueryScheduledSurfaceArgs = { + id: Scalars['ID']['input']; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QuerySearchCorpusArgs = { + filter: CorpusSearchFilters; + pagination?: InputMaybe; + search: CorpusSearchQueryString; + sort?: InputMaybe; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QueryShareSlugArgs = { + slug: Scalars['ID']['input']; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QueryShareableListArgs = { + externalId: Scalars['ID']['input']; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QueryShareableListPublicArgs = { + externalId: Scalars['ID']['input']; + slug: Scalars['String']['input']; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QuerySurfaceArgs = { + id: Scalars['ID']['input']; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QuerySyndicatedArticleBySlugArgs = { + slug: Scalars['String']['input']; +}; + + +/** + * Default root level query type. All authorization checks are done in these queries. + * TODO: These belong in a seperate User Service that provides a User object (the user settings will probably exist there too) + */ +export type QueryUnleashAssignmentsArgs = { + context: UnleashContext; +}; + +/** + * Metadata of an Item in Pocket for preview purposes, + * or an ItemNotFound result if the record does not exist. + */ +export type ReaderFallback = ItemNotFound | ReaderInterstitial; + +/** + * 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. + */ +export type ReaderInterstitial = { + __typename?: 'ReaderInterstitial'; + itemCard?: Maybe; +}; + +/** Result for resolving a getpocket.com/read/ link. */ +export type ReaderViewResult = { + __typename?: 'ReaderViewResult'; + fallbackPage?: Maybe; + /** + * The SavedItem referenced by this reader view slug, if it + * is in the Pocket User's list. + */ + savedItem?: Maybe; + slug: Scalars['ID']['output']; +}; + +export type RecItUserProfile = { + userModels: Array; +}; + +export type RecentSearch = { + __typename?: 'RecentSearch'; + context?: Maybe; + sortId: Scalars['Int']['output']; + term: Scalars['String']['output']; +}; + +export type RecentSearchContext = { + __typename?: 'RecentSearchContext'; + key?: Maybe; + value?: Maybe; +}; + +export type RecentSearchInput = { + /** The term that was used for search */ + term: Scalars['String']['input']; + /** + * Optional, the time the search was performed. + * Defaults to current server time at time of request. + */ + timestamp?: InputMaybe; +}; + +/** Represents a Recommendation from Pocket */ +export type Recommendation = { + __typename?: 'Recommendation'; + curatedInfo?: Maybe; + /** The feed id from mysql that this item was curated from (if it was curated) */ + feedId?: Maybe; + /** + * A generated id from the Data and Learning team that represents the Recommendation - Deprecated + * @deprecated Use `id` + */ + feedItemId?: Maybe; + /** A generated id from the Data and Learning team that represents the Recommendation */ + id: Scalars['ID']['output']; + /** + * The Recommendation entity is owned by the Recommendation API service. + * We extend it in this service to add an extra field ('curationInfo') to the Recommendation entity. + * The key for this entity is the 'itemId' found within the Item entity which is owned by the Parser service. + */ + item: Item; + /** + * The ID of the item this recommendation represents + * TODO: Use apollo federation to turn this into an Item type. + */ + itemId: Scalars['ID']['output']; + /** The publisher of the item */ + publisher?: Maybe; + /** The source of the recommendation */ + recSrc: Scalars['String']['output']; +}; + +export type RecommendationReason = { + __typename?: 'RecommendationReason'; + /** A succinct name for the recommendation reason that can be displayed to the user. */ + name: Scalars['String']['output']; + /** The type of reason for why the recommendation is made. */ + type: RecommendationReasonType; +}; + +/** Reasons why recommendations are made. Focuses on client needs and is not exhaustive. */ +export enum RecommendationReasonType { + /** Recommendations are sourced from the Pocket Hits newsletter. */ + PocketHits = 'POCKET_HITS', + /** Recommendations that match the user's topic preferences are ranked higher. */ + PreferredTopics = 'PREFERRED_TOPICS' +} + +/** Interface that all state based entities must implement */ +export type RemoteEntity = { + /** Unix timestamp of when the entity was created */ + _createdAt?: Maybe; + /** Unix timestamp of when the entity was deleted, 30 days after this date this entity will be HARD deleted from the database and no longer exist */ + _deletedAt?: Maybe; + /** Unix timestamp of when the entity was last updated, if any property on the entity is modified this timestamp is set to the modified time */ + _updatedAt?: Maybe; + /** Version of the entity, this will increment with each modification of the entity's field */ + _version?: Maybe; + /** + * For tags entity, id denotes the unique tag Id. + * For savedItems, id denotes the itemId. + * Along with the userId provided in the header, we will use id to fetch savedItems/tags for the user. + */ + id: Scalars['ID']['output']; +}; + +/** Union type for saveById - retrieving either PocketSaves or NotFound errors */ +export type SaveByIdResult = NotFound | PocketSave; + +/** Payload for mutations that delete Saves */ +export type SaveDeleteMutationPayload = { + __typename?: 'SaveDeleteMutationPayload'; + /** Any errors associated with the mutation. Empty if the mutation was succesful. */ + errors: Array; + success: Scalars['Boolean']['output']; +}; + +/** + * Elasticsearch highlights. + * Highlighted snippets from the following fields in the search results + * so clients can show users where the query matches are. + * Each field, if available, contains an array of html text snippets + * that contain a match to the search term. + * The matching text is wrapped in `` tags, e.g. ["Hiss at vacuum cleaner if it fits i sits"] + */ +export type SaveItemSearchHighlights = { + __typename?: 'SaveItemSearchHighlights'; + fullText?: Maybe>>; + tags?: Maybe>>; + title?: Maybe>>; + url?: Maybe>>; +}; + +/** All types in this union should implement BaseError, for client fallback */ +export type SaveMutationError = NotFound | SyncConflict; + +export type SaveUpdateTagsInput = { + /** + * Tags to add, by name text; if a Tag + * with the given name does not exist, + * one will be created. + */ + addTagNames: Array; + /** Tags to remove, by ID */ + removeTagIds: Array; + saveId: Scalars['ID']['input']; +}; + +/** Input field for upserting a Save. Used by saveUpsert mutation */ +export type SaveUpsertInput = { + /** Optional, create/update the SavedItem as a favorited item */ + isFavorite?: InputMaybe; + /** Optional, title of the SavedItem */ + title?: InputMaybe; + /** + * The url to create/update the SavedItem with. (the url to save to the list) + * Must be at least a 4 character string which is the shortest url + */ + url: Scalars['String']['input']; +}; + +/** Payload for mutations that create or update Saves */ +export type SaveWriteMutationPayload = { + __typename?: 'SaveWriteMutationPayload'; + /** Any errors associated with the mutation. Empty if the mutation was succesful. */ + errors: Array; + /** The mutated Save objects; empty if the mutation did not succeed. */ + save: Array; +}; + +/** + * Represents a Pocket Item that a user has saved to their list. + * (Said otherways, indicates a saved url to a users list and associated user specific information.) + */ +export type SavedItem = RemoteEntity & { + __typename?: 'SavedItem'; + /** Unix timestamp of when the entity was created */ + _createdAt: Scalars['Int']['output']; + /** Unix timestamp of when the entity was deleted, 30 days after this date this entity will be HARD deleted from the database and no longer exist */ + _deletedAt?: Maybe; + /** Unix timestamp of when the entity was last updated, if any property on the entity is modified this timestamp is set to the modified time */ + _updatedAt?: Maybe; + /** Version of the entity, this will increment with each modification of the entity's field */ + _version?: Maybe; + /** Annotations associated to this SavedItem */ + annotations?: Maybe; + /** Timestamp that the SavedItem became archied, null if not archived */ + archivedAt?: Maybe; + /** If the item is in corpus allow the saved item to reference it. Exposing curated info for consistent UX */ + corpusItem?: Maybe; + /** Timestamp that the SavedItem became favorited, null if not favorited */ + favoritedAt?: Maybe; + /** Surrogate primary key. This is usually generated by clients, but will be generated by the server if not passed through creation */ + id: Scalars['ID']['output']; + /** Helper property to indicate if the SavedItem is archived */ + isArchived: Scalars['Boolean']['output']; + /** Helper property to indicate if the SavedItem is favorited */ + isFavorite: Scalars['Boolean']['output']; + /** Link to the underlying Pocket Item for the URL */ + item: ItemResult; + /** The status of this SavedItem */ + status?: Maybe; + /** The Suggested Tags associated with this SavedItem, if the user is not premium or there are none, this will be empty. */ + suggestedTags?: Maybe>; + /** The Tags associated with this SavedItem */ + tags?: Maybe>; + /** The title for user saved item. Set by the user and if not, set by the parser. */ + title?: Maybe; + /** The url the user saved to their list */ + url: Scalars['String']['output']; +}; + +/** + * Container for all annotations associated to a SavedItem. + * Can be extended when more types of annotations are added. + */ +export type SavedItemAnnotations = { + __typename?: 'SavedItemAnnotations'; + /** User-highlighted passages on a SavedItem */ + highlights?: Maybe>>; +}; + +/** The connection type for SavedItem. */ +export type SavedItemConnection = { + __typename?: 'SavedItemConnection'; + /** A list of edges. */ + edges?: Maybe>>; + /** Information to aid in pagination. */ + pageInfo: PageInfo; + /** Identifies the total count of SavedItems in the connection. */ + totalCount: Scalars['Int']['output']; +}; + +/** Payload for mutations that delete Saves */ +export type SavedItemDeleteMutationPayload = { + __typename?: 'SavedItemDeleteMutationPayload'; + /** Any errors associated with the mutation. Empty if the mutation was succesful. */ + errors: Array; + success: Scalars['Boolean']['output']; +}; + +/** An edge in a connection. */ +export type SavedItemEdge = { + __typename?: 'SavedItemEdge'; + /** A cursor for use in pagination. */ + cursor: Scalars['String']['output']; + /** The SavedItem at the end of the edge. */ + node?: Maybe; +}; + +/** All types in this union should implement BaseError, for client fallback */ +export type SavedItemMutationError = NotFound | SyncConflict; + +/** + * We don't have official oneOf support, but this will + * throw if both `id` and `url` are unset/null. + * Don't provide both... but if both are provided, it will + * default to using ID. + */ +export type SavedItemRef = { + id?: InputMaybe; + url?: InputMaybe; +}; + +export type SavedItemSearchResult = { + __typename?: 'SavedItemSearchResult'; + savedItem: SavedItem; + /** + * Highlighted snippets from fields in the search results + * searchHighlights is a premium user feature. Not available for free search. + */ + searchHighlights?: Maybe; +}; + +/** The connection type for SavedItem. */ +export type SavedItemSearchResultConnection = { + __typename?: 'SavedItemSearchResultConnection'; + /** A list of edges. */ + edges: Array; + /** Information to aid in pagination. */ + pageInfo: PageInfo; + /** Identifies the total count of items in the connection. */ + totalCount: Scalars['Int']['output']; +}; + +/** An edge in a connection. */ +export type SavedItemSearchResultEdge = { + __typename?: 'SavedItemSearchResultEdge'; + /** A cursor for use in pagination. */ + cursor: Scalars['String']['output']; + /** The item at the end of the edge. */ + node: SavedItemSearchResult; +}; + +/** A page of SavedItemSearchResult, retrieved by offset-based pagination. */ +export type SavedItemSearchResultPage = { + __typename?: 'SavedItemSearchResultPage'; + entries: Array; + limit: Scalars['Int']['output']; + offset: Scalars['Int']['output']; + totalCount: Scalars['Int']['output']; +}; + +export enum SavedItemStatus { + Archived = 'ARCHIVED', + Deleted = 'DELETED', + Hidden = 'HIDDEN', + Unread = 'UNREAD' +} + +/** Valid statuses a client may use to filter SavedItems */ +export enum SavedItemStatusFilter { + Archived = 'ARCHIVED', + Hidden = 'HIDDEN', + Unread = 'UNREAD' +} + +export type SavedItemTagAssociation = { + __typename?: 'SavedItemTagAssociation'; + /** The ID of the SavedItem associated with the Tag */ + savedItemId: Scalars['ID']['output']; + /** The ID of the Tag associated with the SavedItem */ + tagId: Scalars['ID']['output']; +}; + +/** Input field for adding Tag Associations to a SavedItem, by givenUrl */ +export type SavedItemTagInput = { + givenUrl: Scalars['Url']['input']; + tagNames: Array; +}; + +/** Input field for setting all Tag associations on a SavedItem. */ +export type SavedItemTagUpdateInput = { + /** The SavedItem ID to associate Tags to */ + savedItemId: Scalars['ID']['input']; + /** The set of Tag IDs to associate to the SavedItem */ + tagIds: Array; +}; + +/** Input field for setting all Tag associations on a SavedItem. */ +export type SavedItemTagsInput = { + /** The SavedItem ID to associate Tags to */ + savedItemId: Scalars['ID']['input']; + /** The set of Tag names to associate to the SavedItem */ + tags: Array; +}; + +/** Input field for upserting a SavedItem */ +export type SavedItemUpsertInput = { + /** Optional, create/update the SavedItem as a favorited item */ + isFavorite?: InputMaybe; + /** Optional, time that request was submitted by client epoch/unix time */ + timestamp?: InputMaybe; + /** Optional, title of the SavedItem */ + title?: InputMaybe; + /** + * The url to create/update the SavedItem with. (the url to save to the list) + * Must be at least a 4 character string which is the shortest url + */ + url: Scalars['String']['input']; +}; + +/** Payload for mutations that create or update SavedItems */ +export type SavedItemWriteMutationPayload = { + __typename?: 'SavedItemWriteMutationPayload'; + /** Any errors associated with the mutation. Empty if the mutation was succesful. */ + errors: Array; + /** The mutated SavedItem objects; empty if the mutation did not succeed. */ + savedItem: Array; +}; + +/** A SavedItem can be one of these content types */ +export enum SavedItemsContentType { + /** + * Item is a parsed page can be opened in reader view + * @deprecated Use `IS_READABLE`. + */ + Article = 'ARTICLE', + /** Item is a parsed article that contains videos */ + HasVideo = 'HAS_VIDEO', + /** Item is a video or a parsed article that contains videos */ + HasVideoInclusive = 'HAS_VIDEO_INCLUSIVE', + /** Item is an un-parsable page and will be opened externally */ + IsExternal = 'IS_EXTERNAL', + /** Item is an image */ + IsImage = 'IS_IMAGE', + /** Item is a parsed page can be opened in reader view */ + IsReadable = 'IS_READABLE', + /** Item is a video */ + IsVideo = 'IS_VIDEO', + /** + * Item is a parsed article that contains videos + * @deprecated Use `HAS_VIDEO`. + */ + Video = 'VIDEO' +} + +/** Input field for filtering a user's list */ +export type SavedItemsFilter = { + /** Optional, filter to get SavedItems based on content type */ + contentType?: InputMaybe; + /** + * Optional, filter to get SavedItems that have been archived. + * This field is deprecated. Use status instead. + * TODO: Add deprecate tag once input field deprecation is enabled. + * Ref: https://github.com/apollographql/federation/issues/912 + */ + isArchived?: InputMaybe; + /** Optional, filter to get SavedItems that have been favorited */ + isFavorite?: InputMaybe; + /** Optional, filter to get SavedItems with highlights */ + isHighlighted?: InputMaybe; + /** Optional, filter to get user items based on status. Deprecated: use statuses instead. */ + status?: InputMaybe; + /** Optional, filters to get user items based on multiple statuses (OR operator) */ + statuses?: InputMaybe>>; + /** Optional, filter to get SavedItems associated to the specified Tag. */ + tagIds?: InputMaybe>; + /** + * Optional, filter to get SavedItems associated to the specified Tag name. + * To get untagged items, include the string '_untagged_'. + */ + tagNames?: InputMaybe>; + /** + * Optional, filter to get SavedItems updated before a unix timestamp. + * Mutually exclusive with `updatedSince` option. + */ + updatedBefore?: InputMaybe; + /** + * Optional, filter to get SavedItems updated since a unix timestamp. + * Mutually exclusive with `updatedBefore` option. + */ + updatedSince?: InputMaybe; +}; + +/** A page of SavedItems, retrieved by offset-based pagination. */ +export type SavedItemsPage = { + __typename?: 'SavedItemsPage'; + entries: Array; + limit: Scalars['Int']['output']; + offset: Scalars['Int']['output']; + totalCount: Scalars['Int']['output']; +}; + +/** Input to sort fetched SavedItems. If unspecified, defaults to CREATED_AT, ASC. */ +export type SavedItemsSort = { + /** The field by which to sort SavedItems */ + sortBy: SavedItemsSortBy; + /** The order in which to sort SavedItems */ + sortOrder: SavedItemsSortOrder; +}; + +/** Enum to specify the sort by field (these are the current options, we could add more in the future) */ +export enum SavedItemsSortBy { + ArchivedAt = 'ARCHIVED_AT', + CreatedAt = 'CREATED_AT', + FavoritedAt = 'FAVORITED_AT', + UpdatedAt = 'UPDATED_AT' +} + +/** Enum to specify the sort order of SavedItems fetched */ +export enum SavedItemsSortOrder { + Asc = 'ASC', + Desc = 'DESC' +} + +/** Represents a surface that has scheduled items by day */ +export type ScheduledSurface = { + __typename?: 'ScheduledSurface'; + /** Agreed on GUID that is from our shared data pocket confluence */ + id: Scalars['ID']['output']; + /** Subquery to get the ScheduledSurfaceItems to display to a user for a given date */ + items: Array; + /** Internal name of the surface */ + name: Scalars['String']['output']; +}; + + +/** Represents a surface that has scheduled items by day */ +export type ScheduledSurfaceItemsArgs = { + date: Scalars['Date']['input']; +}; + +/** + * A scheduled entry for an CorpusItem to appear on a Scheduled Surface. + * For example, a story that is scheduled to appear on December 31st, 2021 on the Scheduled Surface in Firefox for the US audience. + */ +export type ScheduledSurfaceItem = { + __typename?: 'ScheduledSurfaceItem'; + /** The curated item that should run */ + corpusItem: CorpusItem; + /** A backend GUID that represents this scheduled run */ + id: Scalars['ID']['output']; + /** The date the item should run at */ + scheduledDate: Scalars['Date']['output']; + /** Agreed on GUID that is from our shared data pocket confluence */ + surfaceId: Scalars['ID']['output']; +}; + +/** Input filed for filtering items */ +export type SearchFilter = { + /** Optional filter to items of a specific content type */ + contentType?: InputMaybe; + /** + * Optional filter to get items that matches the domain + * domain should be in the url format, e.g getpocket.com (or) list.getpocket.com + */ + domain?: InputMaybe; + /** Optional filter to get items that are favorited */ + favorite?: InputMaybe; + /** Optional filter to get items in a specific state */ + status?: InputMaybe; + /** Optional fitler to get item with specific tags */ + tags?: InputMaybe>>; +}; + +export type SearchFilterInput = { + /** Optional, filter to get SavedItems based on content type */ + contentType?: InputMaybe; + /** + * Optional filter to get items that matches the domain + * domain should be in the url format, e.g getpocket.com (or) list.getpocket.com + */ + domain?: InputMaybe; + /** Optional, filter to get user items that have been favorited */ + isFavorite?: InputMaybe; + /** + * Optional, filter to get user items only based on title and url, ie Free Search + * Note, though that if this is selected and the user is premium, they will not get search highligthing. + */ + onlyTitleAndURL?: InputMaybe; + /** Optional, filter to get user items based on status. */ + status?: InputMaybe; +}; + +/** + * Used to detemermine whether to add or multiply a document's score by the + * functional boost factor + */ +export enum SearchFunctionalBoostOperation { + Add = 'ADD', + Multiply = 'MULTIPLY' +} + +/** Input field to get elasticsearch highlights of keywords */ +export type SearchHighlightField = { + /** Field to highlight */ + field: Scalars['String']['input']; + /** The number of characters to return in addition to the keyword */ + size: Scalars['Int']['input']; +}; + +/** A SavedItem can be one of these content types */ +export enum SearchItemsContentType { + Article = 'ARTICLE', + Video = 'VIDEO' +} + +/** Enum to specify the sort by field (these are the current options, we could add more in the future) */ +export enum SearchItemsSortBy { + /** Indicates when a SavedItem was created */ + CreatedAt = 'CREATED_AT', + /** + * Sort SavedItems based on a relevance score + * This is a feature of elasticsearch and current only available for premium search + */ + Relevance = 'RELEVANCE', + /** Estimated time to read a SavedItem */ + TimeToRead = 'TIME_TO_READ' +} + +/** Enum to specify the sort order of user items fetched */ +export enum SearchItemsSortOrder { + Asc = 'ASC', + Desc = 'DESC' +} + +/** Valid statuses a client may use to filter */ +export enum SearchItemsStatusFilter { + Archived = 'ARCHIVED', + Unread = 'UNREAD' +} + +/** Input field for search */ +export type SearchParams = { + /** Fields to search for the keyword in */ + fields: Array>; + /** Filters to be applied to the search */ + filters?: InputMaybe; + /** Offset for pagination */ + from?: InputMaybe; + /** Operation to boost the score of a document based */ + functionalBoosts?: InputMaybe>>; + /** Fields that should be highlighted if keywords are found within them */ + highlightFields?: InputMaybe>>; + /** Number of items to return */ + size?: InputMaybe; + /** Sorting for the search */ + sort?: InputMaybe; + /** The keyword to search for */ + term: Scalars['String']['input']; +}; + +/** The return type for the search query */ +export type SearchResult = { + __typename?: 'SearchResult'; + /** @deprecated Not required by implementing clients */ + page?: Maybe; + /** @deprecated Not required by implementing client */ + perPage?: Maybe; + /** Items found */ + results?: Maybe>>; + /** Number of items found */ + totalResults: Scalars['Int']['output']; +}; + +/** Input field for sorting items */ +export type SearchSort = { + /** Direction of the sort (ASC/DESC) */ + direction: SearchSortDirection; + /** Field in elasticsearch to sort by */ + field: Scalars['String']['input']; +}; + +/** Sort direction of the returned items. */ +export enum SearchSortDirection { + Asc = 'ASC', + Desc = 'DESC' +} + +export type SearchSortInput = { + /** The field by which to sort user items */ + sortBy: SearchItemsSortBy; + /** The order in which to sort user items */ + sortOrder?: InputMaybe; +}; + +/** + * An index item can be in one of these states + * QUEUED implies an item that has not been archived + */ +export enum SearchStatus { + Archived = 'ARCHIVED', + Queued = 'QUEUED' +} + +export type ShareContext = { + __typename?: 'ShareContext'; + /** User-provided highlights of the content */ + highlights?: Maybe>; + /** A user-provided comment/note on the shared content. */ + note?: Maybe; +}; + +/** Input for mutation which creates a new Pocket Share link. */ +export type ShareContextInput = { + /** Quoted content from the Share source */ + highlights?: InputMaybe; + /** A note/comment about the Share (up to 500 characters). */ + note?: InputMaybe; +}; + +export type ShareHighlight = { + __typename?: 'ShareHighlight'; + /** Highlighted text on a piece of shared content. */ + quote: Scalars['String']['output']; +}; + +export type ShareHighlightInput = { + /** + * Highlighted text on a piece of shared content. + * This is a permissive constraint but there needs + * to be _a_ constraint. + * This input is not required, but if present 'quotes' + * is required as it is the only field. + * Limited to 300 characters per quote (longer quotes + * will not be rejected, but will be truncated). + */ + quotes: Array; +}; + +export type ShareNotFound = { + __typename?: 'ShareNotFound'; + message?: Maybe; +}; + +export type ShareResult = PocketShare | ShareNotFound; + +/** A user-created list of Pocket saves that can be shared publicly. */ +export type ShareableList = { + __typename?: 'ShareableList'; + /** The timestamp of when the list was created by its owner. */ + createdAt: Scalars['ISOString']['output']; + /** Optional text description of a Shareable List. Provided by the Pocket user. */ + description?: Maybe; + /** A unique string identifier in UUID format. */ + externalId: Scalars['ID']['output']; + /** Pocket Saves that have been added to this list by the Pocket user. */ + items: ListItemConnection; + /** The visibility of notes added to list items for this list. */ + listItemNoteVisibility: ShareableListVisibility; + /** + * Pocket Saves that have been added to this list by the Pocket user. + * @deprecated use items + */ + listItems: Array; + /** The moderation status of the list. Defaults to VISIBLE. */ + moderationStatus: ShareableListModerationStatus; + /** + * A URL-ready identifier of the list. Generated from the title + * of the list when it's first made public. Unique per user. + */ + slug?: Maybe; + /** The status of the list. Defaults to PRIVATE. */ + status: ShareableListVisibility; + /** The title of the list. Provided by the Pocket user. */ + title: Scalars['String']['output']; + /** + * The timestamp of when the list was last updated by its owner + * or a member of the moderation team. + */ + updatedAt: Scalars['ISOString']['output']; + /** The user who created this shareable list. */ + user: User; +}; + + +/** A user-created list of Pocket saves that can be shared publicly. */ +export type ShareableListItemsArgs = { + pagination?: InputMaybe; +}; + +/** A Pocket Save (story) that has been added to a Shareable List. */ +export type ShareableListItem = { + __typename?: 'ShareableListItem'; + /** A comma-separated list of story authors. Supplied by the Parser. */ + authors?: Maybe; + /** The timestamp of when this story was added to the list by its owner. */ + createdAt: Scalars['ISOString']['output']; + /** The excerpt of the story. Supplied by the Parser. */ + excerpt?: Maybe; + /** A unique string identifier in UUID format. */ + externalId: Scalars['ID']['output']; + /** The URL of the thumbnail image illustrating the story. Supplied by the Parser. */ + imageUrl?: Maybe; + /** The Parser Item ID. */ + itemId: Scalars['ID']['output']; + /** User generated note to accompany this list item. */ + note?: Maybe; + /** The name of the publisher for this story. Supplied by the Parser. */ + publisher?: Maybe; + /** The custom sort order of stories within a list. Defaults to 1. */ + sortOrder: Scalars['Int']['output']; + /** + * The title of the story. Supplied by the Parser. + * May not be available for URLs that cannot be resolved. + * Not editable by the Pocket user, as are all the other + * Parser-supplied story properties below. + */ + title?: Maybe; + /** The timestamp of when the story was last updated. Not used for the MVP. */ + updatedAt: Scalars['ISOString']['output']; + /** The URL of the story saved to a list. */ + url: Scalars['Url']['output']; +}; + +/** The moderation status of a Shareable List. Defaults to VISIBLE. */ +export enum ShareableListModerationStatus { + /** + * The list and its contents have been removed from view and further editing + * by its owner as it violated the Pocket content moderation policy. + */ + Hidden = 'HIDDEN', + /** The list and its contents abide by the Pocket content moderation policy. */ + Visible = 'VISIBLE' +} + +/** + * A list that has been already shared publicly. + * This type is needed as it needs to be cached. + */ +export type ShareableListPublic = { + __typename?: 'ShareableListPublic'; + /** The timestamp of when the list was created by its owner. */ + createdAt: Scalars['ISOString']['output']; + /** Optional text description of a Shareable List. Provided by the Pocket user. */ + description?: Maybe; + /** A unique string identifier in UUID format. */ + externalId: Scalars['ID']['output']; + /** The visibility of notes added to list items for this list. */ + listItemNoteVisibility: ShareableListVisibility; + /** Pocket Saves that have been added to this list by the Pocket user. */ + listItems: Array; + /** The moderation status of the list. Defaults to VISIBLE. */ + moderationStatus: ShareableListModerationStatus; + /** + * A URL-ready identifier of the list. Generated from the title + * of the list when it's first made public. Unique per user. + */ + slug?: Maybe; + /** The status of the list. Defaults to PRIVATE. */ + status: ShareableListVisibility; + /** The title of the list. Provided by the Pocket user. */ + title: Scalars['String']['output']; + /** + * The timestamp of when the list was last updated by its owner + * or a member of the moderation team. + */ + updatedAt: Scalars['ISOString']['output']; + /** The user who created this shareable list. */ + user: User; +}; + +/** The visibility levels used (e.g. list, list item note) in the Shareable List API. Defaults to PRIVATE - visible only to its owner. */ +export enum ShareableListVisibility { + /** Only visible to its owner - the Pocket user who created it. */ + Private = 'PRIVATE', + /** Can be viewed by anyone in the world. */ + Public = 'PUBLIC' +} + +/** A grouping of item recommendations that relate to each other under a specific name and description */ +export type Slate = { + __typename?: 'Slate'; + /** The description of the the slate */ + description?: Maybe; + /** The name to show to the user for this set of recommendations */ + displayName?: Maybe; + /** A unique guid/slug, provided by the Data & Learning team that can identify a specific experiment. Production apps typically won't request a specific one, but can for QA or during a/b testing. */ + experimentId: Scalars['ID']['output']; + id: Scalars['String']['output']; + /** An ordered list of the recommendations to show to the user */ + recommendations: Array; + /** A guid that is unique to every API request that returned slates, such as `getSlateLineup` or `getSlate`. The API will provide a new request id every time apps hit the API. */ + requestId: Scalars['ID']['output']; +}; + +export type SlateLineup = { + __typename?: 'SlateLineup'; + /** A unique guid/slug, provided by the Data & Learning team that can identify a specific experiment. Production apps typically won't request a specific one, but can for QA or during a/b testing. */ + experimentId: Scalars['ID']['output']; + /** A unique slug/id that describes a SlateLineup. The Data & Learning team will provide apps what id to use here for specific cases. */ + id: Scalars['ID']['output']; + /** A guid that is unique to every API request that returned slates, such as `getRecommendationSlateLineup` or `getSlate`. The API will provide a new request id every time apps hit the API. */ + requestId: Scalars['ID']['output']; + /** An ordered list of slates for the client to display */ + slates: Array; +}; + +/** + * Union type to reference a surface + * This is a future improvement, not needed now. + */ +export type Surface = ScheduledSurface; + +export type SyncConflict = BaseError & { + __typename?: 'SyncConflict'; + message: Scalars['String']['output']; + path: Scalars['String']['output']; +}; + +/** An article that Pocket has syndicated and we also host on our own site */ +export type SyndicatedArticle = { + __typename?: 'SyndicatedArticle'; + /** Array of author names in string format */ + authorNames: Array>; + /** Content for the syndicated article */ + content?: Maybe; + /** + * The pocket curation category of the Article, maps to the Pocket Curation Topic lists + * @deprecated use topic instead + */ + curationCategory?: Maybe; + /** Excerpt */ + excerpt?: Maybe; + /** When does the contract for syndication expire */ + expiresAt?: Maybe; + /** The Sub IAB category of the article defined at https://support.aerserv.com/hc/en-us/articles/207148516-List-of-IAB-Categories */ + iabSubCategory?: Maybe; + /** The Main IAB category of the article defined at https://support.aerserv.com/hc/en-us/articles/207148516-List-of-IAB-Categories */ + iabTopCategory?: Maybe; + /** The item id of this Syndicated Article */ + itemId?: Maybe; + /** The locale country of the article */ + localeCountry?: Maybe; + /** The language of the article */ + localeLanguage?: Maybe; + /** Primary image to use in surfacing this content */ + mainImage?: Maybe; + /** The item id of the article we cloned */ + originalItemId: Scalars['ID']['output']; + /** AWSDateTime — Format: YYYY-MM-DDThh:mm:ss.sssZ */ + publishedAt: Scalars['String']['output']; + /** The manually set publisher information for this article */ + publisher?: Maybe; + publisherUrl: Scalars['String']['output']; + /** Recommend similar syndicated articles. */ + relatedEndOfArticle: Array; + /** Recommend similar articles from the same publisher. */ + relatedRightRail: Array; + /** Should ads be shown on this article or not */ + showAds: Scalars['Boolean']['output']; + /** Slug that pocket uses for this article in the url */ + slug?: Maybe; + /** + * DRAFT — Article is not meant to be available to the public + * EXPIRED — Article contract is up and should be redirected to original article + * ACTIVE — Article is clear to be shown in syndicated form + */ + status: ArticleStatus; + /** Title of syndicated article */ + title: Scalars['String']['output']; + /** The pocket topic of the Article, maps to the Pocket Curation Topic lists */ + topic?: Maybe; +}; + + +/** An article that Pocket has syndicated and we also host on our own site */ +export type SyndicatedArticleRelatedEndOfArticleArgs = { + count?: InputMaybe; +}; + + +/** An article that Pocket has syndicated and we also host on our own site */ +export type SyndicatedArticleRelatedRightRailArgs = { + count?: InputMaybe; +}; + +/** Represents a Tag that a User has created for their list */ +export type Tag = { + __typename?: 'Tag'; + /** Unix timestamp of when the entity was deleted, 30 days after this date this entity will be HARD deleted from the database and no longer exist */ + _deletedAt?: Maybe; + /** Version of the entity, this will increment with each modification of the entity's field */ + _version?: Maybe; + /** Surrogate primary key. This is usually generated by clients, but will be generated by the server if not passed through creation */ + id: Scalars['ID']['output']; + /** The actual tag string the user created for their list */ + name: Scalars['String']['output']; + /** paginated listing of all SavedItems associated with this Tag for the user */ + savedItems?: Maybe; +}; + + +/** Represents a Tag that a User has created for their list */ +export type TagSavedItemsArgs = { + filter?: InputMaybe; + pagination?: InputMaybe; + sort?: InputMaybe; +}; + +/** The connection type for Tag. */ +export type TagConnection = { + __typename?: 'TagConnection'; + /** A list of edges. */ + edges?: Maybe>>; + /** Information to aid in pagination. */ + pageInfo: PageInfo; + /** Identifies the total count of Tags in the connection. */ + totalCount: Scalars['Int']['output']; +}; + +/** Input field for creating a Tag */ +export type TagCreateInput = { + /** The user provided tag string */ + name: Scalars['String']['input']; + /** ID of the SavedItem to associate with this Tag */ + savedItemId: Scalars['ID']['input']; +}; + +/** Payload for mutations that delete Tags */ +export type TagDeleteMutationPayload = { + __typename?: 'TagDeleteMutationPayload'; + /** Any errors associated with the mutation. Empty if the mutation was succesful. */ + errors: Array; + success: Scalars['Boolean']['output']; +}; + +/** An edge in a connection. */ +export type TagEdge = { + __typename?: 'TagEdge'; + /** A cursor for use in pagination. */ + cursor: Scalars['String']['output']; + /** The Tag at the end of the edge. */ + node?: Maybe; +}; + +/** All types in this union should implement BaseError, for client fallback */ +export type TagMutationError = NotFound | SyncConflict; + +/** Input field for updating a Tag */ +export type TagUpdateInput = { + /** Tag ID */ + id: Scalars['ID']['input']; + /** The updated tag string */ + name: Scalars['String']['input']; +}; + +/** Payload for mutations that create or update Tags */ +export type TagWriteMutationPayload = { + __typename?: 'TagWriteMutationPayload'; + /** Any errors associated with the mutation. Empty if the mutation was succesful. */ + errors: Array; + /** The mutated Tag objects; empty if the mutation did not succeed. */ + tag: Array; +}; + +/** + * Represents a topic for /explore + * Deprecated for SlateLineups + */ +export type Topic = { + __typename?: 'Topic'; + /** The label the curator uses internally to get items onto this topic */ + curatorLabel: Scalars['String']['output']; + /** The internal feed id that this topic will pull from if set */ + customFeedId?: Maybe; + /** + * The name of the topic to show to the user + * @deprecated displayName is deprecated. Use name instead. + */ + displayName: Scalars['String']['output']; + /** If returned a note to show to the user about the topic */ + displayNote?: Maybe; + /** The legacy UUID id of the topic */ + id: Scalars['ID']['output']; + /** Whether or not clients should show this topic ot users */ + isDisplayed: Scalars['Boolean']['output']; + /** Whether or not this topic should be visiblly promoted (prominent on the page) */ + isPromoted: Scalars['Boolean']['output']; + /** The name of the topic to show to the user */ + name: Scalars['String']['output']; + /** The type of page this topic represents used in generation */ + pageType: PageType; + /** The query that was used internally for elasticsearch to find items */ + query: Scalars['String']['output']; + /** The slug that should be used in the url to represent the topic */ + slug: Scalars['String']['output']; + /** The description to use in the HTML markup for SEO and social media sharing */ + socialDescription?: Maybe; + /** The image to use in the HTML markup for SEO and social media sharing */ + socialImage?: Maybe; + /** The title to use in the HTML markup for SEO and social media sharing */ + socialTitle?: Maybe; +}; + +export type TopicInput = { + /** The id of the topic */ + id: Scalars['ID']['input']; +}; + +/** Represents content that could not be parsed into a valid Marticle* component. */ +export type UnMarseable = { + __typename?: 'UnMarseable'; + /** The html that could not be parsed into a Marticle* component. */ + html: Scalars['String']['output']; +}; + +/** Details on the variant/status of this toggle for a given user/context */ +export type UnleashAssignment = { + __typename?: 'UnleashAssignment'; + /** Whether or not the provided context is assigned */ + assigned: Scalars['Boolean']['output']; + /** The unleash toggle name, the same name as it appears in the admin interface and feature api */ + name: Scalars['String']['output']; + /** If the variant has a payload, its payload value */ + payload?: Maybe; + /** If the toggle has variants, the variant name it is assigned to */ + variant?: Maybe; +}; + +/** Contains a list of all toggles. */ +export type UnleashAssignmentList = { + __typename?: 'UnleashAssignmentList'; + assignments: Array>; +}; + +/** + * Information about the user and device. Based on https://unleash.github.io/docs/unleash_context + * + * Used to calculate assignment values. + */ +export type UnleashContext = { + /** + * A unique name for one of our apps. Can be any string, but here are some known/expected values: + * + * - `android` + * - `ios` + * - `web-discover` + * - `web-app` + */ + appName?: InputMaybe; + /** + * The environment the device is running in: + * - `prod` + * - `beta` + * - `alpha` + */ + environment?: InputMaybe; + properties?: InputMaybe; + /** The device's IP address. If omitted, inferred from either request header `x-forwarded-for` or the origin IP of the request. */ + remoteAddress?: InputMaybe; + /** A device specific identifier that will be consistent across sessions, typically the encoded {guid} or some session token. */ + sessionId?: InputMaybe; + /** If logged in, the user's encoded user id (uid). The {Account.user_id}. */ + userId?: InputMaybe; +}; + +export enum UnleashEnvironment { + /** Internal team builds */ + Alpha = 'alpha', + /** User facing, beta level builds */ + Beta = 'beta', + /** User facing, production builds */ + Prod = 'prod' +} + +/** Extended properties that Unleash can use to assign users through a toggle's strategies. */ +export type UnleashProperties = { + /** Only required on activation strategies that are based on account age */ + accountCreatedAt?: InputMaybe; + /** If omitted, inferred from request header `accept-langauge`. */ + locale?: InputMaybe; + /** Only required on activation strategies that are based whether a user model exists */ + recItUserProfile?: InputMaybe; +}; + +export type UpdateHighlightInput = { + /** The ID of the Item that should be annotated in the User's list */ + itemId: Scalars['ID']['input']; + /** Optional note generated by User */ + note?: InputMaybe; + /** + * Patch string generated by 'DiffMatchPatch' library, serialized + * into text via `patch_toText` method. + * Format is similar to UniDiff but is character-based. + * The patched text depends on version. For example, the version 2 + * patch surrounds the highlighted text portion with a pair of + * sentinel tags: '' + * Reference: https://github.com/google/diff-match-patch + */ + patch: Scalars['String']['input']; + /** + * The full text of the highlighted passage. Used as a fallback for + * rendering highlight if the patch fails. + */ + quote: Scalars['String']['input']; + /** Annotation data version */ + version: Scalars['Int']['input']; +}; + +/** Input data for updating a Shareable List. */ +export type UpdateShareableListInput = { + description?: InputMaybe; + externalId: Scalars['ID']['input']; + listItemNoteVisibility?: InputMaybe; + status?: InputMaybe; + title?: InputMaybe; +}; + +/** Input data for updating a single Shareable List Item. */ +export type UpdateShareableListItemInput = { + externalId: Scalars['ID']['input']; + note?: InputMaybe; + sortOrder?: InputMaybe; +}; + +/** Input data for updating an array of Shareable List Items, targeting sortOrder. */ +export type UpdateShareableListItemsInput = { + externalId: Scalars['ID']['input']; + sortOrder: Scalars['Int']['input']; +}; + +export type UpdateUserRecommendationPreferencesInput = { + /** Topics that the user expressed interest in. */ + preferredTopics: Array; +}; + +/** Resolve by reference the User entity in this graph to provide user data with public lists. */ +export type User = { + __typename?: 'User'; + /** Timestamp of the date when account was created */ + accountCreationDate?: Maybe; + advancedSearch?: Maybe; + advancedSearchByOffset?: Maybe; + /** The public avatar url for the user */ + avatarUrl?: Maybe; + /** A users bio for their profile */ + description?: Maybe; + /** Email address associated with the account. */ + email?: Maybe; + /** The users first name */ + firstName?: Maybe; + /** User id, provided by the user service. */ + id: Scalars['ID']['output']; + /** Indicates if a user is FxA or not */ + isFxa?: Maybe; + /** The user's premium status */ + isPremium?: Maybe; + /** The users last name */ + lastName?: Maybe; + /** The users first name and last name combined */ + name?: Maybe; + /** Premium features that a user has access to */ + premiumFeatures?: Maybe>>; + /** Current premium status of the user */ + premiumStatus?: Maybe; + recentSearches?: Maybe>; + /** Preferences for recommendations that the user has explicitly set. */ + recommendationPreferences?: Maybe; + /** Get a PocketSave(s) by its id(s) */ + saveById: Array; + /** + * Get a SavedItem by its id + * @deprecated Use saveById instead + */ + savedItemById?: Maybe; + /** Get a general paginated listing of all SavedItems for the user */ + savedItems?: Maybe; + /** Fetch SavedItems with offset pagination. Internal backend use only. */ + savedItemsByOffset?: Maybe; + /** + * Premium search query. Name will be updated after client input + * @deprecated Use searchSavedItems + */ + search: SearchResult; + /** Get a paginated list of user items that match a given term */ + searchSavedItems?: Maybe; + searchSavedItemsByOffset?: Maybe; + /** Get a paginated listing of all a user's Tags */ + tags?: Maybe; + /** + * Get all tag names for a user. + * If syncSince is passed, it will only return tags if changes + * to a user's tags have occurred after syncSince. It will return + * all of the user's tags (not just the changes). + * + * Yes, this is bad graphql design. It's serving a specific + * REST API which has unlimited SQL queries, and we do not want to + * make it possible to request every associated SavedItem + * node on a tag object. Just biting the bullet on this one. + */ + tagsList?: Maybe>; + /** The public username for the user */ + username?: Maybe; +}; + + +/** Resolve by reference the User entity in this graph to provide user data with public lists. */ +export type UserAdvancedSearchArgs = { + filter?: InputMaybe; + pagination?: InputMaybe; + queryString?: InputMaybe; + sort?: InputMaybe; +}; + + +/** Resolve by reference the User entity in this graph to provide user data with public lists. */ +export type UserAdvancedSearchByOffsetArgs = { + filter?: InputMaybe; + pagination?: InputMaybe; + queryString?: InputMaybe; + sort?: InputMaybe; +}; + + +/** Resolve by reference the User entity in this graph to provide user data with public lists. */ +export type UserSaveByIdArgs = { + ids: Array; +}; + + +/** Resolve by reference the User entity in this graph to provide user data with public lists. */ +export type UserSavedItemByIdArgs = { + id: Scalars['ID']['input']; +}; + + +/** Resolve by reference the User entity in this graph to provide user data with public lists. */ +export type UserSavedItemsArgs = { + filter?: InputMaybe; + pagination?: InputMaybe; + sort?: InputMaybe; +}; + + +/** Resolve by reference the User entity in this graph to provide user data with public lists. */ +export type UserSavedItemsByOffsetArgs = { + filter?: InputMaybe; + pagination?: InputMaybe; + sort?: InputMaybe; +}; + + +/** Resolve by reference the User entity in this graph to provide user data with public lists. */ +export type UserSearchArgs = { + params: SearchParams; +}; + + +/** Resolve by reference the User entity in this graph to provide user data with public lists. */ +export type UserSearchSavedItemsArgs = { + filter?: InputMaybe; + pagination?: InputMaybe; + sort?: InputMaybe; + term: Scalars['String']['input']; +}; + + +/** Resolve by reference the User entity in this graph to provide user data with public lists. */ +export type UserSearchSavedItemsByOffsetArgs = { + filter?: InputMaybe; + pagination?: InputMaybe; + sort?: InputMaybe; + term: Scalars['String']['input']; +}; + + +/** Resolve by reference the User entity in this graph to provide user data with public lists. */ +export type UserTagsArgs = { + pagination?: InputMaybe; +}; + + +/** Resolve by reference the User entity in this graph to provide user data with public lists. */ +export type UserTagsListArgs = { + syncSince?: InputMaybe; +}; + +export type UserRecommendationPreferences = { + __typename?: 'UserRecommendationPreferences'; + /** Topics that the user expressed interest in. */ + preferredTopics?: Maybe>; +}; + +/** A Video, typically within an Article View of an Item or if the Item is a video itself. */ +export type Video = { + __typename?: 'Video'; + /** If known, the height of the video in px */ + height?: Maybe; + /** If known, the length of the video in seconds */ + length?: Maybe; + /** Absolute url to the video */ + src: Scalars['String']['output']; + /** The type of video */ + type: VideoType; + /** The video's id within the service defined by type */ + vid?: Maybe; + /** 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: Scalars['Int']['output']; + /** If known, the width of the video in px */ + width?: Maybe; +}; + +export enum VideoType { + /** Brightcove (v3 value is 8) */ + Brightcove = 'BRIGHTCOVE', + /** Flash (v3 value is 6) */ + Flash = 'FLASH', + /** html5 (v3 value is 5) */ + Html5 = 'HTML5', + /** iframe (v3 value is 7) */ + Iframe = 'IFRAME', + /** video iframe (v3 value is 4) */ + VimeoIframe = 'VIMEO_IFRAME', + /** Vimeo Link (v3 value is 2) */ + VimeoLink = 'VIMEO_LINK', + /** Vimeo Moogaloop (v3 value is 3) */ + VimeoMoogaloop = 'VIMEO_MOOGALOOP', + /** Youtube (v3 value is 1) */ + Youtube = 'YOUTUBE' +} + +export enum Videoness { + /** Contains videos (v3 value is 1) */ + HasVideos = 'HAS_VIDEOS', + /** Is a video (v3 value is 2) */ + IsVideo = 'IS_VIDEO', + /** No videos (v3 value is 0) */ + NoVideos = 'NO_VIDEOS' +} + +export type PocketCollectionsQueryVariables = Exact<{ + slug: Scalars['String']['input']; +}>; + + +export type PocketCollectionsQuery = { __typename?: 'Query', getCollectionBySlug?: { __typename?: 'Collection', externalId: string, title: string, excerpt?: any | null, imageUrl?: any | null, intro?: any | null, publishedAt?: any | null, stories: Array<{ __typename?: 'CollectionStory', externalId: string, title: string, excerpt: any, imageUrl?: any | null, publisher?: string | null, url: any, authors: Array<{ __typename?: 'CollectionStoryAuthor', name: string }>, item?: { __typename?: 'Item', shortUrl?: any | null } | null }> } | null }; + +export type PocketHitsQueryVariables = Exact<{ + date: Scalars['Date']['input']; + scheduledSurfaceId: Scalars['ID']['input']; +}>; + + +export type PocketHitsQuery = { __typename?: 'Query', scheduledSurface: { __typename?: 'ScheduledSurface', items: Array<{ __typename?: 'ScheduledSurfaceItem', id: string, corpusItem: { __typename?: 'CorpusItem', url: any, shortUrl?: any | null, title: string, topic?: string | null, excerpt: string, imageUrl: any, publisher: string, authors: Array<{ __typename?: 'CorpusItemAuthor', name: string }> } }> } }; + + +export const PocketCollectionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PocketCollections"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"slug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getCollectionBySlug"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"slug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"externalId"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"excerpt"}},{"kind":"Field","name":{"kind":"Name","value":"imageUrl"}},{"kind":"Field","name":{"kind":"Name","value":"intro"}},{"kind":"Field","name":{"kind":"Name","value":"publishedAt"}},{"kind":"Field","name":{"kind":"Name","value":"stories"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"externalId"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"excerpt"}},{"kind":"Field","name":{"kind":"Name","value":"imageUrl"}},{"kind":"Field","name":{"kind":"Name","value":"publisher"}},{"kind":"Field","name":{"kind":"Name","value":"authors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"item"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"shortUrl"}}]}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]}}]}}]} as unknown as DocumentNode; +export const PocketHitsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PocketHits"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"date"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Date"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"scheduledSurfaceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"scheduledSurface"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"scheduledSurfaceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"date"},"value":{"kind":"Variable","name":{"kind":"Name","value":"date"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"corpusItem"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"shortUrl"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"topic"}},{"kind":"Field","name":{"kind":"Name","value":"excerpt"}},{"kind":"Field","name":{"kind":"Name","value":"imageUrl"}},{"kind":"Field","name":{"kind":"Name","value":"authors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"publisher"}}]}}]}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/servers/braze-content-proxy/src/graphql/client-api-proxy.ts b/servers/braze-content-proxy/src/graphql/client-api-proxy.ts index 2dd97c3f7..4cf883296 100644 --- a/servers/braze-content-proxy/src/graphql/client-api-proxy.ts +++ b/servers/braze-content-proxy/src/graphql/client-api-proxy.ts @@ -1,8 +1,18 @@ -import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client/core'; +import { + ApolloClient, + ApolloQueryResult, + HttpLink, + InMemoryCache, +} from '@apollo/client/core'; import fetch from 'cross-fetch'; import config from '../config'; -import gql from 'graphql-tag'; -import { ClientApiResponse } from './types'; +import { + PocketCollectionsDocument, + PocketCollectionsQuery, + PocketCollectionsQueryVariables, + PocketHitsDocument, + PocketHitsQuery, +} from '../generated/graphql/types'; export const client = new ApolloClient({ link: new HttpLink({ fetch, uri: config.clientApi.uri }), @@ -24,34 +34,14 @@ export const client = new ApolloClient({ * @param slug slug identifier of the collction * @returns collections and its story details required by braze */ -export async function getCollectionsFromGraph(slug: string): Promise { - const response = await client.query({ - query: gql` - query PocketCollections($slug: String!) { - getCollectionBySlug(slug: $slug) { - externalId - title - excerpt - imageUrl - intro - publishedAt - stories { - externalId - title - excerpt - imageUrl - publisher - authors { - name - } - item { - shortUrl - } - url - } - } - } - `, +export async function getCollectionsFromGraph( + slug: string, +): Promise> { + const response = await client.query< + PocketCollectionsQuery, + PocketCollectionsQueryVariables + >({ + query: PocketCollectionsDocument, variables: { slug: slug, }, @@ -76,29 +66,9 @@ export async function getCollectionsFromGraph(slug: string): Promise { export async function getScheduledSurfaceStories( date: string, scheduledSurfaceId: string, -): Promise { +): Promise> { const data = await client.query({ - query: gql` - query PocketHits($date: Date!, $scheduledSurfaceId: ID!) { - scheduledSurface(id: $scheduledSurfaceId) { - items(date: $date) { - id - corpusItem { - url - shortUrl - title - topic - excerpt - imageUrl - authors { - name - } - publisher - } - } - } - } - `, + query: PocketHitsDocument, variables: { date, scheduledSurfaceId, diff --git a/servers/braze-content-proxy/src/graphql/queries/collections.graphql b/servers/braze-content-proxy/src/graphql/queries/collections.graphql new file mode 100644 index 000000000..5cef20567 --- /dev/null +++ b/servers/braze-content-proxy/src/graphql/queries/collections.graphql @@ -0,0 +1,24 @@ +query PocketCollections($slug: String!) { + getCollectionBySlug(slug: $slug) { + externalId + title + excerpt + imageUrl + intro + publishedAt + stories { + externalId + title + excerpt + imageUrl + publisher + authors { + name + } + item { + shortUrl + } + url + } + } +} diff --git a/servers/braze-content-proxy/src/graphql/queries/scheduledSurface.graphql b/servers/braze-content-proxy/src/graphql/queries/scheduledSurface.graphql new file mode 100644 index 000000000..a0858b60f --- /dev/null +++ b/servers/braze-content-proxy/src/graphql/queries/scheduledSurface.graphql @@ -0,0 +1,19 @@ +query PocketHits($date: Date!, $scheduledSurfaceId: ID!) { + scheduledSurface(id: $scheduledSurfaceId) { + items(date: $date) { + id + corpusItem { + url + shortUrl + title + topic + excerpt + imageUrl + authors { + name + } + publisher + } + } + } +} diff --git a/servers/braze-content-proxy/src/graphql/types.ts b/servers/braze-content-proxy/src/graphql/types.ts deleted file mode 100644 index c8ea39dc5..000000000 --- a/servers/braze-content-proxy/src/graphql/types.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { ScheduledSurfaceItem } from '../routes/types'; - -//todo: in future, we can extend it to codegen types from graphql schema -/** - * The shape of the query returned by Client API that contains curated items - * scheduled for a given day on a given Pocket Hits surface. - */ -export type ClientApiResponse = { - data: { - scheduledSurface: { - items: ScheduledSurfaceItem[]; - }; - }; -}; diff --git a/servers/braze-content-proxy/src/routes/collection.ts b/servers/braze-content-proxy/src/routes/collection.ts index 0f82a2362..4d964e05f 100644 --- a/servers/braze-content-proxy/src/routes/collection.ts +++ b/servers/braze-content-proxy/src/routes/collection.ts @@ -1,10 +1,12 @@ import { getCollectionsFromGraph } from '../graphql/client-api-proxy'; import { getResizedImageUrl, validateApiKey } from '../utils'; -import { BrazeCollections } from './types'; +import { BrazeCollections, BrazeCollectionStory } from './types'; import config from '../config'; import { Router } from 'express'; +import { PocketCollectionsQuery } from '../generated/graphql/types'; +import type { ApolloQueryResult } from '@apollo/client/core/types'; -const router = Router(); +const router: Router = Router(); /** * GET endpoint to receive collection metadata and its stories information from client @@ -41,22 +43,29 @@ export async function getCollection(slug: string) { return transformToBrazePayload(response); } -function transformToBrazePayload(response): BrazeCollections { +function transformToBrazePayload( + response: ApolloQueryResult, +): BrazeCollections { const collection = response.data.getCollectionBySlug; - const stories = collection.stories.map((story) => { - const res = { - ...story, + const stories: BrazeCollectionStory[] = collection.stories.map((story) => { + return { + title: story.title, + url: story.url, + excerpt: story.excerpt, imageUrl: getResizedImageUrl(story.imageUrl), authors: story.authors.map((author) => author.name), shortUrl: story.item.shortUrl, + publisher: story.publisher, + externalId: story.externalId, }; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { item: _, ...rest } = res; - return rest; }); return { - ...collection, + title: collection.title, + intro: collection.intro, + excerpt: collection.excerpt, + publishedAt: collection.publishedAt, imageUrl: getResizedImageUrl(collection.imageUrl), + externalId: collection.externalId, stories: stories, }; } diff --git a/servers/braze-content-proxy/src/routes/scheduledItems.ts b/servers/braze-content-proxy/src/routes/scheduledItems.ts index 6ed7f3e4f..487ea2947 100644 --- a/servers/braze-content-proxy/src/routes/scheduledItems.ts +++ b/servers/braze-content-proxy/src/routes/scheduledItems.ts @@ -1,11 +1,10 @@ import { BrazeContentProxyResponse, TransformedCorpusItem } from './types'; -import { ClientApiResponse } from '../graphql/types'; import { getResizedImageUrl, validateApiKey, validateDate } from '../utils'; import { getScheduledSurfaceStories } from '../graphql/client-api-proxy'; import config from '../config'; import { Router } from 'express'; -const router = Router(); +const router: Router = Router(); router.get('/:scheduledSurfaceID', async (req, res, next) => { // Enable two minute cache when in AWS. @@ -45,30 +44,29 @@ export const stories = { date: string, scheduledSurfaceId: string, ): Promise => { - const data: ClientApiResponse | null = await getScheduledSurfaceStories( - date, - scheduledSurfaceId, - ); + const data = await getScheduledSurfaceStories(date, scheduledSurfaceId); const stories = data ? data.data.scheduledSurface.items : []; - const transformedStories: TransformedCorpusItem[] = stories.map(function ( - item, - index, - ) { + const transformedStories: TransformedCorpusItem[] = stories.map((item) => { return { // The id of the Scheduled Surface Item id: item.id, - // Properties of the Corpus Item the proxy needs to make available for Braze - ...item.corpusItem, + url: item.corpusItem.url, + shortUrl: item.corpusItem.shortUrl, + title: item.corpusItem.title, + topic: item.corpusItem.topic, + excerpt: item.corpusItem.excerpt, + publisher: item.corpusItem.publisher, // Resize images on the fly so that they don't distort emails when sent out. - imageUrl: getResizedImageUrl(this[index].corpusItem.imageUrl), + imageUrl: getResizedImageUrl(item.corpusItem.imageUrl), // Flatten the authors into a comma-separated string. - authors: this[index].corpusItem.authors + authors: item.corpusItem.authors ?.map((author) => author.name) .join(', '), + __typename: 'CorpusItem', }; - }, stories); + }); return { stories: transformedStories, diff --git a/servers/braze-content-proxy/src/routes/types.ts b/servers/braze-content-proxy/src/routes/types.ts index 7e692e0b9..8eb4f65b2 100644 --- a/servers/braze-content-proxy/src/routes/types.ts +++ b/servers/braze-content-proxy/src/routes/types.ts @@ -1,31 +1,28 @@ /** - * The properties of curated items that we need to fetch from Client API. + * A very lean Corpus Item type with just the data Pocket Hits emails need. */ -export type CorpusItem = { +export type TransformedCorpusItem = { + // Unlike in the Client API response, the Braze Content Proxy response contains + // a string that lists all the authors for each story, not an object. + authors: string; + // This value is the id of the Scheduled Surface Item, rather than the Corpus Item + id: string; + url: string; + shortUrl: string; + title: string; + + topic: string; + excerpt: string; - imageUrl: string; - authors: { name: string }; + publisher: string; - topic: string; -}; -export interface ScheduledSurfaceItem { - id: string; - corpusItem: CorpusItem; -} + imageUrl: string; -/** - * A very lean Corpus Item type with just the data Pocket Hits emails need. - */ -export type TransformedCorpusItem = Omit & { - // Unlike in the Client API response, the Braze Content Proxy response contains - // a string that lists all the authors for each story, not an object. - authors: string; - // This value is the id of the Scheduled Surface Item, rather than the Corpus Item - id: string; + __typename: string; }; /** @@ -44,10 +41,11 @@ export type BrazeCollections = { imageUrl: string; intro: string; publishedAt: string; + externalId: string; stories: BrazeCollectionStory[]; }; -type BrazeCollectionStory = { +export type BrazeCollectionStory = { title: string; url: string; shortUrl: string; @@ -55,4 +53,5 @@ type BrazeCollectionStory = { imageUrl: string; publisher: string; authors: string[]; + externalId: string; }; diff --git a/turbo.json b/turbo.json index a88b7410d..aca88aac1 100644 --- a/turbo.json +++ b/turbo.json @@ -49,7 +49,7 @@ "inputs": ["src/**/*", "eslint.config.js", "package.json"] }, "semantic-release": { - "dependsOn": ["^build", "build"] + "dependsOn": ["^build"] }, "test": { "inputs": ["src/**/*", "package.json", "jest.config.js", "jest.setup.js"],