@rubytech/create-maxy 1.0.506 → 1.0.508
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/package.json +1 -1
- package/payload/platform/config/brand.json +1 -1
- package/payload/platform/lib/mcp-stderr-tee/dist/index.d.ts +18 -0
- package/payload/platform/lib/mcp-stderr-tee/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/mcp-stderr-tee/dist/index.js +45 -0
- package/payload/platform/lib/mcp-stderr-tee/dist/index.js.map +1 -0
- package/payload/platform/lib/mcp-stderr-tee/src/index.ts +51 -0
- package/payload/platform/lib/mcp-stderr-tee/tsconfig.json +8 -0
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/admin/mcp/dist/index.js +7 -3
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/cloudflare/mcp/dist/index.js +2 -0
- package/payload/platform/plugins/cloudflare/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/index.js +2 -0
- package/payload/platform/plugins/contacts/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/index.js +2 -0
- package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/index.js +2 -0
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/replicate/mcp/dist/index.js +2 -0
- package/payload/platform/plugins/replicate/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/index.js +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/tasks/mcp/dist/index.js +2 -0
- package/payload/platform/plugins/tasks/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/index.js +2 -0
- package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/waitlist/mcp/dist/index.js +2 -0
- package/payload/platform/plugins/waitlist/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +5 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/index.js +2 -0
- package/payload/platform/plugins/workflows/mcp/dist/index.js.map +1 -1
- package/payload/platform/scripts/logs-read.sh +4 -3
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/index.js +6 -4
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/index.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/lib/loop-api.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/lib/loop-api.js +47 -12
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/lib/loop-api.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/customer-preferences.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/customer-preferences.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/feedback.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/feedback.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-enquiry.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-enquiry.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-match-batch.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-match-batch.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-match-request.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-match-request.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-match.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/marketing-match.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/people-detail.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/people-detail.js +110 -18
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/people-detail.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/people-search.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/people-search.js +34 -6
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/people-search.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-detail.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-detail.js +59 -16
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-detail.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-listed.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-listed.js +5 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-listed.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-request.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-request.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-search.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-search.js +4 -2
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/property-search.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/supplier.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/supplier.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/team-availability.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/team-availability.js +6 -2
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/team-availability.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/team-info.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/team-info.js +16 -4
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/team-info.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-create.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-create.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-detail.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-detail.js +63 -18
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-detail.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-search.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-search.js +13 -3
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-search.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-update.d.ts.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/dist/tools/viewing-update.js.map +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/index.ts +8 -5
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/lib/loop-api.ts +84 -18
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/customer-preferences.ts +6 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/feedback.ts +6 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/marketing-enquiry.ts +8 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/marketing-match-batch.ts +5 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/marketing-match-request.ts +5 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/marketing-match.ts +6 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/people-detail.ts +203 -21
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/people-search.ts +99 -12
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/property-detail.ts +95 -20
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/property-listed.ts +27 -6
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/property-request.ts +5 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/property-search.ts +20 -8
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/supplier.ts +9 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/team-availability.ts +12 -2
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/team-info.ts +50 -9
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/viewing-create.ts +5 -0
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/viewing-detail.ts +124 -23
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/viewing-search.ts +25 -7
- package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/viewing-update.ts +5 -0
- package/payload/server/server.js +122 -14
|
@@ -4,7 +4,12 @@ import {
|
|
|
4
4
|
loopGet,
|
|
5
5
|
} from "../lib/loop-api.js";
|
|
6
6
|
|
|
7
|
+
// ─── Loop API V2: /team/{agentId}/availability/{searchDate} ────
|
|
8
|
+
// Returns array of: { agentId, start, end }
|
|
9
|
+
// Times are ISO datetime strings (e.g. "2026-04-10T06:00:00")
|
|
10
|
+
// ────────────────────────────────────────────────────────────────
|
|
7
11
|
interface LoopTimeRange {
|
|
12
|
+
agentId?: string;
|
|
8
13
|
start?: string;
|
|
9
14
|
end?: string;
|
|
10
15
|
[key: string]: unknown;
|
|
@@ -33,10 +38,15 @@ export async function teamAvailability(params: {
|
|
|
33
38
|
return formatAggregationResult(
|
|
34
39
|
result,
|
|
35
40
|
(slot) => {
|
|
36
|
-
const start = slot.start
|
|
37
|
-
const end = slot.end
|
|
41
|
+
const start = slot.start ? formatTime(slot.start) : "?";
|
|
42
|
+
const end = slot.end ? formatTime(slot.end) : "?";
|
|
38
43
|
return `- ${start} — ${end}`;
|
|
39
44
|
},
|
|
40
45
|
`availability slots for ${searchDate}`
|
|
41
46
|
);
|
|
42
47
|
}
|
|
48
|
+
|
|
49
|
+
function formatTime(iso: string): string {
|
|
50
|
+
const timePart = iso.split("T")[1];
|
|
51
|
+
return timePart ? timePart.slice(0, 5) : iso;
|
|
52
|
+
}
|
package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/team-info.ts
CHANGED
|
@@ -4,13 +4,39 @@ import {
|
|
|
4
4
|
loopGet,
|
|
5
5
|
} from "../lib/loop-api.js";
|
|
6
6
|
|
|
7
|
+
// ─── Loop API V2: /team ────────────────────────────────────────
|
|
8
|
+
// Fields: apiKey (redacted), clientName, teamName,
|
|
9
|
+
// address1, address2, address3, email, phoneNumber, websiteUrl,
|
|
10
|
+
// primaryDarkColour, primaryLightColour, secondaryDarkColour,
|
|
11
|
+
// secondaryLightColour, legalName, websiteContactUrl,
|
|
12
|
+
// websitePropertiesUrl, dateCreated,
|
|
13
|
+
// members[] (each: id, firstName, lastName, email, mobilePhone,
|
|
14
|
+
// jobTitle, signatureImageUrl, avatarImage, avatarMedium,
|
|
15
|
+
// avatarThumbnail, biography, customUrl, twitterUrl)
|
|
16
|
+
// ────────────────────────────────────────────────────────────────
|
|
7
17
|
interface LoopTeam {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
18
|
+
clientName?: string;
|
|
19
|
+
teamName?: string;
|
|
20
|
+
address1?: string;
|
|
21
|
+
address2?: string;
|
|
22
|
+
address3?: string;
|
|
23
|
+
email?: string;
|
|
24
|
+
phoneNumber?: string;
|
|
25
|
+
websiteUrl?: string;
|
|
26
|
+
legalName?: string;
|
|
27
|
+
dateCreated?: string;
|
|
28
|
+
members?: LoopTeamMember[];
|
|
29
|
+
[key: string]: unknown;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface LoopTeamMember {
|
|
33
|
+
id: string;
|
|
34
|
+
firstName?: string;
|
|
35
|
+
lastName?: string;
|
|
12
36
|
email?: string;
|
|
13
|
-
|
|
37
|
+
mobilePhone?: string;
|
|
38
|
+
jobTitle?: string;
|
|
39
|
+
biography?: string;
|
|
14
40
|
[key: string]: unknown;
|
|
15
41
|
}
|
|
16
42
|
|
|
@@ -43,11 +69,26 @@ export async function teamInfo(params: {
|
|
|
43
69
|
return formatAggregationResult(
|
|
44
70
|
result,
|
|
45
71
|
(t) => {
|
|
46
|
-
const name = t.
|
|
47
|
-
const
|
|
48
|
-
const
|
|
72
|
+
const name = t.teamName ?? t.clientName ?? "Unknown";
|
|
73
|
+
const client = t.clientName && t.clientName !== t.teamName ? ` (${t.clientName})` : "";
|
|
74
|
+
const addr = t.address1 ? ` — ${t.address1}` : "";
|
|
75
|
+
const phone = t.phoneNumber ? ` | ${t.phoneNumber}` : "";
|
|
49
76
|
const email = t.email ? ` | ${t.email}` : "";
|
|
50
|
-
|
|
77
|
+
const web = t.websiteUrl ? ` | ${t.websiteUrl}` : "";
|
|
78
|
+
|
|
79
|
+
const lines = [`- **${name}**${client}${addr}${phone}${email}${web}`];
|
|
80
|
+
|
|
81
|
+
if (t.members?.length) {
|
|
82
|
+
lines.push(` Team members (${t.members.length}):`);
|
|
83
|
+
for (const m of t.members) {
|
|
84
|
+
const mName = [m.firstName, m.lastName].filter(Boolean).join(" ");
|
|
85
|
+
const title = m.jobTitle ? ` (${m.jobTitle})` : "";
|
|
86
|
+
const mEmail = m.email ? ` — ${m.email}` : "";
|
|
87
|
+
lines.push(` - ${mName} [ID: ${m.id}]${title}${mEmail}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return lines.join("\n");
|
|
51
92
|
},
|
|
52
93
|
"teams"
|
|
53
94
|
);
|
package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/viewing-create.ts
CHANGED
|
@@ -2,6 +2,11 @@ import { loopPost, withTeamKey } from "../lib/loop-api.js";
|
|
|
2
2
|
|
|
3
3
|
type Department = "sales" | "lettings";
|
|
4
4
|
|
|
5
|
+
// ─── Loop API V2: POST /residential/{dept}/viewings ────────────
|
|
6
|
+
// Request body: { propertyId, date, time, attendeeName,
|
|
7
|
+
// attendeeEmail?, attendeePhone? }
|
|
8
|
+
// Response: number (the created viewing ID) in data field
|
|
9
|
+
// ────────────────────────────────────────────────────────────────
|
|
5
10
|
interface LoopNumberResponse {
|
|
6
11
|
result?: number;
|
|
7
12
|
[key: string]: unknown;
|
package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/viewing-detail.ts
CHANGED
|
@@ -4,21 +4,73 @@ import {
|
|
|
4
4
|
loopGet,
|
|
5
5
|
} from "../lib/loop-api.js";
|
|
6
6
|
|
|
7
|
+
// ─── Loop API V2: /residential/{dept}/viewings/{id} ────────────
|
|
8
|
+
// Fields: id, dateCreated, dateOfAppointment, dateOfAppointmentEnd,
|
|
9
|
+
// dateBuyerFeedbackGiven, dateSellerFeedbackGiven, dateDone,
|
|
10
|
+
// status, type, comment, buyerFeedback, sellerFeedback,
|
|
11
|
+
// buyerConfirmed, sellerConfirmed, agentConfirmed,
|
|
12
|
+
// property (nested PropertySummary), buyer (nested BuyerSummary),
|
|
13
|
+
// seller (nested SellerSummary),
|
|
14
|
+
// attendingAgent (nested TeamMember), creatingAgent (nested TeamMember),
|
|
15
|
+
// teamId
|
|
16
|
+
// ────────────────────────────────────────────────────────────────
|
|
7
17
|
interface LoopViewingDetail {
|
|
8
|
-
id
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
18
|
+
id: number;
|
|
19
|
+
dateCreated?: string;
|
|
20
|
+
dateOfAppointment?: string;
|
|
21
|
+
dateOfAppointmentEnd?: string;
|
|
22
|
+
dateBuyerFeedbackGiven?: string | null;
|
|
23
|
+
dateSellerFeedbackGiven?: string | null;
|
|
24
|
+
dateDone?: string | null;
|
|
12
25
|
status?: string;
|
|
13
26
|
type?: string;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
27
|
+
comment?: string | null;
|
|
28
|
+
buyerFeedback?: string | null;
|
|
29
|
+
sellerFeedback?: string | null;
|
|
30
|
+
buyerConfirmed?: boolean;
|
|
31
|
+
sellerConfirmed?: boolean;
|
|
32
|
+
agentConfirmed?: boolean;
|
|
33
|
+
property?: {
|
|
34
|
+
id: number;
|
|
35
|
+
propertyAddress?: string;
|
|
36
|
+
status?: string;
|
|
37
|
+
propertyType?: string;
|
|
38
|
+
price?: number;
|
|
39
|
+
bedrooms?: number;
|
|
40
|
+
[key: string]: unknown;
|
|
41
|
+
};
|
|
42
|
+
buyer?: {
|
|
43
|
+
id: number;
|
|
44
|
+
buyerGroupName?: string;
|
|
45
|
+
maxPrice?: number | null;
|
|
46
|
+
position?: string;
|
|
47
|
+
viewingCount?: number;
|
|
48
|
+
offerCount?: number;
|
|
49
|
+
[key: string]: unknown;
|
|
50
|
+
};
|
|
51
|
+
seller?: {
|
|
52
|
+
id: number;
|
|
53
|
+
sellerGroupName?: string;
|
|
54
|
+
propertyAddress?: string;
|
|
55
|
+
price?: number;
|
|
56
|
+
[key: string]: unknown;
|
|
57
|
+
};
|
|
58
|
+
attendingAgent?: {
|
|
59
|
+
id: string;
|
|
60
|
+
firstName?: string;
|
|
61
|
+
lastName?: string;
|
|
62
|
+
email?: string;
|
|
63
|
+
mobilePhone?: string;
|
|
64
|
+
jobTitle?: string;
|
|
65
|
+
[key: string]: unknown;
|
|
66
|
+
};
|
|
67
|
+
creatingAgent?: {
|
|
68
|
+
id: string;
|
|
69
|
+
firstName?: string;
|
|
70
|
+
lastName?: string;
|
|
71
|
+
[key: string]: unknown;
|
|
72
|
+
};
|
|
73
|
+
teamId?: string;
|
|
22
74
|
[key: string]: unknown;
|
|
23
75
|
}
|
|
24
76
|
|
|
@@ -50,21 +102,70 @@ export async function viewingDetail(params: {
|
|
|
50
102
|
return formatAggregationResult(
|
|
51
103
|
result,
|
|
52
104
|
(v) => {
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
|
|
105
|
+
const propAddr = v.property?.propertyAddress ?? "Unknown property";
|
|
106
|
+
const lines = [`**${propAddr}** [Viewing ID: ${v.id}]`];
|
|
107
|
+
|
|
108
|
+
// Appointment time
|
|
109
|
+
if (v.dateOfAppointment) {
|
|
110
|
+
const start = formatDateTime(v.dateOfAppointment);
|
|
111
|
+
const end = v.dateOfAppointmentEnd ? formatDateTime(v.dateOfAppointmentEnd) : "";
|
|
112
|
+
lines.push(`Date/Time: ${start}${end ? ` — ${end}` : ""}`);
|
|
113
|
+
}
|
|
56
114
|
if (v.status) lines.push(`Status: ${v.status}`);
|
|
57
115
|
if (v.type) lines.push(`Type: ${v.type}`);
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (v.
|
|
62
|
-
if (v.
|
|
63
|
-
if (v.
|
|
64
|
-
if (
|
|
65
|
-
|
|
116
|
+
|
|
117
|
+
// Confirmation status
|
|
118
|
+
const confirmParts: string[] = [];
|
|
119
|
+
if (v.buyerConfirmed != null) confirmParts.push(`Buyer: ${v.buyerConfirmed ? "yes" : "no"}`);
|
|
120
|
+
if (v.sellerConfirmed != null) confirmParts.push(`Seller: ${v.sellerConfirmed ? "yes" : "no"}`);
|
|
121
|
+
if (v.agentConfirmed != null) confirmParts.push(`Agent: ${v.agentConfirmed ? "yes" : "no"}`);
|
|
122
|
+
if (confirmParts.length) lines.push(`Confirmed — ${confirmParts.join(", ")}`);
|
|
123
|
+
|
|
124
|
+
// Property details
|
|
125
|
+
if (v.property) {
|
|
126
|
+
const prop = v.property;
|
|
127
|
+
if (prop.price != null) lines.push(`Property price: £${prop.price.toLocaleString("en-GB")}`);
|
|
128
|
+
if (prop.propertyType) lines.push(`Property type: ${prop.propertyType}`);
|
|
129
|
+
if (prop.bedrooms != null) lines.push(`Bedrooms: ${prop.bedrooms}`);
|
|
130
|
+
if (prop.id) lines.push(`Property ID: ${prop.id}`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Buyer
|
|
134
|
+
if (v.buyer) {
|
|
135
|
+
const b = v.buyer;
|
|
136
|
+
lines.push(`\n**Buyer:** ${b.buyerGroupName ?? "Unknown"} [ID: ${b.id}]`);
|
|
137
|
+
if (b.maxPrice != null) lines.push(` Max price: £${b.maxPrice.toLocaleString("en-GB")}`);
|
|
138
|
+
if (b.position && b.position !== "none") lines.push(` Position: ${b.position}`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Seller
|
|
142
|
+
if (v.seller) {
|
|
143
|
+
const s = v.seller;
|
|
144
|
+
lines.push(`\n**Seller:** ${s.sellerGroupName ?? "Unknown"} [ID: ${s.id}]`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Attending agent
|
|
148
|
+
if (v.attendingAgent) {
|
|
149
|
+
const a = v.attendingAgent;
|
|
150
|
+
const agentName = [a.firstName, a.lastName].filter(Boolean).join(" ");
|
|
151
|
+
const title = a.jobTitle ? ` (${a.jobTitle})` : "";
|
|
152
|
+
const contact = a.email ?? a.mobilePhone ?? "";
|
|
153
|
+
lines.push(`\n**Attending agent:** ${agentName}${title}${contact ? ` — ${contact}` : ""}`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Feedback
|
|
157
|
+
if (v.buyerFeedback) lines.push(`\nBuyer feedback: ${v.buyerFeedback}`);
|
|
158
|
+
if (v.sellerFeedback) lines.push(`Seller feedback: ${v.sellerFeedback}`);
|
|
159
|
+
if (v.comment) lines.push(`Notes: ${v.comment}`);
|
|
160
|
+
|
|
66
161
|
return lines.join("\n");
|
|
67
162
|
},
|
|
68
163
|
"viewing details"
|
|
69
164
|
);
|
|
70
165
|
}
|
|
166
|
+
|
|
167
|
+
function formatDateTime(iso: string): string {
|
|
168
|
+
const [datePart, timePart] = iso.split("T");
|
|
169
|
+
if (!timePart) return datePart;
|
|
170
|
+
return `${datePart} ${timePart.slice(0, 5)}`;
|
|
171
|
+
}
|
package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/viewing-search.ts
CHANGED
|
@@ -4,14 +4,22 @@ import {
|
|
|
4
4
|
loopGet,
|
|
5
5
|
} from "../lib/loop-api.js";
|
|
6
6
|
|
|
7
|
+
// ─── Loop API V2: /residential/{dept}/viewings ─────────────────
|
|
8
|
+
// Fields: id, propertyId, propertyAddress, status,
|
|
9
|
+
// dateOfAppointment, dateOfAppointmentEnd,
|
|
10
|
+
// attendingAgentId, creatingAgentId, type, buyerName
|
|
11
|
+
// ────────────────────────────────────────────────────────────────
|
|
7
12
|
interface LoopViewingSummary {
|
|
8
|
-
id
|
|
13
|
+
id: number;
|
|
14
|
+
propertyId?: number;
|
|
9
15
|
propertyAddress?: string;
|
|
10
|
-
date?: string;
|
|
11
|
-
time?: string;
|
|
12
16
|
status?: string;
|
|
17
|
+
dateOfAppointment?: string;
|
|
18
|
+
dateOfAppointmentEnd?: string;
|
|
19
|
+
attendingAgentId?: string;
|
|
20
|
+
creatingAgentId?: string;
|
|
13
21
|
type?: string;
|
|
14
|
-
|
|
22
|
+
buyerName?: string;
|
|
15
23
|
[key: string]: unknown;
|
|
16
24
|
}
|
|
17
25
|
|
|
@@ -63,12 +71,22 @@ export async function viewingSearch(params: {
|
|
|
63
71
|
result,
|
|
64
72
|
(v) => {
|
|
65
73
|
const addr = v.propertyAddress ?? "Unknown property";
|
|
66
|
-
const
|
|
74
|
+
const id = v.id != null ? ` [ID: ${v.id}]` : "";
|
|
75
|
+
// dateOfAppointment is ISO datetime e.g. "2026-04-10T15:30:00"
|
|
76
|
+
const when = v.dateOfAppointment
|
|
77
|
+
? formatDateTime(v.dateOfAppointment)
|
|
78
|
+
: "No date";
|
|
67
79
|
const viewStatus = v.status ? ` [${v.status}]` : "";
|
|
68
|
-
const
|
|
80
|
+
const buyer = v.buyerName ? ` — ${v.buyerName}` : "";
|
|
69
81
|
const viewType = v.type ? ` (${v.type})` : "";
|
|
70
|
-
return `- ${addr} — ${when
|
|
82
|
+
return `- ${addr}${id} — ${when}${viewType}${buyer}${viewStatus}`;
|
|
71
83
|
},
|
|
72
84
|
"viewings"
|
|
73
85
|
);
|
|
74
86
|
}
|
|
87
|
+
|
|
88
|
+
function formatDateTime(iso: string): string {
|
|
89
|
+
const [datePart, timePart] = iso.split("T");
|
|
90
|
+
if (!timePart) return datePart;
|
|
91
|
+
return `${datePart} ${timePart.slice(0, 5)}`;
|
|
92
|
+
}
|
package/payload/premium-plugins/real-agency/plugins/real-agency-loop/mcp/src/tools/viewing-update.ts
CHANGED
|
@@ -8,6 +8,11 @@ type Department = "sales" | "lettings";
|
|
|
8
8
|
type FeedbackParty = "buyer" | "seller" | "renter" | "landlord";
|
|
9
9
|
type Action = "note" | "feedback";
|
|
10
10
|
|
|
11
|
+
// ─── Loop API V2: POST /residential/{dept}/viewings/{id}/{suffix}
|
|
12
|
+
// Suffix: "note" for notes, "{party}-feedback" for feedback
|
|
13
|
+
// Request body: { result: string } (StringResponse format)
|
|
14
|
+
// Response: boolean success
|
|
15
|
+
// ────────────────────────────────────────────────────────────────
|
|
11
16
|
interface LoopBooleanResponse {
|
|
12
17
|
success?: boolean;
|
|
13
18
|
[key: string]: unknown;
|
package/payload/server/server.js
CHANGED
|
@@ -3700,9 +3700,9 @@ async function getRecentMessages(conversationId, limit = 50) {
|
|
|
3700
3700
|
try {
|
|
3701
3701
|
const result = await session.run(
|
|
3702
3702
|
`MATCH (m:Message {conversationId: $conversationId})
|
|
3703
|
+
WITH m ORDER BY m.createdAt DESC LIMIT $limit
|
|
3703
3704
|
RETURN m.messageId AS messageId, m.role AS role, m.content AS content, m.createdAt AS createdAt
|
|
3704
|
-
ORDER BY m.createdAt ASC
|
|
3705
|
-
LIMIT $limit`,
|
|
3705
|
+
ORDER BY m.createdAt ASC`,
|
|
3706
3706
|
{ conversationId, limit: neo4j.int(limit) }
|
|
3707
3707
|
);
|
|
3708
3708
|
return result.records.map((r) => ({
|
|
@@ -3971,6 +3971,26 @@ async function autoLabelSession(conversationId, userMessage) {
|
|
|
3971
3971
|
if (currentEntry) currentEntry.pending = false;
|
|
3972
3972
|
}
|
|
3973
3973
|
}
|
|
3974
|
+
async function renameConversation(conversationId, label) {
|
|
3975
|
+
let embedding = null;
|
|
3976
|
+
try {
|
|
3977
|
+
embedding = await embed(label);
|
|
3978
|
+
} catch (err) {
|
|
3979
|
+
console.error(`[persist] manual-label: embedding failed, persisting without: ${err instanceof Error ? err.message : String(err)}`);
|
|
3980
|
+
}
|
|
3981
|
+
const session = getSession();
|
|
3982
|
+
try {
|
|
3983
|
+
await session.run(
|
|
3984
|
+
`MATCH (c:Conversation {conversationId: $conversationId})
|
|
3985
|
+
SET c.name = $label, c.updatedAt = datetime()
|
|
3986
|
+
${embedding ? ", c.embedding = $embedding" : ""}`,
|
|
3987
|
+
{ conversationId, label, ...embedding ? { embedding } : {} }
|
|
3988
|
+
);
|
|
3989
|
+
console.error(`[persist] manual-label: renamed ${conversationId} to "${label}"${embedding ? " (embedded)" : ""}`);
|
|
3990
|
+
} finally {
|
|
3991
|
+
await session.close();
|
|
3992
|
+
}
|
|
3993
|
+
}
|
|
3974
3994
|
var INITIAL_CONFIDENCE = 0.5;
|
|
3975
3995
|
var REINFORCEMENT_INCREMENT = 0.15;
|
|
3976
3996
|
var DECAY_THRESHOLD_DAYS = 14;
|
|
@@ -5395,41 +5415,42 @@ function consumeStalledSubagents(sessionKey) {
|
|
|
5395
5415
|
return stalls && stalls.length > 0 ? stalls : void 0;
|
|
5396
5416
|
}
|
|
5397
5417
|
function getMcpServers(accountId, userId, enabledPlugins) {
|
|
5418
|
+
const LOG_DIR2 = resolve5(ACCOUNTS_DIR, accountId, "logs");
|
|
5398
5419
|
const servers = {
|
|
5399
5420
|
"memory": {
|
|
5400
5421
|
command: "node",
|
|
5401
5422
|
args: [resolve5(PLATFORM_ROOT4, "plugins/memory/mcp/dist/index.js")],
|
|
5402
|
-
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4, ...userId ? { USER_ID: userId } : {} }
|
|
5423
|
+
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4, LOG_DIR: LOG_DIR2, ...userId ? { USER_ID: userId } : {} }
|
|
5403
5424
|
},
|
|
5404
5425
|
"contacts": {
|
|
5405
5426
|
command: "node",
|
|
5406
5427
|
args: [resolve5(PLATFORM_ROOT4, "plugins/contacts/mcp/dist/index.js")],
|
|
5407
|
-
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4 }
|
|
5428
|
+
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4, LOG_DIR: LOG_DIR2 }
|
|
5408
5429
|
},
|
|
5409
5430
|
"whatsapp": {
|
|
5410
5431
|
command: "node",
|
|
5411
5432
|
args: [resolve5(PLATFORM_ROOT4, "plugins/whatsapp/mcp/dist/index.js")],
|
|
5412
|
-
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4, PLATFORM_PORT: process.env.PORT ?? "19200" }
|
|
5433
|
+
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4, LOG_DIR: LOG_DIR2, PLATFORM_PORT: process.env.PORT ?? "19200" }
|
|
5413
5434
|
},
|
|
5414
5435
|
"admin": {
|
|
5415
5436
|
command: "node",
|
|
5416
5437
|
args: [resolve5(PLATFORM_ROOT4, "plugins/admin/mcp/dist/index.js")],
|
|
5417
|
-
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4, PLATFORM_PORT: process.env.PORT ?? "19200", ...userId ? { USER_ID: userId } : {} }
|
|
5438
|
+
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4, LOG_DIR: LOG_DIR2, PLATFORM_PORT: process.env.PORT ?? "19200", ...userId ? { USER_ID: userId } : {} }
|
|
5418
5439
|
},
|
|
5419
5440
|
"scheduling": {
|
|
5420
5441
|
command: "node",
|
|
5421
5442
|
args: [resolve5(PLATFORM_ROOT4, "plugins/scheduling/mcp/dist/index.js")],
|
|
5422
|
-
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4 }
|
|
5443
|
+
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4, LOG_DIR: LOG_DIR2 }
|
|
5423
5444
|
},
|
|
5424
5445
|
"tasks": {
|
|
5425
5446
|
command: "node",
|
|
5426
5447
|
args: [resolve5(PLATFORM_ROOT4, "plugins/tasks/mcp/dist/index.js")],
|
|
5427
|
-
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4 }
|
|
5448
|
+
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4, LOG_DIR: LOG_DIR2 }
|
|
5428
5449
|
},
|
|
5429
5450
|
"email": {
|
|
5430
5451
|
command: "node",
|
|
5431
5452
|
args: [resolve5(PLATFORM_ROOT4, "plugins/email/mcp/dist/index.js")],
|
|
5432
|
-
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4 }
|
|
5453
|
+
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4, LOG_DIR: LOG_DIR2 }
|
|
5433
5454
|
},
|
|
5434
5455
|
// Playwright MCP server — browser automation for browser-specialist.
|
|
5435
5456
|
// Key matches Claude Code's plugin naming: plugin_{plugin}_{server} so tools
|
|
@@ -5446,7 +5467,7 @@ function getMcpServers(accountId, userId, enabledPlugins) {
|
|
|
5446
5467
|
servers["telegram"] = {
|
|
5447
5468
|
command: "node",
|
|
5448
5469
|
args: [resolve5(PLATFORM_ROOT4, "plugins/telegram/mcp/dist/index.js")],
|
|
5449
|
-
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4 }
|
|
5470
|
+
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4, LOG_DIR: LOG_DIR2 }
|
|
5450
5471
|
};
|
|
5451
5472
|
} else {
|
|
5452
5473
|
console.error("[plugins] telegram MCP: skipped (no TELEGRAM_PUBLIC_BOT_TOKEN)");
|
|
@@ -5454,7 +5475,7 @@ function getMcpServers(accountId, userId, enabledPlugins) {
|
|
|
5454
5475
|
servers["cloudflare"] = {
|
|
5455
5476
|
command: "node",
|
|
5456
5477
|
args: [resolve5(PLATFORM_ROOT4, "plugins/cloudflare/mcp/dist/index.js")],
|
|
5457
|
-
env: { PLATFORM_ROOT: PLATFORM_ROOT4, PLATFORM_PORT: process.env.PORT ?? "19200" }
|
|
5478
|
+
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4, LOG_DIR: LOG_DIR2, PLATFORM_PORT: process.env.PORT ?? "19200" }
|
|
5458
5479
|
};
|
|
5459
5480
|
if (Array.isArray(enabledPlugins) && enabledPlugins.length > 0) {
|
|
5460
5481
|
const pluginsDir = resolve5(PLATFORM_ROOT4, "plugins");
|
|
@@ -5485,7 +5506,7 @@ function getMcpServers(accountId, userId, enabledPlugins) {
|
|
|
5485
5506
|
servers[dir] = {
|
|
5486
5507
|
command: "node",
|
|
5487
5508
|
args: [mcpEntry],
|
|
5488
|
-
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4 }
|
|
5509
|
+
env: { ACCOUNT_ID: accountId, PLATFORM_ROOT: PLATFORM_ROOT4, LOG_DIR: LOG_DIR2 }
|
|
5489
5510
|
};
|
|
5490
5511
|
console.log(`[plugins] optional MCP server started: ${dir}`);
|
|
5491
5512
|
}
|
|
@@ -27210,8 +27231,87 @@ async function GET11(req, { params }) {
|
|
|
27210
27231
|
}
|
|
27211
27232
|
}
|
|
27212
27233
|
|
|
27234
|
+
// app/api/admin/sessions/[id]/label/route.ts
|
|
27235
|
+
var LABEL_MAX_LENGTH = 200;
|
|
27236
|
+
async function POST23(req, { params }) {
|
|
27237
|
+
const { id: conversationId } = await params;
|
|
27238
|
+
const url2 = new URL(req.url);
|
|
27239
|
+
const sessionKey = url2.searchParams.get("session_key");
|
|
27240
|
+
if (!sessionKey) {
|
|
27241
|
+
return Response.json({ error: "session_key required" }, { status: 400 });
|
|
27242
|
+
}
|
|
27243
|
+
if (!validateSession(sessionKey, "admin")) {
|
|
27244
|
+
return Response.json({ error: "Invalid or expired admin session" }, { status: 401 });
|
|
27245
|
+
}
|
|
27246
|
+
const accountId = getAccountIdForSession(sessionKey);
|
|
27247
|
+
if (!accountId) {
|
|
27248
|
+
return Response.json({ error: "Account not found for session" }, { status: 401 });
|
|
27249
|
+
}
|
|
27250
|
+
const owned = await verifyConversationOwnership(conversationId, accountId);
|
|
27251
|
+
if (!owned) {
|
|
27252
|
+
return Response.json({ error: "Conversation not found" }, { status: 404 });
|
|
27253
|
+
}
|
|
27254
|
+
console.error(`[admin] manual-label: requesting suggestion for ${conversationId}`);
|
|
27255
|
+
try {
|
|
27256
|
+
const messages = await getRecentMessages(conversationId, 50);
|
|
27257
|
+
const userMessages = messages.filter((m) => m.role === "user").map((m) => m.content);
|
|
27258
|
+
if (userMessages.length === 0) {
|
|
27259
|
+
console.error(`[admin] manual-label: haiku failed for ${conversationId} \u2014 no user messages`);
|
|
27260
|
+
return Response.json({ label: null });
|
|
27261
|
+
}
|
|
27262
|
+
const label = await generateSessionLabel(userMessages);
|
|
27263
|
+
if (label) {
|
|
27264
|
+
console.error(`[admin] manual-label: haiku suggested "${label}" for ${conversationId}`);
|
|
27265
|
+
} else {
|
|
27266
|
+
console.error(`[admin] manual-label: haiku failed for ${conversationId} \u2014 null response`);
|
|
27267
|
+
}
|
|
27268
|
+
return Response.json({ label });
|
|
27269
|
+
} catch (err) {
|
|
27270
|
+
console.error(`[admin] manual-label: haiku failed for ${conversationId} \u2014 ${err instanceof Error ? err.message : String(err)}`);
|
|
27271
|
+
return Response.json({ label: null });
|
|
27272
|
+
}
|
|
27273
|
+
}
|
|
27274
|
+
async function PUT(req, { params }) {
|
|
27275
|
+
const { id: conversationId } = await params;
|
|
27276
|
+
let body;
|
|
27277
|
+
try {
|
|
27278
|
+
body = await req.json();
|
|
27279
|
+
} catch {
|
|
27280
|
+
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
27281
|
+
}
|
|
27282
|
+
const sessionKey = body.session_key;
|
|
27283
|
+
if (!sessionKey) {
|
|
27284
|
+
return Response.json({ error: "session_key required" }, { status: 400 });
|
|
27285
|
+
}
|
|
27286
|
+
if (!validateSession(sessionKey, "admin")) {
|
|
27287
|
+
return Response.json({ error: "Invalid or expired admin session" }, { status: 401 });
|
|
27288
|
+
}
|
|
27289
|
+
const accountId = getAccountIdForSession(sessionKey);
|
|
27290
|
+
if (!accountId) {
|
|
27291
|
+
return Response.json({ error: "Account not found for session" }, { status: 401 });
|
|
27292
|
+
}
|
|
27293
|
+
const owned = await verifyConversationOwnership(conversationId, accountId);
|
|
27294
|
+
if (!owned) {
|
|
27295
|
+
return Response.json({ error: "Conversation not found" }, { status: 404 });
|
|
27296
|
+
}
|
|
27297
|
+
const label = typeof body.label === "string" ? body.label.trim() : "";
|
|
27298
|
+
if (!label) {
|
|
27299
|
+
return Response.json({ error: "label is required and must be non-empty" }, { status: 400 });
|
|
27300
|
+
}
|
|
27301
|
+
if (label.length > LABEL_MAX_LENGTH) {
|
|
27302
|
+
return Response.json({ error: `label must be ${LABEL_MAX_LENGTH} characters or fewer` }, { status: 400 });
|
|
27303
|
+
}
|
|
27304
|
+
try {
|
|
27305
|
+
await renameConversation(conversationId, label);
|
|
27306
|
+
return Response.json({ ok: true });
|
|
27307
|
+
} catch (err) {
|
|
27308
|
+
console.error(`[persist] manual-label: failed to rename ${conversationId} \u2014 ${err instanceof Error ? err.message : String(err)}`);
|
|
27309
|
+
return Response.json({ error: "Failed to rename session" }, { status: 500 });
|
|
27310
|
+
}
|
|
27311
|
+
}
|
|
27312
|
+
|
|
27213
27313
|
// app/api/admin/browser/launch/route.ts
|
|
27214
|
-
async function
|
|
27314
|
+
async function POST24() {
|
|
27215
27315
|
try {
|
|
27216
27316
|
const vncOk = await ensureVnc();
|
|
27217
27317
|
if (!vncOk) {
|
|
@@ -27609,7 +27709,7 @@ app.post("/api/admin/file-attach", (c) => POST16(c.req.raw));
|
|
|
27609
27709
|
app.get("/api/admin/version", () => GET9());
|
|
27610
27710
|
app.post("/api/admin/version/upgrade", (c) => POST22(c.req.raw));
|
|
27611
27711
|
app.get("/api/admin/agents", () => GET8());
|
|
27612
|
-
app.post("/api/admin/browser/launch", () =>
|
|
27712
|
+
app.post("/api/admin/browser/launch", () => POST24());
|
|
27613
27713
|
app.get("/api/admin/sessions", (c) => GET10(c.req.raw));
|
|
27614
27714
|
app.delete(
|
|
27615
27715
|
"/api/admin/sessions/:id",
|
|
@@ -27619,6 +27719,14 @@ app.get(
|
|
|
27619
27719
|
"/api/admin/sessions/:id/messages",
|
|
27620
27720
|
(c) => GET11(c.req.raw, { params: Promise.resolve({ id: c.req.param("id") }) })
|
|
27621
27721
|
);
|
|
27722
|
+
app.post(
|
|
27723
|
+
"/api/admin/sessions/:id/label",
|
|
27724
|
+
(c) => POST23(c.req.raw, { params: Promise.resolve({ id: c.req.param("id") }) })
|
|
27725
|
+
);
|
|
27726
|
+
app.put(
|
|
27727
|
+
"/api/admin/sessions/:id/label",
|
|
27728
|
+
(c) => PUT(c.req.raw, { params: Promise.resolve({ id: c.req.param("id") }) })
|
|
27729
|
+
);
|
|
27622
27730
|
var SAFE_SLUG_RE = /^[a-z][a-z0-9-]{2,49}$/;
|
|
27623
27731
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
27624
27732
|
var IMAGE_MIME = {
|