@okostream/mcp 0.12.7 → 0.12.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/server.js +63 -21
  2. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -116224,7 +116224,7 @@ function sanitizeScopes(scopes) {
116224
116224
  }
116225
116225
 
116226
116226
  // build/version.js
116227
- var OKO_MCP_VERSION = "0.12.7";
116227
+ var OKO_MCP_VERSION = "0.12.8";
116228
116228
 
116229
116229
  // build/auth.js
116230
116230
  var state = null;
@@ -116348,29 +116348,40 @@ async function exchangeApiKey() {
116348
116348
  latestVersion: typeof data.latestVersion === "string" && parseVersion(data.latestVersion) ? data.latestVersion.trim() : null
116349
116349
  };
116350
116350
  }
116351
- async function ensureAuth(requiredScopes = []) {
116351
+ function singleFlight(run) {
116352
+ let inFlight = null;
116353
+ return () => {
116354
+ inFlight ??= run().finally(() => {
116355
+ inFlight = null;
116356
+ });
116357
+ return inFlight;
116358
+ };
116359
+ }
116360
+ var refreshSession = singleFlight(async () => {
116352
116361
  const now = Date.now();
116353
- if (!state || now > state.expiresAt - 5 * 60 * 1e3 || !auth.currentUser) {
116354
- const exchanged = await exchangeApiKey();
116355
- try {
116356
- await signInWithCustomToken(auth, exchanged.customToken);
116357
- } catch {
116358
- throw new OkoAuthError("unavailable", "OKO MCP received an organizer session but could not initialize it. Reconnect and try again.");
116359
- }
116360
- state = {
116361
- uid: exchanged.organizerUid,
116362
- scopes: exchanged.scopes,
116363
- expiresAt: now + exchanged.expiresIn * 1e3
116364
- };
116365
- if (exchanged.latestVersion)
116366
- recordLatestPublishedVersion(exchanged.latestVersion);
116362
+ const exchanged = await exchangeApiKey();
116363
+ try {
116364
+ await signInWithCustomToken(auth, exchanged.customToken);
116365
+ } catch {
116366
+ throw new OkoAuthError("unavailable", "OKO MCP received an organizer session but could not initialize it. Reconnect and try again.");
116367
116367
  }
116368
+ state = {
116369
+ uid: exchanged.organizerUid,
116370
+ scopes: exchanged.scopes,
116371
+ expiresAt: now + exchanged.expiresIn * 1e3
116372
+ };
116373
+ if (exchanged.latestVersion)
116374
+ recordLatestPublishedVersion(exchanged.latestVersion);
116375
+ return state;
116376
+ });
116377
+ async function ensureAuth(requiredScopes = []) {
116378
+ const current = state && Date.now() <= state.expiresAt - 5 * 60 * 1e3 && auth.currentUser ? state : await refreshSession();
116368
116379
  for (const scope of requiredScopes) {
116369
- if (!state.scopes.includes(scope)) {
116380
+ if (!current.scopes.includes(scope)) {
116370
116381
  throw new OkoScopeError(scope);
116371
116382
  }
116372
116383
  }
116373
- return state;
116384
+ return current;
116374
116385
  }
116375
116386
  function currentScopes() {
116376
116387
  return state?.scopes ?? [];
@@ -116665,6 +116676,27 @@ async function responseBufferWithLimit(response, maxBytes) {
116665
116676
  }
116666
116677
  return Buffer.concat(chunks, total);
116667
116678
  }
116679
+ function shareLinkHint(url) {
116680
+ let host = "";
116681
+ try {
116682
+ host = new URL(url).hostname.toLowerCase();
116683
+ } catch {
116684
+ return "";
116685
+ }
116686
+ if (host === "drive.google.com" || host === "docs.google.com") {
116687
+ return " This is a Google Drive page, not the file: share it as 'anyone with the link' and use https://drive.google.com/uc?export=download&id=<fileId>, or download the file and pass source.path.";
116688
+ }
116689
+ if (host.endsWith("disk.yandex.ru") || host.endsWith("disk.yandex.com") || host === "yadi.sk" || host.endsWith("disk.360.yandex.ru")) {
116690
+ return " This is a Yandex Disk page, not the file: use the direct download link from the page (\u0421\u043A\u0430\u0447\u0430\u0442\u044C \u2192 copy link), or download the file and pass source.path.";
116691
+ }
116692
+ if (host === "dropbox.com" || host.endsWith(".dropbox.com")) {
116693
+ return " This is a Dropbox page: replace ?dl=0 with ?dl=1 in the link, or download the file and pass source.path.";
116694
+ }
116695
+ if (host.endsWith("onedrive.live.com") || host === "1drv.ms" || host.endsWith("sharepoint.com")) {
116696
+ return " This is a OneDrive page: use its direct download link, or download the file and pass source.path.";
116697
+ }
116698
+ return " Use a direct link to the image file (right-click the image \u2192 copy image address), or download the file and pass source.path.";
116699
+ }
116668
116700
  async function readRemoteImage(rawUrl, redirects = 0) {
116669
116701
  if (redirects > REMOTE_IMAGE_MAX_REDIRECTS) {
116670
116702
  throw new Error("Image URL has too many redirects.");
@@ -116697,7 +116729,7 @@ async function readRemoteImage(rawUrl, redirects = 0) {
116697
116729
  }
116698
116730
  const contentType = (response.headers.get("content-type") ?? "").split(";")[0]?.trim().toLowerCase();
116699
116731
  if (!contentType || !contentType.startsWith("image/")) {
116700
- throw new Error("Image URL must return Content-Type image/*.");
116732
+ throw new Error(`Image URL must return Content-Type image/* (got ${contentType || "none"}).${shareLinkHint(rawUrl)}`);
116701
116733
  }
116702
116734
  if (!ALLOWED_REMOTE_IMAGE_TYPES.has(contentType)) {
116703
116735
  throw new Error(`Image URL Content-Type ${contentType} is not supported. Use JPEG, PNG, WEBP, GIF, or AVIF.`);
@@ -116760,6 +116792,12 @@ function serverFetchRefusal(error3) {
116760
116792
  if (code === "functions/invalid-argument" && message.includes("Image payload is empty or too large")) {
116761
116793
  return { reason: "server_without_url_support", message: "The OKO server release in use does not fetch URLs yet." };
116762
116794
  }
116795
+ if (code === "functions/deadline-exceeded") {
116796
+ return { reason: "server_timeout", message: "The OKO server did not finish fetching the URL within its time limit." };
116797
+ }
116798
+ if (code === "functions/internal") {
116799
+ return { reason: "server_error", message: message && message !== "internal" ? message : "The OKO server failed while fetching the URL." };
116800
+ }
116763
116801
  return null;
116764
116802
  }
116765
116803
  var SERVER_FETCH_NOTE = "Image fetched by the OKO server directly from the URL; this machine's network was not involved.";
@@ -118358,7 +118396,10 @@ function registerEventTools(server2) {
118358
118396
  summary: "Read one OKO event visible to the organizer.",
118359
118397
  args: ["eventId: OKO event document id."],
118360
118398
  returns: "full event document fields plus id and public event URL.",
118361
- examples: ["Use after oko_create_webinar to verify setup and return the event URL to the user."]
118399
+ examples: ["Use after oko_create_webinar to verify setup and return the event URL to the user."],
118400
+ notes: [
118401
+ "blocks.chat.mode is a legacy field written by older cabinet versions and read by nothing; chat visibility is blocks.chat.visibility (always | hidden). Ignore mode."
118402
+ ]
118362
118403
  }),
118363
118404
  inputSchema: { eventId: eventIdField },
118364
118405
  outputSchema: eventOutputSchema,
@@ -120474,7 +120515,7 @@ function registerWorkspaceTools(server2) {
120474
120515
  description: toolDescription({
120475
120516
  summary: "Accept a workspace invite code for the authenticated organizer.",
120476
120517
  args: ["code: invite code from /invite/{code}.", "confirm: must be true."],
120477
- returns: "success plus workspace id/name returned by OKO CF19.",
120518
+ returns: "success, workspace id/name, and keptExistingPermissions: true when the organizer was already a member \u2014 an invite never changes existing permissions; the owner changes them with oko_update_workspace_member.",
120478
120519
  examples: ["Use when the organizer wants to join a workspace from an invite code."]
120479
120520
  }),
120480
120521
  inputSchema: {
@@ -120483,6 +120524,7 @@ function registerWorkspaceTools(server2) {
120483
120524
  },
120484
120525
  outputSchema: external_exports.object({
120485
120526
  success: external_exports.boolean(),
120527
+ keptExistingPermissions: external_exports.boolean().optional(),
120486
120528
  workspace: external_exports.object({ id: external_exports.string(), name: external_exports.string() }).passthrough()
120487
120529
  }).passthrough(),
120488
120530
  annotations: writeTool
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@okostream/mcp",
3
- "version": "0.12.7",
3
+ "version": "0.12.8",
4
4
  "description": "Control OKO Stream webinars from Claude, Codex, and other MCP clients.",
5
5
  "license": "UNLICENSED",
6
6
  "author": {