@rubytech/create-maxy-code 0.1.51 → 0.1.57
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/dist/__tests__/platform-port-stamp.test.js +24 -0
- package/dist/index.js +5 -2
- package/dist/port-resolution.js +2 -0
- package/package.json +1 -1
- package/payload/platform/lib/require-port-env/dist/index.d.ts +31 -0
- package/payload/platform/lib/require-port-env/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/require-port-env/dist/index.js +52 -0
- package/payload/platform/lib/require-port-env/dist/index.js.map +1 -0
- package/payload/platform/lib/require-port-env/src/index.ts +56 -0
- package/payload/platform/lib/require-port-env/tsconfig.json +8 -0
- package/payload/platform/package-lock.json +0 -1
- package/payload/platform/package.json +2 -3
- package/payload/platform/plugins/admin/PLUGIN.md +16 -3
- package/payload/platform/plugins/admin/hooks/__tests__/turn-completed-graph-write.test.sh +183 -144
- package/payload/platform/plugins/admin/hooks/turn-completed-graph-write.sh +180 -99
- package/payload/platform/plugins/admin/mcp/dist/index.js +20 -12
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/brochures/PLUGIN.md +2 -0
- package/payload/platform/plugins/brochures/skills/property-market-report/SKILL.md +100 -0
- package/payload/platform/plugins/brochures/skills/property-market-report/references/render.py +267 -0
- package/payload/platform/plugins/brochures/skills/property-market-report/references/template.html +266 -0
- package/payload/platform/plugins/brochures/skills/property-socials/SKILL.md +141 -0
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.d.ts.map +1 -1
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.js +2 -1
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.js.map +1 -1
- package/payload/platform/plugins/docs/references/admin-session.md +33 -3
- package/payload/platform/plugins/docs/references/deployment.md +25 -0
- package/payload/platform/plugins/docs/references/internals.md +26 -0
- package/payload/platform/plugins/docs/references/platform.md +3 -1
- package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.js +2 -1
- package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.js.map +1 -1
- package/payload/platform/plugins/memory/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/memory/PLUGIN.md +1 -1
- package/payload/platform/plugins/memory/mcp/dist/index.js +6 -1
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js +107 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts +4 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js +22 -13
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js.map +1 -1
- package/payload/platform/plugins/memory/references/graph-primitives.md +42 -0
- package/payload/platform/plugins/memory/skills/concept-synthesis/SKILL.md +1 -1
- package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +2 -2
- package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +1 -1
- package/payload/platform/plugins/property-data/.claude-plugin/plugin.json +17 -0
- package/payload/platform/plugins/property-data/PLUGIN.md +100 -0
- package/payload/platform/plugins/property-data/mcp/dist/index.d.ts +2 -0
- package/payload/platform/plugins/property-data/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/index.js +153 -0
- package/payload/platform/plugins/property-data/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.d.ts +3 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.d.ts.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.js +72 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.js.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.d.ts +5 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.d.ts.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.js +38 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.js.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts +29 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.js +112 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.js.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.d.ts +14 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.d.ts.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.js +20 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.js.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.d.ts +4 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.d.ts.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.js +19 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.js.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.d.ts +4 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.d.ts.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.js +10 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.js.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.d.ts +5 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.d.ts.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.js +43 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.js.map +1 -0
- package/payload/platform/plugins/property-data/mcp/package-lock.json +2566 -0
- package/payload/platform/plugins/property-data/mcp/package.json +21 -0
- package/payload/platform/plugins/property-data/mcp/src/__tests__/key-roundtrip.test.ts +107 -0
- package/payload/platform/plugins/property-data/mcp/src/__tests__/propertydata-api.test.ts +184 -0
- package/payload/platform/plugins/property-data/mcp/src/__tests__/schema-parity.test.ts +48 -0
- package/payload/platform/plugins/property-data/mcp/src/index.ts +249 -0
- package/payload/platform/plugins/property-data/mcp/src/lib/crypto.ts +79 -0
- package/payload/platform/plugins/property-data/mcp/src/lib/neo4j.ts +47 -0
- package/payload/platform/plugins/property-data/mcp/src/lib/propertydata-api.ts +135 -0
- package/payload/platform/plugins/property-data/mcp/src/tools/endpoints.ts +27 -0
- package/payload/platform/plugins/property-data/mcp/src/tools/key-deregister.ts +21 -0
- package/payload/platform/plugins/property-data/mcp/src/tools/key-list.ts +10 -0
- package/payload/platform/plugins/property-data/mcp/src/tools/key-register.ts +58 -0
- package/payload/platform/plugins/property-data/mcp/tsconfig.json +20 -0
- package/payload/platform/plugins/property-data/mcp/vitest.config.ts +8 -0
- package/payload/platform/plugins/property-data/skills/property-data/SKILL.md +58 -0
- package/payload/platform/plugins/waitlist/PLUGIN.md +6 -8
- package/payload/platform/plugins/waitlist/mcp/dist/index.js +33 -0
- package/payload/platform/plugins/waitlist/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/waitlist/mcp/dist/lib/admin-model.d.ts +16 -0
- package/payload/platform/plugins/waitlist/mcp/dist/lib/admin-model.d.ts.map +1 -0
- package/payload/platform/plugins/waitlist/mcp/dist/lib/admin-model.js +58 -0
- package/payload/platform/plugins/waitlist/mcp/dist/lib/admin-model.js.map +1 -0
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.d.ts +34 -0
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.d.ts.map +1 -0
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.js +129 -0
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.js.map +1 -0
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.d.ts +12 -18
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.d.ts.map +1 -1
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.js +89 -86
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.js.map +1 -1
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-setup.d.ts.map +1 -1
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-setup.js +15 -53
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-setup.js.map +1 -1
- package/payload/platform/plugins/whatsapp/PLUGIN.md +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +5 -5
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/workflows/PLUGIN.md +10 -176
- package/payload/platform/plugins/workflows/mcp/dist/index.js +14 -142
- package/payload/platform/plugins/workflows/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.d.ts +1 -88
- package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.d.ts.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.js +0 -86
- package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.d.ts +5 -12
- package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.d.ts.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.js +5 -46
- package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.d.ts +1 -16
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.d.ts.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.js +39 -75
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.d.ts +8 -21
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.d.ts.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js +39 -266
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.d.ts +3 -8
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.d.ts.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.js +3 -10
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.d.ts.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.js +38 -86
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.d.ts.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.js +8 -26
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.js +1 -2
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +204 -23
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +39 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +109 -10
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/reaper.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/reaper.js +11 -0
- package/payload/platform/services/claude-session-manager/dist/reaper.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-store.d.ts +21 -0
- package/payload/platform/services/claude-session-manager/dist/session-store.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-store.js.map +1 -1
- package/payload/platform/services/claude-session-manager/vitest.config.ts +14 -0
- package/payload/platform/templates/agents/admin/IDENTITY.md +2 -0
- package/payload/platform/templates/agents/admin/SOUL.md +3 -1
- package/payload/premium-plugins/real-agent/BUNDLE.md +5 -3
- package/payload/premium-plugins/real-agent/agents/negotiator.md +1 -1
- package/payload/premium-plugins/real-agent/agents/valuer.md +1 -1
- package/payload/premium-plugins/real-agent/plugins/.claude-plugin/marketplace.json +5 -0
- package/payload/premium-plugins/real-agent/plugins/brochures/PLUGIN.md +2 -0
- package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-market-report/SKILL.md +100 -0
- package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-market-report/references/render.py +267 -0
- package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-market-report/references/template.html +266 -0
- package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-socials/SKILL.md +141 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/.claude-plugin/plugin.json +17 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/PLUGIN.md +100 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/index.d.ts +2 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/index.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/index.js +153 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/index.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/crypto.d.ts +3 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/crypto.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/crypto.js +72 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/crypto.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/neo4j.d.ts +5 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/neo4j.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/neo4j.js +38 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/neo4j.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts +29 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/propertydata-api.js +112 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/propertydata-api.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/endpoints.d.ts +14 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/endpoints.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/endpoints.js +20 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/endpoints.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-deregister.d.ts +4 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-deregister.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-deregister.js +19 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-deregister.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-list.d.ts +4 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-list.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-list.js +10 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-list.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-register.d.ts +5 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-register.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-register.js +43 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-register.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/package-lock.json +2566 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/package.json +21 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/__tests__/key-roundtrip.test.ts +107 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/__tests__/propertydata-api.test.ts +184 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/__tests__/schema-parity.test.ts +48 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/index.ts +249 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/lib/crypto.ts +79 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/lib/neo4j.ts +47 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/lib/propertydata-api.ts +135 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/tools/endpoints.ts +27 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/tools/key-deregister.ts +21 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/tools/key-list.ts +10 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/tools/key-register.ts +58 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/tsconfig.json +20 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/vitest.config.ts +8 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/skills/property-data/SKILL.md +58 -0
- package/payload/server/{chunk-CWI7NOWK.js → chunk-2IKQERHN.js} +32 -4
- package/payload/server/maxy-edge.js +53 -25
- package/payload/server/public/assets/admin-2ZJmzJ_g.js +216 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-DGHlapUl.js → architectureDiagram-Q4EWVU46-DgfgldJT.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-Dgnf9J14.js → blockDiagram-DXYQGD6D-agu8GDzA.js} +1 -1
- package/payload/server/public/assets/{brand-CtilcX3W.css → brand-BDASZqMG.css} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-GBVmghhJ.js → c4Diagram-AHTNJAMY-CmNsUmAe.js} +1 -1
- package/payload/server/public/assets/channel-DXGOX55q.js +1 -0
- package/payload/server/public/assets/{chunk-336JU56O-CSVC_J3A.js → chunk-336JU56O-D9Uts7k9.js} +2 -2
- package/payload/server/public/assets/{chunk-426QAEUC-CK1Z0942.js → chunk-426QAEUC-D4ABqXMn.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-CaqJYLxL.js → chunk-4TB4RGXK-D1KE4OAX.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-57BmPy_B.js → chunk-5FUZZQ4R-CAh0GXe2.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-Ud03uYx_.js → chunk-5PVQY5BW-DBHa6HOv.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-p5KO0PoG.js → chunk-EDXVE4YY-BDC-6mL3.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-CkxgLujt.js → chunk-ENJZ2VHE-CH3uROkW.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-DwMkY8p7.js → chunk-ICPOFSXX-BzZf0nAw.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-CyYOUKBw.js → chunk-OYMX7WX6-BrLHrI6O.js} +1 -1
- package/payload/server/public/assets/{chunk-U2HBQHQK-Dk5rfJM6.js → chunk-U2HBQHQK-Bw4UkLe_.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-D0qCg9Nq.js → chunk-X2U36JSP-23xgdk05.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-C0uFHrdT.js → chunk-YZCP3GAM-BA8iGgRa.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-C7lSyGRs.js → chunk-ZZ45TVLE-B-ol4EgR.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DTuuDxpK.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-CIw8RU0q.js +1 -0
- package/payload/server/public/assets/clone-O4ZyuvYl.js +1 -0
- package/payload/server/public/assets/{dagre-BWZ4wr8y.js → dagre--kXszEIb.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-C7mpqRpw.js → dagre-KV5264BT-amN1uU2d.js} +1 -1
- package/payload/server/public/assets/data-DlmoKxmN.js +1 -0
- package/payload/server/public/assets/{device-url-actions-347cMDY4.js → device-url-actions-CPoz5fqz.js} +1 -1
- package/payload/server/public/assets/{diagram-5BDNPKRD-BcQRB7_3.js → diagram-5BDNPKRD-Cwizs9tP.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-BLSGUKbc.js → diagram-G4DWMVQ6-BpSu5Uao.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-Ra1VvGJh.js → diagram-MMDJMWI5-DiArtkto.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-Bx_r1USn.js → diagram-TYMM5635-_tygK58Y.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-CJhoN8dG.js → erDiagram-SMLLAGMA-CBV6LWYA.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-Bd5CZIoq.js → flowDiagram-DWJPFMVM-CHZFrtOU.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BNQJqJFh.js → ganttDiagram-T4ZO3ILL-B3vKq5ov.js} +1 -1
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-DoE1AFmA.js → gitGraphDiagram-UUTBAWPF-dnJPjbtj.js} +1 -1
- package/payload/server/public/assets/graph-BVvcFSEQ.js +1 -0
- package/payload/server/public/assets/graph-labels-cCvgu38Y.js +1 -0
- package/payload/server/public/assets/{graphlib-D7JFfLSw.js → graphlib-CNXtnega.js} +1 -1
- package/payload/server/public/assets/{infoDiagram-42DDH7IO-BtsKRO-J.js → infoDiagram-42DDH7IO-D8DYwVAF.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-DapnDR0V.js → ishikawaDiagram-UXIWVN3A-CfEVY2Ud.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-BLqfwMMu.js → journeyDiagram-VCZTEJTY-FmoBq7Kh.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-DqiSbvUW.js → kanban-definition-6JOO6SKY-B-Q9qk99.js} +1 -1
- package/payload/server/public/assets/{line-DcwBbbhp.js → line-DZwbJENP.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-BZwNRInp.js → mermaid-parser.core-C3ahKykw.js} +1 -1
- package/payload/server/public/assets/{mermaid.core-DnsyVInc.js → mermaid.core-B8OFZIE8.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-MPPO8aDx.js → mindmap-definition-QFDTVHPH-CqhkfbWa.js} +1 -1
- package/payload/server/public/assets/{page-Cz_pVOv_.js → page-BnAxPkmg.js} +1 -1
- package/payload/server/public/assets/{page-pXt2BdOS.js → page-BnaN3u86.js} +1 -1
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-BKzbjD_5.js → pieDiagram-DEJITSTG-CJqQ6u3-.js} +1 -1
- package/payload/server/public/assets/{public-C-0V5aC8.js → public-rWe9ADCS.js} +3 -3
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CvvvRvae.js → quadrantDiagram-34T5L4WZ-BtEqOXQM.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-BxXZA7z2.js → requirementDiagram-MS252O5E-DPHWUtE6.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-BRRFjjao.js → sankeyDiagram-XADWPNL6-FBmc3wHT.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-DOy_E8xe.js → sequenceDiagram-FGHM5R23-BMSd2-1M.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-CDqat01p.js → stateDiagram-FHFEXIEX-DqFbU-LT.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CXTnsHGq.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-AK1yuR8Z.js → timeline-definition-GMOUNBTQ-DsfvHVK8.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-CCKJ7H16.js → vennDiagram-DHZGUBPP-kHU05mqC.js} +1 -1
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-CKHKJnG_.js → wardleyDiagram-NUSXRM2D-C696Mez_.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-BBD35k9e.js → xychartDiagram-5P7HB3ND-yht-JyXJ.js} +1 -1
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +5 -5
- package/payload/server/public/index.html +7 -7
- package/payload/server/public/public.html +4 -4
- package/payload/server/server.js +209 -178
- package/payload/server/public/assets/admin-BbcN8otj.js +0 -216
- package/payload/server/public/assets/channel-p5ZCfK_I.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DqDM1D4-.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DeYvPD8H.js +0 -1
- package/payload/server/public/assets/clone-60k82qeh.js +0 -1
- package/payload/server/public/assets/data-oXs84UW6.js +0 -1
- package/payload/server/public/assets/graph-DcpqWbSs.js +0 -1
- package/payload/server/public/assets/graph-labels-DJvuUODB.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DHckg-aj.js +0 -1
- /package/payload/server/public/assets/{brand-B6pMzF6h.js → brand-BWCtpG7_.js} +0 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: property-socials
|
|
3
|
+
description: Use when generating Open Graph / social-share images for a property page built by the real-estate brochure pipeline (estate-agents/<agent>/properties/<slug>/output/web/page.html). Produces landscape, square, and portrait JPGs that match the brochure's brand palette and typography, pulling copy from property.json and hero images already curated for that property. Triggers include "og images for <property>", "social collateral for <listing>", "Instagram tiles for that brochure", or any request to create share-card imagery for a published realagent.chat property page.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Property OG / Social Images
|
|
7
|
+
|
|
8
|
+
The brochure pipeline already produces a styled property page at
|
|
9
|
+
`estate-agents/<agent>/properties/<slug>/output/web/page.html` with curated hero
|
|
10
|
+
images under `images/`, branding tokens in `:root` of the page CSS, and
|
|
11
|
+
structured metadata in the property's `property.json`. This skill renders
|
|
12
|
+
share-ready images by overlaying brand-consistent typography on those hero
|
|
13
|
+
shots — it does not re-design anything.
|
|
14
|
+
|
|
15
|
+
## Inputs the skill consumes (never invents)
|
|
16
|
+
|
|
17
|
+
- **Palette and fonts** — read from `:root` in `output/web/page.html`. Use the
|
|
18
|
+
exact `--paper / --ink / --gold` tokens and Google Font imports already on
|
|
19
|
+
that page. Do not pick new colours.
|
|
20
|
+
- **Copy** — `property.json` is canonical for address, price, qualifier,
|
|
21
|
+
bedrooms/baths/receptions, agent name + phone. The page's
|
|
22
|
+
`<meta name="description">` is the sub-headline. The brochure folder's
|
|
23
|
+
display name (e.g. *Sparrows Farm*) is the headline.
|
|
24
|
+
- **Hero images** — `images/<slug>-hero-1-main.webp`, `hero-2-kitchen.webp`,
|
|
25
|
+
`hero-3-garden.webp` are the curated set. Use them by name; do not pick
|
|
26
|
+
numbered shots from the raw set unless the curated heroes are missing.
|
|
27
|
+
|
|
28
|
+
## Output contract
|
|
29
|
+
|
|
30
|
+
Two deliverables every time: image files and the captions that go with them.
|
|
31
|
+
|
|
32
|
+
**Image files** are written next to `page.html` so they share the same public
|
|
33
|
+
URL prefix:
|
|
34
|
+
|
|
35
|
+
| File | Dimensions | Use |
|
|
36
|
+
|------|------------|-----|
|
|
37
|
+
| `og-landscape-<hero>.jpg` | 1200×628 | Twitter / LinkedIn / Facebook / OG |
|
|
38
|
+
| `og-square-<hero>.jpg` | 1200×1200 | Instagram feed |
|
|
39
|
+
| `og-portrait-<hero>.jpg` | 1080×1350 | Instagram portrait, mobile |
|
|
40
|
+
|
|
41
|
+
`<hero>` is `main`, `kitchen`, or `garden`. At minimum produce
|
|
42
|
+
`og-landscape-main.jpg`; offer the full five-variant set (landscape + square +
|
|
43
|
+
three portraits) when the user wants social collateral, not just a meta image.
|
|
44
|
+
|
|
45
|
+
**Captions** are written into `output/web/social-posts.md`, one section per
|
|
46
|
+
image, ready to paste. Every caption is generated through the `plainly` skill's
|
|
47
|
+
register: no em-dashes, no inflation vocabulary (*discover*, *unlock*,
|
|
48
|
+
*nestled*, *stunning*, *boasts*, *bespoke* where it isn't literally bespoke),
|
|
49
|
+
no antithetical "it's not X, it's Y", no rhetorical openers (*Imagine…*,
|
|
50
|
+
*Picture this…*). Read each draft aloud; if it sounds like an estate-agent
|
|
51
|
+
blurb-bot rather than a person, rewrite it.
|
|
52
|
+
|
|
53
|
+
Per-platform shape (these are caps, not minimums):
|
|
54
|
+
|
|
55
|
+
- **Landscape post (Twitter / X)**: under 280 characters. One sentence of
|
|
56
|
+
scene, one of specs, one of agent + phone. Link as last token.
|
|
57
|
+
- **Landscape post (LinkedIn / Facebook)**: three short paragraphs. Opening
|
|
58
|
+
line that names the property and locality. A middle paragraph of concrete
|
|
59
|
+
features taken from `property.json`'s `key_features`. A closing paragraph
|
|
60
|
+
with price, agent name, phone, listing URL.
|
|
61
|
+
- **Square (Instagram feed)**: property name + locality on line one, two or
|
|
62
|
+
three lines of concrete features, price, agent + phone, "link in bio", four
|
|
63
|
+
to six hashtags drawn from locality + property type + agency.
|
|
64
|
+
- **Portrait (Instagram portrait / Reels cover)**: lead with what is visible
|
|
65
|
+
in *that specific hero* (exterior, kitchen, or garden), not the generic
|
|
66
|
+
property summary. Three lines maximum. Price + agent line at the bottom.
|
|
67
|
+
|
|
68
|
+
Copy sources, in order: `property.json` for facts (address, price, beds, baths,
|
|
69
|
+
acreage, key features); the page's `<meta name="description">` for tone of the
|
|
70
|
+
hero sub-line; the brochure folder display name for the headline. Do not invent
|
|
71
|
+
features that are not in those sources.
|
|
72
|
+
|
|
73
|
+
## How rendering works
|
|
74
|
+
|
|
75
|
+
A single `og.html` template lives at `output/web/og.html` alongside `page.html`
|
|
76
|
+
so it can use relative `images/` paths. It accepts `?format=landscape|square|
|
|
77
|
+
portrait` and `?hero=main|kitchen|garden`, applies the matching CSS class with
|
|
78
|
+
explicit min/max width and height (no relative units), and sets the background
|
|
79
|
+
hero image from the param. Playwright screenshots the URL at exactly the
|
|
80
|
+
container's pixel size.
|
|
81
|
+
|
|
82
|
+
Critical layout rules:
|
|
83
|
+
|
|
84
|
+
- The stage div fixes its own width and height with `width / minWidth / maxWidth`
|
|
85
|
+
(and the height triple). Without max constraints the viewport bleeds.
|
|
86
|
+
- Hero fills the stage with `background-size: cover; background-position: center`
|
|
87
|
+
so the same template works across all three aspect ratios.
|
|
88
|
+
- A vertical gradient scrim (transparent → ink 0.85) sits between hero and copy.
|
|
89
|
+
On bright daytime shots the scrim's bottom stop must reach ≥ 0.85 or the
|
|
90
|
+
eyebrow/sub copy loses contrast.
|
|
91
|
+
- Copy block sits in the bottom-left: eyebrow (locality, gold), headline
|
|
92
|
+
(display serif), sub (italic body serif), thin rule, specs row, footer line
|
|
93
|
+
with `realagent.chat / <agent>` left and `<agent name> · <phone>` right.
|
|
94
|
+
|
|
95
|
+
## Generation flow
|
|
96
|
+
|
|
97
|
+
1. Confirm `output/web/og.html` is in sync with the page's `:root` palette and
|
|
98
|
+
`property.json` copy. If the property page has been re-themed since the last
|
|
99
|
+
render, update the template before screenshotting.
|
|
100
|
+
2. Start a static server in `output/web/` on any free port:
|
|
101
|
+
`python3 -m http.server <port> &`. Hold the PID so it can be killed at the
|
|
102
|
+
end. Relative `images/` paths require a real HTTP origin; `file://` won't
|
|
103
|
+
render webfonts either.
|
|
104
|
+
3. On a fresh machine, `npx -y playwright install chromium` once. The first
|
|
105
|
+
`playwright screenshot` invocation otherwise fails with "Executable doesn't
|
|
106
|
+
exist".
|
|
107
|
+
4. Screenshot each variant. Pass `--wait-for-timeout=2500` so Google Fonts
|
|
108
|
+
land before capture. Always quote URLs that contain `&`.
|
|
109
|
+
5. Stop the server. Verify each JPG with `Read` so the user sees the rendered
|
|
110
|
+
collateral inline — file sizes alone aren't proof of a good render.
|
|
111
|
+
|
|
112
|
+
## Failure modes seen on first use
|
|
113
|
+
|
|
114
|
+
- **Filename mangling.** A bash loop using `for v in "landscape main" …; set --
|
|
115
|
+
$v` collapses to filenames like `og-landscape main-.jpg` (space, then dash).
|
|
116
|
+
Use an explicit per-variant call or an array; never rely on positional
|
|
117
|
+
splitting for two-word tuples.
|
|
118
|
+
- **6 KB screenshots.** A screenshot under ~20 KB is a blank page. Common
|
|
119
|
+
causes: server not running, wrong port, Chromium not installed, or `og.html`
|
|
120
|
+
threw a JS error. Open the URL in a browser to confirm before re-running.
|
|
121
|
+
- **Eyebrow on a light surface.** The garden / pool hero washes the eyebrow
|
|
122
|
+
out. Either deepen the scrim's bottom stop or move the eyebrow above the
|
|
123
|
+
hero crop on that variant. Don't ship a low-contrast tile.
|
|
124
|
+
- **Treating this as a Next.js task.** The brochure site is static HTML. The
|
|
125
|
+
upstream `og-images` skill assumes `app/og/page.tsx`; ignore that scaffold
|
|
126
|
+
and render against the static page directly.
|
|
127
|
+
- **Captions that sound like AI marketing.** "Discover this stunning home
|
|
128
|
+
nestled in the heart of Essex" is the failure mode. Strip *discover*,
|
|
129
|
+
*unlock*, *nestled*, *stunning*, *boasts*, *exquisite*, *charming*, every
|
|
130
|
+
em-dash, every exclamation mark used to fake enthusiasm. The aloud test from
|
|
131
|
+
the `plainly` skill applies: read the caption out; if you would not say it
|
|
132
|
+
in conversation to a buyer, rewrite it.
|
|
133
|
+
|
|
134
|
+
## Out of scope
|
|
135
|
+
|
|
136
|
+
- The brochure page itself (owned by `real-estate-brochure:property-brochure`).
|
|
137
|
+
- Property metadata extraction (owned by
|
|
138
|
+
`real-estate-brochure:property-extract`).
|
|
139
|
+
- Wiring `<meta property="og:image">` into `page.html`. Surface the snippet for
|
|
140
|
+
the operator; the page is regenerated by a separate skill and edits there
|
|
141
|
+
belong in that pipeline, not this one.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "real-agent-property-data",
|
|
3
|
+
"description": "PropertyData UK market analytics — postcode-keyed valuation, asking prices, sold prices, demand, yields, growth, national HPI. One encrypted API key per account.",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Rubytech LLC"
|
|
7
|
+
},
|
|
8
|
+
"mcpServers": {
|
|
9
|
+
"real-agent-property-data": {
|
|
10
|
+
"type": "stdio",
|
|
11
|
+
"command": "node",
|
|
12
|
+
"args": [
|
|
13
|
+
"${CLAUDE_PLUGIN_ROOT}/mcp/dist/index.js"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: real-agent-property-data
|
|
3
|
+
description: "PropertyData UK market analytics — postcode-keyed valuation, asking prices, sold prices, demand, yields, growth, national HPI. One encrypted API key per account."
|
|
4
|
+
tools:
|
|
5
|
+
- name: property-data-key-register
|
|
6
|
+
publicAllowlist: false
|
|
7
|
+
- name: property-data-key-deregister
|
|
8
|
+
publicAllowlist: false
|
|
9
|
+
- name: property-data-key-list
|
|
10
|
+
publicAllowlist: false
|
|
11
|
+
- name: property-data-valuation-sale
|
|
12
|
+
publicAllowlist: false
|
|
13
|
+
- name: property-data-valuation-rent
|
|
14
|
+
publicAllowlist: false
|
|
15
|
+
- name: property-data-prices
|
|
16
|
+
publicAllowlist: false
|
|
17
|
+
- name: property-data-prices-rent
|
|
18
|
+
publicAllowlist: false
|
|
19
|
+
- name: property-data-sold-prices
|
|
20
|
+
publicAllowlist: false
|
|
21
|
+
- name: property-data-demand
|
|
22
|
+
publicAllowlist: false
|
|
23
|
+
- name: property-data-yields
|
|
24
|
+
publicAllowlist: false
|
|
25
|
+
- name: property-data-growth
|
|
26
|
+
publicAllowlist: false
|
|
27
|
+
- name: property-data-national-hpi
|
|
28
|
+
publicAllowlist: false
|
|
29
|
+
skills:
|
|
30
|
+
- skills/property-data/SKILL.md
|
|
31
|
+
always: false
|
|
32
|
+
metadata: {"platform":{"optional":true,"embed":["admin"]}}
|
|
33
|
+
mcp:
|
|
34
|
+
command: node
|
|
35
|
+
args:
|
|
36
|
+
- ${PLATFORM_ROOT}/lib/mcp-spawn-tee/dist/index.js
|
|
37
|
+
- ${PREMIUM_PLUGINS_ROOT}/real-agent/plugins/property-data/mcp/dist/index.js
|
|
38
|
+
env:
|
|
39
|
+
MCP_SPAWN_TEE_NAME: property-data
|
|
40
|
+
LOG_DIR: ${LOG_DIR}
|
|
41
|
+
PLATFORM_ROOT: ${PLATFORM_ROOT}
|
|
42
|
+
ACCOUNT_ID: ${ACCOUNT_ID}
|
|
43
|
+
SESSION_ID: ${SESSION_ID}
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
# Real Agent — PropertyData
|
|
47
|
+
|
|
48
|
+
Local stdio MCP that proxies the PropertyData UK market-analytics HTTP API (propertydata.co.uk). Postcode-keyed analytics powering valuer + negotiator workflows: comparable evidence, asking-price baselines, sold-price history, demand index, rental yield, growth signals, and the national house-price index.
|
|
49
|
+
|
|
50
|
+
## Capabilities
|
|
51
|
+
|
|
52
|
+
- **Key management** — register, deregister, and list a single PropertyData API key per account. AES-256-GCM encrypted at rest in Neo4j under the `PropertyDataKey` label.
|
|
53
|
+
- **Valuation** — point-estimate sale and rent valuations from postcode + property attributes (`valuation-sale`, `valuation-rent`).
|
|
54
|
+
- **Asking-price baselines** — live mean / median / 80th-percentile asking prices for sale and rent in a postcode (`prices`, `prices-rent`).
|
|
55
|
+
- **Sold-price history** — Land Registry sold transactions filtered by postcode, property type, and age (`sold-prices`).
|
|
56
|
+
- **Demand index** — number of properties currently for sale vs. average days to sell-STC for a postcode (`demand`).
|
|
57
|
+
- **Rental yield** — gross yield estimates by postcode and bedroom count (`yields`).
|
|
58
|
+
- **Growth signals** — short and long-term price growth by postcode (`growth`).
|
|
59
|
+
- **National house-price index** — UK-wide HPI series (`national-hpi`).
|
|
60
|
+
|
|
61
|
+
## Security
|
|
62
|
+
|
|
63
|
+
The PropertyData API key is encrypted at rest with AES-256-GCM. Encryption key lives at `~/<configDir>/.property-data-encryption-key` with mode `0600`. Never include the key value in responses; identify the key by registration timestamp only. If the operator asks for the key value, explain that keys are encrypted and cannot be retrieved — they must be re-registered from the PropertyData dashboard.
|
|
64
|
+
|
|
65
|
+
## When to use these tools
|
|
66
|
+
|
|
67
|
+
### Pillar 1 — Comparable evidence for valuation
|
|
68
|
+
|
|
69
|
+
**Triggers** — operator says "comps for", "sold prices around", "what's gone for", "comparable evidence":
|
|
70
|
+
- `property-data-sold-prices` — Land Registry sold prices for the postcode
|
|
71
|
+
|
|
72
|
+
### Pillar 2 — Asking-price baselines and point valuations
|
|
73
|
+
|
|
74
|
+
**Triggers** — operator says "what's it worth", "asking prices in", "point estimate", "ballpark":
|
|
75
|
+
- `property-data-valuation-sale` — point sale estimate for postcode + attributes
|
|
76
|
+
- `property-data-valuation-rent` — point rent estimate
|
|
77
|
+
- `property-data-prices` — distribution of asking prices for sale
|
|
78
|
+
- `property-data-prices-rent` — distribution of asking prices for rent
|
|
79
|
+
|
|
80
|
+
### Pillar 3 — Demand + yield + growth (negotiation signals)
|
|
81
|
+
|
|
82
|
+
**Triggers** — operator says "demand in", "yield on", "growth", "is the market moving":
|
|
83
|
+
- `property-data-demand` — supply count + average days to sell-STC
|
|
84
|
+
- `property-data-yields` — gross rental yield by bedroom count
|
|
85
|
+
- `property-data-growth` — short and long-term price growth
|
|
86
|
+
- `property-data-national-hpi` — national HPI context
|
|
87
|
+
|
|
88
|
+
### Key prerequisite
|
|
89
|
+
|
|
90
|
+
Every PropertyData tool requires a registered key. If `property-data-key-list` returns nothing for the account, surface the registration prompt before attempting any other call — every downstream tool will return `status=key-missing` otherwise.
|
|
91
|
+
|
|
92
|
+
## Tool error envelope
|
|
93
|
+
|
|
94
|
+
Every tool returns either the PropertyData `data` payload as JSON text or an `isError: true` envelope with deterministic text shape:
|
|
95
|
+
|
|
96
|
+
- `Error: key-not-registered. Register a PropertyData API key with property-data-key-register before calling this tool.`
|
|
97
|
+
- `Error: http-<status> from PropertyData. <message>`
|
|
98
|
+
- `Error: bad-response from PropertyData (non-JSON, length=<n>).`
|
|
99
|
+
|
|
100
|
+
Operators see the reason directly; downstream skills branch on the prefix.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { initStderrTee } from "../../../../lib/mcp-stderr-tee/dist/index.js";
|
|
2
|
+
initStderrTee("property-data");
|
|
3
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { keyRegister } from "./tools/key-register.js";
|
|
7
|
+
import { keyDeregister } from "./tools/key-deregister.js";
|
|
8
|
+
import { keyList } from "./tools/key-list.js";
|
|
9
|
+
import { valuationSale, valuationRent, prices, pricesRent, soldPrices, demand, yields, growth, nationalHpi, } from "./tools/endpoints.js";
|
|
10
|
+
import { closeDriver } from "./lib/neo4j.js";
|
|
11
|
+
import { KeyNotRegisteredError, PropertyDataError, BadResponseError, } from "./lib/propertydata-api.js";
|
|
12
|
+
const accountId = process.env.ACCOUNT_ID;
|
|
13
|
+
if (!accountId) {
|
|
14
|
+
throw new Error("ACCOUNT_ID environment variable is required");
|
|
15
|
+
}
|
|
16
|
+
const server = new McpServer({
|
|
17
|
+
name: "maxy-property-data",
|
|
18
|
+
version: "0.1.0",
|
|
19
|
+
});
|
|
20
|
+
console.error(`[property-data] server started, account=${accountId}`);
|
|
21
|
+
function errorEnvelope(err) {
|
|
22
|
+
let text;
|
|
23
|
+
if (err instanceof KeyNotRegisteredError) {
|
|
24
|
+
text =
|
|
25
|
+
"Error: key-not-registered. Register a PropertyData API key with property-data-key-register before calling this tool.";
|
|
26
|
+
}
|
|
27
|
+
else if (err instanceof PropertyDataError) {
|
|
28
|
+
text = `Error: http-${err.status} from PropertyData. ${err.upstreamMessage}`;
|
|
29
|
+
}
|
|
30
|
+
else if (err instanceof BadResponseError) {
|
|
31
|
+
text = `Error: bad-response from PropertyData (non-JSON, length=${err.length}).`;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
text = `Error: ${err instanceof Error ? err.message : String(err)}`;
|
|
35
|
+
}
|
|
36
|
+
return { content: [{ type: "text", text }], isError: true };
|
|
37
|
+
}
|
|
38
|
+
function endpointHandler(fn) {
|
|
39
|
+
return async (params) => {
|
|
40
|
+
try {
|
|
41
|
+
const text = await fn({ ...params, accountId: accountId });
|
|
42
|
+
return { content: [{ type: "text", text }] };
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
return errorEnvelope(err);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// ─────────────────────────────────────────────────────────────────
|
|
50
|
+
// Key Management
|
|
51
|
+
// ─────────────────────────────────────────────────────────────────
|
|
52
|
+
server.tool("property-data-key-register", "Register the account's PropertyData API key. Validates the key against PropertyData's /national-hpi endpoint, encrypts it with AES-256-GCM, and stores it in Neo4j. One key per account; re-registering overwrites the existing key.", {
|
|
53
|
+
apiKey: z.string().min(8).describe("PropertyData API key from propertydata.co.uk dashboard"),
|
|
54
|
+
}, async ({ apiKey }) => {
|
|
55
|
+
try {
|
|
56
|
+
await keyRegister({ apiKey, accountId: accountId });
|
|
57
|
+
return {
|
|
58
|
+
content: [
|
|
59
|
+
{
|
|
60
|
+
type: "text",
|
|
61
|
+
text: "PropertyData API key registered successfully.",
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
return errorEnvelope(err);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
server.tool("property-data-key-deregister", "Remove the account's PropertyData API key. The encrypted key is permanently deleted from Neo4j.", {}, async () => {
|
|
71
|
+
try {
|
|
72
|
+
await keyDeregister({ accountId: accountId });
|
|
73
|
+
return {
|
|
74
|
+
content: [{ type: "text", text: "PropertyData API key deregistered." }],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
return errorEnvelope(err);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
server.tool("property-data-key-list", "Show whether a PropertyData API key is registered for this account. Never reveals the key value.", {}, async () => {
|
|
82
|
+
try {
|
|
83
|
+
const text = await keyList({ accountId: accountId });
|
|
84
|
+
return { content: [{ type: "text", text }] };
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
return errorEnvelope(err);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
// ─────────────────────────────────────────────────────────────────
|
|
91
|
+
// Valuation endpoints
|
|
92
|
+
// ─────────────────────────────────────────────────────────────────
|
|
93
|
+
const valuationSchema = {
|
|
94
|
+
postcode: z.string().min(2).describe("UK postcode (outcode or full)"),
|
|
95
|
+
type: z
|
|
96
|
+
.enum(["detached", "semi-detached", "terraced", "flat"])
|
|
97
|
+
.describe("Property type"),
|
|
98
|
+
bedrooms: z.number().int().min(0).describe("Bedroom count"),
|
|
99
|
+
bathrooms: z.number().int().min(0).optional().describe("Bathroom count"),
|
|
100
|
+
internal_area: z.number().optional().describe("Internal area (sq ft)"),
|
|
101
|
+
construction_date: z.string().optional().describe("Construction date band (e.g. 'pre1900', '1900-1929')"),
|
|
102
|
+
finish_quality: z
|
|
103
|
+
.enum(["luxury", "above_average", "average", "below_average", "needs_modernisation"])
|
|
104
|
+
.optional()
|
|
105
|
+
.describe("Finish quality"),
|
|
106
|
+
};
|
|
107
|
+
server.tool("property-data-valuation-sale", "Point sale-price estimate for a property given postcode + attributes. Returns point estimate plus comparables.", valuationSchema, endpointHandler(valuationSale));
|
|
108
|
+
server.tool("property-data-valuation-rent", "Point rent estimate (PCM) for a property given postcode + attributes. Returns point estimate plus comparables.", valuationSchema, endpointHandler(valuationRent));
|
|
109
|
+
// ─────────────────────────────────────────────────────────────────
|
|
110
|
+
// Asking-price distributions
|
|
111
|
+
// ─────────────────────────────────────────────────────────────────
|
|
112
|
+
const pricesSchema = {
|
|
113
|
+
postcode: z.string().min(2).describe("UK postcode (outcode or full)"),
|
|
114
|
+
type: z
|
|
115
|
+
.enum(["detached", "semi-detached", "terraced", "flat"])
|
|
116
|
+
.optional()
|
|
117
|
+
.describe("Filter by property type"),
|
|
118
|
+
bedrooms: z.number().int().min(0).optional().describe("Filter by bedroom count"),
|
|
119
|
+
};
|
|
120
|
+
server.tool("property-data-prices", "Asking-price distribution for sale listings in a postcode — mean, median, 80th percentile.", pricesSchema, endpointHandler(prices));
|
|
121
|
+
server.tool("property-data-prices-rent", "Asking-price distribution for rental listings in a postcode — mean, median, 80th percentile (PCM).", pricesSchema, endpointHandler(pricesRent));
|
|
122
|
+
// ─────────────────────────────────────────────────────────────────
|
|
123
|
+
// Sold prices (Land Registry)
|
|
124
|
+
// ─────────────────────────────────────────────────────────────────
|
|
125
|
+
server.tool("property-data-sold-prices", "Land Registry sold transactions for a postcode, optionally filtered by age, type, and bedrooms.", {
|
|
126
|
+
postcode: z.string().min(2).describe("UK postcode (outcode or full)"),
|
|
127
|
+
max_age: z.number().int().min(1).optional().describe("Max transaction age in months"),
|
|
128
|
+
type: z
|
|
129
|
+
.enum(["detached", "semi-detached", "terraced", "flat"])
|
|
130
|
+
.optional()
|
|
131
|
+
.describe("Filter by property type"),
|
|
132
|
+
bedrooms: z.number().int().min(0).optional().describe("Filter by bedroom count"),
|
|
133
|
+
}, endpointHandler(soldPrices));
|
|
134
|
+
// ─────────────────────────────────────────────────────────────────
|
|
135
|
+
// Demand / yields / growth / national HPI
|
|
136
|
+
// ─────────────────────────────────────────────────────────────────
|
|
137
|
+
server.tool("property-data-demand", "Demand signals for a postcode — count of properties for sale and average days to sell-STC.", { postcode: z.string().min(2).describe("UK postcode (outcode or full)") }, endpointHandler(demand));
|
|
138
|
+
server.tool("property-data-yields", "Gross rental yield for a postcode and bedroom count.", {
|
|
139
|
+
postcode: z.string().min(2).describe("UK postcode (outcode or full)"),
|
|
140
|
+
bedrooms: z.number().int().min(0).describe("Bedroom count"),
|
|
141
|
+
}, endpointHandler(yields));
|
|
142
|
+
server.tool("property-data-growth", "Short-term and long-term price growth signals for a postcode.", { postcode: z.string().min(2).describe("UK postcode (outcode or full)") }, endpointHandler(growth));
|
|
143
|
+
server.tool("property-data-national-hpi", "UK national house-price index series. No postcode required.", {}, endpointHandler(nationalHpi));
|
|
144
|
+
// ─────────────────────────────────────────────────────────────────
|
|
145
|
+
// Lifecycle
|
|
146
|
+
// ─────────────────────────────────────────────────────────────────
|
|
147
|
+
process.on("SIGINT", async () => {
|
|
148
|
+
await closeDriver();
|
|
149
|
+
process.exit(0);
|
|
150
|
+
});
|
|
151
|
+
const transport = new StdioServerTransport();
|
|
152
|
+
await server.connect(transport);
|
|
153
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/lib/crypto.ts"],"names":[],"mappings":"AAgDA,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAQjD;AAED,wBAAgB,OAAO,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAoBtD"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { randomBytes, createCipheriv, createDecipheriv } from "node:crypto";
|
|
2
|
+
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
const ALGORITHM = "aes-256-gcm";
|
|
6
|
+
const KEY_LENGTH = 32;
|
|
7
|
+
const IV_LENGTH = 12;
|
|
8
|
+
const AUTH_TAG_LENGTH = 16;
|
|
9
|
+
const KEY_FILE_NAME = ".property-data-encryption-key";
|
|
10
|
+
function resolveConfigDir() {
|
|
11
|
+
try {
|
|
12
|
+
const platformRoot = process.env.PLATFORM_ROOT;
|
|
13
|
+
if (platformRoot) {
|
|
14
|
+
const brandPath = resolve(platformRoot, "config/brand.json");
|
|
15
|
+
const brand = JSON.parse(readFileSync(brandPath, "utf-8"));
|
|
16
|
+
if (brand.configDir)
|
|
17
|
+
return brand.configDir;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// Fall back to default
|
|
22
|
+
}
|
|
23
|
+
return ".maxy";
|
|
24
|
+
}
|
|
25
|
+
function keyFilePath() {
|
|
26
|
+
return resolve(homedir(), resolveConfigDir(), KEY_FILE_NAME);
|
|
27
|
+
}
|
|
28
|
+
function loadOrGenerateKey() {
|
|
29
|
+
const path = keyFilePath();
|
|
30
|
+
if (existsSync(path)) {
|
|
31
|
+
const hex = readFileSync(path, "utf-8").trim();
|
|
32
|
+
const buf = Buffer.from(hex, "hex");
|
|
33
|
+
if (buf.length !== KEY_LENGTH) {
|
|
34
|
+
throw new Error(`Encryption key at ${path} is ${buf.length} bytes, expected ${KEY_LENGTH}. ` +
|
|
35
|
+
`Delete the file and re-register the PropertyData API key.`);
|
|
36
|
+
}
|
|
37
|
+
return buf;
|
|
38
|
+
}
|
|
39
|
+
const key = randomBytes(KEY_LENGTH);
|
|
40
|
+
writeFileSync(path, key.toString("hex"), { mode: 0o600 });
|
|
41
|
+
console.error(`[property-data] encryption key generated at ${path}`);
|
|
42
|
+
return key;
|
|
43
|
+
}
|
|
44
|
+
export function encrypt(plaintext) {
|
|
45
|
+
const key = loadOrGenerateKey();
|
|
46
|
+
const iv = randomBytes(IV_LENGTH);
|
|
47
|
+
const cipher = createCipheriv(ALGORITHM, key, iv, { authTagLength: AUTH_TAG_LENGTH });
|
|
48
|
+
let encrypted = cipher.update(plaintext, "utf-8", "hex");
|
|
49
|
+
encrypted += cipher.final("hex");
|
|
50
|
+
const authTag = cipher.getAuthTag().toString("hex");
|
|
51
|
+
return `${iv.toString("hex")}:${encrypted}:${authTag}`;
|
|
52
|
+
}
|
|
53
|
+
export function decrypt(encryptedValue) {
|
|
54
|
+
const parts = encryptedValue.split(":");
|
|
55
|
+
if (parts.length !== 3) {
|
|
56
|
+
throw new Error("Malformed encrypted value — expected iv:ciphertext:authTag");
|
|
57
|
+
}
|
|
58
|
+
const [ivHex, ciphertextHex, authTagHex] = parts;
|
|
59
|
+
const path = keyFilePath();
|
|
60
|
+
if (!existsSync(path)) {
|
|
61
|
+
throw new Error(`Encryption key not found at ${path}. The stored PropertyData API key is unrecoverable. Re-register.`);
|
|
62
|
+
}
|
|
63
|
+
const key = loadOrGenerateKey();
|
|
64
|
+
const iv = Buffer.from(ivHex, "hex");
|
|
65
|
+
const authTag = Buffer.from(authTagHex, "hex");
|
|
66
|
+
const decipher = createDecipheriv(ALGORITHM, key, iv, { authTagLength: AUTH_TAG_LENGTH });
|
|
67
|
+
decipher.setAuthTag(authTag);
|
|
68
|
+
let decrypted = decipher.update(ciphertextHex, "hex", "utf-8");
|
|
69
|
+
decrypted += decipher.final("utf-8");
|
|
70
|
+
return decrypted;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/lib/crypto.ts"],"names":[],"mappings":"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"}
|
|
@@ -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("[property-data] 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(`[property-data] 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,gFAAgF,CACjF,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,sCAAsC,GAAG,EAAE,CAAC,CAAC;QAC3D,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"}
|
package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare class KeyNotRegisteredError extends Error {
|
|
2
|
+
constructor();
|
|
3
|
+
}
|
|
4
|
+
export declare class PropertyDataError extends Error {
|
|
5
|
+
readonly status: number;
|
|
6
|
+
readonly endpoint: string;
|
|
7
|
+
readonly upstreamMessage: string;
|
|
8
|
+
constructor(status: number, endpoint: string, upstreamMessage: string);
|
|
9
|
+
}
|
|
10
|
+
export declare class BadResponseError extends Error {
|
|
11
|
+
readonly endpoint: string;
|
|
12
|
+
readonly length: number;
|
|
13
|
+
constructor(endpoint: string, length: number);
|
|
14
|
+
}
|
|
15
|
+
export interface PropertyDataKey {
|
|
16
|
+
encryptedKey: string;
|
|
17
|
+
createdAt: string;
|
|
18
|
+
updatedAt: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function loadAccountKey(accountId: string): Promise<PropertyDataKey | null>;
|
|
21
|
+
export declare function resolveAccountApiKey(accountId: string): Promise<string>;
|
|
22
|
+
export interface CallOptions {
|
|
23
|
+
endpoint: string;
|
|
24
|
+
toolName: string;
|
|
25
|
+
accountId: string;
|
|
26
|
+
params: Record<string, string | number | undefined>;
|
|
27
|
+
}
|
|
28
|
+
export declare function propertyDataCall(opts: CallOptions): Promise<string>;
|
|
29
|
+
//# sourceMappingURL=propertydata-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propertydata-api.d.ts","sourceRoot":"","sources":["../../src/lib/propertydata-api.ts"],"names":[],"mappings":"AAkBA,qBAAa,qBAAsB,SAAQ,KAAK;;CAK/C;AAED,qBAAa,iBAAkB,SAAQ,KAAK;aAExB,MAAM,EAAE,MAAM;aACd,QAAQ,EAAE,MAAM;aAChB,eAAe,EAAE,MAAM;gBAFvB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM;CAK1C;AAED,qBAAa,gBAAiB,SAAQ,KAAK;aACb,QAAQ,EAAE,MAAM;aAAkB,MAAM,EAAE,MAAM;gBAAhD,QAAQ,EAAE,MAAM,EAAkB,MAAM,EAAE,MAAM;CAI7E;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAoBvF;AAED,wBAAsB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI7E;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;CACrD;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAkDzE"}
|