@rubytech/create-realagent-code 0.1.116 → 0.1.118

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.
Files changed (90) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/neo4j/schema.cypher +104 -0
  3. package/payload/platform/plugins/.claude-plugin/marketplace.json +5 -0
  4. package/payload/platform/plugins/admin/PLUGIN.md +1 -0
  5. package/payload/platform/plugins/aeo/.claude-plugin/plugin.json +17 -0
  6. package/payload/platform/plugins/aeo/PLUGIN.md +81 -0
  7. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.d.ts +2 -0
  8. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.d.ts.map +1 -0
  9. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.js +121 -0
  10. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.js.map +1 -0
  11. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.d.ts +2 -0
  12. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.d.ts.map +1 -0
  13. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.js +129 -0
  14. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.js.map +1 -0
  15. package/payload/platform/plugins/aeo/mcp/dist/index.d.ts +2 -0
  16. package/payload/platform/plugins/aeo/mcp/dist/index.d.ts.map +1 -0
  17. package/payload/platform/plugins/aeo/mcp/dist/index.js +171 -0
  18. package/payload/platform/plugins/aeo/mcp/dist/index.js.map +1 -0
  19. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.d.ts +27 -0
  20. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.d.ts.map +1 -0
  21. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.js +274 -0
  22. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.js.map +1 -0
  23. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.d.ts +5 -0
  24. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.d.ts.map +1 -0
  25. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.js +38 -0
  26. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.js.map +1 -0
  27. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.d.ts +48 -0
  28. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.d.ts.map +1 -0
  29. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.js +254 -0
  30. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.js.map +1 -0
  31. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.d.ts +25 -0
  32. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.d.ts.map +1 -0
  33. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.js +78 -0
  34. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.js.map +1 -0
  35. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.d.ts +18 -0
  36. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.d.ts.map +1 -0
  37. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.js +56 -0
  38. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.js.map +1 -0
  39. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.d.ts +37 -0
  40. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.d.ts.map +1 -0
  41. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.js +94 -0
  42. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.js.map +1 -0
  43. package/payload/platform/plugins/aeo/mcp/package.json +22 -0
  44. package/payload/platform/plugins/aeo/mcp/vitest.config.ts +9 -0
  45. package/payload/platform/plugins/aeo/skills/structured-answer/SKILL.md +53 -0
  46. package/payload/platform/plugins/docs/PLUGIN.md +1 -0
  47. package/payload/platform/plugins/docs/references/admin-session.md +1 -1
  48. package/payload/platform/plugins/docs/references/aeo.md +87 -0
  49. package/payload/platform/plugins/docs/references/deployment.md +1 -1
  50. package/payload/platform/plugins/email/PLUGIN.md +6 -0
  51. package/payload/platform/plugins/email/skills/email-composition/SKILL.md +180 -0
  52. package/payload/platform/plugins/memory/mcp/dist/index.js +5 -0
  53. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  54. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.d.ts +2 -0
  55. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.d.ts.map +1 -0
  56. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.js +62 -0
  57. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.js.map +1 -0
  58. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.d.ts +2 -0
  59. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.d.ts.map +1 -0
  60. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.js +62 -0
  61. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.js.map +1 -0
  62. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.d.ts +18 -0
  63. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.d.ts.map +1 -0
  64. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.js +29 -0
  65. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.js.map +1 -0
  66. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.js +2 -0
  67. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.js.map +1 -1
  68. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.js +1 -1
  69. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.js.map +1 -1
  70. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.d.ts +3 -0
  71. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.d.ts.map +1 -1
  72. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js +9 -1
  73. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js.map +1 -1
  74. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -1
  75. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +8 -0
  76. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -1
  77. package/payload/platform/plugins/memory/mcp/vitest.config.ts +4 -0
  78. package/payload/platform/plugins/memory/references/schema-base.md +5 -1
  79. package/payload/platform/scripts/smoke-boot-services.sh +30 -2
  80. package/payload/platform/templates/specialists/agents/signal-detector.md +1 -1
  81. package/payload/server/public/assets/{admin-DloKrK2i.js → admin-D6IfAzYY.js} +1 -1
  82. package/payload/server/public/assets/{data-NMvGx6jm.js → data-BGbQyufe.js} +1 -1
  83. package/payload/server/public/assets/{graph-CN60KyTy.js → graph-D-1lRTeL.js} +1 -1
  84. package/payload/server/public/assets/{graph-labels-h39S93Xo.js → graph-labels-BRXJHNYE.js} +1 -1
  85. package/payload/server/public/assets/{page-B0iMmY6t.js → page-B4oirCvn.js} +1 -1
  86. package/payload/server/public/assets/{page-CFRU-BdJ.js → page-FmJ7PIYx.js} +1 -1
  87. package/payload/server/public/data.html +3 -3
  88. package/payload/server/public/graph.html +3 -3
  89. package/payload/server/public/index.html +4 -4
  90. package/payload/server/server.js +14 -0
@@ -0,0 +1,171 @@
1
+ import { initStderrTee } from "../../../../lib/mcp-stderr-tee/dist/index.js";
2
+ initStderrTee("aeo");
3
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { eagerTool } from "../../../../lib/mcp-eager/dist/index.js";
5
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
+ import { z } from "zod";
7
+ import { emitJsonLd } from "./tools/aeo-emit-jsonld.js";
8
+ import { writeLlmsTxt } from "./tools/aeo-write-llms-txt.js";
9
+ import { auditPage } from "./tools/aeo-audit-page.js";
10
+ import { closeDriver } from "./lib/neo4j.js";
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+ const server = new McpServer({
13
+ name: "maxy-aeo",
14
+ version: "0.1.0",
15
+ });
16
+ // Plugin-system boot tolerance — see Task 202. Module-init must never
17
+ // throw; plugin-system spawn enumerates tools/list before ACCOUNT_ID
18
+ // is set. Per-call refusal preserves account isolation.
19
+ const accountId = process.env.ACCOUNT_ID ?? null;
20
+ process.stderr.write(`[aeo] boot accountId=${accountId ?? "null"}\n`);
21
+ function refuseNoAccount(toolName) {
22
+ process.stderr.write(`[aeo] tool=${toolName} refuse reason=no-account-context\n`);
23
+ return {
24
+ content: [
25
+ {
26
+ type: "text",
27
+ text: `${toolName} cannot execute: this MCP instance was launched without ACCOUNT_ID (plugin-system metadata-only mode). Per-account AEO operations require ACCOUNT_ID at spawn.`,
28
+ },
29
+ ],
30
+ isError: true,
31
+ };
32
+ }
33
+ const agentSlug = process.env.AGENT_SLUG || undefined;
34
+ const sessionId = process.env.SESSION_ID || undefined;
35
+ // ---------------------------------------------------------------------------
36
+ // aeo-emit-jsonld
37
+ // ---------------------------------------------------------------------------
38
+ eagerTool(server, "aeo-emit-jsonld", "Emit a schema.org JSON-LD block for a typed graph entity. Pass entityId for a Neo4j-sourced render, or label + properties for an inline render. Returns the parsed JSON-LD object and a ready-to-inline <script> block string.", {
39
+ entityId: z
40
+ .string()
41
+ .optional()
42
+ .describe("Neo4j elementId of a typed node (Organization, Person, Service, …)"),
43
+ label: z
44
+ .string()
45
+ .optional()
46
+ .describe("Source label when rendering inline (no entityId)"),
47
+ properties: z
48
+ .record(z.unknown())
49
+ .optional()
50
+ .describe("Property bag for inline render"),
51
+ }, async (args) => {
52
+ if (!accountId)
53
+ return refuseNoAccount("aeo-emit-jsonld");
54
+ try {
55
+ const result = await emitJsonLd({ accountId, ...args });
56
+ return {
57
+ content: [
58
+ {
59
+ type: "text",
60
+ text: JSON.stringify(result, null, 2),
61
+ },
62
+ ],
63
+ };
64
+ }
65
+ catch (err) {
66
+ const message = err instanceof Error ? err.message : String(err);
67
+ process.stderr.write(`[aeo-emit-jsonld] error: ${message}\n`);
68
+ return {
69
+ content: [{ type: "text", text: `Error: ${message}` }],
70
+ isError: true,
71
+ };
72
+ }
73
+ });
74
+ // ---------------------------------------------------------------------------
75
+ // aeo-write-llms-txt
76
+ // ---------------------------------------------------------------------------
77
+ eagerTool(server, "aeo-write-llms-txt", "Generate /llms.txt and /llms-full.txt for the account's published KnowledgeDocument pages. Index lists every page with title, url, summary. Full file concatenates each page's body, demoting any in-body H1s to H2 to keep one heading hierarchy.", {
78
+ siteName: z.string().describe("Display name of the site (top H1 of llms.txt)"),
79
+ siteDescription: z
80
+ .string()
81
+ .optional()
82
+ .describe("One-line site description (emitted as a blockquote)"),
83
+ }, async (args) => {
84
+ if (!accountId)
85
+ return refuseNoAccount("aeo-write-llms-txt");
86
+ try {
87
+ const result = await writeLlmsTxt({ accountId, ...args });
88
+ return {
89
+ content: [
90
+ {
91
+ type: "text",
92
+ text: JSON.stringify({
93
+ pageCount: result.pageCount,
94
+ skippedNoUrl: result.skippedNoUrl,
95
+ sizeBytes: result.sizeBytes,
96
+ llmsTxt: result.llmsTxt,
97
+ llmsFullTxt: result.llmsFullTxt,
98
+ }, null, 2),
99
+ },
100
+ ],
101
+ };
102
+ }
103
+ catch (err) {
104
+ const message = err instanceof Error ? err.message : String(err);
105
+ process.stderr.write(`[aeo-llms-txt] error: ${message}\n`);
106
+ return {
107
+ content: [{ type: "text", text: `Error: ${message}` }],
108
+ isError: true,
109
+ };
110
+ }
111
+ });
112
+ // ---------------------------------------------------------------------------
113
+ // aeo-audit-page
114
+ // ---------------------------------------------------------------------------
115
+ eagerTool(server, "aeo-audit-page", "Run the eight-heuristic AEO audit against a URL or inline HTML. Returns a 0–100 score, per-heuristic pass/warn/fail, and one rewrite suggestion per fail. Pass persist=true with targetKnowledgeDocumentId to record an :AEOAudit node linked from the document.", {
116
+ url: z.string().url().optional().describe("Page URL to fetch and audit"),
117
+ html: z.string().optional().describe("Raw HTML to audit (alternative to url)"),
118
+ persist: z
119
+ .boolean()
120
+ .optional()
121
+ .describe("If true, write an :AEOAudit node and HAS_AEO_AUDIT edge"),
122
+ targetKnowledgeDocumentId: z
123
+ .string()
124
+ .optional()
125
+ .describe("Neo4j elementId of the KnowledgeDocument to link the audit to"),
126
+ }, async (args) => {
127
+ if (!accountId)
128
+ return refuseNoAccount("aeo-audit-page");
129
+ try {
130
+ const result = await auditPage({
131
+ accountId,
132
+ agentSlug,
133
+ sessionId,
134
+ ...args,
135
+ });
136
+ return {
137
+ content: [
138
+ { type: "text", text: JSON.stringify(result, null, 2) },
139
+ ],
140
+ };
141
+ }
142
+ catch (err) {
143
+ const message = err instanceof Error ? err.message : String(err);
144
+ process.stderr.write(`[aeo-audit] error: ${message}\n`);
145
+ return {
146
+ content: [{ type: "text", text: `Error: ${message}` }],
147
+ isError: true,
148
+ };
149
+ }
150
+ });
151
+ // ---------------------------------------------------------------------------
152
+ // Boot
153
+ // ---------------------------------------------------------------------------
154
+ async function shutdown() {
155
+ try {
156
+ await closeDriver();
157
+ }
158
+ catch {
159
+ // already-closed driver during shutdown is benign
160
+ }
161
+ }
162
+ process.on("SIGTERM", () => {
163
+ void shutdown().finally(() => process.exit(0));
164
+ });
165
+ process.on("SIGINT", () => {
166
+ void shutdown().finally(() => process.exit(0));
167
+ });
168
+ const transport = new StdioServerTransport();
169
+ await server.connect(transport);
170
+ process.stderr.write("[aeo] ready\n");
171
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,8CAA8C,CAAC;AAC7E,aAAa,CAAC,KAAK,CAAC,CAAC;AAErB,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,8DAA8D;AAC9D,MAAM,MAAM,GAAQ,IAAI,SAAS,CAAC;IAChC,IAAI,EAAE,UAAU;IAChB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,sEAAsE;AACtE,qEAAqE;AACrE,wDAAwD;AACxD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC;AACjD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,SAAS,IAAI,MAAM,IAAI,CAAC,CAAC;AAEtE,SAAS,eAAe,CAAC,QAAgB;IACvC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,cAAc,QAAQ,qCAAqC,CAC5D,CAAC;IACF,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,GAAG,QAAQ,gKAAgK;aAClL;SACF;QACD,OAAO,EAAE,IAAa;KACvB,CAAC;AACJ,CAAC;AAED,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,SAAS,CAAC;AACtD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,SAAS,CAAC;AAEtD,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E,SAAS,CACP,MAAM,EACN,iBAAiB,EACjB,gOAAgO,EAChO;IACE,QAAQ,EAAE,CAAC;SACR,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,oEAAoE,CAAC;IACjF,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,kDAAkD,CAAC;IAC/D,UAAU,EAAE,CAAC;SACV,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SACnB,QAAQ,EAAE;SACV,QAAQ,CAAC,gCAAgC,CAAC;CAC9C,EACD,KAAK,EAAE,IAIN,EAAE,EAAE;IACH,IAAI,CAAC,SAAS;QAAE,OAAO,eAAe,CAAC,iBAAiB,CAAC,CAAC;IAC1D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;QACxD,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;iBACtC;aACF;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,OAAO,IAAI,CAAC,CAAC;QAC9D,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC;YAC/D,OAAO,EAAE,IAAa;SACvB,CAAC;IACJ,CAAC;AACH,CAAC,CACF,CAAC;AAEF,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E,SAAS,CACP,MAAM,EACN,oBAAoB,EACpB,oPAAoP,EACpP;IACE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC;IAC9E,eAAe,EAAE,CAAC;SACf,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,qDAAqD,CAAC;CACnE,EACD,KAAK,EAAE,IAAoD,EAAE,EAAE;IAC7D,IAAI,CAAC,SAAS;QAAE,OAAO,eAAe,CAAC,oBAAoB,CAAC,CAAC;IAC7D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;QAC1D,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB;wBACE,SAAS,EAAE,MAAM,CAAC,SAAS;wBAC3B,YAAY,EAAE,MAAM,CAAC,YAAY;wBACjC,SAAS,EAAE,MAAM,CAAC,SAAS;wBAC3B,OAAO,EAAE,MAAM,CAAC,OAAO;wBACvB,WAAW,EAAE,MAAM,CAAC,WAAW;qBAChC,EACD,IAAI,EACJ,CAAC,CACF;iBACF;aACF;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,OAAO,IAAI,CAAC,CAAC;QAC3D,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC;YAC/D,OAAO,EAAE,IAAa;SACvB,CAAC;IACJ,CAAC;AACH,CAAC,CACF,CAAC;AAEF,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E,SAAS,CACP,MAAM,EACN,gBAAgB,EAChB,kQAAkQ,EAClQ;IACE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;IACxE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;IAC9E,OAAO,EAAE,CAAC;SACP,OAAO,EAAE;SACT,QAAQ,EAAE;SACV,QAAQ,CAAC,yDAAyD,CAAC;IACtE,yBAAyB,EAAE,CAAC;SACzB,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,+DAA+D,CAAC;CAC7E,EACD,KAAK,EAAE,IAKN,EAAE,EAAE;IACH,IAAI,CAAC,SAAS;QAAE,OAAO,eAAe,CAAC,gBAAgB,CAAC,CAAC;IACzD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC;YAC7B,SAAS;YACT,SAAS;YACT,SAAS;YACT,GAAG,IAAI;SACR,CAAC,CAAC;QACH,OAAO;YACL,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;aACjE;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,OAAO,IAAI,CAAC,CAAC;QACxD,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC;YAC/D,OAAO,EAAE,IAAa;SACvB,CAAC;IACJ,CAAC;AACH,CAAC,CACF,CAAC;AAEF,8EAA8E;AAC9E,OAAO;AACP,8EAA8E;AAE9E,KAAK,UAAU,QAAQ;IACrB,IAAI,CAAC;QACH,MAAM,WAAW,EAAE,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,kDAAkD;IACpD,CAAC;AACH,CAAC;AAED,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;IACzB,KAAK,QAAQ,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC;AACH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;IACxB,KAAK,QAAQ,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC;AAEH,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Page-level AEO (Answer Engine Optimisation) heuristics. Eight checks
3
+ * run against raw HTML; each returns a status and, when the check fails,
4
+ * one concrete rewrite suggestion the operator can apply.
5
+ *
6
+ * The HTML parser is a deliberate single-pass regex scanner: AEO audits
7
+ * run on pages the platform itself renders, so we know they are
8
+ * server-side-generated, well-formed enough for regex inspection, and
9
+ * not gated on script-injected content. Bringing in a full DOM parser
10
+ * (jsdom, cheerio) would dwarf the rest of the plugin and pull in
11
+ * Node-version-coupled native deps. If we later need to audit
12
+ * third-party arbitrary HTML, swap the parser then.
13
+ */
14
+ export type HeuristicStatus = "pass" | "warn" | "fail";
15
+ export interface HeuristicResult {
16
+ name: HeuristicName;
17
+ status: HeuristicStatus;
18
+ detail: string;
19
+ suggestion?: string;
20
+ }
21
+ export type HeuristicName = "h1-present" | "jsonld-present" | "structured-answer" | "faq-section" | "meta-description" | "canonical-url" | "og-tags" | "heading-hierarchy";
22
+ export interface AuditResult {
23
+ score: number;
24
+ heuristics: HeuristicResult[];
25
+ }
26
+ export declare function auditHtml(html: string): AuditResult;
27
+ //# sourceMappingURL=audit-heuristics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-heuristics.d.ts","sourceRoot":"","sources":["../../src/lib/audit-heuristics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAEvD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,eAAe,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,aAAa,GACrB,YAAY,GACZ,gBAAgB,GAChB,mBAAmB,GACnB,aAAa,GACb,kBAAkB,GAClB,eAAe,GACf,SAAS,GACT,mBAAmB,CAAC;AAExB,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B;AAoRD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAOnD"}
@@ -0,0 +1,274 @@
1
+ /**
2
+ * Page-level AEO (Answer Engine Optimisation) heuristics. Eight checks
3
+ * run against raw HTML; each returns a status and, when the check fails,
4
+ * one concrete rewrite suggestion the operator can apply.
5
+ *
6
+ * The HTML parser is a deliberate single-pass regex scanner: AEO audits
7
+ * run on pages the platform itself renders, so we know they are
8
+ * server-side-generated, well-formed enough for regex inspection, and
9
+ * not gated on script-injected content. Bringing in a full DOM parser
10
+ * (jsdom, cheerio) would dwarf the rest of the plugin and pull in
11
+ * Node-version-coupled native deps. If we later need to audit
12
+ * third-party arbitrary HTML, swap the parser then.
13
+ */
14
+ const H1_RX = /<h1\b[^>]*>([\s\S]*?)<\/h1>/gi;
15
+ const JSONLD_RX = /<script[^>]*type=["']application\/ld\+json["'][^>]*>([\s\S]*?)<\/script>/gi;
16
+ const META_DESC_RX = /<meta\b[^>]*name=["']description["'][^>]*content=["']([^"']*)["']/i;
17
+ const META_DESC_RX_REV = /<meta\b[^>]*content=["']([^"']*)["'][^>]*name=["']description["']/i;
18
+ const CANONICAL_RX = /<link\b[^>]*rel=["']canonical["'][^>]*href=["']([^"']*)["']/i;
19
+ const OG_TITLE_RX = /<meta\b[^>]*property=["']og:title["']/i;
20
+ const OG_DESC_RX = /<meta\b[^>]*property=["']og:description["']/i;
21
+ const HEADING_RX = /<(h[1-6])\b[^>]*>([\s\S]*?)<\/\1>/gi;
22
+ const TAG_STRIP = /<[^>]+>/g;
23
+ function stripTags(html) {
24
+ return html.replace(TAG_STRIP, "").replace(/\s+/g, " ").trim();
25
+ }
26
+ function readMetaDescription(html) {
27
+ const m = html.match(META_DESC_RX) ?? html.match(META_DESC_RX_REV);
28
+ return m ? m[1] : null;
29
+ }
30
+ function checkH1(html) {
31
+ const matches = [...html.matchAll(H1_RX)];
32
+ if (matches.length === 0) {
33
+ return {
34
+ name: "h1-present",
35
+ status: "fail",
36
+ detail: "no <h1> found",
37
+ suggestion: "Add one <h1> at the top of the page naming the entity or question this page answers.",
38
+ };
39
+ }
40
+ if (matches.length > 1) {
41
+ return {
42
+ name: "h1-present",
43
+ status: "warn",
44
+ detail: `${matches.length} <h1> elements (expected 1)`,
45
+ };
46
+ }
47
+ return {
48
+ name: "h1-present",
49
+ status: "pass",
50
+ detail: `1 <h1>: "${stripTags(matches[0][1]).slice(0, 80)}"`,
51
+ };
52
+ }
53
+ function checkJsonLd(html) {
54
+ const matches = [...html.matchAll(JSONLD_RX)];
55
+ if (matches.length === 0) {
56
+ return {
57
+ name: "jsonld-present",
58
+ status: "fail",
59
+ detail: "no JSON-LD <script> block",
60
+ suggestion: "Emit a schema.org JSON-LD block via aeo-emit-jsonld and inline it in <head>.",
61
+ };
62
+ }
63
+ let valid = 0;
64
+ for (const m of matches) {
65
+ try {
66
+ JSON.parse(m[1]);
67
+ valid += 1;
68
+ }
69
+ catch {
70
+ // counted below
71
+ }
72
+ }
73
+ if (valid === 0) {
74
+ return {
75
+ name: "jsonld-present",
76
+ status: "fail",
77
+ detail: `${matches.length} JSON-LD block(s) but none parse`,
78
+ suggestion: "Fix the JSON-LD payload — JSON.parse failed on every block.",
79
+ };
80
+ }
81
+ if (valid < matches.length) {
82
+ return {
83
+ name: "jsonld-present",
84
+ status: "warn",
85
+ detail: `${valid}/${matches.length} JSON-LD blocks parse`,
86
+ };
87
+ }
88
+ return {
89
+ name: "jsonld-present",
90
+ status: "pass",
91
+ detail: `${valid} JSON-LD block(s)`,
92
+ };
93
+ }
94
+ function checkStructuredAnswer(html) {
95
+ const h1Matches = [...html.matchAll(H1_RX)];
96
+ if (h1Matches.length === 0) {
97
+ return {
98
+ name: "structured-answer",
99
+ status: "fail",
100
+ detail: "no <h1> — cannot locate structured answer position",
101
+ suggestion: "Add an <h1> followed by a single ≤280-character paragraph that answers the page question directly.",
102
+ };
103
+ }
104
+ const h1 = h1Matches[0];
105
+ const after = html.slice((h1.index ?? 0) + h1[0].length);
106
+ const pMatch = after.match(/<p\b[^>]*>([\s\S]*?)<\/p>/i);
107
+ if (!pMatch) {
108
+ return {
109
+ name: "structured-answer",
110
+ status: "fail",
111
+ detail: "no <p> after <h1>",
112
+ suggestion: "Add one ≤280-character <p> immediately after the <h1> that states the answer in one sentence.",
113
+ };
114
+ }
115
+ const text = stripTags(pMatch[1]);
116
+ if (text.length === 0) {
117
+ return {
118
+ name: "structured-answer",
119
+ status: "fail",
120
+ detail: "first <p> after <h1> is empty",
121
+ suggestion: "Fill the first <p> after <h1> with a ≤280-character direct answer.",
122
+ };
123
+ }
124
+ if (text.length > 280) {
125
+ return {
126
+ name: "structured-answer",
127
+ status: "warn",
128
+ detail: `first <p> after <h1> is ${text.length} chars (target ≤280)`,
129
+ };
130
+ }
131
+ return {
132
+ name: "structured-answer",
133
+ status: "pass",
134
+ detail: `first <p> after <h1> is ${text.length} chars`,
135
+ };
136
+ }
137
+ function checkFaqSection(html) {
138
+ const lower = html.toLowerCase();
139
+ const hasFaqJsonLd = /["']@type["']\s*:\s*["']faqpage["']/i.test(html);
140
+ const hasFaqText = /\bfrequently asked questions\b/i.test(lower) ||
141
+ /\bfaqs?\b/i.test(lower);
142
+ if (hasFaqJsonLd) {
143
+ return {
144
+ name: "faq-section",
145
+ status: "pass",
146
+ detail: "FAQPage JSON-LD present",
147
+ };
148
+ }
149
+ if (hasFaqText) {
150
+ return {
151
+ name: "faq-section",
152
+ status: "warn",
153
+ detail: "FAQ text but no FAQPage JSON-LD",
154
+ };
155
+ }
156
+ return {
157
+ name: "faq-section",
158
+ status: "fail",
159
+ detail: "no FAQ section",
160
+ suggestion: "Add a FAQ section with FAQPage JSON-LD listing the 3–5 questions customers most often ask.",
161
+ };
162
+ }
163
+ function checkMetaDescription(html) {
164
+ const desc = readMetaDescription(html);
165
+ if (!desc) {
166
+ return {
167
+ name: "meta-description",
168
+ status: "fail",
169
+ detail: "no <meta name=\"description\">",
170
+ suggestion: "Add <meta name=\"description\"> with an 80–160 character summary of the page's answer.",
171
+ };
172
+ }
173
+ const len = desc.trim().length;
174
+ if (len < 80 || len > 160) {
175
+ return {
176
+ name: "meta-description",
177
+ status: "warn",
178
+ detail: `description is ${len} chars (target 80–160)`,
179
+ };
180
+ }
181
+ return {
182
+ name: "meta-description",
183
+ status: "pass",
184
+ detail: `description is ${len} chars`,
185
+ };
186
+ }
187
+ function checkCanonical(html) {
188
+ const m = html.match(CANONICAL_RX);
189
+ if (!m) {
190
+ return {
191
+ name: "canonical-url",
192
+ status: "fail",
193
+ detail: "no <link rel=\"canonical\">",
194
+ suggestion: "Add <link rel=\"canonical\" href=\"<page-url>\"> in <head>.",
195
+ };
196
+ }
197
+ return {
198
+ name: "canonical-url",
199
+ status: "pass",
200
+ detail: `canonical=${m[1]}`,
201
+ };
202
+ }
203
+ function checkOgTags(html) {
204
+ const hasTitle = OG_TITLE_RX.test(html);
205
+ const hasDesc = OG_DESC_RX.test(html);
206
+ if (hasTitle && hasDesc) {
207
+ return {
208
+ name: "og-tags",
209
+ status: "pass",
210
+ detail: "og:title + og:description present",
211
+ };
212
+ }
213
+ const missing = [];
214
+ if (!hasTitle)
215
+ missing.push("og:title");
216
+ if (!hasDesc)
217
+ missing.push("og:description");
218
+ return {
219
+ name: "og-tags",
220
+ status: "fail",
221
+ detail: `missing: ${missing.join(", ")}`,
222
+ suggestion: `Add <meta property="${missing.join('"> and <meta property="')}"> in <head>.`,
223
+ };
224
+ }
225
+ function checkHeadingHierarchy(html) {
226
+ const levels = [];
227
+ for (const m of html.matchAll(HEADING_RX)) {
228
+ levels.push(parseInt(m[1].slice(1), 10));
229
+ }
230
+ if (levels.length === 0) {
231
+ return {
232
+ name: "heading-hierarchy",
233
+ status: "fail",
234
+ detail: "no headings on the page",
235
+ suggestion: "Add a semantic heading structure starting with <h1> and stepping down by one level.",
236
+ };
237
+ }
238
+ for (let i = 1; i < levels.length; i += 1) {
239
+ const prev = levels[i - 1];
240
+ const cur = levels[i];
241
+ if (cur > prev + 1) {
242
+ return {
243
+ name: "heading-hierarchy",
244
+ status: "fail",
245
+ detail: `heading skip: h${prev} → h${cur}`,
246
+ suggestion: `Replace the h${cur} after the h${prev} with an h${prev + 1} (or insert an intermediate heading).`,
247
+ };
248
+ }
249
+ }
250
+ return {
251
+ name: "heading-hierarchy",
252
+ status: "pass",
253
+ detail: `${levels.length} headings, no skips`,
254
+ };
255
+ }
256
+ const ALL_CHECKS = [
257
+ checkH1,
258
+ checkJsonLd,
259
+ checkStructuredAnswer,
260
+ checkFaqSection,
261
+ checkMetaDescription,
262
+ checkCanonical,
263
+ checkOgTags,
264
+ checkHeadingHierarchy,
265
+ ];
266
+ export function auditHtml(html) {
267
+ const heuristics = ALL_CHECKS.map((fn) => fn(html));
268
+ const passes = heuristics.filter((r) => r.status === "pass").length;
269
+ const warns = heuristics.filter((r) => r.status === "warn").length;
270
+ const total = heuristics.length;
271
+ const score = Math.round((100 * (passes + 0.5 * warns)) / total);
272
+ return { score, heuristics };
273
+ }
274
+ //# sourceMappingURL=audit-heuristics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-heuristics.js","sourceRoot":"","sources":["../../src/lib/audit-heuristics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { Driver, Session } from "neo4j-driver";
2
+ export declare function getDriver(): Driver;
3
+ export declare function getSession(): Session;
4
+ export declare function closeDriver(): Promise<void>;
5
+ //# sourceMappingURL=neo4j.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"neo4j.d.ts","sourceRoot":"","sources":["../../src/lib/neo4j.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAqBtD,wBAAgB,SAAS,IAAI,MAAM,CAclC;AAED,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAKjD"}
@@ -0,0 +1,38 @@
1
+ import neo4j from "neo4j-driver";
2
+ import { readFileSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ let driver = null;
5
+ function readPassword() {
6
+ if (process.env.NEO4J_PASSWORD)
7
+ return process.env.NEO4J_PASSWORD;
8
+ const passwordFile = resolve(process.env.PLATFORM_ROOT ?? resolve(import.meta.dirname, "../../../.."), "config/.neo4j-password");
9
+ try {
10
+ return readFileSync(passwordFile, "utf-8").trim();
11
+ }
12
+ catch {
13
+ throw new Error(`Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`);
14
+ }
15
+ }
16
+ export function getDriver() {
17
+ if (!driver) {
18
+ const uri = process.env.NEO4J_URI;
19
+ if (!uri) {
20
+ throw new Error("[aeo] NEO4J_URI unset — refusing to default to bolt://localhost:7687");
21
+ }
22
+ const user = process.env.NEO4J_USER ?? "neo4j";
23
+ const password = readPassword();
24
+ console.error(`[aeo] resolved neo4j_uri=${uri}`);
25
+ driver = neo4j.driver(uri, neo4j.auth.basic(user, password));
26
+ }
27
+ return driver;
28
+ }
29
+ export function getSession() {
30
+ return getDriver().session();
31
+ }
32
+ export async function closeDriver() {
33
+ if (driver) {
34
+ await driver.close();
35
+ driver = null;
36
+ }
37
+ }
38
+ //# sourceMappingURL=neo4j.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"neo4j.js","sourceRoot":"","sources":["../../src/lib/neo4j.ts"],"names":[],"mappings":"AAAA,OAAO,KAA0B,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,IAAI,MAAM,GAAkB,IAAI,CAAC;AAEjC,SAAS,YAAY;IACnB,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAClE,MAAM,YAAY,GAAG,OAAO,CAC1B,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,EACxE,wBAAwB,CACzB,CAAC;IACF,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,yCAAyC,YAAY,gCAAgC,CACtF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;QAClC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,sEAAsE,CACvE,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC;QAC/C,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,4BAA4B,GAAG,EAAE,CAAC,CAAC;QACjD,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,SAAS,EAAE,CAAC,OAAO,EAAE,CAAC;AAC/B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;AACH,CAAC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Maps Neo4j node labels to schema.org types and builds JSON-LD payloads
3
+ * suitable for inline `<script type="application/ld+json">` blocks on
4
+ * rendered pages.
5
+ *
6
+ * Coverage matches Task 354 spec §1 — the seven page types that the
7
+ * platform's typed nodes cover natively. Labels outside this set fall
8
+ * through to a generic `schema:Thing` projection; callers should treat
9
+ * a generic result as a doc gap, not a success.
10
+ *
11
+ * The mapper is deliberately strict: every emitted JSON-LD object names
12
+ * `@context` and `@type` and carries `@id` when an `elementId` is
13
+ * available. Missing required properties for the chosen type produce a
14
+ * `MissingPropertyError`; callers surface this rather than emitting an
15
+ * invalid block.
16
+ */
17
+ export type JsonLdValue = string | number | boolean | null | JsonLdObject | JsonLdValue[];
18
+ export interface JsonLdObject {
19
+ "@context"?: string;
20
+ "@type": string;
21
+ "@id"?: string;
22
+ [property: string]: JsonLdValue | undefined;
23
+ }
24
+ export type SupportedPageType = "Organization" | "LocalBusiness" | "Person" | "Service" | "Product" | "Article" | "FAQPage" | "RealEstateListing" | "Event";
25
+ /** Inputs accepted by the mapper. */
26
+ export interface EntityInput {
27
+ /** Source Neo4j label (or one of `SupportedPageType` directly). */
28
+ label: string;
29
+ /** Optional Neo4j elementId — emitted as `@id` when present. */
30
+ elementId?: string;
31
+ /** Flat property bag from the node. */
32
+ properties: Record<string, unknown>;
33
+ }
34
+ export declare class MissingPropertyError extends Error {
35
+ readonly schemaType: SupportedPageType | "Thing";
36
+ readonly missing: string[];
37
+ constructor(schemaType: SupportedPageType | "Thing", missing: string[]);
38
+ }
39
+ export declare function resolveSchemaType(label: string): SupportedPageType | "Thing";
40
+ /**
41
+ * Build a JSON-LD object from a typed entity. Throws
42
+ * `MissingPropertyError` when the resolved schema.org type's required
43
+ * properties are not satisfied.
44
+ */
45
+ export declare function buildJsonLd(input: EntityInput): JsonLdObject;
46
+ /** Render a JSON-LD object as a `<script>` block string. */
47
+ export declare function renderJsonLdScript(obj: JsonLdObject): string;
48
+ //# sourceMappingURL=schema-mapping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-mapping.d.ts","sourceRoot":"","sources":["../../src/lib/schema-mapping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAM,WAAW,GACnB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,YAAY,GACZ,WAAW,EAAE,CAAC;AAElB,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;CAC7C;AAED,MAAM,MAAM,iBAAiB,GACzB,cAAc,GACd,eAAe,GACf,QAAQ,GACR,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,mBAAmB,GACnB,OAAO,CAAC;AAEZ,qCAAqC;AACrC,MAAM,WAAW,WAAW;IAC1B,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,qBAAa,oBAAqB,SAAQ,KAAK;aAE3B,UAAU,EAAE,iBAAiB,GAAG,OAAO;aACvC,OAAO,EAAE,MAAM,EAAE;gBADjB,UAAU,EAAE,iBAAiB,GAAG,OAAO,EACvC,OAAO,EAAE,MAAM,EAAE;CAOpC;AA4BD,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,GACZ,iBAAiB,GAAG,OAAO,CAE7B;AAyLD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,YAAY,CA0B5D;AAED,4DAA4D;AAC5D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAE5D"}