@openclaw/google-meet 2026.9.5 → 2026.9.7

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 (62) hide show
  1. package/assets/icon.png +0 -0
  2. package/dist/.setup/{chrome-create-BZRBHJp9.mjs → chrome-create-wuAK5Pnq.mjs} +14 -19
  3. package/dist/.setup/{cli-MJjnaxoP.mjs → cli-DVDq0TFu.mjs} +27 -695
  4. package/dist/.setup/cli-export-D4IM6KLJ.mjs +632 -0
  5. package/dist/.setup/config-BXGAMntj.mjs +240 -0
  6. package/dist/.setup/{create-sGWmlpgC.mjs → create-UrHOmnWb.mjs} +4 -17
  7. package/dist/.setup/{google-meet-platform-adapter-DQZ74Kd5.mjs → google-meet-platform-adapter-gosgbMIM.mjs} +337 -228
  8. package/dist/.setup/{google-meet-platform-constants-Bs5iAg3E.mjs → google-meet-platform-constants-CnRfrYX7.mjs} +1 -4
  9. package/dist/.setup/{node-host-BOzEP_Us.mjs → node-host-Tr7Mx3da.mjs} +4 -7
  10. package/dist/.setup/{node-invoke-policy-hwXq9MfV.mjs → node-invoke-policy-Dd3krTYV.mjs} +2 -2
  11. package/dist/.setup/{oauth-22Ey-zCb.mjs → oauth-BoyruWcS.mjs} +2 -2
  12. package/dist/.setup/{plugin-helpers-rGjL9QFK.mjs → plugin-helpers-CdQ_YNA7.mjs} +147 -236
  13. package/dist/.setup/{plugin-registration-CfZbUMDY.mjs → plugin-registration-aCEuCerg.mjs} +59 -16
  14. package/dist/.setup/{runtime-D_C0dFI1.mjs → runtime-BdiF53A2.mjs} +89 -41
  15. package/dist/doctor-contract-api.js +3 -6
  16. package/dist/index.js +54 -13
  17. package/node_modules/typebox/build/compile/code.mjs +1 -2
  18. package/node_modules/typebox/build/compile/validator.mjs +5 -1
  19. package/node_modules/typebox/build/format/iri.mjs +16 -9
  20. package/node_modules/typebox/build/guard/emit.mjs +2 -2
  21. package/node_modules/typebox/build/guard/guard.d.mts +7 -5
  22. package/node_modules/typebox/build/guard/guard.mjs +14 -9
  23. package/node_modules/typebox/build/guard/index.mjs +6 -0
  24. package/node_modules/typebox/build/guard/unicode/unicode.d.mts +6 -0
  25. package/node_modules/typebox/build/guard/unicode/unicode.mjs +35 -0
  26. package/node_modules/typebox/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
  27. package/node_modules/typebox/build/schema/build.mjs +2 -3
  28. package/node_modules/typebox/build/schema/engine/_pathing.d.mts +1 -0
  29. package/node_modules/typebox/build/schema/engine/_pathing.mjs +11 -0
  30. package/node_modules/typebox/build/schema/engine/_refine.mjs +13 -5
  31. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +2 -1
  32. package/node_modules/typebox/build/schema/engine/dependencies.mjs +2 -1
  33. package/node_modules/typebox/build/schema/engine/dependentSchemas.mjs +2 -1
  34. package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +1 -1
  35. package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +2 -2
  36. package/node_modules/typebox/build/schema/engine/format.mjs +9 -2
  37. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +3 -2
  38. package/node_modules/typebox/build/schema/engine/properties.mjs +3 -2
  39. package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -1
  40. package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +1 -1
  41. package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +2 -2
  42. package/node_modules/typebox/build/schema/engine/ref.d.mts +1 -1
  43. package/node_modules/typebox/build/schema/engine/ref.mjs +2 -2
  44. package/node_modules/typebox/build/schema/engine/schema.mjs +24 -24
  45. package/node_modules/typebox/build/schema/parse.mjs +3 -0
  46. package/node_modules/typebox/build/schema/pointer/pointer.d.mts +1 -6
  47. package/node_modules/typebox/build/schema/pointer/pointer.mjs +47 -64
  48. package/node_modules/typebox/build/system/settings/internal.d.mts +2 -0
  49. package/node_modules/typebox/build/system/settings/internal.mjs +20 -0
  50. package/node_modules/typebox/build/system/settings/settings.d.mts +11 -0
  51. package/node_modules/typebox/build/system/settings/settings.mjs +14 -0
  52. package/node_modules/typebox/build/type/extends/inference.d.mts +1 -1
  53. package/node_modules/typebox/build/type/extends/inference.mjs +15 -2
  54. package/node_modules/typebox/build/type/extends/tuple.d.mts +2 -1
  55. package/node_modules/typebox/build/type/extends/tuple.mjs +21 -1
  56. package/node_modules/typebox/build/value/parse/parse.mjs +10 -4
  57. package/node_modules/typebox/package.json +1 -1
  58. package/node_modules/typebox/readme.md +3 -1
  59. package/package.json +5 -5
  60. package/dist/.setup/config-C-6enWkx.mjs +0 -328
  61. package/dist/.setup/google-api-errors-BDYXfKRa.mjs +0 -17
  62. /package/node_modules/typebox/build/guard/{string.d.mts → unicode/unicode_segment.d.mts} +0 -0
@@ -1,14 +1,14 @@
1
- import { i as isGoogleMeetBrowserManualActionError, n as GOOGLE_MEET_NODE_COMMAND } from "./google-meet-platform-constants-Bs5iAg3E.mjs";
2
- import { i as resolveGoogleMeetGatewayOperationTimeoutMs } from "./config-C-6enWkx.mjs";
3
- import { asNonArrayRecord as asParamRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
1
+ import { n as GOOGLE_MEET_NODE_COMMAND, r as GoogleMeetBrowserManualActionError } from "./google-meet-platform-constants-CnRfrYX7.mjs";
2
+ import { i as resolveGoogleMeetGatewayOperationTimeoutMs } from "./config-BXGAMntj.mjs";
3
+ import { asNonArrayRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
5
5
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
6
6
  //#region extensions/google-meet/src/plugin-registration.ts
7
- const loadGoogleMeetPluginHelpers = createLazyRuntimeModule(() => import("./plugin-helpers-rGjL9QFK.mjs").then((n) => n.r));
8
- const loadGoogleMeetCliModule = createLazyRuntimeModule(() => import("./cli-MJjnaxoP.mjs"));
9
- const loadGoogleMeetNodeHostModule = createLazyRuntimeModule(() => import("./node-host-BOzEP_Us.mjs"));
10
- const loadGoogleMeetRuntimeModule = createLazyRuntimeModule(() => import("./runtime-D_C0dFI1.mjs"));
11
- const loadGoogleMeetNodeInvokePolicyModule = createLazyRuntimeModule(() => import("./node-invoke-policy-hwXq9MfV.mjs"));
7
+ const loadGoogleMeetPluginHelpers = createLazyRuntimeModule(() => import("./plugin-helpers-CdQ_YNA7.mjs").then((n) => n.i));
8
+ const loadGoogleMeetCliModule = createLazyRuntimeModule(() => import("./cli-DVDq0TFu.mjs"));
9
+ const loadGoogleMeetNodeHostModule = createLazyRuntimeModule(() => import("./node-host-Tr7Mx3da.mjs"));
10
+ const loadGoogleMeetRuntimeModule = createLazyRuntimeModule(() => import("./runtime-BdiF53A2.mjs"));
11
+ const loadGoogleMeetNodeInvokePolicyModule = createLazyRuntimeModule(() => import("./node-invoke-policy-Dd3krTYV.mjs"));
12
12
  const loadGoogleMeetGatewayRuntimeModule = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/gateway-runtime"));
13
13
  const loadGoogleMeetNodeInvokePolicy = async (config) => (await loadGoogleMeetNodeInvokePolicyModule()).createGoogleMeetChromeNodeInvokePolicy(config);
14
14
  function normalizeTransport(value) {
@@ -29,6 +29,7 @@ function shouldJoinCreatedMeet(raw) {
29
29
  const googleMeetToolDeps = { platform: () => process.platform };
30
30
  function googleMeetGatewayMethodForToolAction(action) {
31
31
  switch (action) {
32
+ case "participation_context": return "googlemeet.participationContext";
32
33
  case "recover_current_tab": return "googlemeet.recoverCurrentTab";
33
34
  case "setup_status": return "googlemeet.setup";
34
35
  case "test_speech": return "googlemeet.testSpeech";
@@ -37,6 +38,29 @@ function googleMeetGatewayMethodForToolAction(action) {
37
38
  default: return `googlemeet.${action}`;
38
39
  }
39
40
  }
41
+ function readGoogleMeetParticipationParams(raw) {
42
+ const sessionId = normalizeOptionalString(raw.sessionId);
43
+ if (!sessionId) throw new Error("sessionId required");
44
+ const requestId = normalizeOptionalString(raw.requestId);
45
+ if (!requestId) throw new Error("requestId required");
46
+ for (const name of ["sourceId", "correctionOf"]) if (raw[name] !== void 0 && !normalizeOptionalString(raw[name])) throw new Error(`${name} must be a non-empty string`);
47
+ const action = asNonArrayRecord(raw.participationAction);
48
+ const type = normalizeOptionalString(action.type);
49
+ if (!type) throw new Error("participationAction.type required");
50
+ for (const name of ["text", "reaction"]) if (action[name] !== void 0 && typeof action[name] !== "string") throw new Error(`participationAction.${name} must be a string`);
51
+ return {
52
+ sessionId,
53
+ request: {
54
+ requestId,
55
+ ...raw.sourceId !== void 0 ? { sourceId: normalizeOptionalString(raw.sourceId) } : {},
56
+ ...raw.correctionOf !== void 0 ? { correctionOf: normalizeOptionalString(raw.correctionOf) } : {},
57
+ action: {
58
+ ...action,
59
+ type
60
+ }
61
+ }
62
+ };
63
+ }
40
64
  function isGoogleMeetAgentToolActionUnsupportedOnHost(params) {
41
65
  const platform = googleMeetToolDeps.platform();
42
66
  if (platform === "darwin" || platform === "linux") return false;
@@ -83,15 +107,34 @@ function keepTrustedToolAgentId(raw, client) {
83
107
  } : rest;
84
108
  }
85
109
  function createGoogleMeetRuntimeAccessor(params) {
110
+ let transcriptsEnabled = params.api.config.transcripts?.enabled !== false;
111
+ let runtime;
86
112
  let runtimePromise;
113
+ params.api.registerService({
114
+ id: "google-meet-transcripts",
115
+ reload: { configPrefixes: ["transcripts.enabled"] },
116
+ start: ({ config }) => {
117
+ transcriptsEnabled = config.transcripts?.enabled !== false;
118
+ return runtime?.reconcileTranscriptPolicy(transcriptsEnabled);
119
+ },
120
+ stop: () => {
121
+ transcriptsEnabled = false;
122
+ return runtime?.reconcileTranscriptPolicy(false);
123
+ }
124
+ });
87
125
  return async () => {
88
126
  if (!params.config.enabled) throw new Error("Google Meet plugin disabled in plugin config");
89
- return await (runtimePromise ?? (runtimePromise = loadGoogleMeetRuntimeModule().then(({ GoogleMeetRuntime: Runtime }) => new Runtime({
90
- config: params.config,
91
- fullConfig: params.api.config,
92
- runtime: params.api.runtime,
93
- logger: params.api.logger
94
- }))));
127
+ runtimePromise ??= loadGoogleMeetRuntimeModule().then(async ({ GoogleMeetRuntime: Runtime }) => {
128
+ runtime = new Runtime({
129
+ config: params.config,
130
+ fullConfig: params.api.config,
131
+ runtime: params.api.runtime,
132
+ logger: params.api.logger
133
+ });
134
+ await runtime.reconcileTranscriptPolicy(transcriptsEnabled);
135
+ return runtime;
136
+ });
137
+ return await runtimePromise;
95
138
  };
96
139
  }
97
140
  function createLazyGoogleMeetNodeInvokePolicy(config, loadPolicy = loadGoogleMeetNodeInvokePolicy) {
@@ -117,7 +160,7 @@ function createLazyGoogleMeetNodeInvokePolicy(config, loadPolicy = loadGoogleMee
117
160
  };
118
161
  }
119
162
  function formatGoogleMeetGatewayError(err) {
120
- return isGoogleMeetBrowserManualActionError(err) ? err.payload : { error: formatErrorMessage(err) };
163
+ return err instanceof GoogleMeetBrowserManualActionError ? err.payload : { error: formatErrorMessage(err) };
121
164
  }
122
165
  function sendGoogleMeetGatewayError(respond, err, code = "UNAVAILABLE") {
123
166
  const payload = formatGoogleMeetGatewayError(err);
@@ -128,4 +171,4 @@ function sendGoogleMeetGatewayError(respond, err, code = "UNAVAILABLE") {
128
171
  });
129
172
  }
130
173
  //#endregion
131
- export { createLazyGoogleMeetNodeInvokePolicy as a, loadGoogleMeetCliModule as c, normalizeMode as d, normalizeTransport as f, shouldJoinCreatedMeet as h, createGoogleMeetRuntimeAccessor as i, loadGoogleMeetNodeHostModule as l, sendGoogleMeetGatewayError as m, assertGoogleMeetAgentToolActionSupported as n, formatGoogleMeetGatewayError as o, resolveMeetingInput as p, callGoogleMeetGatewayFromTool as r, keepTrustedToolAgentId as s, asParamRecord as t, loadGoogleMeetPluginHelpers as u };
174
+ export { formatGoogleMeetGatewayError as a, loadGoogleMeetNodeHostModule as c, normalizeTransport as d, readGoogleMeetParticipationParams as f, shouldJoinCreatedMeet as h, createLazyGoogleMeetNodeInvokePolicy as i, loadGoogleMeetPluginHelpers as l, sendGoogleMeetGatewayError as m, callGoogleMeetGatewayFromTool as n, keepTrustedToolAgentId as o, resolveMeetingInput as p, createGoogleMeetRuntimeAccessor as r, loadGoogleMeetCliModule as s, assertGoogleMeetAgentToolActionSupported as t, normalizeMode as u };
@@ -1,28 +1,23 @@
1
- import { n as GOOGLE_MEET_NODE_COMMAND, t as GOOGLE_MEET_BROWSER_NODE_ADAPTER } from "./google-meet-platform-constants-Bs5iAg3E.mjs";
1
+ import { n as GOOGLE_MEET_NODE_COMMAND, t as GOOGLE_MEET_BROWSER_NODE_ADAPTER } from "./google-meet-platform-constants-CnRfrYX7.mjs";
2
2
  import { t as normalizeMeetUrl } from "./meet-url-BP2Jlvjs.mjs";
3
- import { c as callBrowserProxyOnNode, l as resolveChromeNode, u as resolveChromeNodeInfo } from "./chrome-create-BZRBHJp9.mjs";
4
- import { n as normalizeDialInNumber, t as GOOGLE_MEET_PLATFORM_ADAPTER } from "./google-meet-platform-adapter-DQZ74Kd5.mjs";
3
+ import { c as callBrowserProxyOnNode, l as resolveChromeNode, u as resolveChromeNodeInfo } from "./chrome-create-wuAK5Pnq.mjs";
4
+ import { n as normalizeDialInNumber, t as GOOGLE_MEET_PLATFORM_ADAPTER } from "./google-meet-platform-adapter-gosgbMIM.mjs";
5
5
  import { asOptionalRecord, asRecord, normalizeOptionalString, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
6
6
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
7
- import { GatewayClient, startGatewayClientWhenEventLoopReady } from "openclaw/plugin-sdk/gateway-runtime";
8
7
  import path from "node:path";
9
8
  import { isBlockedHostnameOrIp } from "openclaw/plugin-sdk/ssrf-runtime";
10
- import { MeetingPlatformAdapter, MeetingSessionRuntime, addMeetingSetupCheck, createMeetingSession, createMeetingSetupStatus, createMeetingVoiceCallGateway, endMeetingVoiceCallGatewayCall, getMeetingVoiceCallGatewayCall, isMeetingVoiceCallMissingError, joinMeetingViaVoiceCallGateway, leaveMeetingWithBrowser, readMeetingTranscriptWithBrowser, recoverMeetingBrowserTab, resolveLocalMeetingBrowserRequest, speakMeetingViaVoiceCallGateway } from "openclaw/plugin-sdk/meeting-runtime";
9
+ import { GatewayClient, startGatewayClientWhenEventLoopReady } from "openclaw/plugin-sdk/gateway-runtime";
10
+ import { MeetingPlatformAdapter, MeetingSessionRuntime, addMeetingSetupCheck, createMeetingSession, createMeetingSetupStatus, createMeetingVoiceCallGateway, endMeetingVoiceCallGatewayCall, getMeetingVoiceCallGatewayCall, isMeetingVoiceCallMissingError, joinMeetingViaVoiceCallGateway, leaveMeetingWithBrowser, readMeetingTranscriptWithBrowser, recoverMeetingBrowserTab, resolveLocalMeetingBrowserRequest, runMeetingParticipationWithBrowser, speakMeetingViaVoiceCallGateway } from "openclaw/plugin-sdk/meeting-runtime";
11
11
  import { resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime";
12
12
  import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
13
13
  import fs from "node:fs";
14
14
  import os from "node:os";
15
15
  import { resolveTranscriptsConfig } from "openclaw/plugin-sdk/transcripts";
16
16
  //#region extensions/google-meet/src/runtime-probes.ts
17
- function resolveProbeTimeoutMs(input, fallback) {
18
- if (input === void 0) return Math.min(Math.max(fallback, 1), 12e4);
19
- if (!Number.isFinite(input) || input <= 0) throw new Error("timeoutMs must be a positive number");
20
- return Math.min(Math.trunc(input), 12e4);
21
- }
22
17
  const probes = MeetingPlatformAdapter.createRuntimeProbes({
23
18
  defaultSpeechMessage: "Say exactly: Google Meet speech test complete.",
24
19
  invalidRequest: (message) => new Error(message),
25
- resolveTimeoutMs: resolveProbeTimeoutMs,
20
+ resolveTimeoutMs: MeetingPlatformAdapter.resolveProbeTimeoutMs,
26
21
  shouldWaitForListening: (session) => Boolean((session.transport === "chrome" || session.transport === "chrome-node") && session.chrome?.launched),
27
22
  talkBackMode: MeetingPlatformAdapter.isTalkBackMode,
28
23
  normalizeUrl: normalizeMeetUrl,
@@ -200,9 +195,6 @@ function getGoogleMeetSetupStatus(config, options) {
200
195
  }
201
196
  return createMeetingSetupStatus(checks);
202
197
  }
203
- function addGoogleMeetSetupCheck(status, check) {
204
- return addMeetingSetupCheck(status, check);
205
- }
206
198
  //#endregion
207
199
  //#region extensions/google-meet/src/transports/chrome.ts
208
200
  const chromeTransport = MeetingPlatformAdapter.createChromeTransportWithExternalAudio({
@@ -218,13 +210,7 @@ const chromeTransport = MeetingPlatformAdapter.createChromeTransportWithExternal
218
210
  });
219
211
  const assertGoogleMeetAudioAvailable = chromeTransport.assertAudioDeviceAvailable;
220
212
  const launchChromeMeetOnNode = chromeTransport.launchOnNode;
221
- async function launchChromeMeet(params) {
222
- const result = await chromeTransport.launchInChrome(params);
223
- return {
224
- ...result,
225
- audioBridge: result.audioBridge
226
- };
227
- }
213
+ const launchChromeMeet = chromeTransport.launchInChrome;
228
214
  function shouldCaptureCaptions(mode, fullConfig) {
229
215
  return mode === "transcribe" || !fullConfig || resolveTranscriptsConfig(fullConfig.transcripts).enabled;
230
216
  }
@@ -329,7 +315,7 @@ async function getGoogleMeetRuntimeSetupStatus(params) {
329
315
  requestedNode: params.config.chromeNode.node
330
316
  });
331
317
  const label = node.displayName ?? node.remoteIp ?? node.nodeId ?? "connected node";
332
- status = addGoogleMeetSetupCheck(status, {
318
+ status = addMeetingSetupCheck(status, {
333
319
  id: "chrome-node-connected",
334
320
  ok: true,
335
321
  message: `Connected Google Meet node ready: ${label}`
@@ -348,14 +334,14 @@ async function getGoogleMeetRuntimeSetupStatus(params) {
348
334
  },
349
335
  timeoutMs: 12e3
350
336
  });
351
- status = addGoogleMeetSetupCheck(status, {
337
+ status = addMeetingSetupCheck(status, {
352
338
  id: "chrome-node-audio-prerequisites",
353
339
  ok: true,
354
340
  message: setup ? "Remote virtual audio backend and command-pair prerequisites are ready" : "Remote audio setup completed"
355
341
  });
356
342
  }
357
343
  } catch (error) {
358
- status = addGoogleMeetSetupCheck(status, {
344
+ status = addMeetingSetupCheck(status, {
359
345
  id: "chrome-node-connected",
360
346
  ok: false,
361
347
  message: formatErrorMessage(error)
@@ -368,13 +354,13 @@ async function getGoogleMeetRuntimeSetupStatus(params) {
368
354
  config: params.config,
369
355
  timeoutMs: Math.min(params.config.chrome.joinTimeoutMs, 1e4)
370
356
  });
371
- status = addGoogleMeetSetupCheck(status, {
357
+ status = addMeetingSetupCheck(status, {
372
358
  id: "chrome-local-audio-device",
373
359
  ok: true,
374
360
  message: "Virtual meeting audio backend is ready"
375
361
  });
376
362
  } catch (error) {
377
- status = addGoogleMeetSetupCheck(status, {
363
+ status = addMeetingSetupCheck(status, {
378
364
  id: "chrome-local-audio-device",
379
365
  ok: false,
380
366
  message: formatErrorMessage(error)
@@ -387,13 +373,51 @@ async function getGoogleMeetRuntimeSetupStatus(params) {
387
373
  } catch {
388
374
  missingCommands.push(command);
389
375
  }
390
- return addGoogleMeetSetupCheck(status, {
376
+ return addMeetingSetupCheck(status, {
391
377
  id: "chrome-local-audio-commands",
392
378
  ok: commands.length > 0 && missingCommands.length === 0,
393
379
  message: commands.length === 0 ? "Chrome talk-back audio commands are not configured" : missingCommands.length === 0 ? `Chrome audio command${commands.length === 1 ? "" : "s"} available: ${commands.join(", ")}` : `Chrome audio command${missingCommands.length === 1 ? "" : "s"} missing: ${missingCommands.join(", ")}`
394
380
  });
395
381
  }
396
382
  //#endregion
383
+ //#region extensions/google-meet/src/transports/chrome-participation.ts
384
+ async function participateInChromeMeet(params) {
385
+ const adapter = GOOGLE_MEET_PLATFORM_ADAPTER.browser.participation;
386
+ const { session } = params;
387
+ const tab = session.chrome?.browserTab;
388
+ if (!adapter || !tab || session.transport !== "chrome" && session.transport !== "chrome-node") return {
389
+ status: "unsupported",
390
+ message: "Participation requires a supported tracked browser meeting."
391
+ };
392
+ const { nodeId } = session.chrome ?? {};
393
+ const meetingSessionId = session.id;
394
+ const meetingUrl = session.url;
395
+ const targetId = tab.targetId;
396
+ if (session.transport === "chrome-node" && nodeId === void 0) return {
397
+ status: "rejected",
398
+ message: "The meeting has no pinned browser node."
399
+ };
400
+ params.assertCurrent();
401
+ const callBrowser = session.transport === "chrome-node" ? (request) => callBrowserProxyOnNode({
402
+ ...request,
403
+ runtime: params.runtime,
404
+ nodeId
405
+ }) : await resolveLocalMeetingBrowserRequest(params.runtime);
406
+ params.assertCurrent();
407
+ return await runMeetingParticipationWithBrowser({
408
+ adapter,
409
+ callBrowser,
410
+ meetingSessionId,
411
+ meetingUrl,
412
+ targetId,
413
+ requestId: params.request.requestId,
414
+ action: params.request.action,
415
+ assertCurrent: () => params.assertCurrent(),
416
+ isSameMeetingUrl: (left, right) => GOOGLE_MEET_PLATFORM_ADAPTER.urls.isSameMeeting(left, right),
417
+ timeoutMs: Math.min(1e4, params.config.chrome.joinTimeoutMs)
418
+ });
419
+ }
420
+ //#endregion
397
421
  //#region extensions/google-meet/src/voice-call-gateway.ts
398
422
  const GOOGLE_MEET_VOICE_CALL_SURFACE = {
399
423
  clientDisplayName: "Google Meet plugin",
@@ -458,7 +482,6 @@ function createVoiceCallGateway(params) {
458
482
  connectClient: createConnectedGatewayClient
459
483
  });
460
484
  }
461
- const isVoiceCallMissingError = isMeetingVoiceCallMissingError;
462
485
  async function joinMeetViaVoiceCallGateway(params) {
463
486
  return await joinMeetingViaVoiceCallGateway({
464
487
  ...params,
@@ -466,15 +489,6 @@ async function joinMeetViaVoiceCallGateway(params) {
466
489
  surface: GOOGLE_MEET_VOICE_CALL_SURFACE
467
490
  });
468
491
  }
469
- async function endMeetVoiceCallGatewayCall(params) {
470
- await endMeetingVoiceCallGatewayCall(params);
471
- }
472
- async function getMeetVoiceCallGatewayCall(params) {
473
- return await getMeetingVoiceCallGatewayCall(params);
474
- }
475
- async function speakMeetViaVoiceCallGateway(params) {
476
- await speakMeetingViaVoiceCallGateway(params);
477
- }
478
492
  //#endregion
479
493
  //#region extensions/google-meet/src/runtime.ts
480
494
  const nowIso = () => (/* @__PURE__ */ new Date()).toISOString();
@@ -482,13 +496,40 @@ var GoogleMeetRuntime = class {
482
496
  #createdBrowserTabs;
483
497
  #voiceCallGateway;
484
498
  #sessions;
499
+ reconcileTranscriptPolicy(enabled) {
500
+ return this.#sessions.reconcileTranscriptPolicy(enabled);
501
+ }
485
502
  constructor(params) {
486
503
  this.params = params;
487
504
  this.#createdBrowserTabs = /* @__PURE__ */ new Map();
488
505
  this.transcriptSourceRuntime = () => this.#sessions;
489
506
  const adapter = GOOGLE_MEET_PLATFORM_ADAPTER;
490
507
  this.#voiceCallGateway = createVoiceCallGateway(params);
508
+ let participationStore;
509
+ const getParticipationStore = () => participationStore ??= params.runtime.state.openKeyedStore({
510
+ namespace: "meeting-participation",
511
+ maxEntries: 1e4,
512
+ overflowPolicy: "reject-new"
513
+ });
491
514
  this.#sessions = new MeetingSessionRuntime({
515
+ participation: {
516
+ store: {
517
+ entries: async () => await getParticipationStore().entries(),
518
+ delete: async (key) => await getParticipationStore().delete(key),
519
+ lookup: async (key) => await getParticipationStore().lookup(key),
520
+ registerIfAbsent: async (key, attempt) => await getParticipationStore().registerIfAbsent(key, attempt),
521
+ register: async (key, attempt) => await getParticipationStore().register(key, attempt)
522
+ },
523
+ capabilities: (session) => isBrowserTransport(session.transport) && session.chrome?.launched && session.chrome.browserTab && session.chrome.health?.inCall === true && !session.chrome.health.manualAction ? adapter.browser.participation?.capabilities ?? [] : [],
524
+ validateAction: (action) => adapter.browser.participation?.validateAction(action),
525
+ execute: async (session, request, assertCurrent) => await participateInChromeMeet({
526
+ runtime: params.runtime,
527
+ config: params.config,
528
+ session,
529
+ request,
530
+ assertCurrent
531
+ })
532
+ },
492
533
  logger: params.logger,
493
534
  logScope: "[google-meet]",
494
535
  formatError: formatErrorMessage,
@@ -561,6 +602,7 @@ var GoogleMeetRuntime = class {
561
602
  speakViaTransport: async (session, instructions) => await this.#speakViaTransport(session, instructions),
562
603
  durableTranscripts: {
563
604
  config: params.fullConfig.transcripts,
605
+ openclawConfig: params.fullConfig,
564
606
  providerId: "google-meet",
565
607
  providerName: "Google Meet"
566
608
  }
@@ -572,6 +614,12 @@ var GoogleMeetRuntime = class {
572
614
  async status(sessionId) {
573
615
  return await this.#sessions.status(sessionId);
574
616
  }
617
+ participationContext(sessionId) {
618
+ return this.#sessions.participationContext(sessionId);
619
+ }
620
+ participate(sessionId, request) {
621
+ return this.#sessions.participate(sessionId, request);
622
+ }
575
623
  async transcript(sessionId, options = {}) {
576
624
  return await this.#sessions.transcript(sessionId, options);
577
625
  }
@@ -709,7 +757,7 @@ var GoogleMeetRuntime = class {
709
757
  introSent: voiceCallResult?.introSent
710
758
  };
711
759
  if (voiceCallResult?.callId) context.attachRuntimeHandles(session, { stop: async () => {
712
- await endMeetVoiceCallGatewayCall({
760
+ await endMeetingVoiceCallGatewayCall({
713
761
  gateway: this.#voiceCallGateway,
714
762
  callId: voiceCallResult.callId
715
763
  });
@@ -801,7 +849,7 @@ var GoogleMeetRuntime = class {
801
849
  return;
802
850
  }
803
851
  try {
804
- const status = await getMeetVoiceCallGatewayCall({
852
+ const status = await getMeetingVoiceCallGatewayCall({
805
853
  gateway: this.#voiceCallGateway,
806
854
  callId
807
855
  });
@@ -815,13 +863,13 @@ var GoogleMeetRuntime = class {
815
863
  async #speakViaTransport(session, instructions) {
816
864
  if (session.transport !== "twilio" || !session.twilio?.voiceCallId) return;
817
865
  try {
818
- await speakMeetViaVoiceCallGateway({
866
+ await speakMeetingViaVoiceCallGateway({
819
867
  gateway: this.#voiceCallGateway,
820
868
  callId: session.twilio.voiceCallId,
821
869
  message: instructions || this.params.config.voiceCall.introMessage || this.params.config.realtime.introMessage || ""
822
870
  });
823
871
  } catch (error) {
824
- if (!isVoiceCallMissingError(error)) throw error;
872
+ if (!isMeetingVoiceCallMissingError(error)) throw error;
825
873
  this.#sessions.markSessionEnded(session, "Voice Call is no longer active.");
826
874
  return {
827
875
  handled: true,
@@ -1,12 +1,9 @@
1
1
  import { asNullableRecord, normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/string-coerce-runtime";
2
2
  //#region extensions/google-meet/src/config-compat.ts
3
- function hasOwn(record, key) {
4
- return Object.hasOwn(record, key);
5
- }
6
3
  function hasLegacyGoogleRealtimeProvider(value) {
7
4
  const realtime = asNullableRecord(value);
8
5
  if (!realtime || normalizeOptionalLowercaseString(realtime.provider) !== "google") return false;
9
- return !hasOwn(realtime, "voiceProvider") || !hasOwn(realtime, "transcriptionProvider");
6
+ return !Object.hasOwn(realtime, "voiceProvider") || !Object.hasOwn(realtime, "transcriptionProvider");
10
7
  }
11
8
  const legacyConfigRules = [{
12
9
  path: [
@@ -36,8 +33,8 @@ function migrateGoogleMeetLegacyRealtimeProvider(config) {
36
33
  const nextRealtime = asNullableRecord(nextPluginConfig.realtime) ?? {};
37
34
  nextPluginConfig.realtime = nextRealtime;
38
35
  nextRealtime.provider = "openai";
39
- if (!hasOwn(nextRealtime, "transcriptionProvider")) nextRealtime.transcriptionProvider = "openai";
40
- if (!hasOwn(nextRealtime, "voiceProvider")) nextRealtime.voiceProvider = "google";
36
+ if (!Object.hasOwn(nextRealtime, "transcriptionProvider")) nextRealtime.transcriptionProvider = "openai";
37
+ if (!Object.hasOwn(nextRealtime, "voiceProvider")) nextRealtime.voiceProvider = "google";
41
38
  return {
42
39
  config: nextConfig,
43
40
  changes: ["Moved Google Meet legacy realtime.provider=\"google\" intent to realtime.voiceProvider=\"google\" and realtime.transcriptionProvider=\"openai\"."]
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { t as GOOGLE_MEET_CLI_DESCRIPTOR } from "./.setup/cli-output-mode-BwH_6tH8.mjs";
2
- import { n as GOOGLE_MEET_NODE_COMMAND } from "./.setup/google-meet-platform-constants-Bs5iAg3E.mjs";
3
- import { r as resolveGoogleMeetConfig } from "./.setup/config-C-6enWkx.mjs";
4
- import { a as createLazyGoogleMeetNodeInvokePolicy, c as loadGoogleMeetCliModule, d as normalizeMode, f as normalizeTransport, h as shouldJoinCreatedMeet, i as createGoogleMeetRuntimeAccessor, l as loadGoogleMeetNodeHostModule, m as sendGoogleMeetGatewayError, n as assertGoogleMeetAgentToolActionSupported, o as formatGoogleMeetGatewayError, p as resolveMeetingInput, r as callGoogleMeetGatewayFromTool, s as keepTrustedToolAgentId, t as asParamRecord, u as loadGoogleMeetPluginHelpers } from "./.setup/plugin-registration-CfZbUMDY.mjs";
2
+ import { n as GOOGLE_MEET_NODE_COMMAND } from "./.setup/google-meet-platform-constants-CnRfrYX7.mjs";
3
+ import { r as resolveGoogleMeetConfig } from "./.setup/config-BXGAMntj.mjs";
4
+ import { a as formatGoogleMeetGatewayError, c as loadGoogleMeetNodeHostModule, d as normalizeTransport, f as readGoogleMeetParticipationParams, h as shouldJoinCreatedMeet, i as createLazyGoogleMeetNodeInvokePolicy, l as loadGoogleMeetPluginHelpers, m as sendGoogleMeetGatewayError, n as callGoogleMeetGatewayFromTool, o as keepTrustedToolAgentId, p as resolveMeetingInput, r as createGoogleMeetRuntimeAccessor, s as loadGoogleMeetCliModule, t as assertGoogleMeetAgentToolActionSupported, u as normalizeMode } from "./.setup/plugin-registration-aCEuCerg.mjs";
5
5
  import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
6
- import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
+ import { asNonArrayRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
7
7
  import { jsonResult } from "openclaw/plugin-sdk/tool-results";
8
8
  import { optionalPositiveIntegerSchema } from "openclaw/plugin-sdk/channel-actions";
9
9
  import { Type } from "typebox";
@@ -18,6 +18,8 @@ const GoogleMeetToolSchema = Type.Object({
18
18
  "create",
19
19
  "status",
20
20
  "transcript",
21
+ "participation_context",
22
+ "participate",
21
23
  "setup_status",
22
24
  "resolve_space",
23
25
  "preflight",
@@ -69,6 +71,14 @@ const GoogleMeetToolSchema = Type.Object({
69
71
  pin: Type.Optional(Type.String({ description: "Meet phone PIN for Twilio; # is appended if omitted" })),
70
72
  dtmfSequence: Type.Optional(Type.String({ description: "Explicit DTMF sequence for Twilio" })),
71
73
  sessionId: Type.Optional(Type.String({ description: "Meet session ID" })),
74
+ requestId: Type.Optional(Type.String({ description: "For participate, a unique request ID. Reuse the same ID only to retry the same action." })),
75
+ sourceId: Type.Optional(Type.String({ description: "For participate, the current source ID from participation_context." })),
76
+ correctionOf: Type.Optional(Type.String({ description: "For participate, the rejected request ID whose correction is being submitted." })),
77
+ participationAction: Type.Optional(Type.Object({
78
+ type: Type.String({ description: "Action type advertised by participation_context capabilities." }),
79
+ text: Type.Optional(Type.String({ description: "Text for a supported participation action." })),
80
+ reaction: Type.Optional(Type.String({ description: "Native reaction advertised by the current capability." }))
81
+ })),
72
82
  sinceIndex: Type.Optional(Type.Integer({
73
83
  description: "For transcript, resume from the previous response's nextIndex.",
74
84
  minimum: 0
@@ -119,7 +129,7 @@ var google_meet_default = definePluginEntry({
119
129
  });
120
130
  };
121
131
  const resolveTrustedJoinParams = ({ params, client }) => {
122
- const trustedParams = keepTrustedToolAgentId(asParamRecord(params), client);
132
+ const trustedParams = keepTrustedToolAgentId(asNonArrayRecord(params), client);
123
133
  return {
124
134
  url: resolveMeetingInput(config, trustedParams.url),
125
135
  transport: normalizeTransport(trustedParams.transport),
@@ -183,7 +193,7 @@ var google_meet_default = definePluginEntry({
183
193
  options.respond(true, await runtime.join(resolveTrustedJoinParams(options)));
184
194
  });
185
195
  registerGatewayMethod("googlemeet.create", async ({ params, client, respond }) => {
186
- const raw = keepTrustedToolAgentId(asParamRecord(params), client);
196
+ const raw = keepTrustedToolAgentId(asNonArrayRecord(params), client);
187
197
  const helpers = await loadGoogleMeetPluginHelpers();
188
198
  respond(true, shouldJoinCreatedMeet(raw) ? await helpers.createAndJoinMeetFromParams({
189
199
  config,
@@ -212,6 +222,24 @@ var google_meet_default = definePluginEntry({
212
222
  }
213
223
  respond(true, await (await ensureRuntime()).transcript(sessionId, sinceIndex === void 0 ? {} : { sinceIndex }));
214
224
  });
225
+ registerGatewayMethod("googlemeet.participationContext", async ({ params, respond }) => {
226
+ const sessionId = normalizeOptionalString(params?.sessionId);
227
+ if (!sessionId) {
228
+ sendGoogleMeetGatewayError(respond, /* @__PURE__ */ new Error("sessionId required"), "INVALID_REQUEST");
229
+ return;
230
+ }
231
+ respond(true, (await ensureRuntime()).participationContext(sessionId));
232
+ });
233
+ registerGatewayMethod("googlemeet.participate", async ({ params, respond }) => {
234
+ let parsed;
235
+ try {
236
+ parsed = readGoogleMeetParticipationParams(asNonArrayRecord(params));
237
+ } catch (err) {
238
+ sendGoogleMeetGatewayError(respond, err, "INVALID_REQUEST");
239
+ return;
240
+ }
241
+ respond(true, await (await ensureRuntime()).participate(parsed.sessionId, parsed.request));
242
+ });
215
243
  registerGatewayMethod("googlemeet.recoverCurrentTab", async ({ params, respond }) => {
216
244
  respond(true, await (await ensureRuntime()).recoverCurrentTab({
217
245
  url: normalizeOptionalString(params?.url),
@@ -231,10 +259,10 @@ var google_meet_default = definePluginEntry({
231
259
  ["googlemeet.artifacts", "artifacts"],
232
260
  ["googlemeet.attendance", "attendance"]
233
261
  ]) registerGatewayMethod(method, async ({ params, respond }) => {
234
- respond(true, await queryActions[action](asParamRecord(params)));
262
+ respond(true, await queryActions[action](asNonArrayRecord(params)));
235
263
  });
236
264
  registerGatewayMethod("googlemeet.export", async ({ params, respond }) => {
237
- respond(true, await (await loadGoogleMeetPluginHelpers()).exportGoogleMeetBundleFromParams(config, asParamRecord(params)));
265
+ respond(true, await (await loadGoogleMeetPluginHelpers()).exportGoogleMeetBundleFromParams(config, asNonArrayRecord(params)));
238
266
  });
239
267
  registerGatewayMethod("googlemeet.leave", async ({ params, respond }) => {
240
268
  const sessionId = normalizeOptionalString(params?.sessionId);
@@ -245,7 +273,7 @@ var google_meet_default = definePluginEntry({
245
273
  respond(true, await (await ensureRuntime()).leave(sessionId));
246
274
  });
247
275
  registerGatewayMethod("googlemeet.endActiveConference", async ({ params, respond }) => {
248
- const raw = asParamRecord(params);
276
+ const raw = asNonArrayRecord(params);
249
277
  const helpers = await loadGoogleMeetPluginHelpers();
250
278
  const token = await helpers.resolveGoogleMeetTokenFromParams(config, raw);
251
279
  respond(true, await helpers.endGoogleMeetActiveConference({
@@ -266,7 +294,7 @@ var google_meet_default = definePluginEntry({
266
294
  options.respond(true, await runtime.testSpeech(resolveTrustedJoinParams(options)));
267
295
  });
268
296
  registerGatewayMethod("googlemeet.testListen", async ({ params, client, respond }) => {
269
- const trustedParams = keepTrustedToolAgentId(asParamRecord(params), client);
297
+ const trustedParams = keepTrustedToolAgentId(asNonArrayRecord(params), client);
270
298
  const runtime = await ensureRuntime();
271
299
  const { readPositiveIntegerParam } = await import("openclaw/plugin-sdk/param-readers");
272
300
  respond(true, await runtime.testListen({
@@ -280,10 +308,10 @@ var google_meet_default = definePluginEntry({
280
308
  api.registerTool((toolContext) => ({
281
309
  name: "google_meet",
282
310
  label: "Google Meet",
283
- description: "Join and track Google Meet sessions through Chrome or Twilio. Call setup_status before join/create/test_listen/test_speech; if it reports a Chrome node offline, local audio missing, or missing Twilio dial plan, surface that blocker instead of retrying or switching transports. Twilio cannot dial a Meet URL directly: provide dialInNumber plus optional pin/dtmfSequence, or configure twilio.defaultDialInNumber. Offline nodes are diagnostics only, not usable candidates. Local Chrome talk-back needs macOS with BlackHole 2ch or Linux with PipeWire-Pulse; otherwise use mode=transcribe, transport=twilio, or a supported chrome-node. If a Meet tab is already open after a timeout, call recover_current_tab before retrying join to report login, permission, or admission blockers without opening another tab.",
311
+ description: "Join and track Google Meet sessions through Chrome or Twilio. Call setup_status before join/create/test_listen/test_speech; if it reports a Chrome node offline, local audio missing, or missing Twilio dial plan, surface that blocker instead of retrying or switching transports. Twilio cannot dial a Meet URL directly: provide dialInNumber plus optional pin/dtmfSequence, or configure twilio.defaultDialInNumber. Offline nodes are diagnostics only, not usable candidates. Local Chrome talk-back needs macOS with BlackHole 2ch or Linux with PipeWire-Pulse; otherwise use mode=transcribe, transport=twilio, or a supported chrome-node. If a Meet tab is already open after a timeout, call recover_current_tab before retrying join to report login, permission, or admission blockers without opening another tab. For meeting participation, call participation_context for current source identities and supported capabilities, then participate with a unique requestId and participationAction. An empty capability list means native participation is unavailable. Reuse a requestId only for an identical retry; use correctionOf only when a rejected result permits one correction.",
284
312
  parameters: GoogleMeetToolSchema,
285
313
  async execute(_toolCallId, params) {
286
- const raw = asParamRecord(params);
314
+ const raw = asNonArrayRecord(params);
287
315
  const requesterSessionKey = normalizeOptionalString(toolContext.sessionKey);
288
316
  try {
289
317
  const { normalizeAgentId, parseAgentSessionKey } = await import("openclaw/plugin-sdk/routing");
@@ -342,6 +370,14 @@ var google_meet_default = definePluginEntry({
342
370
  const helpers = await loadGoogleMeetPluginHelpers();
343
371
  return jsonResult(await helpers.exportGoogleMeetBundleFromParams(config, raw));
344
372
  }
373
+ case "participate":
374
+ readGoogleMeetParticipationParams(raw);
375
+ return jsonResult(await callGoogleMeetGatewayFromTool({
376
+ config,
377
+ action: raw.action,
378
+ raw
379
+ }));
380
+ case "participation_context":
345
381
  case "leave":
346
382
  case "speak":
347
383
  if (!normalizeOptionalString(raw.sessionId)) throw new Error("sessionId required");
@@ -357,11 +393,16 @@ var google_meet_default = definePluginEntry({
357
393
  }
358
394
  }
359
395
  }), { name: "google_meet" });
396
+ let nodeHost;
360
397
  api.registerNodeHostCommand({
361
398
  command: GOOGLE_MEET_NODE_COMMAND,
362
399
  cap: "google-meet",
363
400
  dangerous: true,
364
- handle: async (paramsJSON) => await (await loadGoogleMeetNodeHostModule()).handleGoogleMeetNodeHostCommand(paramsJSON)
401
+ hasActiveWork: () => nodeHost?.handleGoogleMeetNodeHostCommand.hasActiveWork() ?? false,
402
+ handle: async (paramsJSON) => {
403
+ nodeHost ??= await loadGoogleMeetNodeHostModule();
404
+ return await nodeHost.handleGoogleMeetNodeHostCommand(paramsJSON);
405
+ }
365
406
  });
366
407
  api.registerNodeInvokePolicy(createLazyGoogleMeetNodeInvokePolicy(config));
367
408
  api.registerCli(async ({ program }) => {
@@ -16,9 +16,8 @@ function Separator() {
16
16
  function ImportSection(build) {
17
17
  const context = build.UseUnevaluated() ? [`import { CheckContext } from "typebox/schema"`] : [];
18
18
  const hashing = `import { Hashing } from "typebox/system"`;
19
- const format = `import { Format } from "typebox/format"`;
20
19
  const guard = `import { Guard } from "typebox/guard"`;
21
- return [...context, hashing, format, guard];
20
+ return [...context, hashing, guard];
22
21
  }
23
22
  // ------------------------------------------------------------------
24
23
  // ExternalSection
@@ -1,4 +1,5 @@
1
1
  // deno-fmt-ignore-file
2
+ import { EnableParseErrors, DisableParseErrors } from '../system/settings/internal.mjs';
2
3
  import { Settings } from '../system/settings/index.mjs';
3
4
  import { Errors, Clean, Convert, Create, Default, Decode, Encode, HasCodec, Parser, ParseError } from '../value/index.mjs';
4
5
  import { Build } from '../schema/index.mjs';
@@ -51,7 +52,10 @@ export class Validator {
51
52
  return value;
52
53
  if (Settings.Get().correctiveParse)
53
54
  return Parser(this.Context(), this.Type(), value);
54
- throw new ParseError(value, this.Errors(value));
55
+ EnableParseErrors();
56
+ const errors = this.Errors(value);
57
+ DisableParseErrors();
58
+ throw new ParseError(value, errors);
55
59
  }
56
60
  /** Returns an array of validation errors for the given value. */
57
61
  Errors(value) {
@@ -1,9 +1,10 @@
1
1
  // deno-lint-ignore-file no-control-regex
2
- const IpvFutureMatchMaxLength = 2048;
3
- const IpvFutureMatch = /\[[vV][0-9a-fA-F]+\.[^\]]+\]/; // Guarded By IpvFutureMatchMaxLength
4
- const InvalidIriChars = /[\x00-\x20<>\^`{|}\\]/;
5
- const InvalidPercentEncoding = /%(?![0-9a-fA-F]{2})/;
6
2
  // ------------------------------------------------------------------
3
+ //
4
+ // Removed by the following PR
5
+ //
6
+ // https://github.com/json-schema-org/JSON-Schema-Test-Suite/pull/1176
7
+ //
7
8
  // NarrowIpvFuture
8
9
  //
9
10
  // Substitutes an IPvFuture address with a standard IPv6 loopback
@@ -13,12 +14,18 @@ const InvalidPercentEncoding = /%(?![0-9a-fA-F]{2})/;
13
14
  // be expensive on large strings, this operation is strictly
14
15
  // limited to inputs under a defined length threshold.
15
16
  //
16
- // (review-optimization)
17
+ // ------------------------------------------------------------------
18
+ //
19
+ // const IpvFutureMatchMaxLength = 2048
20
+ // const IpvFutureMatch = /\[[vV][0-9a-fA-F]+\.[^\]]+\]/ // Guarded By IpvFutureMatchMaxLength
21
+ //
22
+ // function NarrowIpvFuture(value: string): string {
23
+ // return value.length < IpvFutureMatchMaxLength ? value.replace(IpvFutureMatch, '[::1]') : value
24
+ // }
17
25
  //
18
26
  // ------------------------------------------------------------------
19
- function NarrowIpvFuture(value) {
20
- return value.length < IpvFutureMatchMaxLength ? value.replace(IpvFutureMatch, '[::1]') : value;
21
- }
27
+ const InvalidIriChars = /[\x00-\x20<>\^`{|}\\]/;
28
+ const InvalidPercentEncoding = /%(?![0-9a-fA-F]{2})/;
22
29
  /**
23
30
  * Returns true if the value is a valid Internationalized Resource Identifier.
24
31
  * @specification https://datatracker.ietf.org/doc/html/rfc3987
@@ -31,5 +38,5 @@ export function IsIri(value) {
31
38
  if (InvalidPercentEncoding.test(value))
32
39
  return false;
33
40
  // 3. Delegate to the native URL parser, patching the IPvFuture edge case beforehand.
34
- return URL.canParse(NarrowIpvFuture(value));
41
+ return URL.canParse(value);
35
42
  }