@financial-times/cp-content-pipeline-schema 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.toolkitrc.yml +12 -0
- package/CHANGELOG.md +72 -0
- package/jest.config.js +3 -0
- package/lib/concept.d.ts +7 -0
- package/lib/concept.js +39 -0
- package/lib/concept.js.map +1 -0
- package/lib/constants/contentTypes.d.ts +2 -0
- package/lib/constants/contentTypes.js +3 -0
- package/lib/constants/contentTypes.js.map +1 -0
- package/lib/content.d.ts +55 -0
- package/lib/content.js +133 -0
- package/lib/content.js.map +1 -0
- package/lib/content.test.d.ts +1 -0
- package/lib/content.test.js +149 -0
- package/lib/content.test.js.map +1 -0
- package/lib/datasources/capi.d.ts +10 -0
- package/lib/datasources/capi.js +28 -0
- package/lib/datasources/capi.js.map +1 -0
- package/lib/datasources/index.d.ts +9 -0
- package/lib/datasources/index.js +9 -0
- package/lib/datasources/index.js.map +1 -0
- package/lib/datasources/origami-image.d.ts +8 -0
- package/lib/datasources/origami-image.js +11 -0
- package/lib/datasources/origami-image.js.map +1 -0
- package/lib/datasources/url-management.d.ts +11 -0
- package/lib/datasources/url-management.js +40 -0
- package/lib/datasources/url-management.js.map +1 -0
- package/lib/datasources/url-management.test.d.ts +1 -0
- package/lib/datasources/url-management.test.js +69 -0
- package/lib/datasources/url-management.test.js.map +1 -0
- package/lib/helpers/byline.d.ts +1 -0
- package/lib/helpers/byline.js +5 -0
- package/lib/helpers/byline.js.map +1 -0
- package/lib/helpers/imageService.d.ts +8 -0
- package/lib/helpers/imageService.js +13 -0
- package/lib/helpers/imageService.js.map +1 -0
- package/lib/helpers/metadata.d.ts +12 -0
- package/lib/helpers/metadata.js +60 -0
- package/lib/helpers/metadata.js.map +1 -0
- package/lib/helpers/syntaxTree.d.ts +23 -0
- package/lib/helpers/syntaxTree.js +23 -0
- package/lib/helpers/syntaxTree.js.map +1 -0
- package/lib/image.d.ts +25 -0
- package/lib/image.js +123 -0
- package/lib/image.js.map +1 -0
- package/lib/image.test.d.ts +1 -0
- package/lib/image.test.js +235 -0
- package/lib/image.test.js.map +1 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.js +69 -0
- package/lib/index.js.map +1 -0
- package/lib/picture.d.ts +22 -0
- package/lib/picture.js +80 -0
- package/lib/picture.js.map +1 -0
- package/lib/richText.d.ts +14 -0
- package/lib/richText.js +48 -0
- package/lib/richText.js.map +1 -0
- package/lib/tags.d.ts +13 -0
- package/lib/tags.js +178 -0
- package/lib/tags.js.map +1 -0
- package/lib/topper.d.ts +7 -0
- package/lib/topper.js +196 -0
- package/lib/topper.js.map +1 -0
- package/lib/unified-plugins/extract-references.d.ts +7 -0
- package/lib/unified-plugins/extract-references.js +36 -0
- package/lib/unified-plugins/extract-references.js.map +1 -0
- package/lib/unified-plugins/map-to-abstract-types.d.ts +4 -0
- package/lib/unified-plugins/map-to-abstract-types.js +17 -0
- package/lib/unified-plugins/map-to-abstract-types.js.map +1 -0
- package/package.json +43 -0
- package/src/__snapshots__/content.test.ts.snap +118 -0
- package/src/concept.ts +58 -0
- package/src/constants/contentTypes.ts +4 -0
- package/src/content.test.ts +163 -0
- package/src/content.ts +146 -0
- package/src/datasources/capi.ts +28 -0
- package/src/datasources/index.ts +11 -0
- package/src/datasources/origami-image.ts +10 -0
- package/src/datasources/url-management.test.ts +92 -0
- package/src/datasources/url-management.ts +65 -0
- package/src/helpers/byline.ts +4 -0
- package/src/helpers/imageService.ts +31 -0
- package/src/helpers/metadata.ts +88 -0
- package/src/helpers/syntaxTree.ts +26 -0
- package/src/image.test.ts +339 -0
- package/src/image.ts +154 -0
- package/src/index.ts +87 -0
- package/src/picture.ts +98 -0
- package/src/richText.ts +62 -0
- package/src/tags.ts +237 -0
- package/src/topper.ts +228 -0
- package/src/types/internal-content.d.ts +78 -0
- package/src/types/n-concept-ids.d.ts +16 -0
- package/src/types/n-display-metadata.d.ts +1 -0
- package/src/types/n-url-management-api-read-client.d.ts +11 -0
- package/src/types/next-metrics.d.ts +1 -0
- package/src/unified-plugins/extract-references.ts +50 -0
- package/src/unified-plugins/map-to-abstract-types.ts +21 -0
- package/tsconfig.json +10 -0
- package/tsconfig.tsbuildinfo +1 -0
package/.toolkitrc.yml
ADDED
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.2.1](https://github.com/Financial-Times/cp-content-pipeline/compare/cp-content-pipeline-schema-v0.2.0...cp-content-pipeline-schema-v0.2.1) (2022-09-27)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* make an innocuous change to trigger a rerelease of these packages ([7ed623d](https://github.com/Financial-Times/cp-content-pipeline/commit/7ed623d126ddc00bc99ee050ddbba1cb18b01ee9))
|
|
9
|
+
|
|
10
|
+
## [0.2.0](https://github.com/Financial-Times/cp-content-pipeline/compare/cp-content-pipeline-schema-v0.1.0...cp-content-pipeline-schema-v0.2.0) (2022-09-27)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### ⚠ BREAKING CHANGES
|
|
14
|
+
|
|
15
|
+
* rename "inline" image to "standard"
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* add a datasource for getting vanity URLs ([cb638a5](https://github.com/Financial-Times/cp-content-pipeline/commit/cb638a5b48bc7726008189376a27d245a7b642d0))
|
|
20
|
+
* add byline and authors to content schema ([37ea933](https://github.com/Financial-Times/cp-content-pipeline/commit/37ea93339f9e2c4a9ef4fed20bf4a8633762d594))
|
|
21
|
+
* add client package with typescript types generated from schema ([c00f07f](https://github.com/Financial-Times/cp-content-pipeline/commit/c00f07f9d9d10f74cdd834ad59efe189f151ede2))
|
|
22
|
+
* add Columnist tag to Opinion topper ([b50dc42](https://github.com/Financial-Times/cp-content-pipeline/commit/b50dc42113f3e477b5b30588d886e84fd800d718))
|
|
23
|
+
* add Headshot to topper ([a832390](https://github.com/Financial-Times/cp-content-pipeline/commit/a8323906e74d1fdd5d877e12efb9d2168ba20fef))
|
|
24
|
+
* add image caption and alt ([3dd2dd8](https://github.com/Financial-Times/cp-content-pipeline/commit/3dd2dd8cf88a33f8114470b57ea8cba4ea69e352))
|
|
25
|
+
* add image type, and fallback alt for graphics ([7589bea](https://github.com/Financial-Times/cp-content-pipeline/commit/7589beabe4a50d16cfff66c0c03536e75a5a2e22))
|
|
26
|
+
* add ImageSet type to graphQL api ([92534f0](https://github.com/Financial-Times/cp-content-pipeline/commit/92534f0f983d8e9c687b9f4c2474aa235c0f01bb))
|
|
27
|
+
* Add isColumn resolver to Content ([0a2af1a](https://github.com/Financial-Times/cp-content-pipeline/commit/0a2af1ae80d103e2d6d0c5a01338c8488b866e10))
|
|
28
|
+
* Add isEditorsChoice resolver to Content ([813e07b](https://github.com/Financial-Times/cp-content-pipeline/commit/813e07b2a70e0d642768d481e4fb38929da4caa2))
|
|
29
|
+
* Add isExclusive resolver to Content ([cef9675](https://github.com/Financial-Times/cp-content-pipeline/commit/cef9675c5c6d5f98c94c722f855671610ab69916))
|
|
30
|
+
* Add isPodcast resolver to Content ([d76eb78](https://github.com/Financial-Times/cp-content-pipeline/commit/d76eb78909accdec6aa8c654524d1ef89d4eaa56))
|
|
31
|
+
* Add isScoop resolver to Content ([0441fba](https://github.com/Financial-Times/cp-content-pipeline/commit/0441fba34374c69422a2d4a4fed82cd43d68c4e1))
|
|
32
|
+
* add metadata and BrandedTopper ([57fc4c5](https://github.com/Financial-Times/cp-content-pipeline/commit/57fc4c524b2b690ba993563d971ad10b14b85c10))
|
|
33
|
+
* Add opinion teasers ([fdbf3b2](https://github.com/Financial-Times/cp-content-pipeline/commit/fdbf3b2c61a9a6f2030bc23d4a0886f1f6a1ef25))
|
|
34
|
+
* add OpinionTopper type ([4fc3e38](https://github.com/Financial-Times/cp-content-pipeline/commit/4fc3e386b6cd45b8dc06bee51515f6a8889bd817))
|
|
35
|
+
* add PictureInline variant ([7d3f721](https://github.com/Financial-Times/cp-content-pipeline/commit/7d3f721fec6c9a79a21d076a5517955a15b7089d))
|
|
36
|
+
* add simple cache implementation for vanities ([3da9261](https://github.com/Financial-Times/cp-content-pipeline/commit/3da9261fbe0faf3ae748f78f03c7174b52ca93c6))
|
|
37
|
+
* add support for Methode layout components ([5013021](https://github.com/Financial-Times/cp-content-pipeline/commit/5013021a6ac0861c3cf191fff043291e747307d8))
|
|
38
|
+
* allow different image widths and breakpoints ([1210b62](https://github.com/Financial-Times/cp-content-pipeline/commit/1210b62e9f778ee09a9ecd1998bffbefb4234c2d))
|
|
39
|
+
* create byline component and add it to topper ([56d6ed1](https://github.com/Financial-Times/cp-content-pipeline/commit/56d6ed1af1dd31e2f51e95b5e538578d5802a726))
|
|
40
|
+
* default fullBleed and mobile images to use standard ([4c98bc6](https://github.com/Financial-Times/cp-content-pipeline/commit/4c98bc66c2adcab220098ad99340eb4cae810965))
|
|
41
|
+
* dont request wider image than the source image ([c4e0161](https://github.com/Financial-Times/cp-content-pipeline/commit/c4e0161fa5f0f7492e280a9bc81c4c75faa71b06))
|
|
42
|
+
* ensure content ID is valid before getting image sources ([a564118](https://github.com/Financial-Times/cp-content-pipeline/commit/a564118ff1eb0a580f719fd520789cadc340eede))
|
|
43
|
+
* handle vanity errors gracefully ([904c997](https://github.com/Financial-Times/cp-content-pipeline/commit/904c997dbdcf14564f624d66e7c10c09f0085c45))
|
|
44
|
+
* memoise vanity URL requests within same execution ([c9a26a7](https://github.com/Financial-Times/cp-content-pipeline/commit/c9a26a7d0ff48e5659da1397169a08ccb0cfb9dc))
|
|
45
|
+
* move schema into separate package ([0fe9f3e](https://github.com/Financial-Times/cp-content-pipeline/commit/0fe9f3e5afd2d31ce7fafd5dfb796c08eaf91c72))
|
|
46
|
+
* override cache TTLs for content API requests ([3a57d9a](https://github.com/Financial-Times/cp-content-pipeline/commit/3a57d9ae580b7899ffcce52d9801c5099d5f8497))
|
|
47
|
+
* provide all possible resolutions for image sources ([4d9d586](https://github.com/Financial-Times/cp-content-pipeline/commit/4d9d586ec4578bbd9d8d12e5333ad1f5f9f4e1ff))
|
|
48
|
+
* remove PictureResponsiveMobile, and rename PictureSingle ([b25b289](https://github.com/Financial-Times/cp-content-pipeline/commit/b25b289368c424c267ab65c9494a65cb437cf99b))
|
|
49
|
+
* render Layout components ([a134e30](https://github.com/Financial-Times/cp-content-pipeline/commit/a134e301f6eaddd6eb665489b76dfd36097a8903))
|
|
50
|
+
* separate types for SplitTextTopper and FullBleedTopper ([702503f](https://github.com/Financial-Times/cp-content-pipeline/commit/702503fcdb9b425108b4054dd1d0f0ded537ca17))
|
|
51
|
+
* support ftcms links for image services ([d19ac84](https://github.com/Financial-Times/cp-content-pipeline/commit/d19ac84e9aaf24b274129fef2b50366b0cf7fc35))
|
|
52
|
+
* use correct image data for different topper themes ([319abde](https://github.com/Financial-Times/cp-content-pipeline/commit/319abde3c62b57f97ea0ed109147517a47ac8848))
|
|
53
|
+
* use ImageSource type for image sources ([db767df](https://github.com/Financial-Times/cp-content-pipeline/commit/db767dfd6cd505b33981373d849d70ae0a343dae))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
### Bug Fixes
|
|
57
|
+
|
|
58
|
+
* correct author url for byline links ([cad3660](https://github.com/Financial-Times/cp-content-pipeline/commit/cad3660938ce5c9afbdcf1d7e135bb9d65b33bc7))
|
|
59
|
+
* correct entry point for schema package ([d19eddd](https://github.com/Financial-Times/cp-content-pipeline/commit/d19eddd8fe59b85521ec99c4821e0fe68b6f957a))
|
|
60
|
+
* correct import paths from tags ([46ad28c](https://github.com/Financial-Times/cp-content-pipeline/commit/46ad28c9362150437d99b47e8173c5427ab3eaa6))
|
|
61
|
+
* extract id correctly from image url ([041f310](https://github.com/Financial-Times/cp-content-pipeline/commit/041f3102e748bcdcbc77f39db7fa57ca7d9afa50))
|
|
62
|
+
* handle errors from image service metadata ([5f89ad4](https://github.com/Financial-Times/cp-content-pipeline/commit/5f89ad4116791577a77d8c9a62000f7699c60c23))
|
|
63
|
+
* handle old methode audio articles ([26b042b](https://github.com/Financial-Times/cp-content-pipeline/commit/26b042bd6441d2cd38c37ceccf709b613fe93a53))
|
|
64
|
+
* move schema compilation back to server and cast to fix types ([816eae7](https://github.com/Financial-Times/cp-content-pipeline/commit/816eae7e24718413737cbda092a95155d0926ef6))
|
|
65
|
+
* retrieve uuid from annotation id for stream page url ([96adabc](https://github.com/Financial-Times/cp-content-pipeline/commit/96adabcccebca6d0c4c4da3bc0d06adf6b5907d0))
|
|
66
|
+
* set imageService params rather than append ([da1f87e](https://github.com/Financial-Times/cp-content-pipeline/commit/da1f87e4abdc24bf0937772aed289e92881a2074))
|
|
67
|
+
* set schema package type to module ([a3460db](https://github.com/Financial-Times/cp-content-pipeline/commit/a3460dbfb34b4a97e9683701666c635b5eb5fc46))
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
### Code Refactoring
|
|
71
|
+
|
|
72
|
+
* rename "inline" image to "standard" ([ca530b9](https://github.com/Financial-Times/cp-content-pipeline/commit/ca530b99f745e2a4f6a07249529601f0acdddd52))
|
package/jest.config.js
ADDED
package/lib/concept.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { IResolvers } from '@graphql-tools/utils';
|
|
2
|
+
import { DataSources } from './index.js';
|
|
3
|
+
export declare const typeDef: import("graphql").DocumentNode;
|
|
4
|
+
export declare const resolvers: IResolvers<unknown, {
|
|
5
|
+
systemCode: string;
|
|
6
|
+
dataSources: DataSources;
|
|
7
|
+
}, never>;
|
package/lib/concept.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { gql } from 'graphql-tag';
|
|
2
|
+
const CAPI_ID_PREFIX = /^https?:\/\/(?:www|api)\.ft\.com\/things?\//;
|
|
3
|
+
const BASE_URL = 'https://www.ft.com/stream/';
|
|
4
|
+
const FT_URL = 'https://www.ft.com';
|
|
5
|
+
export const typeDef = gql `
|
|
6
|
+
type Concept {
|
|
7
|
+
apiUrl: String!
|
|
8
|
+
directType: String
|
|
9
|
+
id: String!
|
|
10
|
+
predicate: String!
|
|
11
|
+
prefLabel: String!
|
|
12
|
+
type: String!
|
|
13
|
+
types: [String!]!
|
|
14
|
+
url(vanity: Boolean, relative: Boolean): String!
|
|
15
|
+
}
|
|
16
|
+
`;
|
|
17
|
+
export const resolvers = {
|
|
18
|
+
Concept: {
|
|
19
|
+
async url(parent, args = { vanity: false, relative: false }, context) {
|
|
20
|
+
let url = parent.id.replace(CAPI_ID_PREFIX, BASE_URL);
|
|
21
|
+
if (args.vanity) {
|
|
22
|
+
try {
|
|
23
|
+
const vanity = await context.dataSources.vanityUrls.get(url);
|
|
24
|
+
if (vanity !== null) {
|
|
25
|
+
url = vanity;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
//TODO:AG:26-09-2022 log error here, but fail gracefully to use non-vanity
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (args.relative) {
|
|
33
|
+
url = url.replace(FT_URL, '');
|
|
34
|
+
}
|
|
35
|
+
return url;
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=concept.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"concept.js","sourceRoot":"","sources":["../src/concept.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAGjC,MAAM,cAAc,GAAG,6CAA6C,CAAA;AACpE,MAAM,QAAQ,GAAG,4BAA4B,CAAA;AAC7C,MAAM,MAAM,GAAG,oBAAoB,CAAA;AAOnC,MAAM,CAAC,MAAM,OAAO,GAAG,GAAG,CAAA;;;;;;;;;;;CAWzB,CAAA;AAED,MAAM,CAAC,MAAM,SAAS,GAIlB;IACF,OAAO,EAAE;QACP,KAAK,CAAC,GAAG,CACP,MAAsB,EACtB,OAAqB,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EACvD,OAAO;YAEP,IAAI,GAAG,GAAG,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAA;YAErD,IAAI,IAAI,CAAC,MAAM,EAAE;gBACf,IAAI;oBACF,MAAM,MAAM,GACV,MAAM,OAAO,CAAC,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;oBAC/C,IAAI,MAAM,KAAK,IAAI,EAAE;wBACnB,GAAG,GAAG,MAAM,CAAA;qBACb;iBACF;gBAAC,OAAO,GAAG,EAAE;oBACZ,0EAA0E;iBAC3E;aACF;YAED,IAAI,IAAI,CAAC,QAAQ,EAAE;gBACjB,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;aAC9B;YACD,OAAO,GAAG,CAAA;QACZ,CAAC;KACF;CACF,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contentTypes.js","sourceRoot":"","sources":["../../src/constants/contentTypes.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,4CAA4C,CAAA;AAEnE,MAAM,CAAC,MAAM,eAAe,GAC1B,oDAAoD,CAAA"}
|
package/lib/content.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { InternalContent } from './types/internal-content.js';
|
|
2
|
+
export declare const typeDef: import("graphql").DocumentNode[];
|
|
3
|
+
export declare const resolvers: {
|
|
4
|
+
Content: {
|
|
5
|
+
body(parent: InternalContent): {
|
|
6
|
+
source: string;
|
|
7
|
+
value: string;
|
|
8
|
+
contentApiData: InternalContent;
|
|
9
|
+
};
|
|
10
|
+
topper(parent: InternalContent): InternalContent;
|
|
11
|
+
byline(parent: InternalContent): {
|
|
12
|
+
tree: {
|
|
13
|
+
type: string;
|
|
14
|
+
children: ({
|
|
15
|
+
type: string;
|
|
16
|
+
tagName: string;
|
|
17
|
+
properties: {
|
|
18
|
+
href: string;
|
|
19
|
+
};
|
|
20
|
+
children: {
|
|
21
|
+
type: string;
|
|
22
|
+
value: string;
|
|
23
|
+
}[];
|
|
24
|
+
value?: undefined;
|
|
25
|
+
} | {
|
|
26
|
+
type: string;
|
|
27
|
+
value: string;
|
|
28
|
+
tagName?: undefined;
|
|
29
|
+
properties?: undefined;
|
|
30
|
+
children?: undefined;
|
|
31
|
+
})[];
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
metaLink(parent: InternalContent): any;
|
|
35
|
+
metaAltLink(parent: InternalContent): any;
|
|
36
|
+
metaPrefixText(parent: InternalContent): any;
|
|
37
|
+
metaSuffixText(parent: InternalContent): any;
|
|
38
|
+
url(parent: InternalContent, args: {
|
|
39
|
+
relative: boolean;
|
|
40
|
+
}): string;
|
|
41
|
+
type(parent: InternalContent): string;
|
|
42
|
+
mainImage(parent: InternalContent): import("./types/internal-content.js").Image | undefined;
|
|
43
|
+
altTitle(parent: InternalContent): string | undefined;
|
|
44
|
+
altStandfirst(parent: InternalContent): string | undefined;
|
|
45
|
+
indicators(parent: InternalContent): {
|
|
46
|
+
accessLevel: import("./types/internal-content.js").AccessLevel;
|
|
47
|
+
isOpinion: boolean;
|
|
48
|
+
isColumn: boolean;
|
|
49
|
+
isPodcast: boolean;
|
|
50
|
+
isEditorsChoice: boolean;
|
|
51
|
+
isExclusive: boolean;
|
|
52
|
+
isScoop: boolean;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
};
|
package/lib/content.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { gql } from 'graphql-tag';
|
|
2
|
+
import metadata from '@financial-times/n-display-metadata';
|
|
3
|
+
import { getAuthorUrlMapping, isColumn, isEditorsChoice, isExclusive, isOpinion, isPodcast, isScoop, } from './helpers/metadata.js';
|
|
4
|
+
import { buildUrlTree } from './helpers/syntaxTree.js';
|
|
5
|
+
import { splitBylineByName } from './helpers/byline.js';
|
|
6
|
+
export const typeDef = [
|
|
7
|
+
gql `
|
|
8
|
+
type Content {
|
|
9
|
+
title: String!
|
|
10
|
+
id: String!
|
|
11
|
+
type: String!
|
|
12
|
+
standfirst: String
|
|
13
|
+
topper: Topper
|
|
14
|
+
body: RichText!
|
|
15
|
+
bodyXML: String!
|
|
16
|
+
url(relative: Boolean): String!
|
|
17
|
+
publishedDate: String!
|
|
18
|
+
firstPublishedDate: String!
|
|
19
|
+
metaLink: Concept
|
|
20
|
+
metaAltLink: Concept
|
|
21
|
+
metaPrefixText: String
|
|
22
|
+
metaSuffixText: String
|
|
23
|
+
mainImage: Image
|
|
24
|
+
indicators: Indicators!
|
|
25
|
+
altTitle: AltTitle
|
|
26
|
+
altStandfirst: AltStandfirst
|
|
27
|
+
byline: StructuredContent!
|
|
28
|
+
}
|
|
29
|
+
type Indicators {
|
|
30
|
+
accessLevel: AccessLevel
|
|
31
|
+
isOpinion: Boolean
|
|
32
|
+
isColumn: Boolean
|
|
33
|
+
isPodcast: Boolean
|
|
34
|
+
isEditorsChoice: Boolean
|
|
35
|
+
isExclusive: Boolean
|
|
36
|
+
isScoop: Boolean
|
|
37
|
+
}
|
|
38
|
+
enum AccessLevel {
|
|
39
|
+
premium
|
|
40
|
+
subscribed
|
|
41
|
+
registered
|
|
42
|
+
free
|
|
43
|
+
}
|
|
44
|
+
type AltTitle {
|
|
45
|
+
promotionalTitle: String
|
|
46
|
+
}
|
|
47
|
+
type AltStandfirst {
|
|
48
|
+
promotionalStandfirst: String
|
|
49
|
+
}
|
|
50
|
+
`,
|
|
51
|
+
];
|
|
52
|
+
function getTeaserMetadata(annotations, field) {
|
|
53
|
+
const meta = metadata.teaser({
|
|
54
|
+
annotations,
|
|
55
|
+
});
|
|
56
|
+
return meta[field];
|
|
57
|
+
}
|
|
58
|
+
export const resolvers = {
|
|
59
|
+
Content: {
|
|
60
|
+
body(parent) {
|
|
61
|
+
return {
|
|
62
|
+
source: 'bodyXML',
|
|
63
|
+
value: parent.bodyXML,
|
|
64
|
+
contentApiData: parent,
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
topper(parent) {
|
|
68
|
+
return parent;
|
|
69
|
+
},
|
|
70
|
+
byline(parent) {
|
|
71
|
+
const { annotations } = parent;
|
|
72
|
+
const authorUrlMapping = getAuthorUrlMapping(annotations);
|
|
73
|
+
const split = splitBylineByName(parent.byline, [
|
|
74
|
+
...authorUrlMapping.keys(),
|
|
75
|
+
]);
|
|
76
|
+
return buildUrlTree(authorUrlMapping, split);
|
|
77
|
+
},
|
|
78
|
+
metaLink(parent) {
|
|
79
|
+
return getTeaserMetadata(parent.annotations, 'link');
|
|
80
|
+
},
|
|
81
|
+
metaAltLink(parent) {
|
|
82
|
+
return getTeaserMetadata(parent.annotations, 'altLink');
|
|
83
|
+
},
|
|
84
|
+
metaPrefixText(parent) {
|
|
85
|
+
return getTeaserMetadata(parent.annotations, 'prefixText');
|
|
86
|
+
},
|
|
87
|
+
metaSuffixText(parent) {
|
|
88
|
+
return getTeaserMetadata(parent.annotations, 'suffixText');
|
|
89
|
+
},
|
|
90
|
+
url(parent, args) {
|
|
91
|
+
const RELATIVE_URL_REGEX = /https?:\/\/www.ft.com/;
|
|
92
|
+
if (args.relative) {
|
|
93
|
+
return parent.webUrl.replace(RELATIVE_URL_REGEX, '');
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
return parent.webUrl;
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
type(parent) {
|
|
100
|
+
const TYPE_REGEX = /https?:\/\/www.ft.com\/ontology\/content\//;
|
|
101
|
+
return parent.types[0].replace(TYPE_REGEX, '').toLowerCase();
|
|
102
|
+
},
|
|
103
|
+
mainImage(parent) {
|
|
104
|
+
var _a, _b;
|
|
105
|
+
if (((_a = parent.mainImage) === null || _a === void 0 ? void 0 : _a.type) === 'http://www.ft.com/ontology/content/Image') {
|
|
106
|
+
return parent.mainImage;
|
|
107
|
+
}
|
|
108
|
+
else if (((_b = parent.mainImage) === null || _b === void 0 ? void 0 : _b.type) === 'http://www.ft.com/ontology/content/ImageSet') {
|
|
109
|
+
return parent.mainImage.members[0];
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
altTitle(parent) {
|
|
113
|
+
var _a;
|
|
114
|
+
return (_a = parent.alternativeTitles) === null || _a === void 0 ? void 0 : _a.promotionalTitle;
|
|
115
|
+
},
|
|
116
|
+
altStandfirst(parent) {
|
|
117
|
+
var _a;
|
|
118
|
+
return (_a = parent.alternativeStandfirsts) === null || _a === void 0 ? void 0 : _a.promotionalStandfirst;
|
|
119
|
+
},
|
|
120
|
+
indicators(parent) {
|
|
121
|
+
return {
|
|
122
|
+
accessLevel: parent.accessLevel,
|
|
123
|
+
isOpinion: isOpinion(parent),
|
|
124
|
+
isColumn: isColumn(parent),
|
|
125
|
+
isPodcast: isPodcast(parent),
|
|
126
|
+
isEditorsChoice: isEditorsChoice(parent),
|
|
127
|
+
isExclusive: isExclusive(parent),
|
|
128
|
+
isScoop: isScoop(parent),
|
|
129
|
+
};
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
//# sourceMappingURL=content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.js","sourceRoot":"","sources":["../src/content.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
import { typeDefs, resolvers } from './index.js';
|
|
3
|
+
import { ApolloServer } from 'apollo-server';
|
|
4
|
+
import { CapiDataSource } from './datasources/capi.js';
|
|
5
|
+
const capiDataSource = new CapiDataSource();
|
|
6
|
+
jest.spyOn(capiDataSource, 'getContent').mockImplementation((uuid) => {
|
|
7
|
+
return Promise.resolve({
|
|
8
|
+
id: uuid,
|
|
9
|
+
byline: 'Chris Giles in London',
|
|
10
|
+
annotations: [
|
|
11
|
+
{
|
|
12
|
+
id: 'http://api.ft.com/things/1d556016-ad16-4fe7-8724-42b3fb15ad28',
|
|
13
|
+
predicate: 'http://www.ft.com/ontology/annotation/hasAuthor',
|
|
14
|
+
prefLabel: 'Chris Giles',
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
describe('byline transformation', () => {
|
|
20
|
+
let capiDataSource;
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
capiDataSource = new CapiDataSource();
|
|
23
|
+
});
|
|
24
|
+
const query = `
|
|
25
|
+
query TestQuery($uuid: String!) {
|
|
26
|
+
content(uuid: $uuid) {
|
|
27
|
+
byline {
|
|
28
|
+
tree
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
const testServer = new ApolloServer({
|
|
34
|
+
typeDefs,
|
|
35
|
+
resolvers,
|
|
36
|
+
dataSources: () => {
|
|
37
|
+
return {
|
|
38
|
+
capi: capiDataSource,
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
test('adds a link around a single known author', async () => {
|
|
43
|
+
var _a;
|
|
44
|
+
jest
|
|
45
|
+
.spyOn(capiDataSource, 'getContent')
|
|
46
|
+
.mockImplementation((uuid) => {
|
|
47
|
+
return Promise.resolve({
|
|
48
|
+
id: uuid,
|
|
49
|
+
byline: 'Chris Giles in London',
|
|
50
|
+
annotations: [
|
|
51
|
+
{
|
|
52
|
+
id: 'http://api.ft.com/things/1d556016-ad16-4fe7-8724-42b3fb15ad28',
|
|
53
|
+
predicate: 'http://www.ft.com/ontology/annotation/hasAuthor',
|
|
54
|
+
prefLabel: 'Chris Giles',
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
const result = await testServer.executeOperation({
|
|
60
|
+
query,
|
|
61
|
+
variables: { uuid: '33d1ac64-88ce-4313-8763-da55200ccf43' },
|
|
62
|
+
});
|
|
63
|
+
const got = (_a = result === null || result === void 0 ? void 0 : result.data) === null || _a === void 0 ? void 0 : _a.content.byline.tree;
|
|
64
|
+
expect(got).toMatchSnapshot();
|
|
65
|
+
});
|
|
66
|
+
test('adds links around multiple known authors', async () => {
|
|
67
|
+
var _a;
|
|
68
|
+
jest
|
|
69
|
+
.spyOn(capiDataSource, 'getContent')
|
|
70
|
+
.mockImplementation((uuid) => {
|
|
71
|
+
return Promise.resolve({
|
|
72
|
+
id: uuid,
|
|
73
|
+
byline: 'Chris Giles and Martin Wolf in London',
|
|
74
|
+
annotations: [
|
|
75
|
+
{
|
|
76
|
+
id: 'http://api.ft.com/things/1d556016-ad16-4fe7-8724-42b3fb15ad28',
|
|
77
|
+
predicate: 'http://www.ft.com/ontology/annotation/hasAuthor',
|
|
78
|
+
prefLabel: 'Chris Giles',
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: 'http://api.ft.com/things/7c1e1e72-57ae-4461-862a-f8d24dd42e22',
|
|
82
|
+
predicate: 'http://www.ft.com/ontology/annotation/hasAuthor',
|
|
83
|
+
prefLabel: 'Martin Wolf',
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
const result = await testServer.executeOperation({
|
|
89
|
+
query,
|
|
90
|
+
variables: { uuid: '33d1ac64-88ce-4313-8763-da55200ccf43' },
|
|
91
|
+
});
|
|
92
|
+
const got = (_a = result === null || result === void 0 ? void 0 : result.data) === null || _a === void 0 ? void 0 : _a.content.byline.tree;
|
|
93
|
+
expect(got).toMatchSnapshot();
|
|
94
|
+
});
|
|
95
|
+
test('ignores unknown authors in byline text', async () => {
|
|
96
|
+
var _a;
|
|
97
|
+
jest
|
|
98
|
+
.spyOn(capiDataSource, 'getContent')
|
|
99
|
+
.mockImplementation((uuid) => {
|
|
100
|
+
return Promise.resolve({
|
|
101
|
+
id: uuid,
|
|
102
|
+
byline: 'Chris Giles and Nick Ramsbottom in London',
|
|
103
|
+
annotations: [
|
|
104
|
+
{
|
|
105
|
+
id: 'http://api.ft.com/things/1d556016-ad16-4fe7-8724-42b3fb15ad28',
|
|
106
|
+
predicate: 'http://www.ft.com/ontology/annotation/hasAuthor',
|
|
107
|
+
prefLabel: 'Chris Giles',
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
const result = await testServer.executeOperation({
|
|
113
|
+
query,
|
|
114
|
+
variables: { uuid: '33d1ac64-88ce-4313-8763-da55200ccf43' },
|
|
115
|
+
});
|
|
116
|
+
const got = (_a = result === null || result === void 0 ? void 0 : result.data) === null || _a === void 0 ? void 0 : _a.content.byline.tree;
|
|
117
|
+
expect(got).toMatchSnapshot();
|
|
118
|
+
});
|
|
119
|
+
test('ignores extra authors in annotations array', async () => {
|
|
120
|
+
var _a;
|
|
121
|
+
jest
|
|
122
|
+
.spyOn(capiDataSource, 'getContent')
|
|
123
|
+
.mockImplementation((uuid) => {
|
|
124
|
+
return Promise.resolve({
|
|
125
|
+
id: uuid,
|
|
126
|
+
byline: 'Martin Wolf in London',
|
|
127
|
+
annotations: [
|
|
128
|
+
{
|
|
129
|
+
id: 'http://api.ft.com/things/1d556016-ad16-4fe7-8724-42b3fb15ad28',
|
|
130
|
+
predicate: 'http://www.ft.com/ontology/annotation/hasAuthor',
|
|
131
|
+
prefLabel: 'Chris Giles',
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
id: 'http://api.ft.com/things/7c1e1e72-57ae-4461-862a-f8d24dd42e22',
|
|
135
|
+
predicate: 'http://www.ft.com/ontology/annotation/hasAuthor',
|
|
136
|
+
prefLabel: 'Martin Wolf',
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
const result = await testServer.executeOperation({
|
|
142
|
+
query,
|
|
143
|
+
variables: { uuid: '33d1ac64-88ce-4313-8763-da55200ccf43' },
|
|
144
|
+
});
|
|
145
|
+
const got = (_a = result === null || result === void 0 ? void 0 : result.data) === null || _a === void 0 ? void 0 : _a.content.byline.tree;
|
|
146
|
+
expect(got).toMatchSnapshot();
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
//# sourceMappingURL=content.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.test.js","sourceRoot":"","sources":["../src/content.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { RESTDataSource, RequestOptions } from 'apollo-datasource-rest';
|
|
2
|
+
export declare class CapiDataSource extends RESTDataSource {
|
|
3
|
+
baseURL: string;
|
|
4
|
+
capiKey: string;
|
|
5
|
+
articleCacheTTL: number;
|
|
6
|
+
peopleCacheTTL: number;
|
|
7
|
+
willSendRequest(request: RequestOptions): void;
|
|
8
|
+
getContent(uuid: string): Promise<any>;
|
|
9
|
+
getPerson(uuid: string): Promise<any>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { RESTDataSource } from 'apollo-datasource-rest';
|
|
2
|
+
export class CapiDataSource extends RESTDataSource {
|
|
3
|
+
constructor() {
|
|
4
|
+
super(...arguments);
|
|
5
|
+
this.baseURL = process.env.CAPI_URL || 'https://api-t.ft.com/';
|
|
6
|
+
this.capiKey = process.env.CAPI_API_KEY || '';
|
|
7
|
+
this.articleCacheTTL = process.env.ARTICLE_CACHE_TTL
|
|
8
|
+
? parseInt(process.env.ARTICLE_CACHE_TTL)
|
|
9
|
+
: 60; // 60 seconds
|
|
10
|
+
this.peopleCacheTTL = process.env.PEOPLE_CACHE_TTL
|
|
11
|
+
? parseInt(process.env.PEOPLE_CACHE_TTL)
|
|
12
|
+
: 600; // 10 minutes
|
|
13
|
+
}
|
|
14
|
+
willSendRequest(request) {
|
|
15
|
+
request.headers.set('x-api-key', this.capiKey);
|
|
16
|
+
}
|
|
17
|
+
async getContent(uuid) {
|
|
18
|
+
return this.get(`internalcontent/${uuid}`, undefined, {
|
|
19
|
+
cacheOptions: { ttl: this.articleCacheTTL },
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
async getPerson(uuid) {
|
|
23
|
+
return this.get(`people/${uuid}`, undefined, {
|
|
24
|
+
cacheOptions: { ttl: this.peopleCacheTTL },
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=capi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capi.js","sourceRoot":"","sources":["../../src/datasources/capi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAkB,MAAM,wBAAwB,CAAA;AAEvE,MAAM,OAAO,cAAe,SAAQ,cAAc;IAAlD;;QACE,YAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,uBAAuB,CAAA;QACzD,YAAO,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAA;QACxC,oBAAe,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB;YAC7C,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;YACzC,CAAC,CAAC,EAAE,CAAA,CAAC,aAAa;QACpB,mBAAc,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB;YAC3C,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;YACxC,CAAC,CAAC,GAAG,CAAA,CAAC,aAAa;IAiBvB,CAAC;IAfC,eAAe,CAAC,OAAuB;QACrC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;IAChD,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,IAAY;QAC3B,OAAO,IAAI,CAAC,GAAG,CAAC,mBAAmB,IAAI,EAAE,EAAE,SAAS,EAAE;YACpD,YAAY,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE;SAC5C,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,IAAY;QAC1B,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,EAAE,EAAE,SAAS,EAAE;YAC3C,YAAY,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE;SAC3C,CAAC,CAAA;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CapiDataSource } from './capi.js';
|
|
2
|
+
import { OrigamiImageDataSource } from './origami-image.js';
|
|
3
|
+
import { URLManagementDataSource } from './url-management.js';
|
|
4
|
+
export declare const dataSources: () => {
|
|
5
|
+
capi: CapiDataSource;
|
|
6
|
+
origami: OrigamiImageDataSource;
|
|
7
|
+
vanityUrls: URLManagementDataSource;
|
|
8
|
+
};
|
|
9
|
+
export declare type DataSources = ReturnType<typeof dataSources>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CapiDataSource } from './capi.js';
|
|
2
|
+
import { OrigamiImageDataSource } from './origami-image.js';
|
|
3
|
+
import { URLManagementDataSource } from './url-management.js';
|
|
4
|
+
export const dataSources = () => ({
|
|
5
|
+
capi: new CapiDataSource(),
|
|
6
|
+
origami: new OrigamiImageDataSource(),
|
|
7
|
+
vanityUrls: new URLManagementDataSource(),
|
|
8
|
+
});
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/datasources/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAE7D,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC,CAAC;IAChC,IAAI,EAAE,IAAI,cAAc,EAAE;IAC1B,OAAO,EAAE,IAAI,sBAAsB,EAAE;IACrC,UAAU,EAAE,IAAI,uBAAuB,EAAE;CAC1C,CAAC,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { RESTDataSource } from 'apollo-datasource-rest';
|
|
2
|
+
export class OrigamiImageDataSource extends RESTDataSource {
|
|
3
|
+
constructor() {
|
|
4
|
+
super(...arguments);
|
|
5
|
+
this.baseURL = 'https://www.ft.com/__origami/service/image/v2';
|
|
6
|
+
}
|
|
7
|
+
async getImageMetadata(url) {
|
|
8
|
+
return this.get(`/images/metadata/${encodeURIComponent(url)}?source=next`);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=origami-image.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"origami-image.js","sourceRoot":"","sources":["../../src/datasources/origami-image.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAEvD,MAAM,OAAO,sBAAuB,SAAQ,cAAc;IAA1D;;QACE,YAAO,GAAG,+CAA+C,CAAA;IAM3D,CAAC;IALC,KAAK,CAAC,gBAAgB,CACpB,GAAW;QAEX,OAAO,IAAI,CAAC,GAAG,CAAC,oBAAoB,kBAAkB,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;IAC5E,CAAC;CACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { DataSource, DataSourceConfig } from 'apollo-datasource';
|
|
2
|
+
import { KeyValueCache } from 'apollo-server-caching';
|
|
3
|
+
export declare class URLManagementDataSource extends DataSource {
|
|
4
|
+
context: unknown;
|
|
5
|
+
cache: KeyValueCache;
|
|
6
|
+
memoizedResults: Map<string, Promise<string>>;
|
|
7
|
+
static clientInitialised: boolean;
|
|
8
|
+
constructor();
|
|
9
|
+
initialize({ context, cache, }: DataSourceConfig<unknown>): void;
|
|
10
|
+
get(fromURL: string, ttl?: number): Promise<string>;
|
|
11
|
+
}
|