@open-everywhere/adapters 0.5.0 → 0.7.0

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 (75) hide show
  1. package/agent/directory/okta.ts +41 -2
  2. package/agent/meetings/native-http.ts +72 -0
  3. package/agent/meetings/native-meet.ts +173 -0
  4. package/agent/meetings/native-sources.ts +14 -0
  5. package/agent/meetings/native-teams.ts +119 -0
  6. package/agent/meetings/native-zoom.ts +98 -0
  7. package/agent/model/gateway.ts +44 -4
  8. package/agent/model/meeting-gateway.ts +88 -0
  9. package/agent/model/transcription-routes.ts +347 -0
  10. package/agent/oe-oauth/config.ts +71 -3
  11. package/agent/oe-oauth/errors.ts +17 -0
  12. package/agent/oe-oauth/oauth-client.ts +118 -2
  13. package/agent/oe-oauth/token-vault.ts +359 -8
  14. package/agent/register-defaults.ts +11 -0
  15. package/agent/sandbox/long-lived-box.ts +464 -0
  16. package/dist/agent/directory/okta.d.ts +10 -0
  17. package/dist/agent/directory/okta.d.ts.map +1 -1
  18. package/dist/agent/directory/okta.js +34 -2
  19. package/dist/agent/directory/okta.js.map +1 -1
  20. package/dist/agent/meetings/native-http.d.ts +22 -0
  21. package/dist/agent/meetings/native-http.d.ts.map +1 -0
  22. package/dist/agent/meetings/native-http.js +61 -0
  23. package/dist/agent/meetings/native-http.js.map +1 -0
  24. package/dist/agent/meetings/native-meet.d.ts +6 -0
  25. package/dist/agent/meetings/native-meet.d.ts.map +1 -0
  26. package/dist/agent/meetings/native-meet.js +176 -0
  27. package/dist/agent/meetings/native-meet.js.map +1 -0
  28. package/dist/agent/meetings/native-sources.d.ts +2 -0
  29. package/dist/agent/meetings/native-sources.d.ts.map +1 -0
  30. package/dist/agent/meetings/native-sources.js +13 -0
  31. package/dist/agent/meetings/native-sources.js.map +1 -0
  32. package/dist/agent/meetings/native-teams.d.ts +6 -0
  33. package/dist/agent/meetings/native-teams.d.ts.map +1 -0
  34. package/dist/agent/meetings/native-teams.js +118 -0
  35. package/dist/agent/meetings/native-teams.js.map +1 -0
  36. package/dist/agent/meetings/native-zoom.d.ts +7 -0
  37. package/dist/agent/meetings/native-zoom.d.ts.map +1 -0
  38. package/dist/agent/meetings/native-zoom.js +98 -0
  39. package/dist/agent/meetings/native-zoom.js.map +1 -0
  40. package/dist/agent/model/gateway.d.ts +10 -0
  41. package/dist/agent/model/gateway.d.ts.map +1 -1
  42. package/dist/agent/model/gateway.js +43 -5
  43. package/dist/agent/model/gateway.js.map +1 -1
  44. package/dist/agent/model/meeting-gateway.d.ts +24 -0
  45. package/dist/agent/model/meeting-gateway.d.ts.map +1 -0
  46. package/dist/agent/model/meeting-gateway.js +75 -0
  47. package/dist/agent/model/meeting-gateway.js.map +1 -0
  48. package/dist/agent/model/transcription-routes.d.ts +89 -0
  49. package/dist/agent/model/transcription-routes.d.ts.map +1 -0
  50. package/dist/agent/model/transcription-routes.js +279 -0
  51. package/dist/agent/model/transcription-routes.js.map +1 -0
  52. package/dist/agent/oe-oauth/config.d.ts +28 -2
  53. package/dist/agent/oe-oauth/config.d.ts.map +1 -1
  54. package/dist/agent/oe-oauth/config.js +40 -1
  55. package/dist/agent/oe-oauth/config.js.map +1 -1
  56. package/dist/agent/oe-oauth/errors.d.ts +14 -0
  57. package/dist/agent/oe-oauth/errors.d.ts.map +1 -1
  58. package/dist/agent/oe-oauth/errors.js +15 -0
  59. package/dist/agent/oe-oauth/errors.js.map +1 -1
  60. package/dist/agent/oe-oauth/oauth-client.d.ts +46 -0
  61. package/dist/agent/oe-oauth/oauth-client.d.ts.map +1 -1
  62. package/dist/agent/oe-oauth/oauth-client.js +82 -1
  63. package/dist/agent/oe-oauth/oauth-client.js.map +1 -1
  64. package/dist/agent/oe-oauth/token-vault.d.ts +15 -0
  65. package/dist/agent/oe-oauth/token-vault.d.ts.map +1 -1
  66. package/dist/agent/oe-oauth/token-vault.js +317 -7
  67. package/dist/agent/oe-oauth/token-vault.js.map +1 -1
  68. package/dist/agent/register-defaults.d.ts.map +1 -1
  69. package/dist/agent/register-defaults.js +9 -0
  70. package/dist/agent/register-defaults.js.map +1 -1
  71. package/dist/agent/sandbox/long-lived-box.d.ts +70 -0
  72. package/dist/agent/sandbox/long-lived-box.d.ts.map +1 -0
  73. package/dist/agent/sandbox/long-lived-box.js +414 -0
  74. package/dist/agent/sandbox/long-lived-box.js.map +1 -0
  75. package/package.json +39 -2
@@ -0,0 +1,61 @@
1
+ // Shared plumbing for the native-transcript readers (OPE-2471): an injectable fetch, a capped body read, and
2
+ // a small token cache. Every reader is host code that calls one vendor API with the organisation's own
3
+ // credential; nothing here enters a sandbox, and no response text is ever echoed into a thread.
4
+ /** How long ONE vendor call may take. A call that runs out throws, and core counts the read as "the platform
5
+ * did not answer": OE checks again on the next sweep. It bounds each call only: a read makes up to a few calls
6
+ * in sequence, and the meeting sweep bounds a whole tick with its own time budget (meetings/native-recap.ts). */
7
+ const NATIVE_CALL_TIMEOUT_MS = 30_000;
8
+ /** The live fetch every reader uses by default: the global fetch with a per-call timeout. */
9
+ export const timedFetch = (url, init) => fetch(url, { ...init, signal: AbortSignal.timeout(NATIVE_CALL_TIMEOUT_MS) });
10
+ /** The largest body a reader accepts: a three-hour transcript is well under 2 MB. */
11
+ const MAX_NATIVE_BODY_BYTES = 8 * 1024 * 1024;
12
+ /** Read a response body as text, refusing one larger than the cap. */
13
+ export async function readCappedText(res) {
14
+ const declared = Number(res.headers.get("content-length") ?? "0");
15
+ if (Number.isFinite(declared) && declared > MAX_NATIVE_BODY_BYTES)
16
+ throw new Error(`response body is ${declared} bytes, over the ${MAX_NATIVE_BODY_BYTES}-byte cap`);
17
+ const text = await res.text();
18
+ if (text.length > MAX_NATIVE_BODY_BYTES)
19
+ throw new Error(`response body is over the ${MAX_NATIVE_BODY_BYTES}-byte cap`);
20
+ return text;
21
+ }
22
+ /** Read a JSON body, or `{}` when it does not parse (an error body need not be JSON). */
23
+ export async function readJsonLoose(res) {
24
+ try {
25
+ const v = JSON.parse(await readCappedText(res));
26
+ return v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
27
+ }
28
+ catch {
29
+ return {};
30
+ }
31
+ }
32
+ /** A thrown error a reader turns into "the platform did not answer, check again later". Never echoes a body. */
33
+ export function unexpectedStatus(what, status) {
34
+ return new Error(`${what} answered HTTP ${status}`);
35
+ }
36
+ /**
37
+ * A per-process access-token cache, keyed by the caller (credential + subject). A token is reused until one
38
+ * minute before it expires. The key never holds the secret itself: callers pass a non-secret key.
39
+ */
40
+ export class TokenCache {
41
+ #tokens = new Map();
42
+ get(key, now) {
43
+ const t = this.#tokens.get(key);
44
+ return t !== undefined && t.expiresAt - 60_000 > now ? t.token : undefined;
45
+ }
46
+ set(key, token, expiresInSeconds, now) {
47
+ const s = typeof expiresInSeconds === "number" && Number.isFinite(expiresInSeconds) && expiresInSeconds > 0 ? expiresInSeconds : 300;
48
+ this.#tokens.set(key, { token, expiresAt: now + s * 1000 });
49
+ }
50
+ }
51
+ /** True when `raw` is an https URL on `host` or one of its subdomains. A reader sends its token only there. */
52
+ export function onHost(raw, host) {
53
+ try {
54
+ const u = new URL(raw);
55
+ return u.protocol === "https:" && u.port === "" && (u.hostname === host || u.hostname.endsWith(`.${host}`));
56
+ }
57
+ catch {
58
+ return false;
59
+ }
60
+ }
61
+ //# sourceMappingURL=native-http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-http.js","sourceRoot":"","sources":["../../../agent/meetings/native-http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { NativeTranscriptSource } from "@open-everywhere/core/agent/adapter-api.js";
2
+ import { type NativeFetch } from "./native-http.js";
3
+ export declare const MEET_SCOPE = "https://www.googleapis.com/auth/meetings.space.readonly";
4
+ export declare const MEET_ACCESS_HINT = "In the Google Workspace Admin console, grant the service account's client id domain-wide delegation of https://www.googleapis.com/auth/meetings.space.readonly, and enable the Google Meet REST API in its Cloud project.";
5
+ export declare function meetTranscriptSource(fetchImpl?: NativeFetch, now?: () => number): NativeTranscriptSource;
6
+ //# sourceMappingURL=native-meet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-meet.d.ts","sourceRoot":"","sources":["../../../agent/meetings/native-meet.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAA0B,sBAAsB,EAAgE,MAAM,4CAA4C,CAAC;AAC/K,OAAO,EAAuD,KAAK,WAAW,EAAc,MAAM,kBAAkB,CAAC;AAIrH,eAAO,MAAM,UAAU,4DAA4D,CAAC;AAGpF,eAAO,MAAM,gBAAgB,8NACgM,CAAC;AA0B9N,wBAAgB,oBAAoB,CAAC,SAAS,GAAE,WAAwB,EAAE,GAAG,GAAE,MAAM,MAAiB,GAAG,sBAAsB,CAyH9H"}
@@ -0,0 +1,176 @@
1
+ // The Google Meet native-transcript reader (OPE-2471): the Meet REST API v2, read through the organisation's
2
+ // service account with domain-wide delegation, acting as the meeting's organiser.
3
+ //
4
+ // 1. token: a JWT signed with the service account's key (RS256), `sub` = the organiser, scope
5
+ // `meetings.space.readonly`, exchanged at oauth2.googleapis.com/token
6
+ // 2. records: GET /v2/conferenceRecords?filter=space.meeting_code="<code>" — one per session
7
+ // 3. transcripts: GET /v2/<record>/transcripts — state STARTED, ENDED or FILE_GENERATED
8
+ // 4. entries: GET /v2/<transcript>/entries — the spoken lines, each naming a participant
9
+ // 5. names: GET /v2/<record>/participants — the participants' display names
10
+ //
11
+ // WHAT THE ADMIN GRANTS: the Google Meet REST API on the service account's Cloud project, and domain-wide
12
+ // delegation of `https://www.googleapis.com/auth/meetings.space.readonly` to the service account's client id
13
+ // in the Workspace Admin console. The meeting needs transcription on. Google keeps transcript entries for 30
14
+ // days after the conference ends, so an older record is `expired`.
15
+ import { createSign } from "node:crypto";
16
+ import { TokenCache, onHost, readJsonLoose, unexpectedStatus, timedFetch } from "./native-http.js";
17
+ const MEET = "https://meet.googleapis.com/v2";
18
+ const TOKEN_URI = "https://oauth2.googleapis.com/token";
19
+ export const MEET_SCOPE = "https://www.googleapis.com/auth/meetings.space.readonly";
20
+ const MAX_PAGES = 100;
21
+ export const MEET_ACCESS_HINT = "In the Google Workspace Admin console, grant the service account's client id domain-wide delegation of https://www.googleapis.com/auth/meetings.space.readonly, and enable the Google Meet REST API in its Cloud project.";
22
+ const b64url = (v) => Buffer.from(v).toString("base64url");
23
+ /** The signed JWT-bearer assertion for one organiser. The test verifies its signature from the token request. */
24
+ function meetAssertion(key, subject, nowMs) {
25
+ const iat = Math.floor(nowMs / 1000);
26
+ const head = b64url(JSON.stringify({ alg: "RS256", typ: "JWT" }));
27
+ const claims = b64url(JSON.stringify({ iss: key.client_email, sub: subject, scope: MEET_SCOPE, aud: TOKEN_URI, iat, exp: iat + 3600 }));
28
+ const signer = createSign("RSA-SHA256");
29
+ signer.update(`${head}.${claims}`);
30
+ return `${head}.${claims}.${b64url(signer.sign(key.private_key))}`;
31
+ }
32
+ function str(o, k) {
33
+ const v = o?.[k];
34
+ return typeof v === "string" ? v : undefined;
35
+ }
36
+ export function meetTranscriptSource(fetchImpl = timedFetch, now = Date.now) {
37
+ const tokens = new TokenCache();
38
+ async function token(keyJson, subject) {
39
+ let key;
40
+ try {
41
+ const k = JSON.parse(keyJson);
42
+ if (typeof k.client_email !== "string" || typeof k.private_key !== "string")
43
+ throw new Error("shape");
44
+ key = { client_email: k.client_email, private_key: k.private_key };
45
+ }
46
+ catch {
47
+ return { status: "refused", reason: "credential", hint: "The stored service-account key is not a Google JSON key file." };
48
+ }
49
+ const cacheKey = `${key.client_email}\n${subject}`;
50
+ const cached = tokens.get(cacheKey, now());
51
+ if (cached !== undefined)
52
+ return cached;
53
+ let assertion;
54
+ try {
55
+ assertion = meetAssertion(key, subject, now());
56
+ }
57
+ catch {
58
+ return { status: "refused", reason: "credential", hint: "The stored service-account key's private key does not sign." };
59
+ }
60
+ const res = await fetchImpl(TOKEN_URI, {
61
+ method: "POST",
62
+ headers: { "content-type": "application/x-www-form-urlencoded" },
63
+ body: new URLSearchParams({ grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", assertion }).toString(),
64
+ });
65
+ const body = await readJsonLoose(res);
66
+ if (!res.ok) {
67
+ // `unauthorized_client`: the delegation for this scope is not granted. Anything else on a 4xx is the key.
68
+ if (body.error === "unauthorized_client")
69
+ return { status: "refused", reason: "access-off", hint: MEET_ACCESS_HINT };
70
+ if (res.status >= 400 && res.status < 500)
71
+ return { status: "refused", reason: "credential", hint: "Google refused the service account's key, or the organiser is not a user in the Workspace." };
72
+ throw unexpectedStatus("the Google token endpoint", res.status);
73
+ }
74
+ if (typeof body.access_token !== "string")
75
+ throw unexpectedStatus("the Google token endpoint", res.status);
76
+ tokens.set(cacheKey, body.access_token, body.expires_in, now());
77
+ return body.access_token;
78
+ }
79
+ async function get(url, bearer, what) {
80
+ if (!onHost(url, "meet.googleapis.com"))
81
+ throw new Error(`${what}: refusing to send the token off meet.googleapis.com`);
82
+ const res = await fetchImpl(url, { headers: { authorization: `Bearer ${bearer}` } });
83
+ if (res.status === 401)
84
+ return { ok: false, result: { status: "refused", reason: "credential", hint: "Google refused the service account's token." } };
85
+ if (res.status === 403)
86
+ return { ok: false, result: { status: "refused", reason: "access-off", hint: MEET_ACCESS_HINT } };
87
+ if (res.status === 404)
88
+ return { ok: false, result: { status: "refused", reason: "expired" } };
89
+ if (!res.ok)
90
+ throw unexpectedStatus(what, res.status);
91
+ return { ok: true, body: await readJsonLoose(res) };
92
+ }
93
+ /** Every page of a list, by `nextPageToken`. A refusal on any page is the answer. */
94
+ async function list(base, field, bearer, what) {
95
+ const out = [];
96
+ let pageToken;
97
+ for (let page = 0; page < MAX_PAGES; page++) {
98
+ const sep = base.includes("?") ? "&" : "?";
99
+ const got = await get(`${base}${sep}pageSize=100${pageToken !== undefined ? `&pageToken=${encodeURIComponent(pageToken)}` : ""}`, bearer, what);
100
+ if (!got.ok)
101
+ return got.result;
102
+ const items = got.body[field];
103
+ if (Array.isArray(items))
104
+ out.push(...items);
105
+ pageToken = str(got.body, "nextPageToken");
106
+ if (pageToken === undefined || pageToken === "")
107
+ break;
108
+ }
109
+ return out;
110
+ }
111
+ return {
112
+ platform: "meet",
113
+ disclosure: "OE reads the transcript Google Meet made, through the Meet REST API, with the organisation's own service account acting as the organiser (domain-wide delegation, read-only).",
114
+ async read(ref, ctx) {
115
+ const m = ctx.policy.meet;
116
+ if (m === undefined)
117
+ return { status: "refused", reason: "credential", hint: "The meeting policy declares no Google Meet credential." };
118
+ const subject = ref.organiserEmail;
119
+ if (subject === undefined || !m.domains.includes(subject.slice(subject.lastIndexOf("@") + 1)))
120
+ return { status: "refused", reason: "not-found" };
121
+ const tok = await token(await ctx.secret(m.serviceAccountKeyRef), subject);
122
+ if (typeof tok !== "string")
123
+ return tok;
124
+ const filter = `space.meeting_code = "${ref.roomId}"`;
125
+ const listed = await list(`${MEET}/conferenceRecords?filter=${encodeURIComponent(filter)}`, "conferenceRecords", tok, "the Meet conference list");
126
+ if (!Array.isArray(listed))
127
+ return listed.status === "refused" && listed.reason === "expired" ? { status: "refused", reason: "not-found" } : listed;
128
+ const records = listed
129
+ .map((r) => ({ name: str(r, "name") ?? "", ...(str(r, "startTime") ? { startTime: str(r, "startTime") } : {}), ...(str(r, "endTime") ? { endTime: str(r, "endTime") } : {}), ...(str(r, "expireTime") ? { expireTime: str(r, "expireTime") } : {}) }))
130
+ .filter((r) => r.name.startsWith("conferenceRecords/") && (ref.startedAfter === undefined || Date.parse(r.startTime ?? "") >= ref.startedAfter))
131
+ .sort((a, b) => Date.parse(b.startTime ?? "") - Date.parse(a.startTime ?? ""));
132
+ const rec = records[0];
133
+ // No session yet, or the session is on now.
134
+ if (rec === undefined || rec.endTime === undefined)
135
+ return { status: "pending" };
136
+ if (rec.expireTime !== undefined && Date.parse(rec.expireTime) <= now())
137
+ return { status: "refused", reason: "expired" };
138
+ const transcripts = await list(`${MEET}/${rec.name}/transcripts`, "transcripts", tok, "the Meet transcript list");
139
+ if (!Array.isArray(transcripts))
140
+ return transcripts;
141
+ if (transcripts.length === 0)
142
+ return { status: "refused", reason: "not-transcribed" };
143
+ const done = transcripts.filter((t) => str(t, "state") === "ENDED" || str(t, "state") === "FILE_GENERATED");
144
+ if (done.length < transcripts.length)
145
+ return { status: "pending" };
146
+ const people = await list(`${MEET}/${rec.name}/participants`, "participants", tok, "the Meet participant list");
147
+ if (!Array.isArray(people))
148
+ return people;
149
+ const names = new Map();
150
+ for (const p of people) {
151
+ const o = p;
152
+ const who = str(o.signedinUser, "displayName") ?? str(o.anonymousUser, "displayName") ?? str(o.phoneUser, "displayName");
153
+ const name = str(o, "name");
154
+ if (name !== undefined && who !== undefined)
155
+ names.set(name, who);
156
+ }
157
+ const start = Date.parse(rec.startTime ?? "");
158
+ const segments = [];
159
+ for (const t of done) {
160
+ const entries = await list(`${MEET}/${str(t, "name")}/entries`, "transcriptEntries", tok, "the Meet transcript entries");
161
+ if (!Array.isArray(entries))
162
+ return entries;
163
+ for (const e of entries) {
164
+ const text = str(e, "text");
165
+ if (text === undefined)
166
+ continue;
167
+ const at = Date.parse(str(e, "startTime") ?? "");
168
+ segments.push({ speaker: names.get(str(e, "participant") ?? "") ?? "", text, ...(Number.isFinite(at) && Number.isFinite(start) ? { startMs: Math.max(0, at - start) } : {}) });
169
+ }
170
+ }
171
+ segments.sort((a, b) => (a.startMs ?? 0) - (b.startMs ?? 0));
172
+ return { status: "ready", segments, ...(rec.startTime !== undefined ? { startedAt: rec.startTime } : {}), endedAt: rec.endTime };
173
+ },
174
+ };
175
+ }
176
+ //# sourceMappingURL=native-meet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-meet.js","sourceRoot":"","sources":["../../../agent/meetings/native-meet.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function registerNativeTranscriptSources(): void;
2
+ //# sourceMappingURL=native-sources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-sources.d.ts","sourceRoot":"","sources":["../../../agent/meetings/native-sources.ts"],"names":[],"mappings":"AASA,wBAAgB,+BAA+B,IAAI,IAAI,CAItD"}
@@ -0,0 +1,13 @@
1
+ // Boot registration of the three native-transcript readers (OPE-2471). Each one reads only when the meeting
2
+ // policy's `native` block declares its platform and a member approves a `meeting.recap` card, so registering
3
+ // all three is harmless on a deployment that uses none.
4
+ import { registerNativeTranscriptSource } from "@open-everywhere/core/agent/adapter-api.js";
5
+ import { teamsTranscriptSource } from "./native-teams.js";
6
+ import { meetTranscriptSource } from "./native-meet.js";
7
+ import { zoomTranscriptSource } from "./native-zoom.js";
8
+ export function registerNativeTranscriptSources() {
9
+ registerNativeTranscriptSource(teamsTranscriptSource());
10
+ registerNativeTranscriptSource(meetTranscriptSource());
11
+ registerNativeTranscriptSource(zoomTranscriptSource());
12
+ }
13
+ //# sourceMappingURL=native-sources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-sources.js","sourceRoot":"","sources":["../../../agent/meetings/native-sources.ts"],"names":[],"mappings":"AAAA,4GAA4G;AAC5G,6GAA6G;AAC7G,wDAAwD;AAExD,OAAO,EAAE,8BAA8B,EAAE,MAAM,4CAA4C,CAAC;AAC5F,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,UAAU,+BAA+B;IAC7C,8BAA8B,CAAC,qBAAqB,EAAE,CAAC,CAAC;IACxD,8BAA8B,CAAC,oBAAoB,EAAE,CAAC,CAAC;IACvD,8BAA8B,CAAC,oBAAoB,EAAE,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { NativeTranscriptSource } from "@open-everywhere/core/agent/adapter-api.js";
2
+ import { type NativeFetch } from "./native-http.js";
3
+ /** The fixed hint for a 403: what an admin grants. Never response text. */
4
+ export declare const TEAMS_ACCESS_HINT = "In Microsoft Entra, grant the app OnlineMeetings.Read.All and OnlineMeetingTranscript.Read.All (application, admin consent), and add an application access policy that covers the organiser (Grant-CsApplicationAccessPolicy). The Teams meeting policy must allow transcription.";
5
+ export declare function teamsTranscriptSource(fetchImpl?: NativeFetch, now?: () => number): NativeTranscriptSource;
6
+ //# sourceMappingURL=native-teams.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-teams.d.ts","sourceRoot":"","sources":["../../../agent/meetings/native-teams.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAA0B,sBAAsB,EAAuC,MAAM,4CAA4C,CAAC;AAEtJ,OAAO,EAAuE,KAAK,WAAW,EAAc,MAAM,kBAAkB,CAAC;AAMrI,2EAA2E;AAC3E,eAAO,MAAM,iBAAiB,sRACuP,CAAC;AAQtR,wBAAgB,qBAAqB,CAAC,SAAS,GAAE,WAAwB,EAAE,GAAG,GAAE,MAAM,MAAiB,GAAG,sBAAsB,CAoF/H"}
@@ -0,0 +1,118 @@
1
+ // The Microsoft Teams native-transcript reader (OPE-2471): Microsoft Graph `callTranscript`, read app-only
2
+ // with the organisation's Entra app registration (client credentials).
3
+ //
4
+ // 1. token: POST login.microsoftonline.com/<tenant>/oauth2/v2.0/token (client_credentials, `.default`)
5
+ // 2. meeting: GET /users/<organiser>/onlineMeetings?$filter=JoinWebUrl eq '<link>'
6
+ // 3. transcripts: GET /users/<organiser>/onlineMeetings/<id>/transcripts
7
+ // 4. content: GET …/transcripts/<id>/content?$format=text/vtt — WebVTT with `<v Speaker>` voice spans
8
+ //
9
+ // WHAT THE ADMIN GRANTS (docs/capabilities/meetings.md says it exactly): the application permissions
10
+ // `OnlineMeetings.Read.All` and `OnlineMeetingTranscript.Read.All` with admin consent, and an application
11
+ // access policy that covers the organisers (Graph refuses app-only meeting reads without one). A 403 at any
12
+ // step is the `access-off` refusal: the grant, the policy, or the tenant's transcript switches are off.
13
+ //
14
+ // Graph names a transcript only after the meeting ends, so "no transcript yet" is `pending`, and the watch's
15
+ // deadline turns a meeting that was never transcribed into a plain sentence in the thread.
16
+ import { parseWebVtt } from "@open-everywhere/core/agent/adapter-api.js";
17
+ import { TokenCache, onHost, readCappedText, readJsonLoose, unexpectedStatus, timedFetch } from "./native-http.js";
18
+ const GRAPH = "https://graph.microsoft.com/v1.0";
19
+ const LOGIN = "https://login.microsoftonline.com";
20
+ const MAX_PAGES = 10;
21
+ /** The fixed hint for a 403: what an admin grants. Never response text. */
22
+ export const TEAMS_ACCESS_HINT = "In Microsoft Entra, grant the app OnlineMeetings.Read.All and OnlineMeetingTranscript.Read.All (application, admin consent), and add an application access policy that covers the organiser (Grant-CsApplicationAccessPolicy). The Teams meeting policy must allow transcription.";
23
+ export function teamsTranscriptSource(fetchImpl = timedFetch, now = Date.now) {
24
+ const tokens = new TokenCache();
25
+ async function token(tenant, clientId, secret) {
26
+ const key = `${tenant}\n${clientId}`;
27
+ const cached = tokens.get(key, now());
28
+ if (cached !== undefined)
29
+ return cached;
30
+ const res = await fetchImpl(`${LOGIN}/${encodeURIComponent(tenant)}/oauth2/v2.0/token`, {
31
+ method: "POST",
32
+ headers: { "content-type": "application/x-www-form-urlencoded" },
33
+ body: new URLSearchParams({ client_id: clientId, client_secret: secret, scope: "https://graph.microsoft.com/.default", grant_type: "client_credentials" }).toString(),
34
+ });
35
+ const body = await readJsonLoose(res);
36
+ if (res.status === 400 || res.status === 401)
37
+ return { status: "refused", reason: "credential", hint: "Microsoft Entra refused the app's client id or client secret." };
38
+ if (!res.ok || typeof body.access_token !== "string")
39
+ throw unexpectedStatus("the Entra token endpoint", res.status);
40
+ tokens.set(key, body.access_token, body.expires_in, now());
41
+ return body.access_token;
42
+ }
43
+ /** One Graph GET. A refusal comes back as a result; anything unexpected throws (checked again later). */
44
+ async function graph(url, bearer, what, on404) {
45
+ if (!onHost(url, "graph.microsoft.com"))
46
+ throw new Error(`${what}: refusing to send the token off graph.microsoft.com`);
47
+ const res = await fetchImpl(url, { headers: { authorization: `Bearer ${bearer}` } });
48
+ if (res.status === 401)
49
+ return { status: "refused", reason: "credential", hint: "Microsoft Graph refused the app's token." };
50
+ if (res.status === 403)
51
+ return { status: "refused", reason: "access-off", hint: TEAMS_ACCESS_HINT };
52
+ if (res.status === 404)
53
+ return on404;
54
+ if (!res.ok)
55
+ throw unexpectedStatus(what, res.status);
56
+ return res;
57
+ }
58
+ return {
59
+ platform: "teams",
60
+ disclosure: "OE reads the transcript Microsoft Teams made, through Microsoft Graph, with the organisation's own Entra app registration (not any person's account).",
61
+ async read(ref, ctx) {
62
+ const t = ctx.policy.teams;
63
+ if (t === undefined)
64
+ return { status: "refused", reason: "credential", hint: "The meeting policy declares no Teams credential." };
65
+ if (ref.tenantId === undefined || ref.organizerId === undefined || !t.tenants.includes(ref.tenantId))
66
+ return { status: "refused", reason: "not-found" };
67
+ const tok = await token(ref.tenantId, t.clientId, await ctx.secret(t.clientSecretRef));
68
+ if (typeof tok !== "string")
69
+ return tok;
70
+ const user = `${GRAPH}/users/${encodeURIComponent(ref.organizerId)}/onlineMeetings`;
71
+ const filter = `JoinWebUrl eq '${ref.url.replace(/'/g, "''")}'`;
72
+ const found = await graph(`${user}?$filter=${encodeURIComponent(filter)}`, tok, "the Graph meeting lookup", { status: "refused", reason: "not-found" });
73
+ if (!(found instanceof Response))
74
+ return found;
75
+ const meetings = (await readJsonLoose(found)).value;
76
+ const meetingId = Array.isArray(meetings) && typeof meetings[0]?.id === "string" ? meetings[0].id : undefined;
77
+ if (meetingId === undefined)
78
+ return { status: "refused", reason: "not-found" };
79
+ const transcripts = [];
80
+ let next = `${user}/${encodeURIComponent(meetingId)}/transcripts`;
81
+ for (let page = 0; next !== undefined && page < MAX_PAGES; page++) {
82
+ const listed = await graph(next, tok, "the Graph transcript list", { status: "refused", reason: "not-found" });
83
+ if (!(listed instanceof Response))
84
+ return listed;
85
+ const body = await readJsonLoose(listed);
86
+ for (const v of Array.isArray(body.value) ? body.value : []) {
87
+ const o = v;
88
+ if (typeof o.id === "string") {
89
+ transcripts.push({
90
+ id: o.id,
91
+ ...(typeof o.createdDateTime === "string" ? { createdDateTime: o.createdDateTime } : {}),
92
+ ...(typeof o.endDateTime === "string" ? { endDateTime: o.endDateTime } : {}),
93
+ });
94
+ }
95
+ }
96
+ next = typeof body["@odata.nextLink"] === "string" ? body["@odata.nextLink"] : undefined;
97
+ }
98
+ // A recurring meeting keeps one join link, so its transcripts span every occurrence: newest first, and
99
+ // only a session that started inside the ask's window.
100
+ const eligible = transcripts
101
+ .filter((x) => ref.startedAfter === undefined || (x.createdDateTime !== undefined && Date.parse(x.createdDateTime) >= ref.startedAfter))
102
+ .sort((a, b) => Date.parse(b.createdDateTime ?? "") - Date.parse(a.createdDateTime ?? ""));
103
+ const pick = eligible[0];
104
+ // No transcript yet (the meeting has not ended), or one Teams is still writing.
105
+ if (pick === undefined || pick.endDateTime === undefined)
106
+ return { status: "pending" };
107
+ const content = await graph(`${user}/${encodeURIComponent(meetingId)}/transcripts/${encodeURIComponent(pick.id)}/content?$format=text/vtt`, tok, "the Graph transcript content", {
108
+ status: "refused",
109
+ reason: "expired",
110
+ });
111
+ if (!(content instanceof Response))
112
+ return content;
113
+ const segments = parseWebVtt(await readCappedText(content));
114
+ return { status: "ready", segments, ...(pick.createdDateTime !== undefined ? { startedAt: pick.createdDateTime } : {}), endedAt: pick.endDateTime };
115
+ },
116
+ };
117
+ }
118
+ //# sourceMappingURL=native-teams.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-teams.js","sourceRoot":"","sources":["../../../agent/meetings/native-teams.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { NativeTranscriptSource } from "@open-everywhere/core/agent/adapter-api.js";
2
+ import { type NativeFetch } from "./native-http.js";
3
+ /** After this long with a finished recording and no transcript file, the transcript is not coming. */
4
+ export declare const ZOOM_TRANSCRIPT_GRACE_MS: number;
5
+ export declare const ZOOM_ACCESS_HINT = "In the Zoom App Marketplace, give the Server-to-Server OAuth app the scope cloud_recording:read:list_recording_files:admin (classic: recording:read:admin), and turn on cloud recording with Create audio transcript in the account settings.";
6
+ export declare function zoomTranscriptSource(fetchImpl?: NativeFetch, now?: () => number): NativeTranscriptSource;
7
+ //# sourceMappingURL=native-zoom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-zoom.d.ts","sourceRoot":"","sources":["../../../agent/meetings/native-zoom.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAA0B,sBAAsB,EAAuC,MAAM,4CAA4C,CAAC;AAEtJ,OAAO,EAAuE,KAAK,WAAW,EAAc,MAAM,kBAAkB,CAAC;AAIrI,sGAAsG;AACtG,eAAO,MAAM,wBAAwB,QAAmB,CAAC;AAEzD,eAAO,MAAM,gBAAgB,kPACoN,CAAC;AASlP,wBAAgB,oBAAoB,CAAC,SAAS,GAAE,WAAwB,EAAE,GAAG,GAAE,MAAM,MAAiB,GAAG,sBAAsB,CA6D9H"}
@@ -0,0 +1,98 @@
1
+ // The Zoom native-transcript reader (OPE-2471): the cloud recording's audio transcript, read with the
2
+ // organisation's own Server-to-Server OAuth app.
3
+ //
4
+ // 1. token: POST zoom.us/oauth/token?grant_type=account_credentials&account_id=<account> (Basic auth)
5
+ // 2. recording: GET api.zoom.us/v2/meetings/<meeting id>/recordings — the newest session's files
6
+ // 3. transcript: the `TRANSCRIPT` file's `download_url`, with the token — WebVTT whose cues start
7
+ // "Speaker Name: text"
8
+ //
9
+ // WHAT THE ADMIN GRANTS: a Server-to-Server OAuth app on the org's Zoom account with the scope
10
+ // `cloud_recording:read:list_recording_files:admin` (classic scope: `recording:read:admin`), and, in the
11
+ // account settings, cloud recording with "Create audio transcript" on. Zoom needs a paid plan for both.
12
+ //
13
+ // HOW READY IS LEARNED: Zoom has a `recording.transcript_completed` webhook, and it is reported unreliable;
14
+ // OE polls this endpoint instead (meetings/native-recap.ts). Zoom writes the transcript after the recording,
15
+ // so a recording without a transcript file is `pending` until a day after it ended, then `not-transcribed`.
16
+ // The token goes only to zoom.us hosts: a `download_url` anywhere else is refused, never fetched.
17
+ import { parseWebVtt } from "@open-everywhere/core/agent/adapter-api.js";
18
+ import { TokenCache, onHost, readCappedText, readJsonLoose, unexpectedStatus, timedFetch } from "./native-http.js";
19
+ const API = "https://api.zoom.us/v2";
20
+ const TOKEN = "https://zoom.us/oauth/token";
21
+ /** After this long with a finished recording and no transcript file, the transcript is not coming. */
22
+ export const ZOOM_TRANSCRIPT_GRACE_MS = 24 * 60 * 60_000;
23
+ export const ZOOM_ACCESS_HINT = "In the Zoom App Marketplace, give the Server-to-Server OAuth app the scope cloud_recording:read:list_recording_files:admin (classic: recording:read:admin), and turn on cloud recording with Create audio transcript in the account settings.";
24
+ export function zoomTranscriptSource(fetchImpl = timedFetch, now = Date.now) {
25
+ const tokens = new TokenCache();
26
+ async function token(accountId, clientId, secret) {
27
+ const key = `${accountId}\n${clientId}`;
28
+ const cached = tokens.get(key, now());
29
+ if (cached !== undefined)
30
+ return cached;
31
+ const res = await fetchImpl(`${TOKEN}?grant_type=account_credentials&account_id=${encodeURIComponent(accountId)}`, {
32
+ method: "POST",
33
+ headers: { authorization: `Basic ${Buffer.from(`${clientId}:${secret}`).toString("base64")}` },
34
+ });
35
+ const body = await readJsonLoose(res);
36
+ if (res.status === 400 || res.status === 401)
37
+ return { status: "refused", reason: "credential", hint: "Zoom refused the Server-to-Server app's account id, client id or client secret." };
38
+ if (!res.ok || typeof body.access_token !== "string")
39
+ throw unexpectedStatus("the Zoom token endpoint", res.status);
40
+ tokens.set(key, body.access_token, body.expires_in, now());
41
+ return body.access_token;
42
+ }
43
+ return {
44
+ platform: "zoom",
45
+ disclosure: "OE reads the audio transcript of the meeting's Zoom cloud recording, through the Zoom API, with the organisation's own Server-to-Server OAuth app (not any person's account).",
46
+ async read(ref, ctx) {
47
+ const z = ctx.policy.zoom;
48
+ if (z === undefined)
49
+ return { status: "refused", reason: "credential", hint: "The meeting policy declares no Zoom credential." };
50
+ const tok = await token(z.accountId, z.clientId, await ctx.secret(z.clientSecretRef));
51
+ if (typeof tok !== "string")
52
+ return tok;
53
+ const res = await fetchImpl(`${API}/meetings/${encodeURIComponent(ref.roomId)}/recordings`, { headers: { authorization: `Bearer ${tok}` } });
54
+ const body = await readJsonLoose(res);
55
+ if (res.status === 401)
56
+ return { status: "refused", reason: "credential", hint: "Zoom refused the app's token." };
57
+ if (res.status === 403)
58
+ return { status: "refused", reason: "access-off", hint: ZOOM_ACCESS_HINT };
59
+ if (res.status === 404) {
60
+ // 3301 "This recording does not exist": no cloud recording yet (or never). 3001: no such meeting on this account.
61
+ if (body.code === 3001)
62
+ return { status: "refused", reason: "not-found" };
63
+ return { status: "pending" };
64
+ }
65
+ // A missing scope can come back as a 400 (code 4711, "does not contain scopes") as well as a 403; code 200 is "no permission".
66
+ if (res.status === 400 && (body.code === 200 || body.code === 4711))
67
+ return { status: "refused", reason: "access-off", hint: ZOOM_ACCESS_HINT };
68
+ if (!res.ok)
69
+ throw unexpectedStatus("the Zoom recordings endpoint", res.status);
70
+ const startedAt = typeof body.start_time === "string" ? body.start_time : undefined;
71
+ // A recurring meeting answers with its newest session: one from before the ask's window is not the meeting asked for.
72
+ if (ref.startedAfter !== undefined && (startedAt === undefined || Date.parse(startedAt) < ref.startedAfter))
73
+ return { status: "pending" };
74
+ const files = (Array.isArray(body.recording_files) ? body.recording_files : []);
75
+ const transcript = files.find((f) => f.file_type === "TRANSCRIPT");
76
+ if (transcript === undefined || transcript.status !== "completed" || typeof transcript.download_url !== "string") {
77
+ const ends = files.map((f) => Date.parse(f.recording_end ?? "")).filter((t) => Number.isFinite(t));
78
+ const finished = files.length > 0 && files.every((f) => f.status === "completed") && ends.length > 0;
79
+ if (transcript === undefined && finished && now() - Math.max(...ends) > ZOOM_TRANSCRIPT_GRACE_MS)
80
+ return { status: "refused", reason: "not-transcribed" };
81
+ return { status: "pending" };
82
+ }
83
+ if (!onHost(transcript.download_url, "zoom.us"))
84
+ throw new Error("the Zoom transcript download_url is not on zoom.us, so the token is not sent there");
85
+ const dl = await fetchImpl(transcript.download_url, { headers: { authorization: `Bearer ${tok}` } });
86
+ if (dl.status === 404)
87
+ return { status: "refused", reason: "expired" };
88
+ if (dl.status === 401 || dl.status === 403)
89
+ return { status: "refused", reason: "access-off", hint: ZOOM_ACCESS_HINT };
90
+ if (!dl.ok)
91
+ throw unexpectedStatus("the Zoom transcript download", dl.status);
92
+ const segments = parseWebVtt(await readCappedText(dl), { namePrefix: true });
93
+ const ends = files.map((f) => f.recording_end).filter((t) => typeof t === "string").sort();
94
+ return { status: "ready", segments, ...(startedAt !== undefined ? { startedAt } : {}), ...(ends.length > 0 ? { endedAt: ends[ends.length - 1] } : {}) };
95
+ },
96
+ };
97
+ }
98
+ //# sourceMappingURL=native-zoom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-zoom.js","sourceRoot":"","sources":["../../../agent/meetings/native-zoom.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,iDAAiD;AACjD,EAAE;AACF,6GAA6G;AAC7G,oGAAoG;AACpG,oGAAoG;AACpG,wCAAwC;AACxC,EAAE;AACF,+FAA+F;AAC/F,yGAAyG;AACzG,wGAAwG;AACxG,EAAE;AACF,4GAA4G;AAC5G,6GAA6G;AAC7G,4GAA4G;AAC5G,kGAAkG;AAGlG,OAAO,EAAE,WAAW,EAAE,MAAM,4CAA4C,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,gBAAgB,EAAoB,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAErI,MAAM,GAAG,GAAG,wBAAwB,CAAC;AACrC,MAAM,KAAK,GAAG,6BAA6B,CAAC;AAC5C,sGAAsG;AACtG,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC;AAEzD,MAAM,CAAC,MAAM,gBAAgB,GAC3B,+OAA+O,CAAC;AASlP,MAAM,UAAU,oBAAoB,CAAC,SAAS,GAAgB,UAAU,EAAE,GAAG,GAAiB,IAAI,CAAC,GAAG;IACpG,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;IAEhC,KAAK,UAAU,KAAK,CAAC,SAAiB,EAAE,QAAgB,EAAE,MAAc;QACtE,MAAM,GAAG,GAAG,GAAG,SAAS,KAAK,QAAQ,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;QACtC,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC;QACxC,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,KAAK,8CAA8C,kBAAkB,CAAC,SAAS,CAAC,EAAE,EAAE;YACjH,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,aAAa,EAAE,SAAS,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,IAAI,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,EAAE;SAC/F,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,iFAAiF,EAAE,CAAC;QAC1L,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,YAAY,KAAK,QAAQ;YAAE,MAAM,gBAAgB,CAAC,yBAAyB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QACpH,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,MAAM;QAChB,UAAU,EAAE,+KAA+K;QAC3L,KAAK,CAAC,IAAI,CAAC,GAAqB,EAAE,GAAsB;YACtD,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;YAC1B,IAAI,CAAC,KAAK,SAAS;gBAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,iDAAiD,EAAE,CAAC;YACjI,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;YACtF,IAAI,OAAO,GAAG,KAAK,QAAQ;gBAAE,OAAO,GAAG,CAAC;YAExC,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,GAAG,aAAa,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;YAC7I,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;YACtC,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,+BAA+B,EAAE,CAAC;YAClH,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;YACnG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBACvB,kHAAkH;gBAClH,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;oBAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;gBAC1E,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YAC/B,CAAC;YACD,+HAA+H;YAC/H,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC;gBAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;YAChJ,IAAI,CAAC,GAAG,CAAC,EAAE;gBAAE,MAAM,gBAAgB,CAAC,8BAA8B,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;YAEhF,MAAM,SAAS,GAAG,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;YACpF,sHAAsH;YACtH,IAAI,GAAG,CAAC,YAAY,KAAK,SAAS,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC,YAAY,CAAC;gBAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YAC1I,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAoB,CAAC;YACnG,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,YAAY,CAAC,CAAC;YACnE,IAAI,UAAU,KAAK,SAAS,IAAI,UAAU,CAAC,MAAM,KAAK,WAAW,IAAI,OAAO,UAAU,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;gBACjH,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;gBACnG,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;gBACrG,IAAI,UAAU,KAAK,SAAS,IAAI,QAAQ,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,wBAAwB;oBAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC;gBAC1J,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YAC/B,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,EAAE,SAAS,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,oFAAoF,CAAC,CAAC;YACvJ,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,UAAU,CAAC,YAAY,EAAE,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;YACrG,IAAI,EAAE,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YACvE,IAAI,EAAE,CAAC,MAAM,KAAK,GAAG,IAAI,EAAE,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;YACvH,IAAI,CAAC,EAAE,CAAC,EAAE;gBAAE,MAAM,gBAAgB,CAAC,8BAA8B,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;YAC9E,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;YAC7E,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;YACxG,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC3J,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -5,6 +5,13 @@ type GatewayModel = ReturnType<typeof gateway>;
5
5
  export declare const DEFAULT_GATEWAY_HOST = "ai-gateway.vercel.sh";
6
6
  /** The one host the model call reaches: the retarget's host, else the default. An unparseable retarget falls back to the default host. */
7
7
  export declare function gatewayHost(baseUrl: string | undefined): string;
8
+ /** The one host this deployment's gateway calls reach — what every host-plane push must keep declaring. */
9
+ export declare const GATEWAY_TARGET_HOST: string;
10
+ /** Add `hosts` to this process's host plane and return the shared fetch (undefined off the proxy tier). */
11
+ export declare function sharedHostPlaneFetch(hosts: readonly string[]): typeof fetch | undefined;
12
+ /** The gateway provider this backend resolves model ids through — retargeted only when
13
+ * {@link GATEWAY_BASE_URL} names a different host. */
14
+ declare const provider: import("@ai-sdk/gateway").GatewayProvider;
8
15
  /** Static defaults for one routed slot — mirrors what a plain string config said. */
9
16
  export interface GatewayRoutedDefaults {
10
17
  /** Default gateway model id (what unrouted channels use), e.g. "zai/glm-5.2". */
@@ -23,6 +30,9 @@ export declare function applyGatewayOptions(route: ModelRoute, options: RoutedCa
23
30
  readonly id: string;
24
31
  readonly defaultId: string;
25
32
  }, defaults?: Record<string, unknown>): RoutedCallOptions;
33
+ /** A gateway TRANSCRIPTION model, on the same provider (retarget and host-plane fetch included) the turn
34
+ * model uses. The meeting bot's `gateway` route (meeting-gateway.ts) reads it. */
35
+ export declare function gatewayTranscriptionModel(id: string): ReturnType<typeof provider.transcriptionModel>;
26
36
  /** The gateway ModelBackend (see core ModelBackend). */
27
37
  export declare function gatewayModelBackend(defaults?: Record<string, unknown>): ModelBackend<GatewayModel>;
28
38
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../../../agent/model/gateway.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAiB,MAAM,IAAI,CAAC;AAC5C,OAAO,EACL,KAAK,UAAU,EAEf,KAAK,YAAY,EACjB,KAAK,iBAAiB,EAIvB,MAAM,4CAA4C,CAAC;AAEpD,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAQ/C,wHAAwH;AACxH,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAE3D,0IAA0I;AAC1I,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAO/D;AAiBD,qFAAqF;AACrF,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC5C;AAKD;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,iBAAiB,EAC1B,GAAG,EAAE;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EACxD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,iBAAiB,CAanB;AAED,wDAAwD;AACxD,wBAAgB,mBAAmB,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY,CAAC,YAAY,CAAC,CAKlG;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,YAAY,CAAC,CAG5H"}
1
+ {"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../../../agent/model/gateway.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAiB,MAAM,IAAI,CAAC;AAC5C,OAAO,EACL,KAAK,UAAU,EAEf,KAAK,YAAY,EACjB,KAAK,iBAAiB,EAKvB,MAAM,4CAA4C,CAAC;AAEpD,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAQ/C,wHAAwH;AACxH,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAE3D,0IAA0I;AAC1I,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAO/D;AAED,2GAA2G;AAC3G,eAAO,MAAM,mBAAmB,QAAgC,CAAC;AA8BjE,2GAA2G;AAC3G,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,KAAK,GAAG,SAAS,CAOvF;AAED;uDACuD;AACvD,QAAA,MAAM,QAAQ,2CAGD,CAAC;AAEd,qFAAqF;AACrF,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC5C;AAKD;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,iBAAiB,EAC1B,GAAG,EAAE;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EACxD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,iBAAiB,CAanB;AAED;mFACmF;AACnF,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,kBAAkB,CAAC,CAEpG;AAED,wDAAwD;AACxD,wBAAgB,mBAAmB,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY,CAAC,YAAY,CAAC,CAKlG;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,YAAY,CAAC,CAG5H"}