@adkinn/astro-ai-readiness 0.0.7 → 0.0.9

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/README.md CHANGED
@@ -1,14 +1,16 @@
1
1
  # @adkinn/astro-ai-readiness
2
2
 
3
- > AI Readiness toolkit for Astro — six JSON-LD helper components plus `dist/llms.txt`, `dist/llms-full.txt`, `dist/agents.md`, `dist/robots.txt`, and `dist/.well-known/mcp.json`.
3
+ > AI Readiness toolkit for Astro — eight JSON-LD helper components plus `dist/llms.txt`, `dist/llms-full.txt`, `dist/agents.md`, `dist/robots.txt`, and `dist/.well-known/mcp.json`.
4
4
 
5
- **Status:** v0.0.7seventh slice in prep. **Component sub-line complete (6 of 6); five of five v0.1 file outputs live.** Multi-output orchestration on the `astro:build:done` hook now covers the full v0.1 artifact set.
5
+ **Status:** v0.0.9app/product support. Adds a `<SoftwareApplicationSchema />` component (screenshots, feature list, offers), Organization `description` + `contactPoint`, `founder.url`, WebSite `inLanguage`, and custom `## sections` for `agents.md` everything an app/product site needs at full fidelity.
6
6
 
7
- ## What ships in v0.0.7
7
+ ## What ships in v0.0.9
8
8
 
9
- **Six JSON-LD components** (component sub-line complete):
10
- - `<OrganizationSchema />` — Organization block. Config-driven; place in your `BaseLayout` so it ships site-wide and the `#organization` `@id` reference resolves on every page.
11
- - `<WebSiteSchema />` — WebSite block. Config-driven; alongside `<OrganizationSchema />` in `BaseLayout`.
9
+ **Eight JSON-LD components**:
10
+ - `<OrganizationSchema />` — Organization block. Config-driven from `organization` (optional; now supports `description`, `contactPoint`, and `founder.url`); place in your `BaseLayout` so it ships site-wide and the `#organization` `@id` reference resolves on every page. Renders nothing if `organization` is unset.
11
+ - `<PersonSchema />` — Person block. Config-driven from `person` (optional); for sites whose primary identity is an individual. Place in your `BaseLayout`; declares `#person`, and becomes the WebSite publisher when set. Renders nothing if `person` is unset.
12
+ - `<SoftwareApplicationSchema />` — SoftwareApplication block. Config-driven from `softwareApplication` (optional); for app/product sites. Emits `#app` with `operatingSystem`, `applicationCategory`, `screenshot[]`, `featureList[]`, `offers[]`, and links `publisher`/`author` to the site's Organization (or Person). Renders nothing if unset.
13
+ - `<WebSiteSchema />` — WebSite block. Config-driven (now supports `inLanguage`); alongside `<OrganizationSchema />` or `<PersonSchema />` in `BaseLayout`.
12
14
  - `<CollectionSchema name url description? />` — CollectionPage block. Props-driven; place on collection-index pages (`/articles/`, `/tags/[tag]/`, etc.).
13
15
  - `<BreadcrumbSchema items={[{ name, url }, ...]} />` — BreadcrumbList. Items-array prop; place on multi-level pages where the navigation hierarchy isn't already declared inline. Empty `items` skips emission.
14
16
  - `<FAQPageSchema items={[{ question, answer }, ...]} />` — FAQPage. Items-array prop; place on pages with FAQ data. Long-form answers escape `</script>` and U+2028 / U+2029 automatically. Empty `items` skips emission.
@@ -17,13 +19,13 @@
17
19
  **Five file outputs**:
18
20
  - `dist/llms.txt` — [llmstxt.org](https://llmstxt.org/) format from the `llmsTxt` config block. H1 / blockquote summary / optional body / H2 sections with bulleted links / optional canonical-reference footer. Opt-in.
19
21
  - `dist/llms-full.txt` — manual full-context markdown from the `llmsFull` config block. This is config-driven in v0.0.7; content-collection introspection is a later layer.
20
- - `dist/agents.md` — Markdown discovery file for AI-agent crawlers from the `agentsMd` config block. H1 / blockquote description / optional `## Audience`, `## Contact`, `## Links` sections. Opt-in.
22
+ - `dist/agents.md` — Markdown discovery file for AI-agent crawlers from the `agentsMd` config block. H1 / blockquote description / optional `## Audience`, arbitrary `## sections` (title + markdown content), `## Contact`, and `## Links`. Opt-in.
21
23
  - `dist/.well-known/mcp.json` — [Model Context Protocol](https://modelcontextprotocol.io/) discovery file from the `mcp` config block. Pretty-printed JSON with `$schema` reference to the toolkit-published v1 shape (per D-22). Supports `status: 'active'` (requires `url` + `tools[]`) and `status: 'planned'` (requires `planned_tools[]`; `url` forbidden by schema). Opt-in.
22
24
  - `dist/robots.txt` — robots policy composition from the `robotsTxt` config block. Presets: `search-visible`, `training-opt-out` (default), and `private`; supports explicit bot rules, `Sitemap`, and optional `Content-Signal` directives.
23
25
 
24
26
  **`@astrojs/sitemap` detection per D-8.** When you call `aiReadiness({...})` and `@astrojs/sitemap` isn't in your integrations list, the toolkit logs a build-time warning. Sitemap is an AI-Readiness baseline; when `robotsTxt` is enabled, the generated `robots.txt` includes a `Sitemap` line by default.
25
27
 
26
- All six components emit canonical Schema.org JSON-LD with cross-component `@id` references (`#organization`, `#website`) so search and AI consumers can resolve the entity graph without redeclaring shared fields.
28
+ All eight components emit canonical Schema.org JSON-LD with cross-component `@id` references (`#organization`, `#person`, `#app`, `#website`) so search and AI consumers can resolve the entity graph without redeclaring shared fields.
27
29
 
28
30
  URL config fields (`site`, `organization.url`, `organization.logo`, `founder.sameAs`, `llmsTxt.*.url`) require `https://` (or `http://localhost` for dev).
29
31
 
@@ -31,7 +33,7 @@ Config validation errors are formatted with one issue per line — `path: messag
31
33
 
32
34
  ## On the roadmap (toward v0.1.0)
33
35
 
34
- - v0.0.8 — fixture Astro app validation against AATT / adamkinney.com install paths; refine robots presets from real traffic policy.
36
+ - v0.0.8 — fixture Astro app validation against adamkinney.com install paths; refine robots presets from real traffic policy.
35
37
  - v0.0.9 — content-collection assisted `llms-full.txt` generation.
36
38
  - v0.1.0 — polish, docs, release hardening; full install on adamkinney.com
37
39
 
@@ -45,7 +47,7 @@ npm install @adkinn/astro-ai-readiness
45
47
 
46
48
  ## Quick start
47
49
 
48
- Configure (v0.0.7 accepts `site`, `organization`, optional `webSite`, optional `llmsTxt`, optional `llmsFull`, optional `agentsMd`, optional `mcp`, and optional `robotsTxt` blocks — the Zod schema rejects unknown keys, and URL fields must use `https://` or `http://localhost`):
50
+ Configure (v0.0.9 accepts `site`, optional `person`, optional `organization`, optional `softwareApplication`, optional `webSite`, optional `llmsTxt`, optional `llmsFull`, optional `agentsMd`, optional `mcp`, and optional `robotsTxt` blocks — provide at least one of `person`/`organization` as the site identity. The Zod schema rejects unknown keys, and URL fields must use `https://` or `http://localhost`):
49
51
 
50
52
  ```ts
51
53
  // astro.config.mjs
@@ -185,7 +187,22 @@ import { OrganizationSchema, WebSiteSchema } from '@adkinn/astro-ai-readiness/co
185
187
  </head>
186
188
  ```
187
189
 
188
- `<OrganizationSchema />` declares `@id: '<site>#organization'`; `<WebSiteSchema />` references it. Order matters in the head — Organization first.
190
+ `<OrganizationSchema />` declares `@id: '<site>#organization'`; `<WebSiteSchema />` references it. Order matters in the head — identity component first.
191
+
192
+ **Personal-brand sites** lead with a `Person` instead. Configure a `person` block (and omit `organization` if you don't need it), then:
193
+
194
+ ```astro
195
+ ---
196
+ // src/layouts/BaseLayout.astro — site-wide
197
+ import { PersonSchema, WebSiteSchema } from '@adkinn/astro-ai-readiness/components'
198
+ ---
199
+ <head>
200
+ <PersonSchema />
201
+ <WebSiteSchema />
202
+ </head>
203
+ ```
204
+
205
+ `<PersonSchema />` declares `@id: '<site>#person'`; when `person` is set, `<WebSiteSchema />` publisher and the `llms.txt` heading follow it.
189
206
 
190
207
  ```astro
191
208
  ---
@@ -273,8 +290,7 @@ The v0.1 line is content → artifacts: components and files. Build-time AI-read
273
290
 
274
291
  ## Shipped on
275
292
 
276
- - [aiallthethings.com](https://aiallthethings.com) — AATT, the toolkit's first reference implementation. Runs all six components on production plus three toolkit-emitted files: `dist/llms.txt` at <https://aiallthethings.com/llms.txt>, `dist/agents.md` at <https://aiallthethings.com/agents.md>, and `dist/.well-known/mcp.json` at <https://aiallthethings.com/.well-known/mcp.json>. Components: Organization + WebSite (site-wide via BaseLayout), CollectionPage (articles + framework + tag indexes), BreadcrumbList (`/about`), FAQPage (articles with FAQ frontmatter), TechArticle (every article-detail page).
277
- - [adamkinney.com](https://adamkinney.com) — Adam Kinney's site. Next SSR reference-implementation target once v0.1.0 publishes.
293
+ - [adamkinney.com](https://adamkinney.com) — the reference implementation. Runs `OrganizationSchema` + `WebSiteSchema` site-wide and emits `dist/llms.txt` at <https://adamkinney.com/llms.txt> and `dist/agents.md` at <https://adamkinney.com/agents.md>.
278
294
 
279
295
  ## Contributing
280
296
 
@@ -4,9 +4,10 @@ import {
4
4
 
5
5
  // src/outputs/agents-md.ts
6
6
  function composeAgentsMd(config) {
7
- const { agentsMd, organization } = config;
7
+ const { agentsMd } = config;
8
+ const name = config.person?.name ?? config.organization?.name ?? config.webSite?.name ?? config.site;
8
9
  const lines = [];
9
- lines.push(`# ${organization.name}`);
10
+ lines.push(`# ${name}`);
10
11
  lines.push("");
11
12
  lines.push(`> ${agentsMd.description}`);
12
13
  lines.push("");
@@ -16,6 +17,14 @@ function composeAgentsMd(config) {
16
17
  lines.push(agentsMd.audience.trimEnd());
17
18
  lines.push("");
18
19
  }
20
+ if (agentsMd.sections) {
21
+ for (const section of agentsMd.sections) {
22
+ lines.push(`## ${section.title}`);
23
+ lines.push("");
24
+ lines.push(section.content.trimEnd());
25
+ lines.push("");
26
+ }
27
+ }
19
28
  if (agentsMd.contact) {
20
29
  lines.push("## Contact");
21
30
  lines.push("");
@@ -4,9 +4,10 @@ import {
4
4
 
5
5
  // src/outputs/llms-full.ts
6
6
  function composeLlmsFullTxt(config) {
7
- const { llmsFull, llmsTxt, organization } = config;
7
+ const { llmsFull, llmsTxt } = config;
8
+ const name = llmsFull.title ?? config.person?.name ?? config.organization?.name ?? config.site;
8
9
  const lines = [];
9
- lines.push(`# ${llmsFull.title ?? organization.name}`);
10
+ lines.push(`# ${name}`);
10
11
  lines.push("");
11
12
  const summary = llmsFull.summary ?? llmsTxt?.summary;
12
13
  if (summary) {
@@ -4,9 +4,10 @@ import {
4
4
 
5
5
  // src/outputs/llms-txt.ts
6
6
  function composeLlmsTxt(config) {
7
- const { llmsTxt, organization } = config;
7
+ const { llmsTxt } = config;
8
+ const name = config.person?.name ?? config.organization?.name ?? config.webSite?.name ?? config.site;
8
9
  const lines = [];
9
- lines.push(`# ${organization.name}`);
10
+ lines.push(`# ${name}`);
10
11
  lines.push("");
11
12
  lines.push(`> ${llmsTxt.summary}`);
12
13
  lines.push("");
@@ -8,21 +8,64 @@ var founderSchema = z.object({
8
8
  name: z.string().min(1),
9
9
  jobTitle: z.string().optional(),
10
10
  description: z.string().optional(),
11
+ url: httpsUrl.optional(),
11
12
  sameAs: z.array(httpsUrl).optional()
12
13
  });
14
+ var contactPointSchema = z.object({
15
+ contactType: z.string().min(1),
16
+ email: z.string().email().optional(),
17
+ telephone: z.string().min(1).optional(),
18
+ url: httpsUrl.optional()
19
+ }).strict();
13
20
  var organizationSchema = z.object({
14
21
  name: z.string().min(1),
15
22
  url: httpsUrl.optional(),
16
23
  logo: httpsUrl.optional(),
24
+ description: z.string().optional(),
17
25
  founder: founderSchema.optional(),
18
26
  foundingDate: z.string().optional(),
19
27
  knowsAbout: z.array(z.string()).optional(),
20
- areaServed: z.string().optional()
28
+ areaServed: z.string().optional(),
29
+ contactPoint: contactPointSchema.optional()
30
+ }).strict();
31
+ var personSchema = z.object({
32
+ name: z.string().min(1),
33
+ url: httpsUrl.optional(),
34
+ jobTitle: z.string().optional(),
35
+ description: z.string().optional(),
36
+ image: httpsUrl.optional(),
37
+ sameAs: z.array(httpsUrl).optional(),
38
+ knowsAbout: z.array(z.string()).optional()
21
39
  }).strict();
22
40
  var webSiteSchema = z.object({
23
41
  name: z.string().optional(),
42
+ description: z.string().optional(),
43
+ inLanguage: z.string().optional()
44
+ }).strict();
45
+ var offerSchema = z.object({
46
+ name: z.string().min(1).optional(),
47
+ price: z.string().min(1),
48
+ priceCurrency: z.string().min(1),
24
49
  description: z.string().optional()
25
50
  }).strict();
51
+ var softwareApplicationSchema = z.object({
52
+ name: z.string().min(1),
53
+ applicationCategory: z.string().optional(),
54
+ applicationSubCategory: z.string().optional(),
55
+ operatingSystem: z.string().optional(),
56
+ description: z.string().optional(),
57
+ url: httpsUrl.optional(),
58
+ image: httpsUrl.optional(),
59
+ screenshot: z.array(httpsUrl).optional(),
60
+ featureList: z.array(z.string()).optional(),
61
+ offers: z.array(offerSchema).optional(),
62
+ installUrl: httpsUrl.optional(),
63
+ downloadUrl: httpsUrl.optional(),
64
+ aggregateRating: z.object({
65
+ ratingValue: z.number(),
66
+ ratingCount: z.number().int().positive()
67
+ }).strict().optional()
68
+ }).strict();
26
69
  var llmsTxtLinkSchema = z.object({
27
70
  title: z.string().min(1),
28
71
  url: httpsUrl,
@@ -62,12 +105,17 @@ var agentsMdLinkSchema = z.object({
62
105
  url: httpsUrl,
63
106
  description: z.string().optional()
64
107
  }).strict();
108
+ var agentsMdSectionSchema = z.object({
109
+ title: z.string().min(1),
110
+ content: z.string().min(1)
111
+ }).strict();
65
112
  var agentsMdSchema = z.object({
66
113
  description: z.string().min(1).refine(
67
114
  (s) => !s.includes("\n"),
68
115
  { message: "description must be single-line \u2014 use audience/contact fields for additional prose" }
69
116
  ),
70
117
  audience: z.string().optional(),
118
+ sections: z.array(agentsMdSectionSchema).min(1).optional(),
71
119
  contact: z.string().optional(),
72
120
  links: z.array(agentsMdLinkSchema).min(1).optional()
73
121
  }).strict();
@@ -127,14 +175,19 @@ var robotsTxtSchema = z.object({
127
175
  }).strict();
128
176
  var aiReadinessConfigSchema = z.object({
129
177
  site: httpsUrl,
130
- organization: organizationSchema,
178
+ organization: organizationSchema.optional(),
179
+ person: personSchema.optional(),
180
+ softwareApplication: softwareApplicationSchema.optional(),
131
181
  webSite: webSiteSchema.optional(),
132
182
  llmsTxt: llmsTxtSchema.optional(),
133
183
  llmsFull: llmsFullSchema.optional(),
134
184
  agentsMd: agentsMdSchema.optional(),
135
185
  mcp: mcpSchema.optional(),
136
186
  robotsTxt: robotsTxtSchema.optional()
137
- }).strict();
187
+ }).strict().refine(
188
+ (value) => Boolean(value.person || value.organization),
189
+ { message: "Provide `person` and/or `organization` \u2014 the site needs at least one identity for the llms.txt heading and JSON-LD." }
190
+ );
138
191
 
139
192
  export {
140
193
  aiReadinessConfigSchema
@@ -6,28 +6,45 @@ const org = config.organization
6
6
 
7
7
  type SchemaJson = Record<string, unknown>
8
8
 
9
- const orgLd: SchemaJson = {
10
- '@context': 'https://schema.org',
11
- '@type': 'Organization',
12
- '@id': `${config.site}#organization`,
13
- name: org.name,
14
- }
9
+ let orgLd: SchemaJson | null = null
10
+
11
+ if (org) {
12
+ orgLd = {
13
+ '@context': 'https://schema.org',
14
+ '@type': 'Organization',
15
+ '@id': `${config.site}#organization`,
16
+ name: org.name,
17
+ }
15
18
 
16
- if (org.url) orgLd.url = org.url
17
- if (org.logo) orgLd.logo = org.logo
18
- if (org.foundingDate) orgLd.foundingDate = org.foundingDate
19
- if (org.knowsAbout && org.knowsAbout.length > 0) orgLd.knowsAbout = org.knowsAbout
20
- if (org.areaServed) orgLd.areaServed = org.areaServed
19
+ if (org.url) orgLd.url = org.url
20
+ if (org.logo) orgLd.logo = org.logo
21
+ if (org.description) orgLd.description = org.description
22
+ if (org.foundingDate) orgLd.foundingDate = org.foundingDate
23
+ if (org.knowsAbout && org.knowsAbout.length > 0) orgLd.knowsAbout = org.knowsAbout
24
+ if (org.areaServed) orgLd.areaServed = org.areaServed
25
+
26
+ if (org.founder) {
27
+ const founder: SchemaJson = {
28
+ '@type': 'Person',
29
+ name: org.founder.name,
30
+ }
31
+ if (org.founder.jobTitle) founder.jobTitle = org.founder.jobTitle
32
+ if (org.founder.description) founder.description = org.founder.description
33
+ if (org.founder.url) founder.url = org.founder.url
34
+ if (org.founder.sameAs && org.founder.sameAs.length > 0) founder.sameAs = org.founder.sameAs
35
+ orgLd.founder = founder
36
+ }
21
37
 
22
- if (org.founder) {
23
- const founder: SchemaJson = {
24
- '@type': 'Person',
25
- name: org.founder.name,
38
+ if (org.contactPoint) {
39
+ const cp: SchemaJson = {
40
+ '@type': 'ContactPoint',
41
+ contactType: org.contactPoint.contactType,
42
+ }
43
+ if (org.contactPoint.email) cp.email = org.contactPoint.email
44
+ if (org.contactPoint.telephone) cp.telephone = org.contactPoint.telephone
45
+ if (org.contactPoint.url) cp.url = org.contactPoint.url
46
+ orgLd.contactPoint = cp
26
47
  }
27
- if (org.founder.jobTitle) founder.jobTitle = org.founder.jobTitle
28
- if (org.founder.description) founder.description = org.founder.description
29
- if (org.founder.sameAs && org.founder.sameAs.length > 0) founder.sameAs = org.founder.sameAs
30
- orgLd.founder = founder
31
48
  }
32
49
  ---
33
- <script type="application/ld+json" is:inline set:html={jsonLd(orgLd)}></script>
50
+ {orgLd && <script type="application/ld+json" is:inline set:html={jsonLd(orgLd)}></script>}
@@ -0,0 +1,26 @@
1
+ ---
2
+ import { config } from 'virtual:ai-readiness-config'
3
+ import { jsonLd } from '../utils/json-ld'
4
+
5
+ const person = config.person
6
+
7
+ type SchemaJson = Record<string, unknown>
8
+
9
+ let personLd: SchemaJson | null = null
10
+
11
+ if (person) {
12
+ personLd = {
13
+ '@context': 'https://schema.org',
14
+ '@type': 'Person',
15
+ '@id': `${config.site}#person`,
16
+ name: person.name,
17
+ }
18
+ if (person.url) personLd.url = person.url
19
+ if (person.jobTitle) personLd.jobTitle = person.jobTitle
20
+ if (person.description) personLd.description = person.description
21
+ if (person.image) personLd.image = person.image
22
+ if (person.sameAs && person.sameAs.length > 0) personLd.sameAs = person.sameAs
23
+ if (person.knowsAbout && person.knowsAbout.length > 0) personLd.knowsAbout = person.knowsAbout
24
+ }
25
+ ---
26
+ {personLd && <script type="application/ld+json" is:inline set:html={jsonLd(personLd)}></script>}
@@ -0,0 +1,64 @@
1
+ ---
2
+ import { config } from 'virtual:ai-readiness-config'
3
+ import { jsonLd } from '../utils/json-ld'
4
+
5
+ const app = config.softwareApplication
6
+
7
+ type SchemaJson = Record<string, unknown>
8
+
9
+ // Link publisher/author to the site identity (Organization preferred, else Person).
10
+ const identityId = config.organization
11
+ ? `${config.site}#organization`
12
+ : config.person
13
+ ? `${config.site}#person`
14
+ : null
15
+
16
+ let appLd: SchemaJson | null = null
17
+
18
+ if (app) {
19
+ appLd = {
20
+ '@context': 'https://schema.org',
21
+ '@type': 'SoftwareApplication',
22
+ '@id': `${config.site}#app`,
23
+ name: app.name,
24
+ }
25
+
26
+ if (app.applicationCategory) appLd.applicationCategory = app.applicationCategory
27
+ if (app.applicationSubCategory) appLd.applicationSubCategory = app.applicationSubCategory
28
+ if (app.operatingSystem) appLd.operatingSystem = app.operatingSystem
29
+ if (app.description) appLd.description = app.description
30
+ if (app.url) appLd.url = app.url
31
+ if (app.image) appLd.image = app.image
32
+ if (app.screenshot && app.screenshot.length > 0) appLd.screenshot = app.screenshot
33
+ if (app.featureList && app.featureList.length > 0) appLd.featureList = app.featureList
34
+ if (app.installUrl) appLd.installUrl = app.installUrl
35
+ if (app.downloadUrl) appLd.downloadUrl = app.downloadUrl
36
+
37
+ if (app.offers && app.offers.length > 0) {
38
+ appLd.offers = app.offers.map((offer) => {
39
+ const o: SchemaJson = {
40
+ '@type': 'Offer',
41
+ price: offer.price,
42
+ priceCurrency: offer.priceCurrency,
43
+ }
44
+ if (offer.name) o.name = offer.name
45
+ if (offer.description) o.description = offer.description
46
+ return o
47
+ })
48
+ }
49
+
50
+ if (app.aggregateRating) {
51
+ appLd.aggregateRating = {
52
+ '@type': 'AggregateRating',
53
+ ratingValue: app.aggregateRating.ratingValue,
54
+ ratingCount: app.aggregateRating.ratingCount,
55
+ }
56
+ }
57
+
58
+ if (identityId) {
59
+ appLd.publisher = { '@id': identityId }
60
+ appLd.author = { '@id': identityId }
61
+ }
62
+ }
63
+ ---
64
+ {appLd && <script type="application/ld+json" is:inline set:html={jsonLd(appLd)}></script>}
@@ -2,15 +2,21 @@
2
2
  import { config } from 'virtual:ai-readiness-config'
3
3
  import { jsonLd } from '../utils/json-ld'
4
4
 
5
+ // A person-first site publishes as the person; otherwise the organization.
6
+ const publisherId = config.person
7
+ ? `${config.site}#person`
8
+ : `${config.site}#organization`
9
+
5
10
  const ws: Record<string, unknown> = {
6
11
  '@context': 'https://schema.org',
7
12
  '@type': 'WebSite',
8
13
  '@id': `${config.site}#website`,
9
- name: config.webSite?.name ?? config.organization.name,
14
+ name: config.webSite?.name ?? config.person?.name ?? config.organization?.name ?? config.site,
10
15
  url: config.site,
11
- publisher: { '@id': `${config.site}#organization` },
16
+ publisher: { '@id': publisherId },
12
17
  }
13
18
 
14
19
  if (config.webSite?.description) ws.description = config.webSite.description
20
+ if (config.webSite?.inLanguage) ws.inLanguage = config.webSite.inLanguage
15
21
  ---
16
22
  <script type="application/ld+json" is:inline set:html={jsonLd(ws)}></script>
@@ -1,4 +1,6 @@
1
1
  export { default as OrganizationSchema } from './OrganizationSchema.astro';
2
+ export { default as PersonSchema } from './PersonSchema.astro';
3
+ export { default as SoftwareApplicationSchema } from './SoftwareApplicationSchema.astro';
2
4
  export { default as WebSiteSchema } from './WebSiteSchema.astro';
3
5
  export { default as CollectionSchema } from './CollectionSchema.astro';
4
6
  export { default as BreadcrumbSchema } from './BreadcrumbSchema.astro';
@@ -1,15 +1,19 @@
1
1
  // src/components/index.ts
2
2
  import { default as default2 } from "./OrganizationSchema.astro";
3
- import { default as default3 } from "./WebSiteSchema.astro";
4
- import { default as default4 } from "./CollectionSchema.astro";
5
- import { default as default5 } from "./BreadcrumbSchema.astro";
6
- import { default as default6 } from "./FAQPageSchema.astro";
7
- import { default as default7 } from "./TechArticleSchema.astro";
3
+ import { default as default3 } from "./PersonSchema.astro";
4
+ import { default as default4 } from "./SoftwareApplicationSchema.astro";
5
+ import { default as default5 } from "./WebSiteSchema.astro";
6
+ import { default as default6 } from "./CollectionSchema.astro";
7
+ import { default as default7 } from "./BreadcrumbSchema.astro";
8
+ import { default as default8 } from "./FAQPageSchema.astro";
9
+ import { default as default9 } from "./TechArticleSchema.astro";
8
10
  export {
9
- default5 as BreadcrumbSchema,
10
- default4 as CollectionSchema,
11
- default6 as FAQPageSchema,
11
+ default7 as BreadcrumbSchema,
12
+ default6 as CollectionSchema,
13
+ default8 as FAQPageSchema,
12
14
  default2 as OrganizationSchema,
13
- default7 as TechArticleSchema,
14
- default3 as WebSiteSchema
15
+ default3 as PersonSchema,
16
+ default4 as SoftwareApplicationSchema,
17
+ default9 as TechArticleSchema,
18
+ default5 as WebSiteSchema
15
19
  };
@@ -1,4 +1,6 @@
1
1
  import './OrganizationSchema.astro';
2
+ import './PersonSchema.astro';
3
+ import './SoftwareApplicationSchema.astro';
2
4
  import './WebSiteSchema.astro';
3
5
  import './CollectionSchema.astro';
4
6
  import './BreadcrumbSchema.astro';