@rubytech/create-maxy-code 0.1.125 → 0.1.127
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/index.js +23 -1
- package/package.json +2 -2
- package/payload/platform/config/brand.json +20 -1
- package/payload/platform/lib/aeo-llms-txt-writer/dist/index.d.ts +33 -0
- package/payload/platform/lib/aeo-llms-txt-writer/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/aeo-llms-txt-writer/dist/index.js +119 -0
- package/payload/platform/lib/aeo-llms-txt-writer/dist/index.js.map +1 -0
- package/payload/platform/lib/aeo-llms-txt-writer/src/index.ts +172 -0
- package/payload/platform/lib/aeo-llms-txt-writer/tsconfig.json +8 -0
- package/payload/platform/lib/graph-style/dist/index.d.ts +78 -0
- package/payload/platform/lib/graph-style/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/graph-style/dist/index.js +296 -0
- package/payload/platform/lib/graph-style/dist/index.js.map +1 -0
- package/payload/platform/lib/graph-style/src/__tests__/parity.test.ts +114 -0
- package/payload/platform/lib/graph-style/src/index.ts +307 -0
- package/payload/platform/lib/graph-style/tsconfig.json +9 -0
- package/payload/platform/lib/graph-style/vitest.config.ts +9 -0
- package/payload/platform/package-lock.json +318 -0
- package/payload/platform/package.json +3 -2
- package/payload/platform/plugins/.claude-plugin/marketplace.json +5 -0
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +4 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +73 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/publish-site.d.ts +34 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/publish-site.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/publish-site.js +176 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/publish-site.js.map +1 -0
- package/payload/platform/plugins/admin/skills/publish-site/SKILL.md +19 -57
- package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.d.ts +5 -38
- package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.d.ts.map +1 -1
- package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.js +7 -114
- package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.js.map +1 -1
- package/payload/platform/plugins/docs/references/visitor-graph.md +4 -3
- package/payload/platform/plugins/graph-viewer/.claude-plugin/plugin.json +8 -0
- package/payload/platform/plugins/graph-viewer/PLUGIN.md +56 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/index.d.ts +7 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/index.js +74 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/lib/neo4j.d.ts +5 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/lib/neo4j.d.ts.map +1 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/lib/neo4j.js +43 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/lib/neo4j.js.map +1 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/render/draw.d.ts +28 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/render/draw.d.ts.map +1 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/render/draw.js +73 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/render/draw.js.map +1 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/render/layout.d.ts +40 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/render/layout.d.ts.map +1 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/render/layout.js +77 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/render/layout.js.map +1 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/tools/graph-render.d.ts +45 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/tools/graph-render.d.ts.map +1 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/tools/graph-render.js +170 -0
- package/payload/platform/plugins/graph-viewer/mcp/dist/tools/graph-render.js.map +1 -0
- package/payload/platform/plugins/graph-viewer/mcp/package.json +25 -0
- package/payload/platform/plugins/graph-viewer/mcp/vitest.config.ts +8 -0
- package/payload/platform/plugins/graph-viewer/skills/render-graph/SKILL.md +35 -0
- package/payload/platform/scripts/check-plugin-tools-mcp-consistency.mjs +136 -0
- package/payload/platform/templates/specialists/agents/content-producer.md +3 -3
- package/payload/server/public/assets/{admin-D6IfAzYY.js → admin-FcRHAL-3.js} +7 -7
- package/payload/server/public/assets/{data-BGbQyufe.js → data-Ds37mflX.js} +1 -1
- package/payload/server/public/assets/{graph-D-1lRTeL.js → graph-CmWRhaiS.js} +1 -1
- package/payload/server/public/assets/graph-labels-Ch2r00Gt.js +1 -0
- package/payload/server/public/assets/page-BOtNny_4.js +51 -0
- package/payload/server/public/assets/page-BcHhJXUt.js +1 -0
- package/payload/server/public/consent.css +97 -0
- package/payload/server/public/consent.js +259 -0
- package/payload/server/public/data.html +3 -3
- package/payload/server/public/graph.html +3 -3
- package/payload/server/public/index.html +4 -4
- package/payload/server/public/privacy.html +68 -5
- package/payload/server/public/v.js +53 -0
- package/payload/server/server.js +465 -176
- package/payload/server/public/assets/graph-labels-BRXJHNYE.js +0 -1
- package/payload/server/public/assets/page-B4oirCvn.js +0 -1
- package/payload/server/public/assets/page-FmJ7PIYx.js +0 -51
package/payload/server/server.js
CHANGED
|
@@ -365,6 +365,239 @@ var require_dist = __commonJS({
|
|
|
365
365
|
}
|
|
366
366
|
});
|
|
367
367
|
|
|
368
|
+
// ../lib/graph-style/dist/index.js
|
|
369
|
+
var require_dist2 = __commonJS({
|
|
370
|
+
"../lib/graph-style/dist/index.js"(exports) {
|
|
371
|
+
"use strict";
|
|
372
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
373
|
+
exports.ALL_GRAPH_LABELS = exports.FALLBACK_LABEL_COLOUR = exports.GRAPH_LABEL_COLOURS = void 0;
|
|
374
|
+
exports.pickDisplayLabel = pickDisplayLabel2;
|
|
375
|
+
exports.colourForLabel = colourForLabel2;
|
|
376
|
+
exports.resolveNodeColour = resolveNodeColour2;
|
|
377
|
+
exports.formatRunTimestamp = formatRunTimestamp;
|
|
378
|
+
exports.formatMessageTimestamp = formatMessageTimestamp;
|
|
379
|
+
exports.pickShortLabel = pickShortLabel;
|
|
380
|
+
exports.pickDisplayName = pickDisplayName;
|
|
381
|
+
exports.GRAPH_LABEL_COLOURS = {
|
|
382
|
+
// Business identity — slate-blue family
|
|
383
|
+
LocalBusiness: "#4F6B8A",
|
|
384
|
+
Service: "#6B85A0",
|
|
385
|
+
PriceSpecification: "#8AA0B8",
|
|
386
|
+
OpeningHoursSpecification: "#A8BACE",
|
|
387
|
+
// Estate-agent ontology. Listing/Property share the business slate-blue
|
|
388
|
+
// family; Viewing/Offer are transactional events placed in a warm amber
|
|
389
|
+
// family distinct from Agent and from the dusty-rose Task/Project/Event
|
|
390
|
+
// hues so the legend reads them as a separate band.
|
|
391
|
+
Listing: "#3F5670",
|
|
392
|
+
Property: "#5C7A99",
|
|
393
|
+
Viewing: "#D4A574",
|
|
394
|
+
Offer: "#B08850",
|
|
395
|
+
// External business entity — schema:Organization, written by memory-write
|
|
396
|
+
// as the Supplier label. Warm tobacco — distinct hue from internal-business
|
|
397
|
+
// slates so external entities are scannable at a glance.
|
|
398
|
+
Organization: "#8A6B47",
|
|
399
|
+
// People — terracotta family (warm, human)
|
|
400
|
+
Person: "#B86E4A",
|
|
401
|
+
UserProfile: "#D08960",
|
|
402
|
+
Preference: "#DFA67A",
|
|
403
|
+
AdminUser: "#8C5230",
|
|
404
|
+
AccessGrant: "#66381F",
|
|
405
|
+
// Knowledge — moss family (organic)
|
|
406
|
+
KnowledgeDocument: "#6E8A5A",
|
|
407
|
+
// chunked WhatsApp/messaging archive parent. Sits in the
|
|
408
|
+
// knowledge moss family because it's structurally a document parent
|
|
409
|
+
// (HAS_SECTION → :Section:Conversation chunks); the conversational
|
|
410
|
+
// plum family is reserved for the live Conversation/Message labels.
|
|
411
|
+
ConversationArchive: "#82A06A",
|
|
412
|
+
Section: "#8AA876",
|
|
413
|
+
Chunk: "#A6C194",
|
|
414
|
+
DigitalDocument: "#5A7548",
|
|
415
|
+
CreativeWork: "#B5C9A2",
|
|
416
|
+
Question: "#C7D6B5",
|
|
417
|
+
FAQPage: "#95B385",
|
|
418
|
+
DefinedTerm: "#76906A",
|
|
419
|
+
Review: "#3F5A2E",
|
|
420
|
+
ImageObject: "#A0BB8C",
|
|
421
|
+
// Conversational — muted plum/lavender family.
|
|
422
|
+
// Pairwise-distinctness invariants enforced by the UI test
|
|
423
|
+
// graph-labels.test.ts; UserMessage matches Preference (Person/family cue,
|
|
424
|
+
// the one intentional duplicate in the registry).
|
|
425
|
+
Conversation: "#6B5A85",
|
|
426
|
+
AdminConversation: "#4F4070",
|
|
427
|
+
PublicConversation: "#8A75A8",
|
|
428
|
+
Message: "#6B7280",
|
|
429
|
+
UserMessage: "#DFA67A",
|
|
430
|
+
AssistantMessage: "#C9A876",
|
|
431
|
+
ToolCall: "#B5ABCB",
|
|
432
|
+
// Tasks / projects / events — dusty rose family
|
|
433
|
+
Task: "#B0617A",
|
|
434
|
+
Project: "#8E4A60",
|
|
435
|
+
Event: "#C68095",
|
|
436
|
+
// Workflows — muted teal
|
|
437
|
+
Workflow: "#3A6F77",
|
|
438
|
+
WorkflowStep: "#5A8E96",
|
|
439
|
+
WorkflowRun: "#7AAAB2",
|
|
440
|
+
StepResult: "#9CC4CB",
|
|
441
|
+
// Email — muted moss, hue-adjacent to Knowledge but lower-saturation
|
|
442
|
+
// and warmer; never co-rendered with KnowledgeDocument.
|
|
443
|
+
Email: "#6F7F4A",
|
|
444
|
+
EmailAccount: "#91A063",
|
|
445
|
+
// Public-agent projection — burnished bronze sits between
|
|
446
|
+
// people-terracotta and email-moss but shares neither hue.
|
|
447
|
+
Agent: "#B8893D"
|
|
448
|
+
};
|
|
449
|
+
exports.FALLBACK_LABEL_COLOUR = "#94A3B8";
|
|
450
|
+
exports.ALL_GRAPH_LABELS = Object.freeze(Object.keys(exports.GRAPH_LABEL_COLOURS));
|
|
451
|
+
function pickDisplayLabel2(labels) {
|
|
452
|
+
for (let i = 1; i < labels.length; i++) {
|
|
453
|
+
if (Object.prototype.hasOwnProperty.call(exports.GRAPH_LABEL_COLOURS, labels[i])) {
|
|
454
|
+
return labels[i];
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
return labels[0] ?? null;
|
|
458
|
+
}
|
|
459
|
+
function colourForLabel2(label) {
|
|
460
|
+
return exports.GRAPH_LABEL_COLOURS[label] ?? exports.FALLBACK_LABEL_COLOUR;
|
|
461
|
+
}
|
|
462
|
+
function resolveNodeColour2(labels) {
|
|
463
|
+
const displayLabel = pickDisplayLabel2(labels);
|
|
464
|
+
const colour = displayLabel ? colourForLabel2(displayLabel) : exports.FALLBACK_LABEL_COLOUR;
|
|
465
|
+
let driftCandidates = 0;
|
|
466
|
+
for (let i = 1; i < labels.length; i++) {
|
|
467
|
+
if (Object.prototype.hasOwnProperty.call(exports.GRAPH_LABEL_COLOURS, labels[i])) {
|
|
468
|
+
driftCandidates++;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
return { displayLabel, colour, driftCandidates };
|
|
472
|
+
}
|
|
473
|
+
var ISO_MINUTE_RE = /^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2})/;
|
|
474
|
+
var ISO_SECOND_RE = /^\d{4}-\d{2}-\d{2}T(\d{2}:\d{2}:\d{2})/;
|
|
475
|
+
function formatRunTimestamp(iso) {
|
|
476
|
+
const m = iso.match(ISO_MINUTE_RE);
|
|
477
|
+
if (!m)
|
|
478
|
+
return null;
|
|
479
|
+
return `${m[1]} ${m[2]}`;
|
|
480
|
+
}
|
|
481
|
+
function formatMessageTimestamp(iso) {
|
|
482
|
+
const m = iso.match(ISO_SECOND_RE);
|
|
483
|
+
if (!m)
|
|
484
|
+
return null;
|
|
485
|
+
return m[1];
|
|
486
|
+
}
|
|
487
|
+
function pickShortLabel(node) {
|
|
488
|
+
const props = node.properties;
|
|
489
|
+
const primaryLabel = node.labels[0];
|
|
490
|
+
if (primaryLabel === "ToolCall") {
|
|
491
|
+
const v = props.toolName;
|
|
492
|
+
if (typeof v === "string" && v.length > 0) {
|
|
493
|
+
return v.length > 24 ? v.slice(0, 24) + "\u2026" : v;
|
|
494
|
+
}
|
|
495
|
+
} else if (primaryLabel === "WorkflowRun") {
|
|
496
|
+
const v = props.startedAt;
|
|
497
|
+
if (typeof v === "string" && v.length > 0) {
|
|
498
|
+
const ts = formatRunTimestamp(v);
|
|
499
|
+
if (ts)
|
|
500
|
+
return ts;
|
|
501
|
+
}
|
|
502
|
+
} else if (primaryLabel === "WorkflowStep") {
|
|
503
|
+
const v = props.label;
|
|
504
|
+
if (typeof v === "string" && v.length > 0) {
|
|
505
|
+
return v.length > 24 ? v.slice(0, 24) + "\u2026" : v;
|
|
506
|
+
}
|
|
507
|
+
} else if (primaryLabel === "Person") {
|
|
508
|
+
const given = typeof props.givenName === "string" ? props.givenName : "";
|
|
509
|
+
const family = typeof props.familyName === "string" ? props.familyName : "";
|
|
510
|
+
const full = [given, family].filter((s) => s.length > 0).join(" ");
|
|
511
|
+
if (full.length > 0) {
|
|
512
|
+
return full.length > 24 ? full.slice(0, 24) + "\u2026" : full;
|
|
513
|
+
}
|
|
514
|
+
} else if (primaryLabel === "Agent") {
|
|
515
|
+
const dn = typeof props.displayName === "string" ? props.displayName : "";
|
|
516
|
+
const slug = typeof props.slug === "string" ? props.slug : "";
|
|
517
|
+
const v = dn.length > 0 ? dn : slug;
|
|
518
|
+
if (v.length > 0) {
|
|
519
|
+
return v.length > 24 ? v.slice(0, 24) + "\u2026" : v;
|
|
520
|
+
}
|
|
521
|
+
} else if (primaryLabel === "Message") {
|
|
522
|
+
const role = typeof props.role === "string" ? props.role : "";
|
|
523
|
+
const roleShort = role === "user" ? "user" : role === "assistant" ? "asst" : role === "system" ? "sys" : role === "tool" ? "tool" : null;
|
|
524
|
+
const createdAt = typeof props.createdAt === "string" ? props.createdAt : "";
|
|
525
|
+
if (roleShort && createdAt) {
|
|
526
|
+
const ts = formatMessageTimestamp(createdAt);
|
|
527
|
+
if (ts)
|
|
528
|
+
return `${roleShort} ${ts}`;
|
|
529
|
+
}
|
|
530
|
+
} else if (primaryLabel === "ConversationArchive") {
|
|
531
|
+
const t = typeof props.title === "string" ? props.title : "";
|
|
532
|
+
if (t.length > 0) {
|
|
533
|
+
return t.length > 24 ? t.slice(0, 24) + "\u2026" : t;
|
|
534
|
+
}
|
|
535
|
+
return primaryLabel;
|
|
536
|
+
}
|
|
537
|
+
for (const k of ["name", "title", "summary", "givenName", "subject", "text"]) {
|
|
538
|
+
const v = props[k];
|
|
539
|
+
if (typeof v === "string" && v.length > 0) {
|
|
540
|
+
return v.length > 24 ? v.slice(0, 24) + "\u2026" : v;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
if (primaryLabel === "Conversation") {
|
|
544
|
+
const id = typeof props.conversationId === "string" ? props.conversationId : null;
|
|
545
|
+
if (id)
|
|
546
|
+
return `Conv ${id.slice(0, 8)}`;
|
|
547
|
+
}
|
|
548
|
+
return primaryLabel ?? "\u2026";
|
|
549
|
+
}
|
|
550
|
+
function pickDisplayName(node) {
|
|
551
|
+
const props = node.properties;
|
|
552
|
+
const primaryLabel = node.labels[0];
|
|
553
|
+
if (primaryLabel === "ToolCall") {
|
|
554
|
+
const v = props.toolName;
|
|
555
|
+
if (typeof v === "string" && v.length > 0)
|
|
556
|
+
return v;
|
|
557
|
+
} else if (primaryLabel === "WorkflowRun") {
|
|
558
|
+
const v = props.startedAt;
|
|
559
|
+
if (typeof v === "string" && v.length > 0) {
|
|
560
|
+
const ts = formatRunTimestamp(v);
|
|
561
|
+
if (ts)
|
|
562
|
+
return ts;
|
|
563
|
+
}
|
|
564
|
+
} else if (primaryLabel === "WorkflowStep") {
|
|
565
|
+
const v = props.label;
|
|
566
|
+
if (typeof v === "string" && v.length > 0)
|
|
567
|
+
return v;
|
|
568
|
+
} else if (primaryLabel === "Person") {
|
|
569
|
+
const given = typeof props.givenName === "string" ? props.givenName : "";
|
|
570
|
+
const family = typeof props.familyName === "string" ? props.familyName : "";
|
|
571
|
+
const full = [given, family].filter((s) => s.length > 0).join(" ");
|
|
572
|
+
if (full.length > 0)
|
|
573
|
+
return full;
|
|
574
|
+
} else if (primaryLabel === "Agent") {
|
|
575
|
+
const dn = typeof props.displayName === "string" ? props.displayName : "";
|
|
576
|
+
const slug = typeof props.slug === "string" ? props.slug : "";
|
|
577
|
+
const v = dn.length > 0 ? dn : slug;
|
|
578
|
+
if (v.length > 0)
|
|
579
|
+
return v;
|
|
580
|
+
} else if (primaryLabel === "ConversationArchive") {
|
|
581
|
+
const t = typeof props.title === "string" ? props.title : "";
|
|
582
|
+
if (t.length > 0)
|
|
583
|
+
return t;
|
|
584
|
+
return primaryLabel;
|
|
585
|
+
}
|
|
586
|
+
for (const k of ["name", "title", "summary", "givenName", "subject", "text"]) {
|
|
587
|
+
const v = props[k];
|
|
588
|
+
if (typeof v === "string" && v.length > 0)
|
|
589
|
+
return v;
|
|
590
|
+
}
|
|
591
|
+
if (primaryLabel === "Conversation") {
|
|
592
|
+
const id = typeof props.conversationId === "string" ? props.conversationId : null;
|
|
593
|
+
if (id)
|
|
594
|
+
return `Conv ${id.slice(0, 8)}`;
|
|
595
|
+
}
|
|
596
|
+
return primaryLabel ?? "\u2026";
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
});
|
|
600
|
+
|
|
368
601
|
// node_modules/hono/dist/utils/mime.js
|
|
369
602
|
var getMimeType = (filename, mimes = baseMimes) => {
|
|
370
603
|
const regexp = /\.([a-zA-Z0-9]+?)$/;
|
|
@@ -9943,97 +10176,8 @@ var graph_search_default = app19;
|
|
|
9943
10176
|
import neo4j from "neo4j-driver";
|
|
9944
10177
|
|
|
9945
10178
|
// app/lib/graph-labels.ts
|
|
9946
|
-
var
|
|
9947
|
-
|
|
9948
|
-
LocalBusiness: "#4F6B8A",
|
|
9949
|
-
Service: "#6B85A0",
|
|
9950
|
-
PriceSpecification: "#8AA0B8",
|
|
9951
|
-
OpeningHoursSpecification: "#A8BACE",
|
|
9952
|
-
// Estate-agent ontology (Task 358). :Listing and :Property
|
|
9953
|
-
// share the business slate-blue family (they describe a business's
|
|
9954
|
-
// inventory). :Viewing and :Offer are transactional events — placed in
|
|
9955
|
-
// a warm amber family distinct from Agent (#B8893D) and the dusty-rose
|
|
9956
|
-
// Task/Project/Event hues so the legend reads them as a separate band.
|
|
9957
|
-
Listing: "#3F5670",
|
|
9958
|
-
Property: "#5C7A99",
|
|
9959
|
-
Viewing: "#D4A574",
|
|
9960
|
-
Offer: "#B08850",
|
|
9961
|
-
// External business entity — schema:Organization, written by memory-write
|
|
9962
|
-
// as the Supplier label (per platform/plugins/memory/references/schema-base.md).
|
|
9963
|
-
// Warm tobacco — distinct hue from internal-business slates so external
|
|
9964
|
-
// entities are scannable at a glance.
|
|
9965
|
-
Organization: "#8A6B47",
|
|
9966
|
-
// People — terracotta family (warm, human)
|
|
9967
|
-
Person: "#B86E4A",
|
|
9968
|
-
UserProfile: "#D08960",
|
|
9969
|
-
Preference: "#DFA67A",
|
|
9970
|
-
AdminUser: "#8C5230",
|
|
9971
|
-
AccessGrant: "#66381F",
|
|
9972
|
-
// Knowledge — moss family (organic)
|
|
9973
|
-
KnowledgeDocument: "#6E8A5A",
|
|
9974
|
-
// chunked WhatsApp/messaging archive parent. Sits in the
|
|
9975
|
-
// knowledge moss family because it's structurally a document parent
|
|
9976
|
-
// (HAS_SECTION → :Section:Conversation chunks); the conversational
|
|
9977
|
-
// plum family is reserved for the live Conversation/Message labels.
|
|
9978
|
-
ConversationArchive: "#82A06A",
|
|
9979
|
-
Section: "#8AA876",
|
|
9980
|
-
Chunk: "#A6C194",
|
|
9981
|
-
DigitalDocument: "#5A7548",
|
|
9982
|
-
CreativeWork: "#B5C9A2",
|
|
9983
|
-
Question: "#C7D6B5",
|
|
9984
|
-
FAQPage: "#95B385",
|
|
9985
|
-
DefinedTerm: "#76906A",
|
|
9986
|
-
Review: "#3F5A2E",
|
|
9987
|
-
ImageObject: "#A0BB8C",
|
|
9988
|
-
// Conversational — muted plum/lavender family
|
|
9989
|
-
//
|
|
9990
|
-
// Pairwise-distinctness invariants (carried forward
|
|
9991
|
-
// palette):
|
|
9992
|
-
// - Four sublabelled conversation/message labels (AdminConversation,
|
|
9993
|
-
// PublicConversation, UserMessage, AssistantMessage) are pairwise
|
|
9994
|
-
// distinct on canvas.
|
|
9995
|
-
// - UserMessage matches Preference (Person/family cue: a user-authored
|
|
9996
|
-
// message inherits the person family colour). This is the one
|
|
9997
|
-
// intentional duplicate in the registry — see the
|
|
9998
|
-
// `INTENTIONAL_DUPLICATES` set in `graph-labels.test.ts`.
|
|
9999
|
-
// - Conversation base distinct from both AdminConversation and
|
|
10000
|
-
// PublicConversation so base-Conversation rows don't visually
|
|
10001
|
-
// collide with the sublabelled split.
|
|
10002
|
-
// - Message base distinct from PublicConversation (`#A78BFA`
|
|
10003
|
-
// collision class).
|
|
10004
|
-
Conversation: "#6B5A85",
|
|
10005
|
-
AdminConversation: "#4F4070",
|
|
10006
|
-
PublicConversation: "#8A75A8",
|
|
10007
|
-
Message: "#6B7280",
|
|
10008
|
-
UserMessage: "#DFA67A",
|
|
10009
|
-
AssistantMessage: "#C9A876",
|
|
10010
|
-
ToolCall: "#B5ABCB",
|
|
10011
|
-
// Tasks / projects / events — dusty rose family
|
|
10012
|
-
Task: "#B0617A",
|
|
10013
|
-
Project: "#8E4A60",
|
|
10014
|
-
Event: "#C68095",
|
|
10015
|
-
// Workflows — muted teal
|
|
10016
|
-
Workflow: "#3A6F77",
|
|
10017
|
-
WorkflowStep: "#5A8E96",
|
|
10018
|
-
WorkflowRun: "#7AAAB2",
|
|
10019
|
-
StepResult: "#9CC4CB",
|
|
10020
|
-
// Email — muted moss (hue-adjacent to Knowledge but lower-saturation
|
|
10021
|
-
// and warmer; never co-rendered with KnowledgeDocument so visual
|
|
10022
|
-
// confusion doesn't apply, but kept distinguishable for the legend)
|
|
10023
|
-
Email: "#6F7F4A",
|
|
10024
|
-
EmailAccount: "#91A063",
|
|
10025
|
-
// Public-agent projection — burnished bronze sits between
|
|
10026
|
-
// people-terracotta and email-moss but shares neither hue, signalling
|
|
10027
|
-
// "operator-defined persona that traverses to KnowledgeDocuments,
|
|
10028
|
-
// Conversations, and other entities" without colliding with any existing
|
|
10029
|
-
// family. Pairs with the four owned KnowledgeDocument projections rendered
|
|
10030
|
-
// in the moss family — visual contrast cues the operator that the agent
|
|
10031
|
-
// node is a different kind of thing from its IDENTITY/SOUL/KNOWLEDGE docs.
|
|
10032
|
-
Agent: "#B8893D"
|
|
10033
|
-
};
|
|
10034
|
-
var ALL_GRAPH_LABELS = Object.freeze(
|
|
10035
|
-
Object.keys(GRAPH_LABEL_COLOURS)
|
|
10036
|
-
);
|
|
10179
|
+
var import_dist2 = __toESM(require_dist2(), 1);
|
|
10180
|
+
var import_dist3 = __toESM(require_dist2(), 1);
|
|
10037
10181
|
var HIDDEN_BY_DEFAULT_LABELS = Object.freeze(
|
|
10038
10182
|
/* @__PURE__ */ new Set(["Chunk", "GraphPreference"])
|
|
10039
10183
|
);
|
|
@@ -10089,7 +10233,7 @@ var EXCLUDED_EDGE_TYPES = Object.freeze(
|
|
|
10089
10233
|
])
|
|
10090
10234
|
);
|
|
10091
10235
|
function isKnownLabel(label) {
|
|
10092
|
-
return Object.prototype.hasOwnProperty.call(GRAPH_LABEL_COLOURS, label);
|
|
10236
|
+
return Object.prototype.hasOwnProperty.call(import_dist3.GRAPH_LABEL_COLOURS, label);
|
|
10093
10237
|
}
|
|
10094
10238
|
function isHiddenByDefault(label) {
|
|
10095
10239
|
return HIDDEN_BY_DEFAULT_LABELS.has(label);
|
|
@@ -12252,11 +12396,161 @@ function verifyVisitorToken(token, now = Date.now()) {
|
|
|
12252
12396
|
var VISITOR_COOKIE_NAME = "mxy_v";
|
|
12253
12397
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
12254
12398
|
|
|
12399
|
+
// app/lib/brand-config.ts
|
|
12400
|
+
import { existsSync as existsSync22, readFileSync as readFileSync19 } from "fs";
|
|
12401
|
+
import { join as join14 } from "path";
|
|
12402
|
+
var cached2 = null;
|
|
12403
|
+
var cachedAttempted = false;
|
|
12404
|
+
function readBrandConfig() {
|
|
12405
|
+
if (cachedAttempted) return cached2;
|
|
12406
|
+
cachedAttempted = true;
|
|
12407
|
+
const platformRoot = process.env.MAXY_PLATFORM_ROOT;
|
|
12408
|
+
if (!platformRoot) return null;
|
|
12409
|
+
const brandPath = join14(platformRoot, "config", "brand.json");
|
|
12410
|
+
if (!existsSync22(brandPath)) return null;
|
|
12411
|
+
try {
|
|
12412
|
+
cached2 = JSON.parse(readFileSync19(brandPath, "utf-8"));
|
|
12413
|
+
return cached2;
|
|
12414
|
+
} catch {
|
|
12415
|
+
return null;
|
|
12416
|
+
}
|
|
12417
|
+
}
|
|
12418
|
+
|
|
12419
|
+
// server/routes/visitor-consent.ts
|
|
12420
|
+
var app35 = new Hono();
|
|
12421
|
+
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
12422
|
+
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
12423
|
+
var DEFAULT_CONSENT_COPY = {
|
|
12424
|
+
title: "Before you browse",
|
|
12425
|
+
body: "We use a small first-party script to count page views, scrolls and clicks on this listing. Nothing is shared with third parties. You can change your mind at any time.",
|
|
12426
|
+
accept: "Accept",
|
|
12427
|
+
reject: "Reject",
|
|
12428
|
+
manage: "Manage cookies",
|
|
12429
|
+
policyLinkText: "Read the cookie policy",
|
|
12430
|
+
policyHref: "/privacy.html#cookies"
|
|
12431
|
+
};
|
|
12432
|
+
var DEFAULT_CONSENT_PALETTE = {
|
|
12433
|
+
bg: "#FFFFFF",
|
|
12434
|
+
fg: "#1F1F1F",
|
|
12435
|
+
accent: "#1F1F1F",
|
|
12436
|
+
accentFg: "#FFFFFF",
|
|
12437
|
+
border: "#E5E5E2"
|
|
12438
|
+
};
|
|
12439
|
+
function getOrigin(c) {
|
|
12440
|
+
return c.req.header("origin") ?? c.req.header("referer") ?? "";
|
|
12441
|
+
}
|
|
12442
|
+
function setCorsHeaders(c, origin) {
|
|
12443
|
+
if (origin) c.header("Access-Control-Allow-Origin", origin);
|
|
12444
|
+
c.header("Access-Control-Allow-Credentials", "true");
|
|
12445
|
+
c.header("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
|
|
12446
|
+
c.header("Access-Control-Allow-Headers", "Content-Type");
|
|
12447
|
+
c.header("Vary", "Origin");
|
|
12448
|
+
}
|
|
12449
|
+
function parseConsent(body) {
|
|
12450
|
+
if (!body || typeof body !== "object") return null;
|
|
12451
|
+
const b = body;
|
|
12452
|
+
if (b.decision !== "yes" && b.decision !== "no") return null;
|
|
12453
|
+
const v = typeof b.v === "string" && b.v.length > 0 && b.v.length <= 2048 ? b.v : null;
|
|
12454
|
+
return { decision: b.decision, v };
|
|
12455
|
+
}
|
|
12456
|
+
function siteSlugFromReferer(referer) {
|
|
12457
|
+
try {
|
|
12458
|
+
const u = new URL(referer);
|
|
12459
|
+
const parts = u.pathname.split("/").filter(Boolean);
|
|
12460
|
+
return parts[parts.length - 1]?.slice(0, 120) ?? "";
|
|
12461
|
+
} catch {
|
|
12462
|
+
return "";
|
|
12463
|
+
}
|
|
12464
|
+
}
|
|
12465
|
+
app35.options("/consent", (c) => {
|
|
12466
|
+
const origin = getOrigin(c);
|
|
12467
|
+
setCorsHeaders(c, origin);
|
|
12468
|
+
return c.body(null, 204);
|
|
12469
|
+
});
|
|
12470
|
+
app35.options("/brand-config", (c) => {
|
|
12471
|
+
const origin = getOrigin(c);
|
|
12472
|
+
setCorsHeaders(c, origin);
|
|
12473
|
+
return c.body(null, 204);
|
|
12474
|
+
});
|
|
12475
|
+
app35.post("/consent", async (c) => {
|
|
12476
|
+
const origin = getOrigin(c);
|
|
12477
|
+
setCorsHeaders(c, origin);
|
|
12478
|
+
let raw;
|
|
12479
|
+
try {
|
|
12480
|
+
raw = await c.req.json();
|
|
12481
|
+
} catch {
|
|
12482
|
+
console.error("[consent-error] reason=bad-json");
|
|
12483
|
+
return c.text("Bad Request", 400);
|
|
12484
|
+
}
|
|
12485
|
+
const parsed = parseConsent(raw);
|
|
12486
|
+
if (!parsed) {
|
|
12487
|
+
console.error("[consent-error] reason=bad-body");
|
|
12488
|
+
return c.text("Bad Request", 400);
|
|
12489
|
+
}
|
|
12490
|
+
const referer = c.req.header("referer") ?? "";
|
|
12491
|
+
const site = siteSlugFromReferer(referer);
|
|
12492
|
+
const brand = readBrandConfig();
|
|
12493
|
+
const brandName = brand?.productName ?? "-";
|
|
12494
|
+
const cookies = [];
|
|
12495
|
+
cookies.push(
|
|
12496
|
+
`${CONSENT_COOKIE_NAME}=${parsed.decision}; Max-Age=${CONSENT_COOKIE_MAX_AGE_SECONDS}; Path=/; SameSite=Lax; Secure`
|
|
12497
|
+
);
|
|
12498
|
+
let tokenBound = false;
|
|
12499
|
+
if (parsed.decision === "yes" && parsed.v) {
|
|
12500
|
+
const verify = verifyVisitorToken(parsed.v);
|
|
12501
|
+
if (verify.ok) {
|
|
12502
|
+
cookies.push(
|
|
12503
|
+
`${VISITOR_COOKIE_NAME}=${parsed.v}; Max-Age=${VISITOR_COOKIE_MAX_AGE_SECONDS}; Path=/; SameSite=Lax; Secure; HttpOnly`
|
|
12504
|
+
);
|
|
12505
|
+
tokenBound = true;
|
|
12506
|
+
console.log(`[token-bind] via=consent site=${site} person=${verify.personId}`);
|
|
12507
|
+
} else {
|
|
12508
|
+
console.error(`[token-bind] reject reason=${verify.reason} via=consent site=${site}`);
|
|
12509
|
+
}
|
|
12510
|
+
}
|
|
12511
|
+
for (const cookie of cookies) c.header("Set-Cookie", cookie, { append: true });
|
|
12512
|
+
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
12513
|
+
return c.body(null, 204);
|
|
12514
|
+
});
|
|
12515
|
+
app35.get("/brand-config", (c) => {
|
|
12516
|
+
const origin = getOrigin(c);
|
|
12517
|
+
setCorsHeaders(c, origin);
|
|
12518
|
+
const brand = readBrandConfig();
|
|
12519
|
+
const consent = brand?.consent ?? {};
|
|
12520
|
+
const copy = { ...DEFAULT_CONSENT_COPY, ...consent.copy ?? {} };
|
|
12521
|
+
const palette = { ...DEFAULT_CONSENT_PALETTE, ...consent.palette ?? {} };
|
|
12522
|
+
c.header("Cache-Control", "public, max-age=300");
|
|
12523
|
+
return c.json({ consent: { copy, palette } });
|
|
12524
|
+
});
|
|
12525
|
+
var visitor_consent_default = app35;
|
|
12526
|
+
|
|
12255
12527
|
// server/routes/listings.ts
|
|
12528
|
+
function getCookie(headerValue, name) {
|
|
12529
|
+
if (!headerValue) return null;
|
|
12530
|
+
for (const part of headerValue.split(";")) {
|
|
12531
|
+
const [k, ...rest] = part.trim().split("=");
|
|
12532
|
+
if (k === name) return rest.join("=");
|
|
12533
|
+
}
|
|
12534
|
+
return null;
|
|
12535
|
+
}
|
|
12536
|
+
function appendConsentParams(pageUrl, token) {
|
|
12537
|
+
try {
|
|
12538
|
+
const u = new URL(pageUrl);
|
|
12539
|
+
u.searchParams.set("consent", "needed");
|
|
12540
|
+
u.searchParams.set("v", token);
|
|
12541
|
+
return u.toString();
|
|
12542
|
+
} catch {
|
|
12543
|
+
const hashIdx = pageUrl.indexOf("#");
|
|
12544
|
+
const hash = hashIdx >= 0 ? pageUrl.slice(hashIdx) : "";
|
|
12545
|
+
const base = hashIdx >= 0 ? pageUrl.slice(0, hashIdx) : pageUrl;
|
|
12546
|
+
const sep4 = base.indexOf("?") >= 0 ? "&" : "?";
|
|
12547
|
+
return base + sep4 + `consent=needed&v=${encodeURIComponent(token)}` + hash;
|
|
12548
|
+
}
|
|
12549
|
+
}
|
|
12256
12550
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
12257
12551
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
12258
|
-
var
|
|
12259
|
-
|
|
12552
|
+
var app36 = new Hono();
|
|
12553
|
+
app36.get("/:slug/click", async (c) => {
|
|
12260
12554
|
const slug = c.req.param("slug") ?? "";
|
|
12261
12555
|
const rawSession = c.req.query("session") ?? "";
|
|
12262
12556
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -12297,45 +12591,33 @@ app35.get("/:slug/click", async (c) => {
|
|
|
12297
12591
|
console.error(`[property-card-click] reject reason=listing-not-found slug=${slug} sessionKey=${sessionKey} accountId=${account.accountId} status=404`);
|
|
12298
12592
|
return c.text("Not Found", 404);
|
|
12299
12593
|
}
|
|
12594
|
+
let redirectUrl = pageUrl;
|
|
12595
|
+
const consentCookie = getCookie(c.req.header("cookie"), CONSENT_COOKIE_NAME);
|
|
12596
|
+
const consented = consentCookie === "yes";
|
|
12300
12597
|
if (tokenParam) {
|
|
12301
12598
|
const verify = verifyVisitorToken(tokenParam);
|
|
12302
12599
|
if (verify.ok) {
|
|
12303
|
-
|
|
12304
|
-
|
|
12305
|
-
|
|
12306
|
-
|
|
12307
|
-
|
|
12600
|
+
if (consented) {
|
|
12601
|
+
c.header(
|
|
12602
|
+
"Set-Cookie",
|
|
12603
|
+
`${VISITOR_COOKIE_NAME}=${tokenParam}; Max-Age=${VISITOR_COOKIE_MAX_AGE_SECONDS}; Path=/; SameSite=Lax; Secure; HttpOnly`
|
|
12604
|
+
);
|
|
12605
|
+
console.log(`[token-bind] sessionKey=${sessionKey} person=${verify.personId} listingSlug=${slug}`);
|
|
12606
|
+
} else {
|
|
12607
|
+
redirectUrl = appendConsentParams(pageUrl, tokenParam);
|
|
12608
|
+
console.error(`[token-bind] reject reason=no-consent sessionKey=${sessionKey} person=${verify.personId} listingSlug=${slug}`);
|
|
12609
|
+
}
|
|
12308
12610
|
} else {
|
|
12309
12611
|
console.error(`[token-bind] reject reason=${verify.reason} sessionKey=${sessionKey} listingSlug=${slug}`);
|
|
12310
12612
|
}
|
|
12311
12613
|
}
|
|
12312
|
-
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
12313
|
-
return c.redirect(
|
|
12614
|
+
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
12615
|
+
return c.redirect(redirectUrl, 302);
|
|
12314
12616
|
});
|
|
12315
|
-
var listings_default =
|
|
12316
|
-
|
|
12317
|
-
// app/lib/brand-config.ts
|
|
12318
|
-
import { existsSync as existsSync22, readFileSync as readFileSync19 } from "fs";
|
|
12319
|
-
import { join as join14 } from "path";
|
|
12320
|
-
var cached2 = null;
|
|
12321
|
-
var cachedAttempted = false;
|
|
12322
|
-
function readBrandConfig() {
|
|
12323
|
-
if (cachedAttempted) return cached2;
|
|
12324
|
-
cachedAttempted = true;
|
|
12325
|
-
const platformRoot = process.env.MAXY_PLATFORM_ROOT;
|
|
12326
|
-
if (!platformRoot) return null;
|
|
12327
|
-
const brandPath = join14(platformRoot, "config", "brand.json");
|
|
12328
|
-
if (!existsSync22(brandPath)) return null;
|
|
12329
|
-
try {
|
|
12330
|
-
cached2 = JSON.parse(readFileSync19(brandPath, "utf-8"));
|
|
12331
|
-
return cached2;
|
|
12332
|
-
} catch {
|
|
12333
|
-
return null;
|
|
12334
|
-
}
|
|
12335
|
-
}
|
|
12617
|
+
var listings_default = app36;
|
|
12336
12618
|
|
|
12337
12619
|
// server/routes/visitor-event.ts
|
|
12338
|
-
var
|
|
12620
|
+
var app37 = new Hono();
|
|
12339
12621
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
12340
12622
|
var buckets = /* @__PURE__ */ new Map();
|
|
12341
12623
|
var RATE_LIMIT = 60;
|
|
@@ -12368,7 +12650,7 @@ function parseEvent(body) {
|
|
|
12368
12650
|
if (typeof e.ts !== "number" || !Number.isFinite(e.ts)) return null;
|
|
12369
12651
|
return e;
|
|
12370
12652
|
}
|
|
12371
|
-
function
|
|
12653
|
+
function getCookie2(c, name) {
|
|
12372
12654
|
const raw = c.req.header("cookie");
|
|
12373
12655
|
if (!raw) return null;
|
|
12374
12656
|
for (const part of raw.split(";")) {
|
|
@@ -12377,10 +12659,10 @@ function getCookie(c, name) {
|
|
|
12377
12659
|
}
|
|
12378
12660
|
return null;
|
|
12379
12661
|
}
|
|
12380
|
-
function
|
|
12662
|
+
function getOrigin2(c) {
|
|
12381
12663
|
return c.req.header("origin") ?? c.req.header("referer") ?? "";
|
|
12382
12664
|
}
|
|
12383
|
-
function
|
|
12665
|
+
function setCorsHeaders2(c, origin) {
|
|
12384
12666
|
if (origin) c.header("Access-Control-Allow-Origin", origin);
|
|
12385
12667
|
c.header("Access-Control-Allow-Credentials", "true");
|
|
12386
12668
|
c.header("Access-Control-Allow-Methods", "POST, OPTIONS");
|
|
@@ -12402,14 +12684,14 @@ function originAllowed(origin, allowlist) {
|
|
|
12402
12684
|
return false;
|
|
12403
12685
|
}
|
|
12404
12686
|
}
|
|
12405
|
-
|
|
12406
|
-
const origin =
|
|
12407
|
-
|
|
12687
|
+
app37.options("/event", (c) => {
|
|
12688
|
+
const origin = getOrigin2(c);
|
|
12689
|
+
setCorsHeaders2(c, origin);
|
|
12408
12690
|
return c.body(null, 204);
|
|
12409
12691
|
});
|
|
12410
|
-
|
|
12411
|
-
const origin =
|
|
12412
|
-
|
|
12692
|
+
app37.post("/event", async (c) => {
|
|
12693
|
+
const origin = getOrigin2(c);
|
|
12694
|
+
setCorsHeaders2(c, origin);
|
|
12413
12695
|
const ua = c.req.header("user-agent") ?? "";
|
|
12414
12696
|
if (BOT_UA_RE.test(ua)) {
|
|
12415
12697
|
console.error(`[v-event-error] reason=bot-ua ua=${JSON.stringify(ua.slice(0, 120))}`);
|
|
@@ -12432,6 +12714,11 @@ app36.post("/event", async (c) => {
|
|
|
12432
12714
|
console.error(`[v-event-error] reason=origin-mismatch origin=${JSON.stringify(origin)} ip=${ip}`);
|
|
12433
12715
|
return c.text("Forbidden", 403);
|
|
12434
12716
|
}
|
|
12717
|
+
const consentCookie = getCookie2(c, CONSENT_COOKIE_NAME);
|
|
12718
|
+
if (consentCookie !== "yes") {
|
|
12719
|
+
console.log(`[v-event] drop reason=no-consent consent=${consentCookie ?? "absent"} ip=${ip} origin=${JSON.stringify(origin)}`);
|
|
12720
|
+
return c.body(null, 204);
|
|
12721
|
+
}
|
|
12435
12722
|
let raw;
|
|
12436
12723
|
try {
|
|
12437
12724
|
raw = await c.req.json();
|
|
@@ -12444,7 +12731,7 @@ app36.post("/event", async (c) => {
|
|
|
12444
12731
|
console.error(`[v-event-error] reason=bad-event ip=${ip}`);
|
|
12445
12732
|
return c.text("Bad Request", 400);
|
|
12446
12733
|
}
|
|
12447
|
-
const cookieVal =
|
|
12734
|
+
const cookieVal = getCookie2(c, VISITOR_COOKIE_NAME);
|
|
12448
12735
|
let personId = null;
|
|
12449
12736
|
if (cookieVal) {
|
|
12450
12737
|
const v = verifyVisitorToken(cookieVal);
|
|
@@ -12474,7 +12761,7 @@ app36.post("/event", async (c) => {
|
|
|
12474
12761
|
});
|
|
12475
12762
|
}
|
|
12476
12763
|
console.log(
|
|
12477
|
-
`[visitor-event] type=${event.type} sessionId=${event.sid} visitorId=${event.vid} personId=${personId ?? "-"} path=${event.path ?? ""} label=${event.label ?? "-"} depth=${event.depth ?? "-"} ms=${event.ms ?? "-"}`
|
|
12764
|
+
`[visitor-event] type=${event.type} sessionId=${event.sid} visitorId=${event.vid} personId=${personId ?? "-"} consent=${consentCookie} path=${event.path ?? ""} label=${event.label ?? "-"} depth=${event.depth ?? "-"} ms=${event.ms ?? "-"}`
|
|
12478
12765
|
);
|
|
12479
12766
|
return c.body(null, 204);
|
|
12480
12767
|
});
|
|
@@ -12607,7 +12894,7 @@ async function writeEvent(opts) {
|
|
|
12607
12894
|
);
|
|
12608
12895
|
}
|
|
12609
12896
|
}
|
|
12610
|
-
var visitor_event_default =
|
|
12897
|
+
var visitor_event_default = app37;
|
|
12611
12898
|
|
|
12612
12899
|
// app/lib/graph-health.ts
|
|
12613
12900
|
var HOUR_MS = 60 * 60 * 1e3;
|
|
@@ -13044,9 +13331,9 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
|
13044
13331
|
function isPublicHost(host) {
|
|
13045
13332
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
13046
13333
|
}
|
|
13047
|
-
var
|
|
13048
|
-
|
|
13049
|
-
|
|
13334
|
+
var app38 = new Hono();
|
|
13335
|
+
app38.use("*", clientIpMiddleware);
|
|
13336
|
+
app38.use("*", async (c, next) => {
|
|
13050
13337
|
await next();
|
|
13051
13338
|
c.header("X-Content-Type-Options", "nosniff");
|
|
13052
13339
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -13056,7 +13343,7 @@ app37.use("*", async (c, next) => {
|
|
|
13056
13343
|
);
|
|
13057
13344
|
});
|
|
13058
13345
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
13059
|
-
|
|
13346
|
+
app38.use("*", async (c, next) => {
|
|
13060
13347
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
13061
13348
|
await next();
|
|
13062
13349
|
return;
|
|
@@ -13089,7 +13376,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
|
|
|
13089
13376
|
"/sites/"
|
|
13090
13377
|
];
|
|
13091
13378
|
var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
|
|
13092
|
-
|
|
13379
|
+
app38.use("*", async (c, next) => {
|
|
13093
13380
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13094
13381
|
if (!isPublicHost(host)) {
|
|
13095
13382
|
await next();
|
|
@@ -13129,7 +13416,7 @@ function resolveRemoteAuthOpts() {
|
|
|
13129
13416
|
return brandLoginOpts;
|
|
13130
13417
|
}
|
|
13131
13418
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
13132
|
-
|
|
13419
|
+
app38.post("/__remote-auth/login", async (c) => {
|
|
13133
13420
|
const client = clientFrom(c);
|
|
13134
13421
|
const clientIp = client.ip || "unknown";
|
|
13135
13422
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -13174,7 +13461,7 @@ app37.post("/__remote-auth/login", async (c) => {
|
|
|
13174
13461
|
}
|
|
13175
13462
|
});
|
|
13176
13463
|
});
|
|
13177
|
-
|
|
13464
|
+
app38.get("/__remote-auth/logout", (c) => {
|
|
13178
13465
|
const client = clientFrom(c);
|
|
13179
13466
|
const clientIp = client.ip || "unknown";
|
|
13180
13467
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -13187,7 +13474,7 @@ app37.get("/__remote-auth/logout", (c) => {
|
|
|
13187
13474
|
}
|
|
13188
13475
|
});
|
|
13189
13476
|
});
|
|
13190
|
-
|
|
13477
|
+
app38.post("/__remote-auth/change-password", async (c) => {
|
|
13191
13478
|
const client = clientFrom(c);
|
|
13192
13479
|
const clientIp = client.ip || "unknown";
|
|
13193
13480
|
const rateLimited = checkRateLimit(client);
|
|
@@ -13238,13 +13525,13 @@ app37.post("/__remote-auth/change-password", async (c) => {
|
|
|
13238
13525
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
13239
13526
|
}
|
|
13240
13527
|
});
|
|
13241
|
-
|
|
13528
|
+
app38.get("/__remote-auth/setup", (c) => {
|
|
13242
13529
|
if (isRemoteAuthConfigured()) {
|
|
13243
13530
|
return c.redirect("/");
|
|
13244
13531
|
}
|
|
13245
13532
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
|
|
13246
13533
|
});
|
|
13247
|
-
|
|
13534
|
+
app38.post("/__remote-auth/set-initial-password", async (c) => {
|
|
13248
13535
|
if (isRemoteAuthConfigured()) {
|
|
13249
13536
|
return c.redirect("/");
|
|
13250
13537
|
}
|
|
@@ -13282,10 +13569,10 @@ app37.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
13282
13569
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
13283
13570
|
}
|
|
13284
13571
|
});
|
|
13285
|
-
|
|
13572
|
+
app38.get("/api/remote-auth/status", (c) => {
|
|
13286
13573
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
13287
13574
|
});
|
|
13288
|
-
|
|
13575
|
+
app38.post("/api/remote-auth/set-password", async (c) => {
|
|
13289
13576
|
let body;
|
|
13290
13577
|
try {
|
|
13291
13578
|
body = await c.req.json();
|
|
@@ -13316,9 +13603,9 @@ app37.post("/api/remote-auth/set-password", async (c) => {
|
|
|
13316
13603
|
return c.json({ error: "Failed to save password" }, 500);
|
|
13317
13604
|
}
|
|
13318
13605
|
});
|
|
13319
|
-
|
|
13606
|
+
app38.route("/api/_client-error", client_error_default);
|
|
13320
13607
|
console.log("[client-error-route] mounted");
|
|
13321
|
-
|
|
13608
|
+
app38.use("*", async (c, next) => {
|
|
13322
13609
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13323
13610
|
const path2 = c.req.path;
|
|
13324
13611
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
|
|
@@ -13351,11 +13638,11 @@ app37.use("*", async (c, next) => {
|
|
|
13351
13638
|
console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
|
|
13352
13639
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
|
|
13353
13640
|
});
|
|
13354
|
-
|
|
13355
|
-
|
|
13356
|
-
|
|
13357
|
-
|
|
13358
|
-
|
|
13641
|
+
app38.route("/api/health", health_default);
|
|
13642
|
+
app38.route("/api/chat", chat_default);
|
|
13643
|
+
app38.route("/api/whatsapp", whatsapp_default);
|
|
13644
|
+
app38.route("/api/onboarding", onboarding_default);
|
|
13645
|
+
app38.route("/api/admin", admin_default);
|
|
13359
13646
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
13360
13647
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
13361
13648
|
var IMAGE_MIME = {
|
|
@@ -13367,7 +13654,7 @@ var IMAGE_MIME = {
|
|
|
13367
13654
|
".svg": "image/svg+xml",
|
|
13368
13655
|
".ico": "image/x-icon"
|
|
13369
13656
|
};
|
|
13370
|
-
|
|
13657
|
+
app38.get("/agent-assets/:slug/:filename", (c) => {
|
|
13371
13658
|
const slug = c.req.param("slug");
|
|
13372
13659
|
const filename = c.req.param("filename");
|
|
13373
13660
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -13402,7 +13689,7 @@ app37.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
13402
13689
|
"Cache-Control": "public, max-age=3600"
|
|
13403
13690
|
});
|
|
13404
13691
|
});
|
|
13405
|
-
|
|
13692
|
+
app38.get("/generated/:filename", (c) => {
|
|
13406
13693
|
const filename = c.req.param("filename");
|
|
13407
13694
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
13408
13695
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -13432,9 +13719,10 @@ app37.get("/generated/:filename", (c) => {
|
|
|
13432
13719
|
"Cache-Control": "public, max-age=86400"
|
|
13433
13720
|
});
|
|
13434
13721
|
});
|
|
13435
|
-
|
|
13436
|
-
|
|
13437
|
-
|
|
13722
|
+
app38.route("/sites", sites_default);
|
|
13723
|
+
app38.route("/listings", listings_default);
|
|
13724
|
+
app38.route("/v", visitor_event_default);
|
|
13725
|
+
app38.route("/v", visitor_consent_default);
|
|
13438
13726
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
13439
13727
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
13440
13728
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
@@ -13571,7 +13859,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
13571
13859
|
function escapeHtml(s) {
|
|
13572
13860
|
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
13573
13861
|
}
|
|
13574
|
-
|
|
13862
|
+
app38.get("/", (c) => {
|
|
13575
13863
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13576
13864
|
if (isPublicHost(host)) {
|
|
13577
13865
|
const defaultSlug = resolveDefaultSlug();
|
|
@@ -13579,12 +13867,12 @@ app37.get("/", (c) => {
|
|
|
13579
13867
|
}
|
|
13580
13868
|
return c.html(cachedHtml("index.html"));
|
|
13581
13869
|
});
|
|
13582
|
-
|
|
13870
|
+
app38.get("/public", (c) => {
|
|
13583
13871
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13584
13872
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
13585
13873
|
return c.html(cachedHtml("public.html"));
|
|
13586
13874
|
});
|
|
13587
|
-
|
|
13875
|
+
app38.get("/chat", (c) => {
|
|
13588
13876
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13589
13877
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
13590
13878
|
return c.html(cachedHtml("public.html"));
|
|
@@ -13603,9 +13891,9 @@ async function logViewerFetch(c, next) {
|
|
|
13603
13891
|
duration_ms: Date.now() - start
|
|
13604
13892
|
});
|
|
13605
13893
|
}
|
|
13606
|
-
|
|
13607
|
-
|
|
13608
|
-
|
|
13894
|
+
app38.use("/vnc-viewer.html", logViewerFetch);
|
|
13895
|
+
app38.use("/vnc-popout.html", logViewerFetch);
|
|
13896
|
+
app38.get("/vnc-popout.html", (c) => {
|
|
13609
13897
|
let html = htmlCache.get("vnc-popout.html");
|
|
13610
13898
|
if (!html) {
|
|
13611
13899
|
html = readFileSync21(resolve21(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
@@ -13618,7 +13906,7 @@ app37.get("/vnc-popout.html", (c) => {
|
|
|
13618
13906
|
}
|
|
13619
13907
|
return c.html(html);
|
|
13620
13908
|
});
|
|
13621
|
-
|
|
13909
|
+
app38.post("/api/vnc/client-event", async (c) => {
|
|
13622
13910
|
let body;
|
|
13623
13911
|
try {
|
|
13624
13912
|
body = await c.req.json();
|
|
@@ -13639,25 +13927,25 @@ app37.post("/api/vnc/client-event", async (c) => {
|
|
|
13639
13927
|
});
|
|
13640
13928
|
return c.json({ ok: true });
|
|
13641
13929
|
});
|
|
13642
|
-
|
|
13930
|
+
app38.get("/g/:slug", (c) => {
|
|
13643
13931
|
return c.html(brandedPublicHtml());
|
|
13644
13932
|
});
|
|
13645
|
-
|
|
13933
|
+
app38.get("/graph", (c) => {
|
|
13646
13934
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13647
13935
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
13648
13936
|
return c.html(cachedHtml("graph.html"));
|
|
13649
13937
|
});
|
|
13650
|
-
|
|
13938
|
+
app38.get("/sessions", (c) => {
|
|
13651
13939
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13652
13940
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
13653
13941
|
return c.html(cachedHtml("sessions.html"));
|
|
13654
13942
|
});
|
|
13655
|
-
|
|
13943
|
+
app38.get("/data", (c) => {
|
|
13656
13944
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13657
13945
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
13658
13946
|
return c.html(cachedHtml("data.html"));
|
|
13659
13947
|
});
|
|
13660
|
-
|
|
13948
|
+
app38.get("/:slug", async (c, next) => {
|
|
13661
13949
|
const slug = c.req.param("slug");
|
|
13662
13950
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
13663
13951
|
const branding = loadBrandingCache(slug);
|
|
@@ -13667,15 +13955,15 @@ app37.get("/:slug", async (c, next) => {
|
|
|
13667
13955
|
await next();
|
|
13668
13956
|
});
|
|
13669
13957
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
13670
|
-
|
|
13958
|
+
app38.get("/favicon.ico", (c) => {
|
|
13671
13959
|
c.header("Cache-Control", "public, max-age=300");
|
|
13672
13960
|
return c.redirect(brandFaviconPath, 302);
|
|
13673
13961
|
});
|
|
13674
13962
|
}
|
|
13675
|
-
|
|
13963
|
+
app38.use("/*", serveStatic({ root: "./public" }));
|
|
13676
13964
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
13677
13965
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
13678
|
-
var httpServer = serve({ fetch:
|
|
13966
|
+
var httpServer = serve({ fetch: app38.fetch, port, hostname });
|
|
13679
13967
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
13680
13968
|
{
|
|
13681
13969
|
const loopHist = monitorEventLoopDelay({ resolution: 50 });
|
|
@@ -13701,7 +13989,8 @@ var SUBAPP_MANIFEST = [
|
|
|
13701
13989
|
{ prefix: "/api/admin", file: "server/routes/admin/index.ts", subapp: admin_default },
|
|
13702
13990
|
{ prefix: "/api/_client-error", file: "server/routes/client-error.ts", subapp: client_error_default },
|
|
13703
13991
|
{ prefix: "/listings", file: "server/routes/listings.ts", subapp: listings_default },
|
|
13704
|
-
{ prefix: "/v", file: "server/routes/visitor-event.ts", subapp: visitor_event_default }
|
|
13992
|
+
{ prefix: "/v", file: "server/routes/visitor-event.ts", subapp: visitor_event_default },
|
|
13993
|
+
{ prefix: "/v", file: "server/routes/visitor-consent.ts", subapp: visitor_consent_default }
|
|
13705
13994
|
];
|
|
13706
13995
|
for (const m of SUBAPP_MANIFEST) {
|
|
13707
13996
|
const routeCount = Array.isArray(m.subapp.routes) ? m.subapp.routes.length : 0;
|
|
@@ -13709,7 +13998,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
13709
13998
|
}
|
|
13710
13999
|
try {
|
|
13711
14000
|
const registered = [];
|
|
13712
|
-
for (const r of
|
|
14001
|
+
for (const r of app38.routes ?? []) {
|
|
13713
14002
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
13714
14003
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
13715
14004
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|