@openclaw/zoom-meetings 2026.9.6 → 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.
- package/assets/icon.png +0 -0
- package/dist/index.js +36 -76
- package/node_modules/typebox/build/compile/code.mjs +1 -2
- package/node_modules/typebox/build/compile/validator.mjs +5 -1
- package/node_modules/typebox/build/format/iri.mjs +16 -9
- package/node_modules/typebox/build/guard/emit.mjs +2 -2
- package/node_modules/typebox/build/guard/guard.d.mts +7 -5
- package/node_modules/typebox/build/guard/guard.mjs +14 -9
- package/node_modules/typebox/build/guard/index.mjs +6 -0
- package/node_modules/typebox/build/guard/unicode/unicode.d.mts +6 -0
- package/node_modules/typebox/build/guard/unicode/unicode.mjs +35 -0
- package/node_modules/typebox/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
- package/node_modules/typebox/build/schema/build.mjs +2 -3
- package/node_modules/typebox/build/schema/engine/_pathing.d.mts +1 -0
- package/node_modules/typebox/build/schema/engine/_pathing.mjs +11 -0
- package/node_modules/typebox/build/schema/engine/_refine.mjs +13 -5
- package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dependencies.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dependentSchemas.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/format.mjs +9 -2
- package/node_modules/typebox/build/schema/engine/patternProperties.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/properties.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/ref.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/ref.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/schema.mjs +24 -24
- package/node_modules/typebox/build/schema/parse.mjs +3 -0
- package/node_modules/typebox/build/schema/pointer/pointer.d.mts +1 -6
- package/node_modules/typebox/build/schema/pointer/pointer.mjs +47 -64
- package/node_modules/typebox/build/system/settings/internal.d.mts +2 -0
- package/node_modules/typebox/build/system/settings/internal.mjs +20 -0
- package/node_modules/typebox/build/system/settings/settings.d.mts +11 -0
- package/node_modules/typebox/build/system/settings/settings.mjs +14 -0
- package/node_modules/typebox/build/type/extends/inference.d.mts +1 -1
- package/node_modules/typebox/build/type/extends/inference.mjs +15 -2
- package/node_modules/typebox/build/type/extends/tuple.d.mts +2 -1
- package/node_modules/typebox/build/type/extends/tuple.mjs +21 -1
- package/node_modules/typebox/build/value/parse/parse.mjs +10 -4
- package/node_modules/typebox/package.json +1 -1
- package/node_modules/typebox/readme.md +3 -1
- package/package.json +5 -5
- /package/node_modules/typebox/build/guard/{string.d.mts → unicode/unicode_segment.d.mts} +0 -0
package/assets/icon.png
CHANGED
|
Binary file
|
package/dist/index.js
CHANGED
|
@@ -143,32 +143,6 @@ function zoomMeetingStatusCallSource() {
|
|
|
143
143
|
});
|
|
144
144
|
}
|
|
145
145
|
//#endregion
|
|
146
|
-
//#region extensions/zoom-meetings/src/transports/zoom-meetings-status-access-source.ts
|
|
147
|
-
function zoomMeetingStatusAccessSource() {
|
|
148
|
-
return ` const passcodeInput = firstRaw(selectors.passcode);
|
|
149
|
-
const passcodeRequired = Boolean(passcodeInput) &&
|
|
150
|
-
/meeting passcode|enter (?:the )?passcode|invalid passcode|incorrect passcode/i.test(
|
|
151
|
-
pageText + " " + label(passcodeInput)
|
|
152
|
-
);
|
|
153
|
-
const captchaRequired = Boolean(firstRaw(selectors.captcha)) ||
|
|
154
|
-
/complete (?:the )?captcha|security check|verify (?:that )?you(?:'re| are) (?:a )?human/i.test(pageTextLower);
|
|
155
|
-
if (identityVerified && !inCall && passcodeRequired) {
|
|
156
|
-
controlManualAction = manualActionFor("zoom-passcode-required", "Enter the Zoom meeting passcode in the OpenClaw browser profile, then retry joining.");
|
|
157
|
-
} else if (identityVerified && !inCall && captchaRequired) {
|
|
158
|
-
controlManualAction = manualActionFor("zoom-captcha-required", "Complete Zoom's security check in the OpenClaw browser profile, then retry joining.");
|
|
159
|
-
}
|
|
160
|
-
`;
|
|
161
|
-
}
|
|
162
|
-
//#endregion
|
|
163
|
-
//#region extensions/zoom-meetings/src/transports/zoom-meetings-status-page-source.ts
|
|
164
|
-
function zoomMeetingStatusPageSource() {
|
|
165
|
-
return ` const pageText = text(document.body);
|
|
166
|
-
const pageTextLower = pageText.toLowerCase();
|
|
167
|
-
const lobbyWaiting = Boolean(first(selectors.lobby)) ||
|
|
168
|
-
/host will let you in soon|waiting for the host to start|someone will let you in shortly|waiting for someone to let you in|when someone admits you|you.?re in the lobby|we.?ve let people in the meeting know you.?re waiting/i.test(pageTextLower);
|
|
169
|
-
`;
|
|
170
|
-
}
|
|
171
|
-
//#endregion
|
|
172
146
|
//#region extensions/zoom-meetings/src/transports/zoom-meetings-status-prejoin-source.ts
|
|
173
147
|
function zoomMeetingStatusPreludeSource(params) {
|
|
174
148
|
return MeetingPlatformAdapter.createStatusPreludeSource(params, {
|
|
@@ -231,7 +205,11 @@ function zoomMeetingStatusPreludeSource(params) {
|
|
|
231
205
|
await waitForUi();
|
|
232
206
|
}
|
|
233
207
|
}
|
|
234
|
-
|
|
208
|
+
const pageText = text(document.body);
|
|
209
|
+
const pageTextLower = pageText.toLowerCase();
|
|
210
|
+
const lobbyWaiting = Boolean(first(selectors.lobby)) ||
|
|
211
|
+
/host will let you in soon|waiting for the host to start|someone will let you in shortly|waiting for someone to let you in|when someone admits you|you.?re in the lobby|we.?ve let people in the meeting know you.?re waiting/i.test(pageTextLower);
|
|
212
|
+
|
|
235
213
|
const devicesDisabled = Boolean(!allowMicrophone && (dismissedDevicePrompt || (priorMeeting?.identity === expectedIdentity && (!sessionId || priorMeeting?.sessionId === sessionId) && priorMeeting?.devicesDisabled === true)));
|
|
236
214
|
// Zoom replaces the meeting URL after admission; retain only an adopted in-call control.
|
|
237
215
|
// Lobby ownership remains durable because host admission has no bounded wait.
|
|
@@ -319,10 +297,27 @@ function zoomMeetingStatusPreludeSource(params) {
|
|
|
319
297
|
}
|
|
320
298
|
const microphone = first(selectors.microphone) || findTextButton(/mute|unmute|microphone/i);
|
|
321
299
|
let microphoneState = identityVerified ? (toggleState(microphone, "microphone") || (devicesDisabled ? "off" : undefined)) : undefined;
|
|
300
|
+
const refreshMicrophoneState = async () => {
|
|
301
|
+
await waitForUi();
|
|
302
|
+
const currentMicrophone = first(selectors.microphone) || findTextButton(/mute|unmute|microphone/i);
|
|
303
|
+
microphoneState = toggleState(currentMicrophone, "microphone");
|
|
304
|
+
};
|
|
322
305
|
const camera = first(selectors.camera) || findTextButton(/camera|video/i);
|
|
323
306
|
let cameraState = identityVerified ? (toggleState(camera, "camera") || (devicesDisabled ? "off" : undefined)) : undefined;
|
|
324
307
|
let controlManualAction;
|
|
325
|
-
|
|
308
|
+
const passcodeInput = firstRaw(selectors.passcode);
|
|
309
|
+
const passcodeRequired = Boolean(passcodeInput) &&
|
|
310
|
+
/meeting passcode|enter (?:the )?passcode|invalid passcode|incorrect passcode/i.test(
|
|
311
|
+
pageText + " " + label(passcodeInput)
|
|
312
|
+
);
|
|
313
|
+
const captchaRequired = Boolean(firstRaw(selectors.captcha)) ||
|
|
314
|
+
/complete (?:the )?captcha|security check|verify (?:that )?you(?:'re| are) (?:a )?human/i.test(pageTextLower);
|
|
315
|
+
if (identityVerified && !inCall && passcodeRequired) {
|
|
316
|
+
controlManualAction = manualActionFor("zoom-passcode-required", "Enter the Zoom meeting passcode in the OpenClaw browser profile, then retry joining.");
|
|
317
|
+
} else if (identityVerified && !inCall && captchaRequired) {
|
|
318
|
+
controlManualAction = manualActionFor("zoom-captcha-required", "Complete Zoom's security check in the OpenClaw browser profile, then retry joining.");
|
|
319
|
+
}
|
|
320
|
+
|
|
326
321
|
if (
|
|
327
322
|
canMutateSession &&
|
|
328
323
|
identityVerified &&
|
|
@@ -416,25 +411,19 @@ function zoomMeetingStatusPreludeSource(params) {
|
|
|
416
411
|
if (!audioInputRouted) {
|
|
417
412
|
if (canMutateSession && microphoneState === "on") {
|
|
418
413
|
microphone.click();
|
|
419
|
-
await
|
|
420
|
-
const currentMicrophone = first(selectors.microphone) || findTextButton(/mute|unmute|microphone/i);
|
|
421
|
-
microphoneState = toggleState(currentMicrophone, "microphone");
|
|
414
|
+
await refreshMicrophoneState();
|
|
422
415
|
}
|
|
423
416
|
notes.push("The virtual audio input will be selected from Zoom's in-call audio controls.");
|
|
424
417
|
} else if (canMutateSession && microphoneState === "off") {
|
|
425
418
|
microphone.click();
|
|
426
|
-
await
|
|
427
|
-
const currentMicrophone = first(selectors.microphone) || findTextButton(/mute|unmute|microphone/i);
|
|
428
|
-
microphoneState = toggleState(currentMicrophone, "microphone");
|
|
419
|
+
await refreshMicrophoneState();
|
|
429
420
|
if (microphoneState === "on") {
|
|
430
421
|
notes.push("Unmuted the Zoom microphone after verifying the virtual audio input.");
|
|
431
422
|
}
|
|
432
423
|
}
|
|
433
424
|
} else if (canMutateSession && identityVerified && !allowMicrophone && microphoneState === "on") {
|
|
434
425
|
microphone.click();
|
|
435
|
-
await
|
|
436
|
-
const currentMicrophone = first(selectors.microphone) || findTextButton(/mute|unmute|microphone/i);
|
|
437
|
-
microphoneState = toggleState(currentMicrophone, "microphone");
|
|
426
|
+
await refreshMicrophoneState();
|
|
438
427
|
if (microphoneState === "off") {
|
|
439
428
|
notes.push("Muted the Zoom microphone for observe-only mode.");
|
|
440
429
|
}
|
|
@@ -442,21 +431,15 @@ function zoomMeetingStatusPreludeSource(params) {
|
|
|
442
431
|
if (identityVerified && inCall && allowMicrophone) {
|
|
443
432
|
if (!selectedMicrophoneLabel() && canMutateSession && microphoneState === "on") {
|
|
444
433
|
microphone?.click();
|
|
445
|
-
await
|
|
446
|
-
const currentMicrophone = first(selectors.microphone) || findTextButton(/mute|unmute|microphone/i);
|
|
447
|
-
microphoneState = toggleState(currentMicrophone, "microphone");
|
|
434
|
+
await refreshMicrophoneState();
|
|
448
435
|
}
|
|
449
436
|
audioInputRouted = await ensureVirtualAudioInput();
|
|
450
437
|
if (audioInputRouted && canMutateSession && microphoneState === "off") {
|
|
451
438
|
microphone?.click();
|
|
452
|
-
await
|
|
453
|
-
const currentMicrophone = first(selectors.microphone) || findTextButton(/mute|unmute|microphone/i);
|
|
454
|
-
microphoneState = toggleState(currentMicrophone, "microphone");
|
|
439
|
+
await refreshMicrophoneState();
|
|
455
440
|
} else if (!audioInputRouted && canMutateSession && microphoneState === "on") {
|
|
456
441
|
microphone?.click();
|
|
457
|
-
await
|
|
458
|
-
const currentMicrophone = first(selectors.microphone) || findTextButton(/mute|unmute|microphone/i);
|
|
459
|
-
microphoneState = toggleState(currentMicrophone, "microphone");
|
|
442
|
+
await refreshMicrophoneState();
|
|
460
443
|
if (microphoneState === "off") {
|
|
461
444
|
notes.push("Muted the Zoom microphone because the virtual audio input could not be reverified.");
|
|
462
445
|
}
|
|
@@ -728,14 +711,6 @@ function zoomMeetingLeaveScript(params) {
|
|
|
728
711
|
});
|
|
729
712
|
}
|
|
730
713
|
//#endregion
|
|
731
|
-
//#region extensions/zoom-meetings/src/transports/zoom-meetings-platform-constants.ts
|
|
732
|
-
const ZOOM_MEETINGS_NODE_COMMAND = "zoommeetings.chrome";
|
|
733
|
-
const ZOOM_MEETINGS_BROWSER_NODE_ADAPTER = {
|
|
734
|
-
displayName: "Zoom meetings",
|
|
735
|
-
nodeCommandName: ZOOM_MEETINGS_NODE_COMMAND,
|
|
736
|
-
nodeConfigPath: "plugins.entries.zoom-meetings.config.chromeNode.node"
|
|
737
|
-
};
|
|
738
|
-
//#endregion
|
|
739
714
|
//#region extensions/zoom-meetings/src/transports/zoom-meetings-platform-adapter.ts
|
|
740
715
|
function zoomMeetingOrigin(meetingUrl) {
|
|
741
716
|
return normalizeZoomMeetingUrlForReuse(meetingUrl) ? "https://app.zoom.us" : void 0;
|
|
@@ -776,7 +751,7 @@ const ZOOM_MEETINGS_PLATFORM_ADAPTER = MeetingPlatformAdapter.create({
|
|
|
776
751
|
idPrefix: "zoom_meeting",
|
|
777
752
|
participantIdentity: (transport) => transport === "chrome-node" ? "Zoom guest in Chrome on a paired node" : "Zoom guest in the OpenClaw Chrome profile"
|
|
778
753
|
},
|
|
779
|
-
nodeCommandName:
|
|
754
|
+
nodeCommandName: "zoommeetings.chrome",
|
|
780
755
|
nodeConfigPath: "plugins.entries.zoom-meetings.config.chromeNode.node",
|
|
781
756
|
urls: {
|
|
782
757
|
validateAndNormalize: normalizeZoomMeetingUrl,
|
|
@@ -856,33 +831,25 @@ function createZoomMeetingsNodeInvokePolicy(config) {
|
|
|
856
831
|
}
|
|
857
832
|
//#endregion
|
|
858
833
|
//#region extensions/zoom-meetings/src/runtime-probes.ts
|
|
859
|
-
const
|
|
834
|
+
const zoomMeetingsProbes = MeetingPlatformAdapter.createRuntimeProbes({
|
|
860
835
|
defaultSpeechMessage: "Say exactly: Zoom speech test complete.",
|
|
861
836
|
invalidRequest: zoomMeetingsInvalidRequest,
|
|
862
837
|
resolveTimeoutMs: (input, fallback) => MeetingPlatformAdapter.resolveProbeTimeoutMs(input, fallback, zoomMeetingsInvalidRequest),
|
|
863
838
|
shouldWaitForListening: (session) => Boolean(session.chrome?.browserTab?.targetId),
|
|
864
839
|
talkBackMode: MeetingPlatformAdapter.isTalkBackMode
|
|
865
840
|
});
|
|
866
|
-
const testZoomMeetingListening = probes.testListening;
|
|
867
|
-
const testZoomMeetingSpeech = probes.testSpeech;
|
|
868
841
|
//#endregion
|
|
869
842
|
//#region extensions/zoom-meetings/src/transports/chrome.ts
|
|
870
|
-
const
|
|
843
|
+
const zoomMeetingsChrome = MeetingPlatformAdapter.createPluginChromeTransport({
|
|
871
844
|
meetingLabel: "Zoom meeting",
|
|
872
845
|
platform: ZOOM_MEETINGS_PLATFORM_ADAPTER,
|
|
873
846
|
preserveTrackedBrowserOnEngineFailure: true,
|
|
874
847
|
runtime: MeetingPlatformAdapter.createChromeRuntimeBindings()
|
|
875
848
|
});
|
|
876
|
-
const assertZoomMeetingsAudioAvailable = chromeTransport.assertAudioDeviceAvailable;
|
|
877
|
-
const launchZoomMeetingInChrome = chromeTransport.launchInChrome;
|
|
878
|
-
const launchZoomMeetingOnNode = chromeTransport.launchOnNode;
|
|
879
|
-
const leaveZoomMeetingInBrowser = chromeTransport.leaveInBrowser;
|
|
880
|
-
const readZoomMeetingTranscript = chromeTransport.readTranscript;
|
|
881
|
-
const recoverCurrentZoomMeetingTab = chromeTransport.recoverCurrentTab;
|
|
882
849
|
//#endregion
|
|
883
850
|
//#region extensions/zoom-meetings/src/runtime-setup.ts
|
|
884
851
|
const getZoomMeetingsSetupStatus = MeetingPlatformAdapter.createRuntimeSetup({
|
|
885
|
-
assertAudioDeviceAvailable:
|
|
852
|
+
assertAudioDeviceAvailable: zoomMeetingsChrome.assertAudioDeviceAvailable,
|
|
886
853
|
captionsMessage: (mode) => mode === "transcribe" ? "Zoom live-caption capture is enabled and ready" : "Caption scraping is not used by talk-back modes",
|
|
887
854
|
connectedNodeMessage: (node) => `Connected Zoom meeting node ready: ${node}`,
|
|
888
855
|
guestJoinCheck: (config) => {
|
|
@@ -893,23 +860,16 @@ const getZoomMeetingsSetupStatus = MeetingPlatformAdapter.createRuntimeSetup({
|
|
|
893
860
|
};
|
|
894
861
|
},
|
|
895
862
|
missingNodeIdMessage: "Connected Zoom meetings node did not include a node id.",
|
|
896
|
-
nodeAdapter:
|
|
863
|
+
nodeAdapter: ZOOM_MEETINGS_PLATFORM_ADAPTER
|
|
897
864
|
});
|
|
898
865
|
//#endregion
|
|
899
866
|
//#region extensions/zoom-meetings/src/runtime.ts
|
|
900
867
|
const ZoomMeetingsRuntime = MeetingPlatformAdapter.createRuntimeFacade({
|
|
901
868
|
platform: ZOOM_MEETINGS_PLATFORM_ADAPTER,
|
|
902
|
-
transport:
|
|
903
|
-
launchInChrome: launchZoomMeetingInChrome,
|
|
904
|
-
launchOnNode: launchZoomMeetingOnNode,
|
|
905
|
-
leaveInBrowser: leaveZoomMeetingInBrowser,
|
|
906
|
-
readTranscript: readZoomMeetingTranscript,
|
|
907
|
-
recoverCurrentTab: recoverCurrentZoomMeetingTab
|
|
908
|
-
},
|
|
869
|
+
transport: zoomMeetingsChrome,
|
|
909
870
|
probes: {
|
|
910
871
|
setupStatus: getZoomMeetingsSetupStatus,
|
|
911
|
-
|
|
912
|
-
testSpeech: testZoomMeetingSpeech
|
|
872
|
+
...zoomMeetingsProbes
|
|
913
873
|
},
|
|
914
874
|
hooks: {
|
|
915
875
|
normalizeJoinRequest: (request, context) => {
|
|
@@ -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,
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
20
|
-
|
|
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(
|
|
41
|
+
return URL.canParse(value);
|
|
35
42
|
}
|
|
@@ -97,10 +97,10 @@ export function IsGreaterEqualThan(left, right) {
|
|
|
97
97
|
// String
|
|
98
98
|
// --------------------------------------------------------------------------
|
|
99
99
|
export function IsMinLength(value, length) {
|
|
100
|
-
return `Guard.
|
|
100
|
+
return `(${value}.length >= ${(+length) << 1} || (${value}.length >= ${length} && Guard.CodePointCount(${value}) >= ${length}))`;
|
|
101
101
|
}
|
|
102
102
|
export function IsMaxLength(value, length) {
|
|
103
|
-
return `Guard.
|
|
103
|
+
return `(${value}.length <= ${length} || (${value}.length <= ${(+length) << 1} && Guard.CodePointCount(${value}) <= ${length}))`;
|
|
104
104
|
}
|
|
105
105
|
// --------------------------------------------------------------------------
|
|
106
106
|
// Array
|
|
@@ -33,12 +33,14 @@ export declare function IsMultipleOf(dividend: bigint | number, divisor: bigint
|
|
|
33
33
|
/** Returns true if the value appears to be an instance of a class. */
|
|
34
34
|
export declare function IsClassInstance(value: unknown): boolean;
|
|
35
35
|
export declare function IsValueLike(value: unknown): value is bigint | boolean | null | number | string | undefined;
|
|
36
|
-
/** Returns the number of grapheme clusters in the string */
|
|
36
|
+
/** Returns the total number of visual grapheme clusters in the string. */
|
|
37
37
|
export declare function GraphemeCount(value: string): number;
|
|
38
|
-
/** Returns
|
|
39
|
-
export declare function
|
|
40
|
-
/** Returns true if the string
|
|
41
|
-
export declare function
|
|
38
|
+
/** Returns the total number of Unicode code points in the string. */
|
|
39
|
+
export declare function CodePointCount(value: string): number;
|
|
40
|
+
/** Returns true if the string length in Unicode code points does not exceed maxLength */
|
|
41
|
+
export declare function IsMaxLength(value: string, maxLength: number): boolean;
|
|
42
|
+
/** Returns true if the string length in Unicode code points is at least minLength */
|
|
43
|
+
export declare function IsMinLength(value: string, minLength: number): boolean;
|
|
42
44
|
/** Returns true if every element from offset satisfies the callback, short-circuiting on the first failure */
|
|
43
45
|
export declare function Every<T>(value: T[], offset: number, callback: (value: T, index: number) => boolean): boolean;
|
|
44
46
|
/** Returns true if every element from offset satisfies the callback, using exhaustive enumeration */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// deno-fmt-ignore-file
|
|
2
|
-
import * as
|
|
2
|
+
import * as UnicodeSegmentGuard from './unicode/unicode_segment.mjs';
|
|
3
|
+
import * as UnicodeGuard from './unicode/unicode.mjs';
|
|
3
4
|
// --------------------------------------------------------------------------
|
|
4
5
|
// Guards
|
|
5
6
|
// --------------------------------------------------------------------------
|
|
@@ -123,17 +124,21 @@ export function IsValueLike(value) {
|
|
|
123
124
|
// --------------------------------------------------------------------------
|
|
124
125
|
// String
|
|
125
126
|
// --------------------------------------------------------------------------
|
|
126
|
-
/** Returns the number of grapheme clusters in the string */
|
|
127
|
+
/** Returns the total number of visual grapheme clusters in the string. */
|
|
127
128
|
export function GraphemeCount(value) {
|
|
128
|
-
return
|
|
129
|
+
return UnicodeSegmentGuard.GraphemeCount(value);
|
|
129
130
|
}
|
|
130
|
-
/** Returns
|
|
131
|
-
export function
|
|
132
|
-
return
|
|
131
|
+
/** Returns the total number of Unicode code points in the string. */
|
|
132
|
+
export function CodePointCount(value) {
|
|
133
|
+
return UnicodeGuard.CodePointCount(value);
|
|
133
134
|
}
|
|
134
|
-
/** Returns true if the string
|
|
135
|
-
export function
|
|
136
|
-
return
|
|
135
|
+
/** Returns true if the string length in Unicode code points does not exceed maxLength */
|
|
136
|
+
export function IsMaxLength(value, maxLength) {
|
|
137
|
+
return UnicodeGuard.IsMaxLength(value, maxLength);
|
|
138
|
+
}
|
|
139
|
+
/** Returns true if the string length in Unicode code points is at least minLength */
|
|
140
|
+
export function IsMinLength(value, minLength) {
|
|
141
|
+
return UnicodeGuard.IsMinLength(value, minLength);
|
|
137
142
|
}
|
|
138
143
|
// --------------------------------------------------------------------------
|
|
139
144
|
// Array
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
// ------------------------------------------------------------------
|
|
2
|
+
// Guards
|
|
3
|
+
// ------------------------------------------------------------------
|
|
1
4
|
export * as EmitGuard from './emit.mjs';
|
|
2
5
|
export * as GlobalsGuard from './globals.mjs';
|
|
3
6
|
export * as NativeGuard from './native.mjs';
|
|
7
|
+
// ------------------------------------------------------------------
|
|
8
|
+
// Default
|
|
9
|
+
// ------------------------------------------------------------------
|
|
4
10
|
import * as Guard from './guard.mjs';
|
|
5
11
|
export * as Guard from './guard.mjs';
|
|
6
12
|
export default Guard;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Returns the total number of Unicode code points in the string */
|
|
2
|
+
export declare function CodePointCount(value: string): number;
|
|
3
|
+
/** Returns true if the string length in Unicode code points is less than or equal to maxLength */
|
|
4
|
+
export declare function IsMaxLength(value: string, maxLength: number): boolean;
|
|
5
|
+
/** Returns true if the string length in Unicode code points is greater than or equal to minLength */
|
|
6
|
+
export declare function IsMinLength(value: string, minLength: number): boolean;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// ------------------------------------------------------------------
|
|
2
|
+
// CodePointCount (10-bit Shift Branchless)
|
|
3
|
+
//
|
|
4
|
+
// Counts code points by enumerating UTF-16 sequences and incrementing
|
|
5
|
+
// when not within a high/low pairing. Because surrogate blocks are
|
|
6
|
+
// 1024 (2^10) wide and aligned, by shifting right by (0xA), we can
|
|
7
|
+
// collapse each unit to a constant per block (high: 0x36, low: 0x37)
|
|
8
|
+
// and shift again into a packed (0x3637) for comparison. Fetch calls
|
|
9
|
+
// to charCodeAt(...) are kept to one call per iteration.
|
|
10
|
+
//
|
|
11
|
+
// ------------------------------------------------------------------
|
|
12
|
+
/** Returns the total number of Unicode code points in the string */
|
|
13
|
+
export function CodePointCount(value) {
|
|
14
|
+
let result = 0, index = 0, prev = 0;
|
|
15
|
+
while (index < value.length) {
|
|
16
|
+
const next = value.charCodeAt(index++) >> 0xA; // shift (10-bits into high/low)
|
|
17
|
+
result += +(((prev << 8) | next) !== 0x3637); // packed (or +!(prev === 0x36 && next === 0x37))
|
|
18
|
+
prev = next;
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
// ------------------------------------------------------------------
|
|
23
|
+
// IsMaxLength
|
|
24
|
+
// ------------------------------------------------------------------
|
|
25
|
+
/** Returns true if the string length in Unicode code points is less than or equal to maxLength */
|
|
26
|
+
export function IsMaxLength(value, maxLength) {
|
|
27
|
+
return value.length <= maxLength || (value.length <= (maxLength << 1) && CodePointCount(value) <= maxLength);
|
|
28
|
+
}
|
|
29
|
+
// ------------------------------------------------------------------
|
|
30
|
+
// IsMinLength
|
|
31
|
+
// ------------------------------------------------------------------
|
|
32
|
+
/** Returns true if the string length in Unicode code points is greater than or equal to minLength */
|
|
33
|
+
export function IsMinLength(value, minLength) {
|
|
34
|
+
return value.length >= (minLength << 1) || (value.length >= minLength && CodePointCount(value) >= minLength);
|
|
35
|
+
}
|
|
@@ -91,26 +91,12 @@ function IsGraphemeCodePoint(value) {
|
|
|
91
91
|
IsZeroWidthJoiner(value)));
|
|
92
92
|
}
|
|
93
93
|
// --------------------------------------------------------------------------
|
|
94
|
-
// GraphemeCount
|
|
95
|
-
// --------------------------------------------------------------------------
|
|
96
|
-
/** Returns the number of grapheme clusters in a string */
|
|
97
|
-
export function GraphemeCount(value) {
|
|
98
|
-
let count = 0;
|
|
99
|
-
let index = 0;
|
|
100
|
-
while (index < value.length) {
|
|
101
|
-
index = NextGraphemeClusterIndex(value, index);
|
|
102
|
-
count++;
|
|
103
|
-
}
|
|
104
|
-
return count;
|
|
105
|
-
}
|
|
106
|
-
// --------------------------------------------------------------------------
|
|
107
94
|
// IsMinLengthSegmented
|
|
108
95
|
// --------------------------------------------------------------------------
|
|
109
96
|
/** Checks if a string has at least a minimum number of grapheme clusters */
|
|
110
97
|
function IsMinLengthSegmented(value, minLength) {
|
|
111
98
|
// if (minLength === 0) return true // 0-length (unreachable)
|
|
112
|
-
let count = 0;
|
|
113
|
-
let index = 0;
|
|
99
|
+
let count = 0, index = 0;
|
|
114
100
|
while (index < value.length) {
|
|
115
101
|
index = NextGraphemeClusterIndex(value, index);
|
|
116
102
|
if ((++count) >= minLength)
|
|
@@ -123,8 +109,7 @@ function IsMinLengthSegmented(value, minLength) {
|
|
|
123
109
|
// --------------------------------------------------------------------------
|
|
124
110
|
/** Checks if a string has at most a maximum number of grapheme clusters */
|
|
125
111
|
function IsMaxLengthSegmented(value, maxLength) {
|
|
126
|
-
let count = 0;
|
|
127
|
-
let index = 0;
|
|
112
|
+
let count = 0, index = 0;
|
|
128
113
|
while (index < value.length) {
|
|
129
114
|
index = NextGraphemeClusterIndex(value, index);
|
|
130
115
|
if ((++count) > maxLength)
|
|
@@ -133,7 +118,19 @@ function IsMaxLengthSegmented(value, maxLength) {
|
|
|
133
118
|
return true;
|
|
134
119
|
}
|
|
135
120
|
// --------------------------------------------------------------------------
|
|
136
|
-
//
|
|
121
|
+
// GraphemeCount
|
|
122
|
+
// --------------------------------------------------------------------------
|
|
123
|
+
/** Returns the number of grapheme clusters in a string */
|
|
124
|
+
export function GraphemeCount(value) {
|
|
125
|
+
let count = 0, index = 0;
|
|
126
|
+
while (index < value.length) {
|
|
127
|
+
index = NextGraphemeClusterIndex(value, index);
|
|
128
|
+
count++;
|
|
129
|
+
}
|
|
130
|
+
return count;
|
|
131
|
+
}
|
|
132
|
+
// --------------------------------------------------------------------------
|
|
133
|
+
// IsMinLength
|
|
137
134
|
// --------------------------------------------------------------------------
|
|
138
135
|
/** Fast check for minimum grapheme length, falls back to full check if needed */
|
|
139
136
|
export function IsMinLength(value, minLength) {
|
|
@@ -151,7 +148,7 @@ export function IsMinLength(value, minLength) {
|
|
|
151
148
|
}
|
|
152
149
|
}
|
|
153
150
|
// --------------------------------------------------------------------------
|
|
154
|
-
//
|
|
151
|
+
// IsMaxLength
|
|
155
152
|
// --------------------------------------------------------------------------
|
|
156
153
|
/** Fast check for maximum grapheme length, falls back to full check if needed */
|
|
157
154
|
export function IsMaxLength(value, maxLength) {
|
|
@@ -4,7 +4,6 @@ import { Arguments } from '../system/arguments/index.mjs';
|
|
|
4
4
|
import { Environment } from '../system/environment/index.mjs';
|
|
5
5
|
import { Hashing } from '../system/hashing/index.mjs';
|
|
6
6
|
import { Guard } from '../guard/index.mjs';
|
|
7
|
-
import { Format } from '../format/index.mjs';
|
|
8
7
|
import * as Engine from './engine/index.mjs';
|
|
9
8
|
// ------------------------------------------------------------------
|
|
10
9
|
// CreateCode
|
|
@@ -20,8 +19,8 @@ function CreateCode(build) {
|
|
|
20
19
|
// CreateEvaluatedCheck
|
|
21
20
|
// ------------------------------------------------------------------
|
|
22
21
|
function CreateEvaluatedCheck(build, code) {
|
|
23
|
-
const factory = Environment.Evaluate('CheckContext', 'Guard', '
|
|
24
|
-
return factory(Engine.CheckContext, Guard,
|
|
22
|
+
const factory = Environment.Evaluate('CheckContext', 'Guard', 'Hashing', build.External().identifier, code);
|
|
23
|
+
return factory(Engine.CheckContext, Guard, Hashing, build.External().variables);
|
|
25
24
|
}
|
|
26
25
|
// ------------------------------------------------------------------
|
|
27
26
|
// CreateDynamicCheck
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function EncodeFragment(fragment: string): string;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// ------------------------------------------------------------------
|
|
2
|
+
// EncodeFragment
|
|
3
|
+
//
|
|
4
|
+
// We use this function to encode instancePath and schemaPath path
|
|
5
|
+
// fragments for errors. We need this encoding such that callers
|
|
6
|
+
// can use Pointer to deref error targets. We should consider adding
|
|
7
|
+
// this to the Pointer module as Pointer.Encode(...) (review)
|
|
8
|
+
// ------------------------------------------------------------------
|
|
9
|
+
export function EncodeFragment(fragment) {
|
|
10
|
+
return fragment.replace(/~/g, '~0').replace(/\//g, '~1');
|
|
11
|
+
}
|
|
@@ -4,9 +4,18 @@ import { EmitGuard as E, Guard as G } from '../../guard/index.mjs';
|
|
|
4
4
|
// ------------------------------------------------------------------
|
|
5
5
|
// Build
|
|
6
6
|
// ------------------------------------------------------------------
|
|
7
|
+
function BuildRefineMultiple(_stack, _context, schema, value) {
|
|
8
|
+
const external = Externals.CreateVariable(schema['~refine']);
|
|
9
|
+
return E.Every(external, E.Constant(0), ['refinement', '_'], E.Call(E.Member('refinement', 'check'), [value]));
|
|
10
|
+
}
|
|
11
|
+
function BuildRefineSingle(_stack, _context, schema, value) {
|
|
12
|
+
const external = Externals.CreateVariable(schema['~refine'][0]);
|
|
13
|
+
return E.Call(E.Member(external, 'check'), [value]);
|
|
14
|
+
}
|
|
7
15
|
export function BuildRefine(_stack, _context, schema, value) {
|
|
8
|
-
|
|
9
|
-
|
|
16
|
+
return G.IsEqual(schema['~refine'].length, 1)
|
|
17
|
+
? BuildRefineSingle(_stack, _context, schema, value)
|
|
18
|
+
: BuildRefineMultiple(_stack, _context, schema, value);
|
|
10
19
|
}
|
|
11
20
|
// ------------------------------------------------------------------
|
|
12
21
|
// Check
|
|
@@ -19,8 +28,7 @@ export function CheckRefine(_stack, _context, schema, value) {
|
|
|
19
28
|
// ------------------------------------------------------------------
|
|
20
29
|
export function ErrorRefine(_stack, context, schemaPath, instancePath, schema, value) {
|
|
21
30
|
return G.EveryAll(schema['~refine'], 0, (refinement, index) => {
|
|
22
|
-
return refinement.check(value) ||
|
|
23
|
-
index, message: refinement.error(value)
|
|
24
|
-
});
|
|
31
|
+
return refinement.check(value) ||
|
|
32
|
+
context.AddError('~refine', schemaPath, instancePath, { index, message: refinement.error(value) });
|
|
25
33
|
});
|
|
26
34
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// deno-fmt-ignore-file
|
|
2
2
|
import * as Schema from '../types/index.mjs';
|
|
3
3
|
import * as Externals from './_externals.mjs';
|
|
4
|
+
import * as Pathing from './_pathing.mjs';
|
|
4
5
|
import { Unique } from './_unique.mjs';
|
|
5
6
|
import { UnicodeRegExp } from './_regexp.mjs';
|
|
6
7
|
import { EmitGuard as E, Guard as G } from '../../guard/index.mjs';
|
|
@@ -107,7 +108,7 @@ export function ErrorAdditionalProperties(stack, context, schemaPath, instancePa
|
|
|
107
108
|
const additionalProperties = [];
|
|
108
109
|
const isAdditionalProperties = G.EveryAll(G.Keys(value), 0, (key, _index) => {
|
|
109
110
|
const nextSchemaPath = `${schemaPath}/additionalProperties`;
|
|
110
|
-
const nextInstancePath = `${instancePath}/${key}`;
|
|
111
|
+
const nextInstancePath = `${instancePath}/${Pathing.EncodeFragment(key)}`;
|
|
111
112
|
const isAdditionalProperty = regexp.test(key) ||
|
|
112
113
|
(ErrorSchemaPushStack(stack, context, nextSchemaPath, nextInstancePath, schema.additionalProperties, value[key]) && context.AddKey(key));
|
|
113
114
|
if (!isAdditionalProperty)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// deno-fmt-ignore-file
|
|
2
|
+
import * as Pathing from './_pathing.mjs';
|
|
2
3
|
import { EmitGuard as E, Guard as G } from '../../guard/index.mjs';
|
|
3
4
|
import { BuildSchema, CheckSchema, ErrorSchema } from './schema.mjs';
|
|
4
5
|
// ------------------------------------------------------------------
|
|
@@ -32,7 +33,7 @@ export function CheckDependencies(stack, context, schema, value) {
|
|
|
32
33
|
export function ErrorDependencies(stack, context, schemaPath, instancePath, schema, value) {
|
|
33
34
|
const isLength = G.IsEqual(G.Keys(value).length, 0);
|
|
34
35
|
const isEvery = G.EveryAll(G.Entries(schema.dependencies), 0, ([key, schema]) => {
|
|
35
|
-
const nextSchemaPath = `${schemaPath}/dependencies/${key}`;
|
|
36
|
+
const nextSchemaPath = `${schemaPath}/dependencies/${Pathing.EncodeFragment(key)}`;
|
|
36
37
|
return !G.HasPropertyKey(value, key) || (G.IsArray(schema)
|
|
37
38
|
? schema.every((dependency) => G.HasPropertyKey(value, dependency) ||
|
|
38
39
|
context.AddError('dependencies', schemaPath, instancePath, { property: key, dependencies: schema }))
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// deno-fmt-ignore-file
|
|
2
|
+
import * as Pathing from './_pathing.mjs';
|
|
2
3
|
import { Guard as G, EmitGuard as E } from '../../guard/index.mjs';
|
|
3
4
|
import { BuildSchema, CheckSchema, ErrorSchema } from './schema.mjs';
|
|
4
5
|
// ------------------------------------------------------------------
|
|
@@ -30,7 +31,7 @@ export function CheckDependentSchemas(stack, context, schema, value) {
|
|
|
30
31
|
export function ErrorDependentSchemas(stack, context, schemaPath, instancePath, schema, value) {
|
|
31
32
|
const isLength = G.IsEqual(G.Keys(value).length, 0);
|
|
32
33
|
const isEvery = G.EveryAll(G.Entries(schema.dependentSchemas), 0, ([key, schema]) => {
|
|
33
|
-
const nextSchemaPath = `${schemaPath}/dependentSchemas/${key}`;
|
|
34
|
+
const nextSchemaPath = `${schemaPath}/dependentSchemas/${Pathing.EncodeFragment(key)}`;
|
|
34
35
|
return !G.HasPropertyKey(value, key) ||
|
|
35
36
|
ErrorSchema(stack, context, nextSchemaPath, instancePath, schema, value);
|
|
36
37
|
});
|
|
@@ -3,4 +3,4 @@ import * as Stack from './_stack.mjs';
|
|
|
3
3
|
import { BuildContext, CheckContext, ErrorContext } from './_context.mjs';
|
|
4
4
|
export declare function BuildDynamicRef(stack: Stack.XStack, context: BuildContext, schema: Schema.XDynamicRef, value: string): string;
|
|
5
5
|
export declare function CheckDynamicRef(stack: Stack.XStack, context: CheckContext, schema: Schema.XDynamicRef, value: unknown): boolean;
|
|
6
|
-
export declare function ErrorDynamicRef(stack: Stack.XStack, context: ErrorContext,
|
|
6
|
+
export declare function ErrorDynamicRef(stack: Stack.XStack, context: ErrorContext, schemaPath: string, instancePath: string, schema: Schema.XDynamicRef, value: unknown): boolean;
|
|
@@ -22,8 +22,8 @@ export function CheckDynamicRef(stack, context, schema, value) {
|
|
|
22
22
|
// ------------------------------------------------------------------
|
|
23
23
|
// Error
|
|
24
24
|
// ------------------------------------------------------------------
|
|
25
|
-
export function ErrorDynamicRef(stack, context,
|
|
25
|
+
export function ErrorDynamicRef(stack, context, schemaPath, instancePath, schema, value) {
|
|
26
26
|
const target = Resolve.DynamicRef(stack, schema) ?? false;
|
|
27
27
|
const nextStack = target ? { ...stack, pendingResource: true } : stack;
|
|
28
|
-
return (Schema.IsSchema(target) && ErrorSchema(nextStack, context,
|
|
28
|
+
return (Schema.IsSchema(target) && ErrorSchema(nextStack, context, schemaPath, instancePath, target, value));
|
|
29
29
|
}
|