PageSourceSearch

https://www.recordedfuture.com/scripts/schema.js

js recordedfuture.com collected 2026-09-24 07:17:14 UTC 9,640 bytes, 286 lines download raw bytes

1import { getMetadata } from './aem.js';
2
3const SITE_URL = 'https://www.recordedfuture.com';
4const ORG_ID = `${SITE_URL}#organization`;
5const WEBSITE_ID = `${SITE_URL}#website`;
6const ORG_NAME = 'Recorded Future';
7const LOGO_URL = 'https://www.recordedfuture.com/media_1f4421a86fb70701080e681db00fb61c46faf2612.png';
8const SAME_AS = [
9  'https://www.linkedin.com/company/recorded-future',
10  'https://x.com/RecordedFuture',
11  'https://www.youtube.com/@RecordedFuture',
12];
13
14export function toISODate(input) {
15  if (!input) return '';
16  let date;
17  if (/^\d+$/.test(input)) {
18    const ts = Number(input);
19    date = new Date(ts < 1e12 ? ts * 1000 : ts);
20  } else {
21    date = new Date(input);
22  }
23  if (Number.isNaN(date.getTime())) return '';
24  return date.toISOString().split('T')[0];
25}
26
27export function injectSchema(obj) {
28  if (!obj) return;
29  const script = document.createElement('script');
30  script.type = 'application/ld+json';
31  script.textContent = JSON.stringify(obj);
32  document.head.appendChild(script);
33}
34
35export function buildOrganizationSchema() {
36  return {
37    '@context': 'https://schema.org',
38    '@type': 'Organization',
39    '@id': ORG_ID,
40    name: ORG_NAME,
41    url: SITE_URL,
42    logo: {
43      '@type': 'ImageObject',
44      '@id': `${SITE_URL}#logo`,
45      url: LOGO_URL,
46    },
47    sameAs: SAME_AS,
48  };
49}
50
51export function buildWebSiteSchema() {
52  return {
53    '@context': 'https://schema.org',
54    '@type': 'WebSite',
55    '@id': WEBSITE_ID,
56    name: ORG_NAME,
57    url: SITE_URL,
58    publisher: { '@id': ORG_ID },
59  };
60}
61
62const BLOG_TYPE = 'blog';
63
64export function buildArticleSchema() {
65  const canonical =
66    document.querySelector('link[rel="canonical"]')?.href || `${window.location.origin}${window.location.pathname}`;
67  const resourceType = getMetadata('resource-type').toLowerCase();
68  const schemaType = resourceType === BLOG_TYPE ? 'BlogPosting' : 'Article';
69  const headline = getMetadata('og:title') || document.querySelector('h1')?.textContent?.trim() || '';
70  const description = getMetadata('og:description') || '';
71  const imageUrl = getMetadata('og:image') || document.querySelector('picture img')?.src || '';
72  const authorName = getMetadata('author');
73  const datePublished = toISODate(getMetadata('published-date'));
74  const dateModified = toISODate(document.lastModified);
75  const topicTags = getMetadata('topic-tags')
76    .split(',')
77    .map((t) => t.trim())
78    .filter(Boolean);
79
80  const schema = {
81    '@context': 'https://schema.org',
82    '@type': schemaType,
83    headline,
84    description,
85    image: { '@type': 'ImageObject', url: imageUrl },
86    publisher: {
87      '@id': ORG_ID,
88      '@type': 'Organization',
89      name: ORG_NAME,
90      logo: {
91        '@type': 'ImageObject',
92        '@id': `${SITE_URL}#logo`,
93        url: LOGO_URL,
94      },
95    },
96    mainEntityOfPage: { '@id': `${canonical}#webpage` },
97  };
98
99  if (authorName) schema.author = { '@type': 'Person', name: authorName };
100  if (datePublished) schema.datePublished = datePublished;
101  if (dateModified) schema.dateModified = dateModified;
102  if (topicTags.length) schema.keywords = topicTags;
103
104  return schema;
105}
106
107export function buildResearchSchema() {
108  const canonical =
109    document.querySelector('link[rel="canonical"]')?.href || `${window.location.origin}${window.location.pathname}`;
110  const headline = getMetadata('og:title') || document.querySelector('h1')?.textContent?.trim() || '';
111  const description = getMetadata('og:description') || '';
112  const imageUrl = getMetadata('og:image') || document.querySelector('picture img')?.src || '';
113  const authorName = getMetadata('author');
114  const datePublished = toISODate(getMetadata('published-date'));
115  const dateModified = toISODate(document.lastModified);
116  const topicTags = getMetadata('topic-tags')
117    .split(',')
118    .map((t) => t.trim())
119    .filter(Boolean);
120
121  const schema = {
122    '@context': 'https://schema.org',
123    '@type': 'ScholarlyArticle',
124    headline,
125    description,
126    image: { '@type': 'ImageObject', url: imageUrl },
127    publisher: { '@id': ORG_ID },
128    mainEntityOfPage: { '@id': `${canonical}#webpage` },
129  };
130
131  if (authorName) schema.author = { '@type': 'Person', name: authorName };
132  if (datePublished) schema.datePublished = datePublished;
133  if (dateModified) schema.dateModified = dateModified;
134  if (topicTags.length) schema.keywords = topicTags;
135
136  return schema;
137}
138
139export function buildCaseStudySchema() {
140  const canonical =
141    document.querySelector('link[rel="canonical"]')?.href || `${window.location.origin}${window.location.pathname}`;
142  const headline = getMetadata('og:title') || document.querySelector('h1')?.textContent?.trim() || '';
143  const description = getMetadata('og:description') || '';
144  const imageUrl = getMetadata('og:image') || document.querySelector('picture img')?.src || '';
145  const datePublished = toISODate(getMetadata('published-date'));
146  const dateModified = toISODate(document.lastModified);
147  const topicTags = getMetadata('topic-tags')
148    .split(',')
149    .map((t) => t.trim())
150    .filter(Boolean);
151
152  const schema = {
153    '@context': 'https://schema.org',
154    '@type': 'Article',
155    headline,
156    description,
157    image: { '@type': 'ImageObject', url: imageUrl },
158    publisher: { '@id': ORG_ID },
159    mainEntityOfPage: { '@id': `${canonical}#webpage` },
160  };
161
162  if (datePublished) schema.datePublished = datePublished;
163  if (dateModified) schema.dateModified = dateModified;
164  if (topicTags.length) schema.keywords = topicTags;
165
166  return schema;
167}
168
169export function buildIntegrationsSchema() {
170  const name = getMetadata('og:title') || document.querySelector('h1')?.textContent?.trim() || '';
171  const description = getMetadata('og:description') || '';
172
173  return {
174    '@context': 'https://schema.org',
175    '@type': 'SoftwareApplication',
176    name,
177    description,
178    applicationCategory: 'SecurityApplication',
179    operatingSystem: 'All',
180    provider: { '@id': ORG_ID },
181  };
182}
183
184export function buildServiceSchema() {
185  if (getMetadata('schema').toLowerCase() !== 'service') return null;
186  const canonical =
187    document.querySelector('link[rel="canonical"]')?.href || `${window.location.origin}${window.location.pathname}`;
188  const name = getMetadata('og:title') || document.querySelector('h1')?.textContent?.trim() || '';
189  const description = getMetadata('og:description') || '';
190
191  return {
192    '@context': 'https://schema.org',
193    '@type': 'Service',
194    name,
195    description,
196    url: canonical,
197    provider: { '@id': ORG_ID },
198  };
199}
200
201export function buildServiceBreadcrumbSchema() {
202  if (getMetadata('schema').toLowerCase() !== 'service') return null;
203  return buildBreadcrumbSchema('Services', '/services');
204}
205
206export function buildProductSchema() {
207  if (getMetadata('schema').toLowerCase() !== 'product') return null;
208  const canonical =
209    document.querySelector('link[rel="canonical"]')?.href || `${window.location.origin}${window.location.pathname}`;
210  const name = getMetadata('og:title') || document.querySelector('h1')?.textContent?.trim() || '';
211  const description = getMetadata('og:description') || '';
212  const imageUrl = getMetadata('og:image') || document.querySelector('picture img')?.src || LOGO_URL;
213
214  return {
215    '@context': 'https://schema.org',
216    '@type': 'Product',
217    name,
218    description,
219    image: { '@type': 'ImageObject', url: imageUrl },
220    url: canonical,
221    provider: { '@id': ORG_ID },
222  };
223}
224
225export function buildCveSchema() {
226  const canonical =
227    document.querySelector('link[rel="canonical"]')?.href || `${window.location.origin}${window.location.pathname}`;
228  const headline = getMetadata('og:title') || document.querySelector('h1')?.textContent?.trim() || '';
229  const description = getMetadata('og:description') || '';
230
231  return {
232    '@context': 'https://schema.org',
233    '@type': 'TechArticle',
234    headline,
235    description,
236    publisher: { '@id': ORG_ID },
237    mainEntityOfPage: { '@id': `${canonical}#webpage` },
238  };
239}
240
241export function buildWebPageSchema() {
242  const canonical = document.querySelector('link[rel="canonical"]')?.href || window.location.href;
243  const name = getMetadata('og:title') || document.querySelector('h1')?.textContent?.trim() || '';
244  const description = getMetadata('og:description') || getMetadata('description') || '';
245  const dateModified = toISODate(document.lastModified);
246  const topicTags = getMetadata('topic-tags')
247    .split(',')
248    .map((t) => t.trim())
249    .filter(Boolean);
250
251  const schema = {
252    '@context': 'https://schema.org',
253    '@type': 'WebPage',
254    '@id': `${canonical}#webpage`,
255    name,
256    description,
257    url: canonical,
258    isPartOf: { '@id': WEBSITE_ID },
259    about: { '@id': ORG_ID },
260  };
261
262  if (dateModified) schema.dateModified = dateModified;
263  if (topicTags.length) schema.keywords = topicTags;
264  return schema;
265}
266
267export function buildBreadcrumbSchema(parentLabel = '', parentUrl = '') {
268  const canonical =
269    document.querySelector('link[rel="canonical"]')?.href || `${window.location.origin}${window.location.pathname}`;
270  const name = getMetadata('og:title') || document.querySelector('h1')?.textContent?.trim() || '';
271  const absoluteParentUrl = parentUrl.startsWith('/') ? `${SITE_URL}${parentUrl}` : parentUrl;
272
273  const items = [{ '@type': 'ListItem', position: 1, name: 'Home', item: SITE_URL }];
274
275  if (parentLabel && parentUrl) {
276    items.push({ '@type': 'ListItem', position: 2, name: parentLabel, item: absoluteParentUrl });
277  }
278
279  items.push({ '@type': 'ListItem', position: items.length + 1, name, item: canonical });
280
281  return {
282    '@context': 'https://schema.org',
283    '@type': 'BreadcrumbList',
284    itemListElement: items,
285  };
286}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.