@openclaw/google-meet 2026.10.10 → 2026.11.5-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/activity.svg +1 -1
- package/dist/.setup/{chrome-create-DIcW4QCh.mjs → chrome-create-BlDlV2YP.mjs} +11 -30
- package/dist/.setup/{cli-9linTFHb.mjs → cli-C-MrY7IZ.mjs} +275 -309
- package/dist/.setup/{cli-export-CaDYoSP8.mjs → cli-export-6eiywS3T.mjs} +16 -35
- package/dist/.setup/{cli-output-mode-BJSm88N9.mjs → cli-output-mode-DztqqVeZ.mjs} +5 -6
- package/dist/.setup/config-CMTw0Anh.mjs +110 -0
- package/dist/.setup/{create-D3fHR8uX.mjs → create-DMk4zbMq.mjs} +23 -9
- package/dist/.setup/{google-meet-platform-adapter-D7poqL1J.mjs → google-meet-platform-adapter-DgchqNLV.mjs} +52 -18
- package/dist/.setup/{node-host-B196lvNZ.mjs → node-host-BIZD9InM.mjs} +2 -2
- package/dist/.setup/{node-invoke-policy-BzRAe25r.mjs → node-invoke-policy-bg7p_BWB.mjs} +1 -1
- package/dist/.setup/oauth-DZkuGMs1.mjs +1 -0
- package/dist/.setup/{plugin-helpers-Buhixxsx.mjs → plugin-helpers-ChCBuyAl.mjs} +363 -69
- package/dist/.setup/{plugin-registration-B_nOxAym.mjs → plugin-registration-CAW7_zO_.mjs} +8 -8
- package/dist/.setup/{runtime-D-dwEsSW.mjs → runtime-Cyc6bv1i.mjs} +37 -38
- package/dist/.source-module-urls/c06239f68b6f4959b5d3db7e0cee004911d8eb43092f4135c729b507e37f6333.json +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/doctor-contract-api.js +25 -21
- package/dist/index.js +14 -13
- package/node_modules/typebox/build/format/duration.d.mts +2 -2
- package/node_modules/typebox/build/format/duration.mjs +2 -2
- package/node_modules/typebox/build/format/idn_email.d.mts +1 -0
- package/node_modules/typebox/build/format/idn_email.mjs +1 -0
- package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -1
- package/node_modules/typebox/build/format/idn_hostname.mjs +1 -1
- package/node_modules/typebox/build/format/ipv4.d.mts +2 -2
- package/node_modules/typebox/build/format/ipv4.mjs +2 -2
- package/node_modules/typebox/build/format/ipv6.d.mts +1 -1
- package/node_modules/typebox/build/format/ipv6.mjs +1 -1
- package/node_modules/typebox/build/format/relative_json_pointer.d.mts +2 -2
- package/node_modules/typebox/build/format/relative_json_pointer.mjs +2 -2
- package/node_modules/typebox/build/schema/build.mjs +1 -0
- package/node_modules/typebox/build/schema/engine/_unique.d.mts +4 -2
- package/node_modules/typebox/build/schema/engine/_unique.mjs +7 -3
- package/node_modules/typebox/build/schema/engine/additionalItems.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/additionalProperties.d.mts +0 -3
- package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +15 -17
- package/node_modules/typebox/build/schema/engine/contains.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/index.d.mts +1 -0
- package/node_modules/typebox/build/schema/engine/index.mjs +1 -0
- package/node_modules/typebox/build/schema/engine/items.mjs +7 -4
- package/node_modules/typebox/build/schema/engine/maxContains.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/minContains.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/oneOf.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/patternProperties.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/unevaluatedItems.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/unevaluatedProperties.mjs +2 -2
- package/node_modules/typebox/build/system/hashing/hash.mjs +63 -34
- package/node_modules/typebox/build/system/locale/en_US.mjs +2 -1
- package/node_modules/typebox/build/system/memory/assign.d.mts +2 -8
- package/node_modules/typebox/build/system/memory/assign.mjs +13 -6
- package/node_modules/typebox/build/system/memory/clone.d.mts +4 -5
- package/node_modules/typebox/build/system/memory/clone.mjs +8 -96
- package/node_modules/typebox/build/system/memory/create.d.mts +1 -5
- package/node_modules/typebox/build/system/memory/create.mjs +18 -13
- package/node_modules/typebox/build/system/memory/deep.d.mts +2 -0
- package/node_modules/typebox/build/system/memory/deep.mjs +108 -0
- package/node_modules/typebox/build/system/memory/discard.d.mts +1 -1
- package/node_modules/typebox/build/system/memory/discard.mjs +9 -8
- package/node_modules/typebox/build/system/memory/finalize.d.mts +4 -0
- package/node_modules/typebox/build/system/memory/finalize.mjs +30 -0
- package/node_modules/typebox/build/system/memory/keys.d.mts +2 -0
- package/node_modules/typebox/build/system/memory/keys.mjs +8 -0
- package/node_modules/typebox/build/system/memory/update.d.mts +1 -4
- package/node_modules/typebox/build/system/memory/update.mjs +43 -16
- package/node_modules/typebox/build/type/engine/call/index.d.mts +1 -0
- package/node_modules/typebox/build/type/engine/call/index.mjs +1 -0
- package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +2 -24
- package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +2 -29
- package/node_modules/typebox/build/type/engine/evaluate/index.d.mts +1 -0
- package/node_modules/typebox/build/type/engine/evaluate/index.mjs +1 -0
- package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +5 -1
- package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +6 -1
- package/node_modules/typebox/build/type/engine/evaluate/property.d.mts +30 -0
- package/node_modules/typebox/build/type/engine/evaluate/property.mjs +29 -0
- package/node_modules/typebox/build/type/engine/immutable/instantiate_add.d.mts +1 -3
- package/node_modules/typebox/build/type/engine/immutable/instantiate_add.mjs +1 -4
- package/node_modules/typebox/build/type/engine/object/from_intersect.d.mts +2 -2
- package/node_modules/typebox/build/type/engine/object/from_intersect.mjs +2 -2
- package/node_modules/typebox/build/type/engine/object/from_union.d.mts +2 -2
- package/node_modules/typebox/build/type/engine/object/from_union.mjs +2 -2
- package/node_modules/typebox/build/type/engine/optional/instantiate_add.d.mts +1 -3
- package/node_modules/typebox/build/type/engine/optional/instantiate_add.mjs +1 -4
- package/node_modules/typebox/build/type/engine/readonly/instantiate_add.d.mts +1 -3
- package/node_modules/typebox/build/type/engine/readonly/instantiate_add.mjs +1 -4
- package/node_modules/typebox/build/type/engine/this/index.d.mts +1 -0
- package/node_modules/typebox/build/type/engine/this/index.mjs +1 -0
- package/node_modules/typebox/build/value/clone/clone.d.mts +4 -3
- package/node_modules/typebox/build/value/clone/clone.mjs +5 -7
- package/node_modules/typebox/build/value/repair/from_cyclic.d.mts +2 -0
- package/node_modules/typebox/build/value/repair/from_cyclic.mjs +6 -0
- package/node_modules/typebox/build/value/shared/union_priority_sort.mjs +25 -14
- package/node_modules/typebox/package.json +1 -1
- package/node_modules/typebox/readme.md +1 -1
- package/package.json +5 -5
- package/dist/.setup/config-Cu3zsl_3.mjs +0 -239
- package/dist/.setup/oauth-DGv28ZgA.mjs +0 -158
- package/node_modules/typebox/build/system/memory/freeze.d.mts +0 -4
- package/node_modules/typebox/build/system/memory/freeze.mjs +0 -6
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
// deno-fmt-ignore-file
|
|
2
2
|
import { Memory } from '../../../system/memory/index.mjs';
|
|
3
3
|
import { InstantiateType } from '../instantiate.mjs';
|
|
4
|
-
function AddReadonlyOperation(type) {
|
|
5
|
-
return Memory.Update(type, { '~readonly': true }, {});
|
|
6
|
-
}
|
|
7
4
|
export function AddReadonlyAction(type, options) {
|
|
8
|
-
const result = Memory.Update(
|
|
5
|
+
const result = Memory.Update(type, { '~readonly': true }, options);
|
|
9
6
|
return result;
|
|
10
7
|
}
|
|
11
8
|
export function AddReadonlyInstantiate(context, state, type, options) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './expand_this.mjs';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './expand_this.mjs';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Returns a Clone of the given value. This function is similar to structuredClone()
|
|
3
|
-
* but also supports deep cloning
|
|
2
|
+
* Returns a deep Clone of the given value. This function is similar to `structuredClone()`,
|
|
3
|
+
* but also supports deep cloning `Map`, `Set`, and `TypeArray` instances. This function can also be used
|
|
4
|
+
* to clone TypeBox types while retaining their enumerable and non-enumerable properties.
|
|
4
5
|
*/
|
|
5
|
-
export declare function Clone<Value extends unknown>(value: Value): Value;
|
|
6
|
+
export declare function Clone<Value extends unknown = unknown>(value: Value): Value;
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
// deno-fmt-ignore-file
|
|
2
|
-
import {
|
|
3
|
-
// ------------------------------------------------------------------
|
|
4
|
-
// Clone
|
|
5
|
-
// ------------------------------------------------------------------
|
|
2
|
+
import { Deep } from '../../system/memory/deep.mjs';
|
|
6
3
|
/**
|
|
7
|
-
* Returns a Clone of the given value. This function is similar to structuredClone()
|
|
8
|
-
* but also supports deep cloning
|
|
4
|
+
* Returns a deep Clone of the given value. This function is similar to `structuredClone()`,
|
|
5
|
+
* but also supports deep cloning `Map`, `Set`, and `TypeArray` instances. This function can also be used
|
|
6
|
+
* to clone TypeBox types while retaining their enumerable and non-enumerable properties.
|
|
9
7
|
*/
|
|
10
8
|
export function Clone(value) {
|
|
11
|
-
return
|
|
9
|
+
return Deep(value);
|
|
12
10
|
}
|
|
@@ -1,28 +1,27 @@
|
|
|
1
1
|
// deno-fmt-ignore-file
|
|
2
2
|
import Guard from '../../guard/index.mjs';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { Memory } from '../../system/memory/index.mjs';
|
|
4
|
+
import { Array as _Array_, ArrayOptions, IsArray } from '../../type/index.mjs';
|
|
5
|
+
import { Intersect, IsIntersect } from '../../type/index.mjs';
|
|
5
6
|
import { IsObject, Object as _Object_ } from '../../type/index.mjs';
|
|
6
|
-
import { IsRecord, Record,
|
|
7
|
+
import { IsRecord, Record, RecordPattern, RecordValue } from '../../type/index.mjs';
|
|
8
|
+
import { String } from '../../type/index.mjs';
|
|
7
9
|
import { IsTuple, Tuple } from '../../type/index.mjs';
|
|
8
|
-
import {
|
|
10
|
+
import { IsUnion, Union } from '../../type/index.mjs';
|
|
9
11
|
import { Priority } from '../../type/index.mjs';
|
|
10
12
|
// ------------------------------------------------------------------
|
|
11
13
|
// Modifiers (Mutable)
|
|
12
14
|
//
|
|
13
15
|
// Prioritized types lose `~modifier` properties and additional constraints
|
|
14
16
|
// (e.g. additionalProperties) during the mapping phase and need to be
|
|
15
|
-
// reassigned afterward.
|
|
16
|
-
//
|
|
17
|
+
// reassigned afterward. We previously used a mutable assignment on this
|
|
18
|
+
// function, however `immutableTypes: true` caused errors. We use the
|
|
19
|
+
// Memory.Assign to ensure modifiers are retained and we preserve type
|
|
20
|
+
// configurations (review)
|
|
17
21
|
//
|
|
18
22
|
// ------------------------------------------------------------------
|
|
19
23
|
function Modifiers(type, next) {
|
|
20
|
-
|
|
21
|
-
if (Guard.HasPropertyKey(next, key))
|
|
22
|
-
continue;
|
|
23
|
-
next[key] = type[key];
|
|
24
|
-
}
|
|
25
|
-
return next;
|
|
24
|
+
return Memory.Assign(type, next);
|
|
26
25
|
}
|
|
27
26
|
// ------------------------------------------------------------------
|
|
28
27
|
// Properties
|
|
@@ -34,6 +33,18 @@ function FromProperties(properties) {
|
|
|
34
33
|
return result;
|
|
35
34
|
}
|
|
36
35
|
// ------------------------------------------------------------------
|
|
36
|
+
// FromRecordKey
|
|
37
|
+
//
|
|
38
|
+
// This is required because RecordKey(...) returns a canonical
|
|
39
|
+
// decoded type derived from the pattern. When the pattern is an
|
|
40
|
+
// unrecognized user-defined one, the result falls through to
|
|
41
|
+
// TString (^.*$) and the user-defined pattern is lost. This
|
|
42
|
+
// function ensures the exact pattern is retained.
|
|
43
|
+
// ------------------------------------------------------------------
|
|
44
|
+
function FromRecordKey(type) {
|
|
45
|
+
return String({ pattern: RecordPattern(type) });
|
|
46
|
+
}
|
|
47
|
+
// ------------------------------------------------------------------
|
|
37
48
|
// PriorityTypes
|
|
38
49
|
// ------------------------------------------------------------------
|
|
39
50
|
function FromPriorityTypes(types) {
|
|
@@ -43,7 +54,7 @@ function FromPriorityTypes(types) {
|
|
|
43
54
|
// Types
|
|
44
55
|
// ------------------------------------------------------------------
|
|
45
56
|
function FromTypes(types) {
|
|
46
|
-
return types.map(type => FromType(type));
|
|
57
|
+
return types.map((type) => FromType(type));
|
|
47
58
|
}
|
|
48
59
|
// ------------------------------------------------------------------
|
|
49
60
|
// Type
|
|
@@ -53,7 +64,7 @@ function FromType(type) {
|
|
|
53
64
|
IsIntersect(type) ? Intersect(FromTypes(type.allOf)) :
|
|
54
65
|
IsUnion(type) ? Union(FromPriorityTypes(type.anyOf)) :
|
|
55
66
|
IsObject(type) ? _Object_(FromProperties(type.properties)) :
|
|
56
|
-
IsRecord(type) ? Record(
|
|
67
|
+
IsRecord(type) ? Record(FromRecordKey(type), FromType(RecordValue(type))) :
|
|
57
68
|
IsTuple(type) ? Tuple(FromTypes(type.items)) :
|
|
58
69
|
type);
|
|
59
70
|
return Modifiers(type, next);
|
|
@@ -196,7 +196,7 @@ const result = Vector.Parse({ x: 1, y: 0, z: 0 }) // const result: {
|
|
|
196
196
|
|
|
197
197
|
[JSON Schema Test Suite](https://github.com/json-schema-org/JSON-Schema-Test-Suite) | [JSON Schema Compliance Suite](https://github.com/sinclairzx81/json-schema-compliance-suite)
|
|
198
198
|
|
|
199
|
-
TypeBox supports all versions of JSON Schema and is heavily tested against the official JSON Schema Test Suite. It
|
|
199
|
+
TypeBox supports all versions of JSON Schema and is heavily tested against the official JSON Schema Test Suite. It has high compatibility with modern specifications while also offering broad support for legacy versions if their semantics are not in conflict with modern specifications.
|
|
200
200
|
|
|
201
201
|
| Spec | 3 | 4 | 6 | 7 | 2019-09 | 2020-12 | v1 |
|
|
202
202
|
|:-----|:--|:--|:--|:--|:--|:--|:--|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/google-meet",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.11.5-beta.1",
|
|
4
4
|
"description": "OpenClaw Google Meet participant plugin for joining calls through Chrome or Twilio transports.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
"type": "module",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"jszip": "3.10.2",
|
|
12
|
-
"typebox": "1.
|
|
12
|
+
"typebox": "1.4.2"
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
|
-
"openclaw": ">=2026.
|
|
15
|
+
"openclaw": ">=2026.11.5-beta.1"
|
|
16
16
|
},
|
|
17
17
|
"peerDependenciesMeta": {
|
|
18
18
|
"openclaw": {
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
"minHostVersion": ">=2026.4.20"
|
|
31
31
|
},
|
|
32
32
|
"compat": {
|
|
33
|
-
"pluginApi": ">=2026.
|
|
33
|
+
"pluginApi": ">=2026.11.5-beta.1"
|
|
34
34
|
},
|
|
35
35
|
"build": {
|
|
36
|
-
"openclawVersion": "2026.
|
|
36
|
+
"openclawVersion": "2026.11.5-beta.1"
|
|
37
37
|
},
|
|
38
38
|
"release": {
|
|
39
39
|
"publishToClawHub": true,
|
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
import { asBoolean, asRecord, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeOptionalTrimmedStringList, parseBooleanValue, readStringValue } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
2
|
-
import { addTimerTimeoutGraceMs, asPositiveFiniteNumber, resolvePositiveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
3
|
-
import { REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME, resolveRealtimeVoiceAgentConsultToolPolicy } from "openclaw/plugin-sdk/realtime-voice";
|
|
4
|
-
// extensions/google-meet/src/config.ts
|
|
5
|
-
function resolveGoogleMeetGatewayOperationTimeoutMs(config) {
|
|
6
|
-
return Math.max(6e4, addTimerTimeoutGraceMs(config.chrome.joinTimeoutMs, 3e4) ?? 1, addTimerTimeoutGraceMs(config.voiceCall.requestTimeoutMs, 1e4) ?? 1);
|
|
7
|
-
}
|
|
8
|
-
const SOX_DEFAULT_BUFFER_BYTES = 8192;
|
|
9
|
-
const SOX_MIN_BUFFER_BYTES = 17;
|
|
10
|
-
const DEFAULT_GOOGLE_MEET_AUDIO_BUFFER_BYTES = SOX_DEFAULT_BUFFER_BYTES / 2;
|
|
11
|
-
const PLAIN_DECIMAL_NUMBER_RE = /^\d+(?:\.\d+)?$/;
|
|
12
|
-
function buildGoogleMeetAudioCommands(backend, format, bufferBytes) {
|
|
13
|
-
const pipeWire = backend === "pipewire-pulse" || backend === "auto" && process.platform === "linux";
|
|
14
|
-
const sampleRate = format === "g711-ulaw-8khz" ? 8e3 : 24e3;
|
|
15
|
-
const bits = format === "g711-ulaw-8khz" ? 8 : 16;
|
|
16
|
-
if (pipeWire) {
|
|
17
|
-
const pulseFormat = format === "g711-ulaw-8khz" ? "ulaw" : "s16le";
|
|
18
|
-
const latencyMs = Math.max(1, Math.ceil(bufferBytes / (sampleRate * Math.ceil(bits / 8)) * 1e3));
|
|
19
|
-
const common = [
|
|
20
|
-
"--device=openclaw_meeting_audio",
|
|
21
|
-
`--format=${pulseFormat}`,
|
|
22
|
-
`--rate=${sampleRate}`,
|
|
23
|
-
"--channels=1",
|
|
24
|
-
`--latency-msec=${latencyMs}`
|
|
25
|
-
];
|
|
26
|
-
return {
|
|
27
|
-
inputCommand: [
|
|
28
|
-
"parec",
|
|
29
|
-
"--raw",
|
|
30
|
-
...common
|
|
31
|
-
],
|
|
32
|
-
outputCommand: [
|
|
33
|
-
"pacat",
|
|
34
|
-
"--raw",
|
|
35
|
-
"--playback",
|
|
36
|
-
...common
|
|
37
|
-
]
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
const wire = format === "g711-ulaw-8khz" ? [
|
|
41
|
-
"-t",
|
|
42
|
-
"raw",
|
|
43
|
-
"-r",
|
|
44
|
-
"8000",
|
|
45
|
-
"-c",
|
|
46
|
-
"1",
|
|
47
|
-
"-e",
|
|
48
|
-
"mu-law",
|
|
49
|
-
"-b",
|
|
50
|
-
"8",
|
|
51
|
-
"-"
|
|
52
|
-
] : [
|
|
53
|
-
"-t",
|
|
54
|
-
"raw",
|
|
55
|
-
"-r",
|
|
56
|
-
"24000",
|
|
57
|
-
"-c",
|
|
58
|
-
"1",
|
|
59
|
-
"-e",
|
|
60
|
-
"signed-integer",
|
|
61
|
-
"-b",
|
|
62
|
-
"16",
|
|
63
|
-
"-L",
|
|
64
|
-
"-"
|
|
65
|
-
];
|
|
66
|
-
const withBuffer = (executable, args) => [
|
|
67
|
-
executable,
|
|
68
|
-
"-q",
|
|
69
|
-
"--buffer",
|
|
70
|
-
String(bufferBytes),
|
|
71
|
-
...args
|
|
72
|
-
];
|
|
73
|
-
return {
|
|
74
|
-
inputCommand: withBuffer("sox", [
|
|
75
|
-
"-t",
|
|
76
|
-
"coreaudio",
|
|
77
|
-
"BlackHole 2ch",
|
|
78
|
-
...wire
|
|
79
|
-
]),
|
|
80
|
-
outputCommand: withBuffer("sox", [
|
|
81
|
-
...wire,
|
|
82
|
-
"-t",
|
|
83
|
-
"coreaudio",
|
|
84
|
-
"BlackHole 2ch"
|
|
85
|
-
])
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
const DEFAULT_GOOGLE_MEET_AUDIO_COMMANDS = buildGoogleMeetAudioCommands("blackhole-2ch", "pcm16-24khz", DEFAULT_GOOGLE_MEET_AUDIO_BUFFER_BYTES);
|
|
89
|
-
const DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND = DEFAULT_GOOGLE_MEET_AUDIO_COMMANDS.inputCommand;
|
|
90
|
-
const DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND = DEFAULT_GOOGLE_MEET_AUDIO_COMMANDS.outputCommand;
|
|
91
|
-
const DEFAULT_GOOGLE_MEET_REALTIME_INSTRUCTIONS = `You are joining a private Google Meet as an OpenClaw voice transport. Keep spoken replies brief and natural. In agent mode, wait for OpenClaw consult results and speak them exactly. In bidi mode, answer directly and call ${REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME} for deeper reasoning, current information, or tools.`;
|
|
92
|
-
const DEFAULT_GOOGLE_MEET_REALTIME_INTRO_MESSAGE = "Say exactly: I'm here and listening.";
|
|
93
|
-
function resolveOptionalNumber(value) {
|
|
94
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
95
|
-
if (typeof value === "string" && value.trim()) {
|
|
96
|
-
const trimmed = value.trim();
|
|
97
|
-
const parsed = PLAIN_DECIMAL_NUMBER_RE.test(trimmed) ? Number(trimmed) : NaN;
|
|
98
|
-
return Number.isFinite(parsed) ? parsed : void 0;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
function readGoogleMeetEnv(env, name) {
|
|
102
|
-
return normalizeOptionalString(env[name]) ?? normalizeOptionalString(env[name.slice(9)]);
|
|
103
|
-
}
|
|
104
|
-
function resolveProvidersConfig(value) {
|
|
105
|
-
const raw = asRecord(value);
|
|
106
|
-
const providers = {};
|
|
107
|
-
for (const [key, entry] of Object.entries(raw)) {
|
|
108
|
-
const providerId = normalizeOptionalLowercaseString(key);
|
|
109
|
-
if (!providerId) continue;
|
|
110
|
-
providers[providerId] = asRecord(entry);
|
|
111
|
-
}
|
|
112
|
-
return providers;
|
|
113
|
-
}
|
|
114
|
-
function resolveTransport(value, fallback) {
|
|
115
|
-
const normalized = normalizeOptionalLowercaseString(value);
|
|
116
|
-
return normalized === "chrome" || normalized === "chrome-node" || normalized === "twilio" ? normalized : fallback;
|
|
117
|
-
}
|
|
118
|
-
function resolveMode(value, fallback) {
|
|
119
|
-
const normalized = normalizeOptionalLowercaseString(value);
|
|
120
|
-
if (normalized === "realtime") return "agent";
|
|
121
|
-
return normalized === "agent" || normalized === "bidi" || normalized === "transcribe" ? normalized : fallback;
|
|
122
|
-
}
|
|
123
|
-
function resolveRealtimeStrategy(value, fallback) {
|
|
124
|
-
const normalized = normalizeOptionalLowercaseString(value);
|
|
125
|
-
return normalized === "agent" || normalized === "bidi" ? normalized : fallback;
|
|
126
|
-
}
|
|
127
|
-
function resolveChromeAudioFormat(value) {
|
|
128
|
-
switch (normalizeOptionalString(value)?.toLowerCase().replaceAll("_", "-")) {
|
|
129
|
-
case "pcm16-24khz":
|
|
130
|
-
case "pcm16-24k":
|
|
131
|
-
case "pcm24":
|
|
132
|
-
case "pcm": return "pcm16-24khz";
|
|
133
|
-
case "g711-ulaw-8khz":
|
|
134
|
-
case "g711-ulaw-8k":
|
|
135
|
-
case "g711-ulaw":
|
|
136
|
-
case "mulaw":
|
|
137
|
-
case "mu-law": return "g711-ulaw-8khz";
|
|
138
|
-
default: return;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
function resolveAudioBufferBytes(value, fallback) {
|
|
142
|
-
return Math.max(SOX_MIN_BUFFER_BYTES, Math.trunc(asPositiveFiniteNumber(value) ?? fallback));
|
|
143
|
-
}
|
|
144
|
-
function resolveAudioBackend(value) {
|
|
145
|
-
const normalized = normalizeOptionalLowercaseString(value)?.replaceAll("_", "-");
|
|
146
|
-
return normalized === "blackhole-2ch" || normalized === "pipewire-pulse" ? normalized : "auto";
|
|
147
|
-
}
|
|
148
|
-
function resolveGoogleMeetConfig(input) {
|
|
149
|
-
const env = process.env;
|
|
150
|
-
const raw = asRecord(input);
|
|
151
|
-
const defaults = asRecord(raw.defaults);
|
|
152
|
-
const preview = asRecord(raw.preview);
|
|
153
|
-
const chrome = asRecord(raw.chrome);
|
|
154
|
-
const configuredAudioInputCommand = normalizeOptionalTrimmedStringList(chrome.audioInputCommand);
|
|
155
|
-
const configuredAudioOutputCommand = normalizeOptionalTrimmedStringList(chrome.audioOutputCommand);
|
|
156
|
-
const hasCustomAudioCommand = configuredAudioInputCommand !== void 0 || configuredAudioOutputCommand !== void 0;
|
|
157
|
-
const audioFormat = resolveChromeAudioFormat(chrome.audioFormat) ?? (hasCustomAudioCommand ? "g711-ulaw-8khz" : "pcm16-24khz");
|
|
158
|
-
const audioBufferBytes = resolveAudioBufferBytes(chrome.audioBufferBytes, DEFAULT_GOOGLE_MEET_AUDIO_BUFFER_BYTES);
|
|
159
|
-
const audioBackend = resolveAudioBackend(chrome.audioBackend);
|
|
160
|
-
const audioCommands = buildGoogleMeetAudioCommands(audioBackend, audioFormat, audioBufferBytes);
|
|
161
|
-
const chromeNode = asRecord(raw.chromeNode);
|
|
162
|
-
const twilio = asRecord(raw.twilio);
|
|
163
|
-
const voiceCall = asRecord(raw.voiceCall);
|
|
164
|
-
const realtime = asRecord(raw.realtime);
|
|
165
|
-
const realtimeProvider = normalizeOptionalString(realtime.provider);
|
|
166
|
-
const resolvedRealtimeProvider = realtimeProvider ?? "openai";
|
|
167
|
-
const oauth = asRecord(raw.oauth);
|
|
168
|
-
const auth = asRecord(raw.auth);
|
|
169
|
-
return {
|
|
170
|
-
enabled: asBoolean(raw.enabled) ?? true,
|
|
171
|
-
defaults: { meeting: normalizeOptionalString(defaults.meeting) ?? readGoogleMeetEnv(env, "OPENCLAW_GOOGLE_MEET_DEFAULT_MEETING") },
|
|
172
|
-
preview: { enrollmentAcknowledged: asBoolean(preview.enrollmentAcknowledged) ?? parseBooleanValue(readGoogleMeetEnv(env, "OPENCLAW_GOOGLE_MEET_PREVIEW_ACK")) ?? false },
|
|
173
|
-
defaultTransport: resolveTransport(raw.defaultTransport, "chrome"),
|
|
174
|
-
defaultMode: resolveMode(raw.defaultMode, "agent"),
|
|
175
|
-
chrome: {
|
|
176
|
-
audioBackend,
|
|
177
|
-
audioFormat,
|
|
178
|
-
audioBufferBytes,
|
|
179
|
-
launch: asBoolean(chrome.launch) ?? true,
|
|
180
|
-
browserProfile: normalizeOptionalString(chrome.browserProfile),
|
|
181
|
-
guestName: normalizeOptionalString(chrome.guestName) ?? "OpenClaw Agent",
|
|
182
|
-
reuseExistingTab: asBoolean(chrome.reuseExistingTab) ?? true,
|
|
183
|
-
autoJoin: asBoolean(chrome.autoJoin) ?? true,
|
|
184
|
-
joinTimeoutMs: resolvePositiveTimerTimeoutMs(chrome.joinTimeoutMs, 3e4),
|
|
185
|
-
waitForInCallMs: resolvePositiveTimerTimeoutMs(chrome.waitForInCallMs, 2e4),
|
|
186
|
-
audioInputCommand: configuredAudioInputCommand ?? audioCommands.inputCommand,
|
|
187
|
-
audioOutputCommand: configuredAudioOutputCommand ?? audioCommands.outputCommand,
|
|
188
|
-
audioInputCommandOverride: configuredAudioInputCommand,
|
|
189
|
-
audioOutputCommandOverride: configuredAudioOutputCommand,
|
|
190
|
-
bargeInInputCommand: normalizeOptionalTrimmedStringList(chrome.bargeInInputCommand),
|
|
191
|
-
bargeInRmsThreshold: asPositiveFiniteNumber(chrome.bargeInRmsThreshold) ?? 650,
|
|
192
|
-
bargeInPeakThreshold: asPositiveFiniteNumber(chrome.bargeInPeakThreshold) ?? 2500,
|
|
193
|
-
bargeInCooldownMs: resolvePositiveTimerTimeoutMs(chrome.bargeInCooldownMs, 900),
|
|
194
|
-
audioBridgeCommand: normalizeOptionalTrimmedStringList(chrome.audioBridgeCommand),
|
|
195
|
-
audioBridgeHealthCommand: normalizeOptionalTrimmedStringList(chrome.audioBridgeHealthCommand)
|
|
196
|
-
},
|
|
197
|
-
chromeNode: { node: normalizeOptionalString(chromeNode.node) },
|
|
198
|
-
twilio: {
|
|
199
|
-
defaultDialInNumber: normalizeOptionalString(twilio.defaultDialInNumber),
|
|
200
|
-
defaultPin: normalizeOptionalString(twilio.defaultPin),
|
|
201
|
-
defaultDtmfSequence: normalizeOptionalString(twilio.defaultDtmfSequence)
|
|
202
|
-
},
|
|
203
|
-
voiceCall: {
|
|
204
|
-
enabled: asBoolean(voiceCall.enabled) ?? true,
|
|
205
|
-
gatewayUrl: normalizeOptionalString(voiceCall.gatewayUrl),
|
|
206
|
-
token: normalizeOptionalString(voiceCall.token),
|
|
207
|
-
requestTimeoutMs: resolvePositiveTimerTimeoutMs(voiceCall.requestTimeoutMs, 3e4),
|
|
208
|
-
dtmfDelayMs: resolvePositiveTimerTimeoutMs(voiceCall.dtmfDelayMs, 12e3),
|
|
209
|
-
postDtmfSpeechDelayMs: resolvePositiveTimerTimeoutMs(voiceCall.postDtmfSpeechDelayMs, 5e3),
|
|
210
|
-
introMessage: normalizeOptionalString(voiceCall.introMessage)
|
|
211
|
-
},
|
|
212
|
-
realtime: {
|
|
213
|
-
strategy: resolveRealtimeStrategy(realtime.strategy, "agent"),
|
|
214
|
-
provider: resolvedRealtimeProvider,
|
|
215
|
-
transcriptionProvider: normalizeOptionalString(realtime.transcriptionProvider) ?? (realtimeProvider && realtimeProvider !== "google" ? resolvedRealtimeProvider : "openai"),
|
|
216
|
-
voiceProvider: normalizeOptionalString(realtime.voiceProvider),
|
|
217
|
-
model: normalizeOptionalString(realtime.model),
|
|
218
|
-
instructions: normalizeOptionalString(realtime.instructions) ?? DEFAULT_GOOGLE_MEET_REALTIME_INSTRUCTIONS,
|
|
219
|
-
introMessage: readStringValue(realtime.introMessage)?.trim() ?? DEFAULT_GOOGLE_MEET_REALTIME_INTRO_MESSAGE,
|
|
220
|
-
agentId: normalizeOptionalString(realtime.agentId),
|
|
221
|
-
toolPolicy: resolveRealtimeVoiceAgentConsultToolPolicy(realtime.toolPolicy, "safe-read-only"),
|
|
222
|
-
providers: resolveProvidersConfig(realtime.providers)
|
|
223
|
-
},
|
|
224
|
-
oauth: {
|
|
225
|
-
clientId: normalizeOptionalString(oauth.clientId) ?? normalizeOptionalString(auth.clientId) ?? readGoogleMeetEnv(env, "OPENCLAW_GOOGLE_MEET_CLIENT_ID"),
|
|
226
|
-
clientSecret: normalizeOptionalString(oauth.clientSecret) ?? normalizeOptionalString(auth.clientSecret) ?? readGoogleMeetEnv(env, "OPENCLAW_GOOGLE_MEET_CLIENT_SECRET"),
|
|
227
|
-
refreshToken: normalizeOptionalString(oauth.refreshToken) ?? readGoogleMeetEnv(env, "OPENCLAW_GOOGLE_MEET_REFRESH_TOKEN"),
|
|
228
|
-
accessToken: normalizeOptionalString(oauth.accessToken) ?? readGoogleMeetEnv(env, "OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN"),
|
|
229
|
-
expiresAt: resolveOptionalNumber(oauth.expiresAt) ?? resolveOptionalNumber(readGoogleMeetEnv(env, "OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT"))
|
|
230
|
-
},
|
|
231
|
-
auth: {
|
|
232
|
-
provider: "google-oauth",
|
|
233
|
-
clientId: normalizeOptionalString(auth.clientId),
|
|
234
|
-
clientSecret: normalizeOptionalString(auth.clientSecret),
|
|
235
|
-
tokenPath: normalizeOptionalString(auth.tokenPath)
|
|
236
|
-
}
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
export { resolveGoogleMeetGatewayOperationTimeoutMs as i, DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND as n, resolveGoogleMeetConfig as r, DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND as t };
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import { t as readGoogleApiErrorDetail } from "./google-api-B5FR9zy2.mjs";
|
|
2
|
-
import { MAX_DATE_TIMESTAMP_MS, resolveDateTimestampMs, resolveExpiresAtMsFromDurationSeconds } from "openclaw/plugin-sdk/number-runtime";
|
|
3
|
-
import { readProviderJsonResponse } from "openclaw/plugin-sdk/provider-http";
|
|
4
|
-
import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
5
|
-
import { parseOAuthCallbackInput, waitForLocalOAuthCallback } from "openclaw/plugin-sdk/provider-auth-runtime";
|
|
6
|
-
// extensions/google-meet/src/oauth.ts
|
|
7
|
-
const GOOGLE_MEET_REDIRECT_URI = "http://localhost:8085/oauth2callback";
|
|
8
|
-
const GOOGLE_MEET_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
9
|
-
const GOOGLE_MEET_TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
10
|
-
const GOOGLE_MEET_TOKEN_HOST = "oauth2.googleapis.com";
|
|
11
|
-
const GOOGLE_MEET_DEFAULT_TOKEN_LIFETIME_SECONDS = 3600;
|
|
12
|
-
const GOOGLE_OAUTH_TOKEN_JSON_MAX_BYTES = 262144;
|
|
13
|
-
const GOOGLE_OAUTH_REQUEST_TIMEOUT_MS = 3e4;
|
|
14
|
-
const GOOGLE_MEET_SCOPES = [
|
|
15
|
-
"https://www.googleapis.com/auth/meetings.space.created",
|
|
16
|
-
"https://www.googleapis.com/auth/meetings.space.readonly",
|
|
17
|
-
"https://www.googleapis.com/auth/meetings.space.settings",
|
|
18
|
-
"https://www.googleapis.com/auth/meetings.conference.media.readonly",
|
|
19
|
-
"https://www.googleapis.com/auth/calendar.events.readonly",
|
|
20
|
-
"https://www.googleapis.com/auth/drive.meet.readonly"
|
|
21
|
-
];
|
|
22
|
-
function resolveGoogleMeetTokenExpiresAt(value) {
|
|
23
|
-
const now = resolveDateTimestampMs(Date.now());
|
|
24
|
-
if (typeof value === "number" && Number.isFinite(value) && value <= 0) return now;
|
|
25
|
-
return resolveExpiresAtMsFromDurationSeconds(value, { nowMs: now }) ?? resolveExpiresAtMsFromDurationSeconds(GOOGLE_MEET_DEFAULT_TOKEN_LIFETIME_SECONDS, { nowMs: now }) ?? now;
|
|
26
|
-
}
|
|
27
|
-
function buildGoogleMeetAuthUrl(params) {
|
|
28
|
-
const search = new URLSearchParams({
|
|
29
|
-
client_id: params.clientId,
|
|
30
|
-
response_type: "code",
|
|
31
|
-
redirect_uri: params.redirectUri ?? GOOGLE_MEET_REDIRECT_URI,
|
|
32
|
-
scope: (params.scopes ?? GOOGLE_MEET_SCOPES).join(" "),
|
|
33
|
-
code_challenge: params.challenge,
|
|
34
|
-
code_challenge_method: "S256",
|
|
35
|
-
access_type: "offline",
|
|
36
|
-
prompt: "consent",
|
|
37
|
-
state: params.state
|
|
38
|
-
});
|
|
39
|
-
return `${GOOGLE_MEET_AUTH_URL}?${search.toString()}`;
|
|
40
|
-
}
|
|
41
|
-
async function executeGoogleTokenRequest(body) {
|
|
42
|
-
const { response, release } = await fetchWithSsrFGuard({
|
|
43
|
-
url: GOOGLE_MEET_TOKEN_URL,
|
|
44
|
-
init: {
|
|
45
|
-
method: "POST",
|
|
46
|
-
headers: {
|
|
47
|
-
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
|
|
48
|
-
Accept: "application/json"
|
|
49
|
-
},
|
|
50
|
-
body
|
|
51
|
-
},
|
|
52
|
-
policy: { allowedHostnames: [GOOGLE_MEET_TOKEN_HOST] },
|
|
53
|
-
auditContext: "google-meet.oauth.token",
|
|
54
|
-
timeoutMs: GOOGLE_OAUTH_REQUEST_TIMEOUT_MS
|
|
55
|
-
});
|
|
56
|
-
try {
|
|
57
|
-
if (!response.ok) {
|
|
58
|
-
const detail = await readGoogleApiErrorDetail(response);
|
|
59
|
-
throw new Error(`Google OAuth token request failed (${response.status}): ${detail}`);
|
|
60
|
-
}
|
|
61
|
-
const payload = await readProviderJsonResponse(response, "Google OAuth token", { maxBytes: GOOGLE_OAUTH_TOKEN_JSON_MAX_BYTES });
|
|
62
|
-
const accessToken = payload.access_token?.trim();
|
|
63
|
-
if (!accessToken) throw new Error("Google OAuth token response was missing access_token");
|
|
64
|
-
return {
|
|
65
|
-
accessToken,
|
|
66
|
-
expiresAt: resolveGoogleMeetTokenExpiresAt(payload.expires_in),
|
|
67
|
-
refreshToken: payload.refresh_token?.trim() || void 0,
|
|
68
|
-
scope: payload.scope?.trim() || void 0,
|
|
69
|
-
tokenType: payload.token_type?.trim() || void 0
|
|
70
|
-
};
|
|
71
|
-
} finally {
|
|
72
|
-
await release();
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
function tokenRequestBody(values) {
|
|
76
|
-
const body = new URLSearchParams();
|
|
77
|
-
for (const [key, value] of Object.entries(values)) if (value?.trim()) body.set(key, value);
|
|
78
|
-
return body;
|
|
79
|
-
}
|
|
80
|
-
async function exchangeGoogleMeetAuthCode(params) {
|
|
81
|
-
return await executeGoogleTokenRequest(tokenRequestBody({
|
|
82
|
-
client_id: params.clientId,
|
|
83
|
-
client_secret: params.clientSecret,
|
|
84
|
-
code: params.code,
|
|
85
|
-
grant_type: "authorization_code",
|
|
86
|
-
redirect_uri: params.redirectUri ?? GOOGLE_MEET_REDIRECT_URI,
|
|
87
|
-
code_verifier: params.verifier
|
|
88
|
-
}));
|
|
89
|
-
}
|
|
90
|
-
async function refreshGoogleMeetAccessToken(params) {
|
|
91
|
-
return await executeGoogleTokenRequest(tokenRequestBody({
|
|
92
|
-
client_id: params.clientId,
|
|
93
|
-
client_secret: params.clientSecret,
|
|
94
|
-
grant_type: "refresh_token",
|
|
95
|
-
refresh_token: params.refreshToken
|
|
96
|
-
}));
|
|
97
|
-
}
|
|
98
|
-
function shouldUseCachedGoogleMeetAccessToken(params) {
|
|
99
|
-
const now = Date.now();
|
|
100
|
-
return Boolean(params.accessToken?.trim() && typeof params.expiresAt === "number" && Number.isFinite(params.expiresAt) && params.expiresAt <= MAX_DATE_TIMESTAMP_MS && params.expiresAt > now + 6e4);
|
|
101
|
-
}
|
|
102
|
-
async function resolveGoogleMeetAccessToken(params) {
|
|
103
|
-
if (shouldUseCachedGoogleMeetAccessToken(params)) return {
|
|
104
|
-
accessToken: params.accessToken.trim(),
|
|
105
|
-
expiresAt: params.expiresAt,
|
|
106
|
-
refreshed: false
|
|
107
|
-
};
|
|
108
|
-
if (!params.clientId?.trim() || !params.refreshToken?.trim()) throw new Error("Missing Google Meet OAuth credentials. Configure oauth.clientId and oauth.refreshToken, or pass --client-id and --refresh-token.");
|
|
109
|
-
const refreshed = await refreshGoogleMeetAccessToken({
|
|
110
|
-
clientId: params.clientId,
|
|
111
|
-
clientSecret: params.clientSecret,
|
|
112
|
-
refreshToken: params.refreshToken
|
|
113
|
-
});
|
|
114
|
-
return {
|
|
115
|
-
accessToken: refreshed.accessToken,
|
|
116
|
-
expiresAt: refreshed.expiresAt,
|
|
117
|
-
refreshed: true
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
function isLocalCallbackListenerError(error) {
|
|
121
|
-
if (!(error instanceof Error)) return false;
|
|
122
|
-
return error.message.includes("EADDRINUSE") || error.message.includes("port") || error.message.includes("listen");
|
|
123
|
-
}
|
|
124
|
-
async function readManualGoogleMeetAuthCode(params) {
|
|
125
|
-
const input = await params.promptInput("Paste the full redirect URL here: ");
|
|
126
|
-
const parsed = parseOAuthCallbackInput(input, {
|
|
127
|
-
missingState: "Missing 'state' parameter. Paste the full redirect URL.",
|
|
128
|
-
invalidInput: "Paste the full redirect URL, not just the code."
|
|
129
|
-
});
|
|
130
|
-
if ("error" in parsed) throw new Error(parsed.error);
|
|
131
|
-
if (parsed.state !== params.state) throw new Error("OAuth state mismatch - please try again");
|
|
132
|
-
return parsed.code;
|
|
133
|
-
}
|
|
134
|
-
async function waitForGoogleMeetAuthCode(params) {
|
|
135
|
-
params.writeLine(`Open this URL in your browser:\n\n${params.authUrl}\n`);
|
|
136
|
-
if (params.manual) return await readManualGoogleMeetAuthCode({
|
|
137
|
-
state: params.state,
|
|
138
|
-
promptInput: params.promptInput
|
|
139
|
-
});
|
|
140
|
-
try {
|
|
141
|
-
return (await waitForLocalOAuthCallback({
|
|
142
|
-
expectedState: params.state,
|
|
143
|
-
timeoutMs: params.timeoutMs,
|
|
144
|
-
port: 8085,
|
|
145
|
-
callbackPath: "/oauth2callback",
|
|
146
|
-
redirectUri: GOOGLE_MEET_REDIRECT_URI,
|
|
147
|
-
successTitle: "Google Meet OAuth complete"
|
|
148
|
-
})).code;
|
|
149
|
-
} catch (error) {
|
|
150
|
-
if (!isLocalCallbackListenerError(error)) throw error;
|
|
151
|
-
params.writeLine("Local callback server failed. Switching to manual mode...");
|
|
152
|
-
return await readManualGoogleMeetAuthCode({
|
|
153
|
-
state: params.state,
|
|
154
|
-
promptInput: params.promptInput
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
export { buildGoogleMeetAuthUrl, exchangeGoogleMeetAuthCode, resolveGoogleMeetAccessToken, waitForGoogleMeetAuthCode };
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
// deno-lint-ignore-file no-explicit-any
|
|
2
|
-
import { Settings } from '../settings/index.mjs';
|
|
3
|
-
/** Conditionally freezes the value if `immutableTypes` is true, otherwise no action. */
|
|
4
|
-
export function Freeze(value) {
|
|
5
|
-
return Settings.Get().immutableTypes ? Object.freeze(value) : value;
|
|
6
|
-
}
|