Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/JAVA/Openclaw/extensions/google-meet/src/   (KI Agentensystem Version 22©)  Datei vom 26.3.2026 mit Größe 21 kB image not shown  

Quelle  meet.ts

  Sprache: JAVA
 

Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";

const GOOGLE_MEET_API_ORIGIN = "https://meet.googleapis.com";
const GOOGLE_MEET_API_BASE_URL = `${GOOGLE_MEET_API_ORIGIN}/v2`;
const GOOGLE_MEET_URL_HOST = "meet.google.com";
const GOOGLE_MEET_API_HOST = "meet.googleapis.com";

export type GoogleMeetSpace = {
  name: string;
  meetingCode?: string;
  meetingUri?: string;
  activeConference?: Record<string, unknown>;
  config?: Record<string, unknown>;
};

export type GoogleMeetPreflightReport = {
  input: string;
  resolvedSpaceName: string;
  meetingCode?: string;
  meetingUri?: string;
  hasActiveConference: boolean;
  previewAcknowledged: boolean;
  tokenSource: "cached-access-token" | "refresh-token";
  blockers: string[];
};

export type GoogleMeetCreateSpaceResult = {
  space: GoogleMeetSpace;
  meetingUri: string;
};

export type GoogleMeetConferenceRecord = {
  name: string;
  space?: string;
  startTime?: string;
  endTime?: string;
  expireTime?: string;
};

export type GoogleMeetParticipant = {
  name: string;
  earliestStartTime?: string;
  latestEndTime?: string;
  signedinUser?: {
    user?: string;
    displayName?: string;
  };
  anonymousUser?: {
    displayName?: string;
  };
  phoneUser?: {
    displayName?: string;
  };
};

export type GoogleMeetParticipantSession = {
  name: string;
  startTime?: string;
  endTime?: string;
};

export type GoogleMeetRecording = {
  name: string;
  startTime?: string;
  endTime?: string;
  driveDestination?: Record<string, unknown>;
};

export type GoogleMeetTranscript = {
  name: string;
  startTime?: string;
  endTime?: string;
  docsDestination?: Record<string, unknown>;
};

export type GoogleMeetTranscriptEntry = {
  name: string;
  participant?: string;
  text?: string;
  languageCode?: string;
  startTime?: string;
  endTime?: string;
};

export type GoogleMeetTranscriptEntries = {
  transcript: string;
  entries: GoogleMeetTranscriptEntry[];
  entriesError?: string;
};

export type GoogleMeetSmartNote = {
  name: string;
  startTime?: string;
  endTime?: string;
  docsDestination?: Record<string, unknown>;
};

export type GoogleMeetArtifactsEntry = {
  conferenceRecord: GoogleMeetConferenceRecord;
  participants: GoogleMeetParticipant[];
  recordings: GoogleMeetRecording[];
  transcripts: GoogleMeetTranscript[];
  transcriptEntries: GoogleMeetTranscriptEntries[];
  smartNotes: GoogleMeetSmartNote[];
  smartNotesError?: string;
};

export type GoogleMeetArtifactsResult = {
  input?: string;
  space?: GoogleMeetSpace;
  conferenceRecords: GoogleMeetConferenceRecord[];
  artifacts: GoogleMeetArtifactsEntry[];
};

export type GoogleMeetLatestConferenceRecordResult = {
  input: string;
  space: GoogleMeetSpace;
  conferenceRecord?: GoogleMeetConferenceRecord;
};

export type GoogleMeetAttendanceRow = {
  conferenceRecord: string;
  participant: string;
  displayName?: string;
  user?: string;
  earliestStartTime?: string;
  latestEndTime?: string;
  sessions: GoogleMeetParticipantSession[];
};

export type GoogleMeetAttendanceResult = {
  input?: string;
  space?: GoogleMeetSpace;
  conferenceRecords: GoogleMeetConferenceRecord[];
  attendance: GoogleMeetAttendanceRow[];
};

type GoogleMeetSmartNotesListResult = {
  smartNotes: GoogleMeetSmartNote[];
  smartNotesError?: string;
};

export function normalizeGoogleMeetSpaceName(input: string): string {
  const trimmed = input.trim();
  if (!trimmed) {
    throw new Error("Meeting input is required");
  }
  if (trimmed.startsWith("spaces/")) {
    const suffix = trimmed.slice("spaces/".length).trim();
    if (!suffix) {
      throw new Error("spaces/ input must include a meeting code or space id");
    }
    return `spaces/${suffix}`;
  }
  if (/^https?:\/\//i.test(trimmed)) {
    const url = new URL(trimmed);
    if (url.hostname !== GOOGLE_MEET_URL_HOST) {
      throw new Error(`Expected a ${GOOGLE_MEET_URL_HOST} URL, received ${url.hostname}`);
    }
    const firstSegment = url.pathname
      .split("/")
      .map((segment) => segment.trim())
      .find(Boolean);
    if (!firstSegment) {
      throw new Error("Google Meet URL did not include a meeting code");
    }
    return `spaces/${firstSegment}`;
  }
  return `spaces/${trimmed}`;
}

function encodeSpaceNameForPath(name: string): string {
  return name.split("/").map(encodeURIComponent).join("/");
}

function encodeResourceNameForPath(name: string): string {
  const trimmed = name.trim();
  if (!trimmed) {
    throw new Error("Google Meet resource name is required");
  }
  return trimmed.split("/").map(encodeURIComponent).join("/");
}

function normalizeConferenceRecordName(input: string): string {
  const trimmed = input.trim();
  if (!trimmed) {
    throw new Error("Conference record is required");
  }
  return trimmed.startsWith("conferenceRecords/") ? trimmed : `conferenceRecords/${trimmed}`;
}

function appendQuery(
  url: string,
  query?: Record<string, string | number | boolean | undefined>,
): string {
  if (!query) {
    return url;
  }
  const parsed = new URL(url);
  for (const [key, value] of Object.entries(query)) {
    if (value !== undefined) {
      parsed.searchParams.set(key, String(value));
    }
  }
  return parsed.toString();
}

function assertResourceArray<T extends { name?: string }>(
  value: unknown,
  key: string,
  context: string,
): T[] {
  if (value === undefined) {
    return [];
  }
  if (!Array.isArray(value)) {
    throw new Error(`Google Meet ${context} response had non-array ${key}`);
  }
  const resources = value as T[];
  for (const resource of resources) {
    if (!resource.name?.trim()) {
      throw new Error(`Google Meet ${context} response included a resource without name`);
    }
  }
  return resources;
}

function getErrorMessage(error: unknown): string {
  return error instanceof Error ? error.message : String(error);
}

async function fetchGoogleMeetJson<T>(params: {
  accessToken: string;
  path: string;
  query?: Record<string, string | number | boolean | undefined>;
  auditContext: string;
  errorPrefix: string;
}): Promise<T> {
  const { response, release } = await fetchWithSsrFGuard({
    url: appendQuery(`${GOOGLE_MEET_API_BASE_URL}/${params.path}`, params.query),
    init: {
      headers: {
        Authorization: `Bearer ${params.accessToken}`,
        Accept: "application/json",
      },
    },
    policy: { allowedHostnames: [GOOGLE_MEET_API_HOST] },
    auditContext: params.auditContext,
  });
  try {
    if (!response.ok) {
      const detail = await response.text();
      throw new Error(`${params.errorPrefix} failed (${response.status}): ${detail}`);
    }
    return (await response.json()) as T;
  } finally {
    await release();
  }
}

async function listGoogleMeetCollection<T extends { name?: string }>(params: {
  accessToken: string;
  path: string;
  collectionKey: string;
  query?: Record<string, string | number | boolean | undefined>;
  maxItems?: number;
  auditContext: string;
  errorPrefix: string;
}): Promise<T[]> {
  const items: T[] = [];
  let pageToken: string | undefined;
  do {
    const payload = await fetchGoogleMeetJson<Record<string, unknown>>({
      accessToken: params.accessToken,
      path: params.path,
      query: { ...params.query, pageToken },
      auditContext: params.auditContext,
      errorPrefix: params.errorPrefix,
    });
    const pageItems = assertResourceArray<T>(
      payload[params.collectionKey],
      params.collectionKey,
      params.errorPrefix,
    );
    const remaining =
      typeof params.maxItems === "number" ? Math.max(params.maxItems - items.length, 0) : undefined;
    items.push(...(remaining === undefined ? pageItems : pageItems.slice(0, remaining)));
    if (typeof params.maxItems === "number" && items.length >= params.maxItems) {
      break;
    }
    pageToken = typeof payload.nextPageToken === "string" ? payload.nextPageToken : undefined;
  } while (pageToken);
  return items;
}

export async function fetchGoogleMeetSpace(params: {
  accessToken: string;
  meeting: string;
}): Promise<GoogleMeetSpace> {
  const name = normalizeGoogleMeetSpaceName(params.meeting);
  const { response, release } = await fetchWithSsrFGuard({
    url: `${GOOGLE_MEET_API_BASE_URL}/${encodeSpaceNameForPath(name)}`,
    init: {
      headers: {
        Authorization: `Bearer ${params.accessToken}`,
        Accept: "application/json",
      },
    },
    policy: { allowedHostnames: [GOOGLE_MEET_API_HOST] },
    auditContext: "google-meet.spaces.get",
  });
  try {
    if (!response.ok) {
      const detail = await response.text();
      throw new Error(`Google Meet spaces.get failed (${response.status}): ${detail}`);
    }
    const payload = (await response.json()) as GoogleMeetSpace;
    if (!payload.name?.trim()) {
      throw new Error("Google Meet spaces.get response was missing name");
    }
    return payload;
  } finally {
    await release();
  }
}

export async function createGoogleMeetSpace(params: {
  accessToken: string;
}): Promise<GoogleMeetCreateSpaceResult> {
  const { response, release } = await fetchWithSsrFGuard({
    url: `${GOOGLE_MEET_API_BASE_URL}/spaces`,
    init: {
      method: "POST",
      headers: {
        Authorization: `Bearer ${params.accessToken}`,
        Accept: "application/json",
        "Content-Type": "application/json",
      },
      body: "{}",
    },
    policy: { allowedHostnames: [GOOGLE_MEET_API_HOST] },
    auditContext: "google-meet.spaces.create",
  });
  try {
    if (!response.ok) {
      const detail = await response.text();
      throw new Error(`Google Meet spaces.create failed (${response.status}): ${detail}`);
    }
    const payload = (await response.json()) as GoogleMeetSpace;
    if (!payload.name?.trim()) {
      throw new Error("Google Meet spaces.create response was missing name");
    }
    const meetingUri = payload.meetingUri?.trim();
    if (!meetingUri) {
      throw new Error("Google Meet spaces.create response was missing meetingUri");
    }
    return { space: payload, meetingUri };
  } finally {
    await release();
  }
}

export async function fetchGoogleMeetConferenceRecord(params: {
  accessToken: string;
  conferenceRecord: string;
}): Promise<GoogleMeetConferenceRecord> {
  const name = normalizeConferenceRecordName(params.conferenceRecord);
  const payload = await fetchGoogleMeetJson<GoogleMeetConferenceRecord>({
    accessToken: params.accessToken,
    path: encodeResourceNameForPath(name),
    auditContext: "google-meet.conferenceRecords.get",
    errorPrefix: "Google Meet conferenceRecords.get",
  });
  if (!payload.name?.trim()) {
    throw new Error("Google Meet conferenceRecords.get response was missing name");
  }
  return payload;
}

export async function listGoogleMeetConferenceRecords(params: {
  accessToken: string;
  meeting?: string;
  pageSize?: number;
  maxItems?: number;
}): Promise<GoogleMeetConferenceRecord[]> {
  const filter = params.meeting
    ? `space.name = "${normalizeGoogleMeetSpaceName(params.meeting)}"`
    : undefined;
  return listGoogleMeetCollection<GoogleMeetConferenceRecord>({
    accessToken: params.accessToken,
    path: "conferenceRecords",
    collectionKey: "conferenceRecords",
    query: {
      pageSize: params.pageSize,
      filter,
    },
    maxItems: params.maxItems,
    auditContext: "google-meet.conferenceRecords.list",
    errorPrefix: "Google Meet conferenceRecords.list",
  });
}

export async function fetchLatestGoogleMeetConferenceRecord(params: {
  accessToken: string;
  meeting: string;
}): Promise<GoogleMeetLatestConferenceRecordResult> {
  const space = await fetchGoogleMeetSpace({
    accessToken: params.accessToken,
    meeting: params.meeting,
  });
  const [conferenceRecord] = await listGoogleMeetConferenceRecords({
    accessToken: params.accessToken,
    meeting: space.name,
    pageSize: 1,
    maxItems: 1,
  });
  return {
    input: params.meeting,
    space,
    ...(conferenceRecord ? { conferenceRecord } : {}),
  };
}

export async function listGoogleMeetParticipants(params: {
  accessToken: string;
  conferenceRecord: string;
  pageSize?: number;
}): Promise<GoogleMeetParticipant[]> {
  const parent = normalizeConferenceRecordName(params.conferenceRecord);
  return listGoogleMeetCollection<GoogleMeetParticipant>({
    accessToken: params.accessToken,
    path: `${encodeResourceNameForPath(parent)}/participants`,
    collectionKey: "participants",
    query: { pageSize: params.pageSize },
    auditContext: "google-meet.conferenceRecords.participants.list",
    errorPrefix: "Google Meet conferenceRecords.participants.list",
  });
}

export async function listGoogleMeetParticipantSessions(params: {
  accessToken: string;
  participant: string;
  pageSize?: number;
}): Promise<GoogleMeetParticipantSession[]> {
  return listGoogleMeetCollection<GoogleMeetParticipantSession>({
    accessToken: params.accessToken,
    path: `${encodeResourceNameForPath(params.participant)}/participantSessions`,
    collectionKey: "participantSessions",
    query: { pageSize: params.pageSize },
    auditContext: "google-meet.conferenceRecords.participants.participantSessions.list",
    errorPrefix: "Google Meet conferenceRecords.participants.participantSessions.list",
  });
}

export async function listGoogleMeetRecordings(params: {
  accessToken: string;
  conferenceRecord: string;
  pageSize?: number;
}): Promise<GoogleMeetRecording[]> {
  const parent = normalizeConferenceRecordName(params.conferenceRecord);
  return listGoogleMeetCollection<GoogleMeetRecording>({
    accessToken: params.accessToken,
    path: `${encodeResourceNameForPath(parent)}/recordings`,
    collectionKey: "recordings",
    query: { pageSize: params.pageSize },
    auditContext: "google-meet.conferenceRecords.recordings.list",
    errorPrefix: "Google Meet conferenceRecords.recordings.list",
  });
}

export async function listGoogleMeetTranscripts(params: {
  accessToken: string;
  conferenceRecord: string;
  pageSize?: number;
}): Promise<GoogleMeetTranscript[]> {
  const parent = normalizeConferenceRecordName(params.conferenceRecord);
  return listGoogleMeetCollection<GoogleMeetTranscript>({
    accessToken: params.accessToken,
    path: `${encodeResourceNameForPath(parent)}/transcripts`,
    collectionKey: "transcripts",
    query: { pageSize: params.pageSize },
    auditContext: "google-meet.conferenceRecords.transcripts.list",
    errorPrefix: "Google Meet conferenceRecords.transcripts.list",
  });
}

export async function listGoogleMeetTranscriptEntries(params: {
  accessToken: string;
  transcript: string;
  pageSize?: number;
}): Promise<GoogleMeetTranscriptEntry[]> {
  return listGoogleMeetCollection<GoogleMeetTranscriptEntry>({
    accessToken: params.accessToken,
    path: `${encodeResourceNameForPath(params.transcript)}/entries`,
    collectionKey: "transcriptEntries",
    query: { pageSize: params.pageSize },
    auditContext: "google-meet.conferenceRecords.transcripts.entries.list",
    errorPrefix: "Google Meet conferenceRecords.transcripts.entries.list",
  });
}

export async function listGoogleMeetSmartNotes(params: {
  accessToken: string;
  conferenceRecord: string;
  pageSize?: number;
}): Promise<GoogleMeetSmartNote[]> {
  const parent = normalizeConferenceRecordName(params.conferenceRecord);
  return listGoogleMeetCollection<GoogleMeetSmartNote>({
    accessToken: params.accessToken,
    path: `${encodeResourceNameForPath(parent)}/smartNotes`,
    collectionKey: "smartNotes",
    query: { pageSize: params.pageSize },
    auditContext: "google-meet.conferenceRecords.smartNotes.list",
    errorPrefix: "Google Meet conferenceRecords.smartNotes.list",
  });
}

function getParticipantDisplayName(participant: GoogleMeetParticipant): string | undefined {
  return (
    participant.signedinUser?.displayName ??
    participant.anonymousUser?.displayName ??
    participant.phoneUser?.displayName
  );
}

function getParticipantUser(participant: GoogleMeetParticipant): string | undefined {
  return participant.signedinUser?.user;
}

async function resolveConferenceRecordQuery(params: {
  accessToken: string;
  meeting?: string;
  conferenceRecord?: string;
  pageSize?: number;
  allConferenceRecords?: boolean;
}): Promise<{
  input?: string;
  space?: GoogleMeetSpace;
  conferenceRecords: GoogleMeetConferenceRecord[];
}> {
  if (params.conferenceRecord?.trim()) {
    const conferenceRecord = await fetchGoogleMeetConferenceRecord({
      accessToken: params.accessToken,
      conferenceRecord: params.conferenceRecord,
    });
    return {
      input: params.conferenceRecord.trim(),
      conferenceRecords: [conferenceRecord],
    };
  }
  if (!params.meeting?.trim()) {
    throw new Error("Meeting input or conference record is required");
  }
  const space = await fetchGoogleMeetSpace({
    accessToken: params.accessToken,
    meeting: params.meeting,
  });
  const conferenceRecords = await listGoogleMeetConferenceRecords({
    accessToken: params.accessToken,
    meeting: space.name,
    pageSize: params.allConferenceRecords ? params.pageSize : 1,
    maxItems: params.allConferenceRecords ? undefined : 1,
  });
  return {
    input: params.meeting,
    space,
    conferenceRecords,
  };
}

export async function fetchGoogleMeetArtifacts(params: {
  accessToken: string;
  meeting?: string;
  conferenceRecord?: string;
  pageSize?: number;
  includeTranscriptEntries?: boolean;
  allConferenceRecords?: boolean;
}): Promise<GoogleMeetArtifactsResult> {
  const resolved = await resolveConferenceRecordQuery(params);
  const artifacts = await Promise.all(
    resolved.conferenceRecords.map(async (conferenceRecord) => {
      const [participants, recordings, transcripts, smartNotesResult] = await Promise.all([
        listGoogleMeetParticipants({
          accessToken: params.accessToken,
          conferenceRecord: conferenceRecord.name,
          pageSize: params.pageSize,
        }),
        listGoogleMeetRecordings({
          accessToken: params.accessToken,
          conferenceRecord: conferenceRecord.name,
          pageSize: params.pageSize,
        }),
        listGoogleMeetTranscripts({
          accessToken: params.accessToken,
          conferenceRecord: conferenceRecord.name,
          pageSize: params.pageSize,
        }),
        listGoogleMeetSmartNotes({
          accessToken: params.accessToken,
          conferenceRecord: conferenceRecord.name,
          pageSize: params.pageSize,
        })
          .then<GoogleMeetSmartNotesListResult>((smartNotes) => ({ smartNotes }))
          .catch((error: unknown) => ({
            smartNotes: [],
            smartNotesError: getErrorMessage(error),
          })),
      ]);
      const transcriptEntries =
        params.includeTranscriptEntries === false
          ? []
          : await Promise.all(
              transcripts.map(async (transcript) => {
                try {
                  return {
                    transcript: transcript.name,
                    entries: await listGoogleMeetTranscriptEntries({
                      accessToken: params.accessToken,
                      transcript: transcript.name,
                      pageSize: params.pageSize,
                    }),
                  };
                } catch (error) {
                  return {
                    transcript: transcript.name,
                    entries: [],
                    entriesError: getErrorMessage(error),
                  };
                }
              }),
            );
      return {
        conferenceRecord,
        participants,
        recordings,
        transcripts,
        transcriptEntries,
        smartNotes: smartNotesResult.smartNotes,
        ...(smartNotesResult.smartNotesError
          ? { smartNotesError: smartNotesResult.smartNotesError }
          : {}),
      };
    }),
  );
  return {
    input: resolved.input,
    space: resolved.space,
    conferenceRecords: resolved.conferenceRecords,
    artifacts,
  };
}

export async function fetchGoogleMeetAttendance(params: {
  accessToken: string;
  meeting?: string;
  conferenceRecord?: string;
  pageSize?: number;
  allConferenceRecords?: boolean;
}): Promise<GoogleMeetAttendanceResult> {
  const resolved = await resolveConferenceRecordQuery(params);
  const nestedRows = await Promise.all(
    resolved.conferenceRecords.map(async (conferenceRecord) => {
      const participants = await listGoogleMeetParticipants({
        accessToken: params.accessToken,
        conferenceRecord: conferenceRecord.name,
        pageSize: params.pageSize,
      });
      return Promise.all(
        participants.map(async (participant) => ({
          conferenceRecord: conferenceRecord.name,
          participant: participant.name,
          displayName: getParticipantDisplayName(participant),
          user: getParticipantUser(participant),
          earliestStartTime: participant.earliestStartTime,
          latestEndTime: participant.latestEndTime,
          sessions: await listGoogleMeetParticipantSessions({
            accessToken: params.accessToken,
            participant: participant.name,
            pageSize: params.pageSize,
          }),
        })),
      );
    }),
  );
  return {
    input: resolved.input,
    space: resolved.space,
    conferenceRecords: resolved.conferenceRecords,
    attendance: nestedRows.flat(),
  };
}

export function buildGoogleMeetPreflightReport(params: {
  input: string;
  space: GoogleMeetSpace;
  previewAcknowledged: boolean;
  tokenSource: "cached-access-token" | "refresh-token";
}): GoogleMeetPreflightReport {
  const blockers: string[] = [];
  if (!params.previewAcknowledged) {
    blockers.push(
      "Set preview.enrollmentAcknowledged=true after confirming your Cloud project, OAuth principal, and meeting participants are enrolled in the Google Workspace Developer Preview Program.",
    );
  }
  return {
    input: params.input,
    resolvedSpaceName: params.space.name,
    meetingCode: params.space.meetingCode,
    meetingUri: params.space.meetingUri,
    hasActiveConference: Boolean(params.space.activeConference),
    previewAcknowledged: params.previewAcknowledged,
    tokenSource: params.tokenSource,
    blockers,
  };
}

¤ Dauer der Verarbeitung: 0.25 Sekunden  (vorverarbeitet am  2026-04-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.