@okostream/mcp 0.12.10 → 0.12.11
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/server.js +56 -23
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -116291,7 +116291,7 @@ function sanitizeScopes(scopes) {
|
|
|
116291
116291
|
}
|
|
116292
116292
|
|
|
116293
116293
|
// build/version.js
|
|
116294
|
-
var OKO_MCP_VERSION = "0.12.
|
|
116294
|
+
var OKO_MCP_VERSION = "0.12.11";
|
|
116295
116295
|
|
|
116296
116296
|
// build/auth.js
|
|
116297
116297
|
var state = null;
|
|
@@ -117195,16 +117195,43 @@ async function updateCardImageInTransaction(eventId, cardId, patch) {
|
|
|
117195
117195
|
});
|
|
117196
117196
|
});
|
|
117197
117197
|
}
|
|
117198
|
-
|
|
117198
|
+
function descendPath(root, segments) {
|
|
117199
|
+
let current = root;
|
|
117200
|
+
for (const segment of segments) {
|
|
117201
|
+
if (current === null || typeof current !== "object")
|
|
117202
|
+
return void 0;
|
|
117203
|
+
current = current[segment];
|
|
117204
|
+
}
|
|
117205
|
+
return current;
|
|
117206
|
+
}
|
|
117207
|
+
function valueAfterPatch(fresh, patch, path) {
|
|
117208
|
+
if (Object.prototype.hasOwnProperty.call(patch, path))
|
|
117209
|
+
return patch[path];
|
|
117210
|
+
const segments = path.split(".");
|
|
117211
|
+
for (let cut = segments.length - 1; cut > 0; cut--) {
|
|
117212
|
+
const ancestor = segments.slice(0, cut).join(".");
|
|
117213
|
+
if (!Object.prototype.hasOwnProperty.call(patch, ancestor))
|
|
117214
|
+
continue;
|
|
117215
|
+
return descendPath(patch[ancestor], segments.slice(cut));
|
|
117216
|
+
}
|
|
117217
|
+
return descendPath(fresh, segments);
|
|
117218
|
+
}
|
|
117219
|
+
function scheduleMissesDate(sessionMode, eventDate) {
|
|
117220
|
+
return sessionMode === "schedule" && !eventDate;
|
|
117221
|
+
}
|
|
117222
|
+
async function writeEventPatchWithCards(eventId, basePatch, buildItems, validate = null) {
|
|
117199
117223
|
const eventRef = doc(firestore, "events", eventId);
|
|
117200
117224
|
await runTransaction2(firestore, async (transaction) => {
|
|
117201
117225
|
const snap = await transaction.get(eventRef);
|
|
117202
117226
|
if (!snap.exists())
|
|
117203
117227
|
throw new Error("Event not found.");
|
|
117228
|
+
const fresh = snap.data();
|
|
117204
117229
|
const patch = { ...basePatch };
|
|
117205
117230
|
if (buildItems) {
|
|
117206
|
-
patch["blocks.cards.items"] = buildItems(
|
|
117231
|
+
patch["blocks.cards.items"] = buildItems(fresh);
|
|
117207
117232
|
}
|
|
117233
|
+
if (validate)
|
|
117234
|
+
validate(fresh, patch);
|
|
117208
117235
|
if (Object.keys(patch).length === 0)
|
|
117209
117236
|
return;
|
|
117210
117237
|
transaction.update(eventRef, patch);
|
|
@@ -118425,6 +118452,9 @@ function validateEventSetup(eventId, event) {
|
|
|
118425
118452
|
} else if (eventDateMs < Date.now() - 60 * 60 * 1e3) {
|
|
118426
118453
|
add(warnings, "date_in_past", "meta.eventDate", "Configured webinar date appears to be in the past.");
|
|
118427
118454
|
}
|
|
118455
|
+
if (scheduleMissesDate(event.analyticsSessionMode, meta2.eventDate)) {
|
|
118456
|
+
add(errors, "schedule_missing_date", "analyticsSessionMode", "Session mode is 'schedule' but meta.eventDate is empty, so OKO can never start or end the session automatically and the reminder is never sent. Set eventDate, or switch sessionMode to 'manual' \u2014 oko_update_event accepts both fields in one call.");
|
|
118457
|
+
}
|
|
118428
118458
|
const duplicateFormIds = /* @__PURE__ */ new Set();
|
|
118429
118459
|
const seenFormIds = /* @__PURE__ */ new Set();
|
|
118430
118460
|
forms.forEach((form, index) => {
|
|
@@ -118540,6 +118570,24 @@ function telegramBlocksPatch(args) {
|
|
|
118540
118570
|
"telegram.channelIds": args.telegramChannelIds
|
|
118541
118571
|
};
|
|
118542
118572
|
}
|
|
118573
|
+
function assertScheduleHasDate(fresh, patch) {
|
|
118574
|
+
const missing = scheduleMissesDate(valueAfterPatch(fresh, patch, "analyticsSessionMode"), valueAfterPatch(fresh, patch, "meta.eventDate"));
|
|
118575
|
+
if (!missing)
|
|
118576
|
+
return;
|
|
118577
|
+
throw new Error("sessionMode 'schedule' requires meta.eventDate: without a date OKO can never start the session automatically. Set eventDate in the same call, or switch sessionMode to 'manual' in the same call to clear the date.");
|
|
118578
|
+
}
|
|
118579
|
+
function assertFormBindingsExist(fresh, patch) {
|
|
118580
|
+
const formsAfterPatch = valueAfterPatch(fresh, patch, "forms");
|
|
118581
|
+
const knownFormIds = new Set((Array.isArray(formsAfterPatch) ? formsAfterPatch : []).map((form) => typeof form?.id === "string" ? form.id : null).filter((id) => Boolean(id)));
|
|
118582
|
+
for (const field2 of ["blocks.promoBanner.formId", "blocks.primaryCta.formId"]) {
|
|
118583
|
+
if (!Object.prototype.hasOwnProperty.call(patch, field2))
|
|
118584
|
+
continue;
|
|
118585
|
+
const value = patch[field2];
|
|
118586
|
+
if (typeof value === "string" && value && !knownFormIds.has(value)) {
|
|
118587
|
+
throw new Error(`${field2}: form "${value}" not found in event.forms. Create the form in the same call (or beforehand) \u2014 a button bound to a missing form does nothing for viewers.`);
|
|
118588
|
+
}
|
|
118589
|
+
}
|
|
118590
|
+
}
|
|
118543
118591
|
function configureBlocksScopes(args) {
|
|
118544
118592
|
return Object.keys(telegramBlocksPatch(args)).length > 0 ? ["setup:write", "telegram:write"] : ["setup:write"];
|
|
118545
118593
|
}
|
|
@@ -118719,7 +118767,8 @@ function registerEventTools(server2) {
|
|
|
118719
118767
|
returns: "event id and the list of Firestore fields updated.",
|
|
118720
118768
|
examples: ["Use for title/date/speaker/video edits; use oko_configure_blocks for blocks and forms."],
|
|
118721
118769
|
notes: [
|
|
118722
|
-
"sessionMode 'schedule' makes OKO start and end the analytics session automatically at eventDate for durationMinutes; 'manual' keeps the Start/End buttons and a Telegram reminder 10 minutes before eventDate. This is still an analytics session, not an event status."
|
|
118770
|
+
"sessionMode 'schedule' makes OKO start and end the analytics session automatically at eventDate for durationMinutes; 'manual' keeps the Start/End buttons and a Telegram reminder 10 minutes before eventDate. This is still an analytics session, not an event status.",
|
|
118771
|
+
"sessionMode 'schedule' and eventDate travel together: setting the mode without a date, or clearing the date while the mode stays, is refused. Change both in one call."
|
|
118723
118772
|
]
|
|
118724
118773
|
}),
|
|
118725
118774
|
inputSchema: {
|
|
@@ -118745,13 +118794,7 @@ function registerEventTools(server2) {
|
|
|
118745
118794
|
if (requiredScopes.size === 0)
|
|
118746
118795
|
throw new Error("Provide at least one field to update.");
|
|
118747
118796
|
const { uid } = await authed([...requiredScopes]);
|
|
118748
|
-
|
|
118749
|
-
if (args.sessionMode === "schedule") {
|
|
118750
|
-
const dateAfterPatch = args.eventDate !== void 0 ? args.eventDate : current.meta?.eventDate ?? null;
|
|
118751
|
-
if (!dateAfterPatch) {
|
|
118752
|
-
throw new Error("sessionMode 'schedule' requires meta.eventDate: without a date OKO can never start the session automatically. Set eventDate in the same call, or keep sessionMode 'manual'.");
|
|
118753
|
-
}
|
|
118754
|
-
}
|
|
118797
|
+
await readEvent(args.eventId, uid, "edit");
|
|
118755
118798
|
const patch = {};
|
|
118756
118799
|
if (args.title !== void 0)
|
|
118757
118800
|
patch.title = args.title.trim();
|
|
@@ -118776,7 +118819,7 @@ function registerEventTools(server2) {
|
|
|
118776
118819
|
patch.analyticsSessionMode = args.sessionMode;
|
|
118777
118820
|
if (args.durationMinutes !== void 0)
|
|
118778
118821
|
patch["meta.durationMinutes"] = args.durationMinutes;
|
|
118779
|
-
await
|
|
118822
|
+
await writeEventPatchWithCards(args.eventId, patch, null, assertScheduleHasDate);
|
|
118780
118823
|
return textResult({ id: args.eventId, updated: Object.keys(patch) });
|
|
118781
118824
|
});
|
|
118782
118825
|
server2.registerTool("oko_configure_blocks", {
|
|
@@ -118874,17 +118917,7 @@ function registerEventTools(server2) {
|
|
|
118874
118917
|
}))
|
|
118875
118918
|
}));
|
|
118876
118919
|
Object.assign(patch, telegramPatch);
|
|
118877
|
-
|
|
118878
|
-
const knownFormIds = new Set((Array.isArray(formsAfterPatch) ? formsAfterPatch : []).map((form) => typeof form?.id === "string" ? form.id : null).filter((id) => Boolean(id)));
|
|
118879
|
-
for (const [field2, value] of [
|
|
118880
|
-
["blocks.promoBanner.formId", patch["blocks.promoBanner.formId"]],
|
|
118881
|
-
["blocks.primaryCta.formId", patch["blocks.primaryCta.formId"]]
|
|
118882
|
-
]) {
|
|
118883
|
-
if (typeof value === "string" && value && !knownFormIds.has(value)) {
|
|
118884
|
-
throw new Error(`${field2}: form "${value}" not found in event.forms. Create the form in the same call (or beforehand) \u2014 a button bound to a missing form does nothing for viewers.`);
|
|
118885
|
-
}
|
|
118886
|
-
}
|
|
118887
|
-
await updateDoc(doc(firestore, "events", args.eventId), patch);
|
|
118920
|
+
await writeEventPatchWithCards(args.eventId, patch, null, assertFormBindingsExist);
|
|
118888
118921
|
const hints = [];
|
|
118889
118922
|
if (args.chat?.visibility !== void 0) {
|
|
118890
118923
|
hints.push("blocks.chat.visibility was stored but the event page does not read it: the chat panel exists exactly when blocks.chat.enabled is true, and sending is opened or closed live with oko_set_chat_mode. Drop the field.");
|