arcane-os 0.5.16 → 0.5.18
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/CHANGELOG.md +44 -0
- package/README.md +42 -19
- package/bin/arcane-test.mjs +16 -13
- package/browser-runtime/ai/browser-speech-artifacts.mjs +41 -38
- package/browser-runtime/ai/browser-speech-providers.mjs +53 -46
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +127 -124
- package/browser-runtime/ai/browser-wasm.mjs +6 -3
- package/browser-runtime/ai/browser-wllama-runtime.mjs +26 -23
- package/browser-runtime/ai/model-controller.mjs +94 -91
- package/browser-runtime/ai/speech-worker-client.mjs +12 -9
- package/browser-runtime/ai/speech-worker-runtime.mjs +56 -53
- package/browser-runtime/dependencies/strong-type/index.js +207 -82
- package/browser-runtime/dependencies/strong-type/package.json +15 -6
- package/browser-runtime/dom-event-instrumentation.mjs +24 -20
- package/browser-runtime/event-manager.mjs +111 -108
- package/browser-runtime/speech-text.mjs +35 -0
- package/docs/architecture.md +1 -1
- package/docs/reference/README.md +8 -8
- package/docs/reference/ai/browser-speech.md +230 -16
- package/docs/reference/ai/twin-cloud.md +1 -1
- package/docs/reference/availability-and-normalization.md +42 -1
- package/docs/reference/cli.md +1 -1
- package/docs/reference/core/arcane-ai-contracts.md +1 -1
- package/docs/reference/inventory/package-api.json +60 -4
- package/docs/reference/inventory/runtime-components.json +2 -2
- package/docs/reference/inventory/runtime-modules.json +29 -31
- package/docs/reference/protocols.md +17 -13
- package/docs/reference/runtime-components.md +6 -5
- package/docs/reference/runtime-modules.md +212 -70
- package/docs/reference/sdk-api.md +197 -11
- package/examples/wasm-ai-demo/index.html +1 -0
- package/node_modules/event-pubsub/node_modules/strong-type/README.md +408 -0
- package/node_modules/event-pubsub/node_modules/strong-type/assets/strong-type-header.png +0 -0
- package/node_modules/event-pubsub/node_modules/strong-type/index.js +1151 -0
- package/node_modules/event-pubsub/node_modules/strong-type/licence +21 -0
- package/node_modules/event-pubsub/node_modules/strong-type/node.js +125 -0
- package/node_modules/event-pubsub/node_modules/strong-type/package.json +61 -0
- package/node_modules/strong-type/README.md +42 -24
- package/node_modules/strong-type/benchmark/core.js +324 -0
- package/node_modules/strong-type/index.js +207 -82
- package/node_modules/strong-type/package.json +14 -6
- package/package.json +4 -3
- package/runtime/arcane/components/app-bar.html +5 -2
- package/runtime/arcane/components/assistant-panel.html +5 -2
- package/runtime/arcane/components/chart.html +15 -12
- package/runtime/arcane/components/chat.html +118 -141
- package/runtime/arcane/components/dashboard-config.html +6 -3
- package/runtime/arcane/components/data-view.html +4 -1
- package/runtime/arcane/components/directory-picker.html +5 -2
- package/runtime/arcane/components/document-inspector.html +6 -3
- package/runtime/arcane/components/file-drop.html +5 -2
- package/runtime/arcane/components/file-inspector.html +9 -6
- package/runtime/arcane/components/file-manager.html +16 -13
- package/runtime/arcane/components/local-ai-status.html +5 -2
- package/runtime/arcane/components/markdown-document.html +14 -11
- package/runtime/arcane/components/markdown-editor.html +4 -1
- package/runtime/arcane/components/modal.html +4 -1
- package/runtime/arcane/components/output-panel.html +6 -3
- package/runtime/arcane/components/preferences-form.html +4 -1
- package/runtime/arcane/components/record-timeline.html +8 -5
- package/runtime/arcane/components/relationship-board.html +9 -6
- package/runtime/arcane/components/source-code-viewer.html +12 -9
- package/runtime/arcane/components/source-explanation.html +8 -5
- package/runtime/arcane/components/speech.html +24 -21
- package/runtime/arcane/components/summary-strip.html +4 -1
- package/runtime/arcane/components/task-progress.html +6 -3
- package/runtime/arcane/components/terminal-workspace.html +4 -1
- package/runtime/arcane/components/voice-transcription.html +11 -8
- package/runtime/arcane/components/web-navigator.html +5 -2
- package/runtime/arcane/entities/ApiModelRecord.js +5 -2
- package/runtime/arcane/entities/Calculation.js +5 -2
- package/runtime/arcane/entities/Chat.js +33 -33
- package/runtime/arcane/entities/CommunicationMessage.js +4 -1
- package/runtime/arcane/entities/CommunicationThread.js +4 -1
- package/runtime/arcane/entities/File.js +1 -1
- package/runtime/arcane/entities/Image.js +8 -5
- package/runtime/arcane/entities/IntentEnvelope.js +20 -17
- package/runtime/arcane/entities/Preference.js +9 -6
- package/runtime/arcane/entities/Theme.js +5 -2
- package/runtime/arcane/entities/User.js +11 -11
- package/runtime/arcane/entities/Weather.js +5 -2
- package/runtime/arcane/modules/AI.js +503 -187
- package/runtime/arcane/modules/AIPreferenceRuntime.js +5 -2
- package/runtime/arcane/modules/AIPreferenceTuple.js +9 -6
- package/runtime/arcane/modules/AIProviderRuntime.js +117 -92
- package/runtime/arcane/modules/AIResponseURLPolicy.js +148 -62
- package/runtime/arcane/modules/AIRuntimeState.js +29 -26
- package/runtime/arcane/modules/AnsiText.js +4 -1
- package/runtime/arcane/modules/ApiModelDatabase.js +22 -19
- package/runtime/arcane/modules/AppDataScope.js +8 -5
- package/runtime/arcane/modules/ArcaneCommunicationBridge.js +4 -1
- package/runtime/arcane/modules/ArcaneNavigationPolicy.js +8 -5
- package/runtime/arcane/modules/ArcaneNetworkPolicy.js +18 -15
- package/runtime/arcane/modules/AsyncBoundary.js +13 -10
- package/runtime/arcane/modules/BrowserTestSuite.js +19 -16
- package/runtime/arcane/modules/CalculatorEngine.js +5 -2
- package/runtime/arcane/modules/ChatRecords.js +18 -15
- package/runtime/arcane/modules/CommunicationAppController.js +9 -6
- package/runtime/arcane/modules/CommunicationHub.js +9 -6
- package/runtime/arcane/modules/CommunicationPreferences.js +4 -1
- package/runtime/arcane/modules/CommunicationProviderRegistry.js +4 -1
- package/runtime/arcane/modules/ComponentContracts.js +56 -53
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +30 -27
- package/runtime/arcane/modules/ConversationActionItems.js +15 -12
- package/runtime/arcane/modules/ConversationClosingReport.js +11 -8
- package/runtime/arcane/modules/ConversationTimebox.js +28 -25
- package/runtime/arcane/modules/CoreLocalModelCatalog.js +17 -14
- package/runtime/arcane/modules/DBLS.js +7 -4
- package/runtime/arcane/modules/DBOPFS.js +7 -7
- package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +34 -31
- package/runtime/arcane/modules/DevelopmentWorkspace.js +4 -1
- package/runtime/arcane/modules/DirectoryPicker.js +8 -5
- package/runtime/arcane/modules/DocumentLexicalSearch.js +11 -8
- package/runtime/arcane/modules/DocumentNavigation.js +7 -4
- package/runtime/arcane/modules/Errors.js +28 -25
- package/runtime/arcane/modules/HTMLImport.js +7 -4
- package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +15 -12
- package/runtime/arcane/modules/LocalAIReadiness.js +21 -18
- package/runtime/arcane/modules/LocalAIReadinessController.js +6 -3
- package/runtime/arcane/modules/MD.js +1 -1
- package/runtime/arcane/modules/Mail.js +46 -43
- package/runtime/arcane/modules/MailOutbox.mjs +48 -45
- package/runtime/arcane/modules/MailTransport.mjs +29 -26
- package/runtime/arcane/modules/MarkdownSpeech.js +1 -50
- package/runtime/arcane/modules/MemoryRecords.js +7 -4
- package/runtime/arcane/modules/MessageAdvisory.js +6 -3
- package/runtime/arcane/modules/ModelDefinition.js +7 -4
- package/runtime/arcane/modules/Ollama.js +6 -3
- package/runtime/arcane/modules/OllamaModelIdentifier.js +4 -1
- package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +18 -15
- package/runtime/arcane/modules/PersistentAIChatSession.js +33 -30
- package/runtime/arcane/modules/PreferenceStore.js +20 -17
- package/runtime/arcane/modules/PreparedSpeech.js +485 -0
- package/runtime/arcane/modules/Questionnaire.js +6 -3
- package/runtime/arcane/modules/RecordLinkIndex.js +4 -1
- package/runtime/arcane/modules/RecordPassageIndex.js +9 -6
- package/runtime/arcane/modules/RecordReviewStore.js +12 -9
- package/runtime/arcane/modules/RiskSignalAnalyzer.js +4 -1
- package/runtime/arcane/modules/ScopedOPFSCache.js +6 -3
- package/runtime/arcane/modules/ScreenCapture.js +20 -17
- package/runtime/arcane/modules/SpeechPlayback.js +61 -28
- package/runtime/arcane/modules/StaticDocumentCatalog.js +33 -30
- package/runtime/arcane/modules/SystemAppearance.js +5 -2
- package/runtime/arcane/modules/SystemToolRegistry.js +6 -3
- package/runtime/arcane/modules/TerminalClient.js +14 -11
- package/runtime/arcane/modules/TerminalCommandRegistry.js +4 -1
- package/runtime/arcane/modules/ThemeBootstrap.js +9 -6
- package/runtime/arcane/modules/ThemeManager.js +5 -2
- package/runtime/arcane/modules/TimeGuard.js +1 -1
- package/runtime/arcane/modules/ToolCallRouter.js +11 -8
- package/runtime/arcane/modules/WaitForComponent.js +19 -16
- package/runtime/arcane/modules/YouTubeMedia.js +4 -1
- package/runtime/strong-type/index.js +1276 -352
- package/runtime/strong-type/package.json +69 -45
- package/src/app-descriptor.mjs +17 -14
- package/src/application-tests.mjs +4 -1
- package/src/cli/main.mjs +8 -5
- package/src/constants.mjs +4 -1
- package/src/dev-server.mjs +8 -5
- package/src/doctor.mjs +5 -2
- package/src/dom-event-instrumentation.mjs +24 -20
- package/src/errors.mjs +7 -3
- package/src/event-manager.mjs +111 -108
- package/src/event-queue.mjs +8 -5
- package/src/events.mjs +12 -9
- package/src/import-map.mjs +36 -27
- package/src/installed-sdk-runtime.mjs +4 -1
- package/src/integrated-provider-loader.mjs +9 -6
- package/src/mail-credentials.mjs +16 -13
- package/src/mail-server.mjs +53 -50
- package/src/mail.mjs +18 -15
- package/src/native-plan.mjs +12 -9
- package/src/native-provider-loader.mjs +7 -4
- package/src/packager/core.mjs +18 -15
- package/src/process.mjs +6 -3
- package/src/release-bundle.mjs +14 -11
- package/src/runtime.mjs +4 -1
- package/src/scaffold.mjs +9 -6
- package/src/sdk-browser-runtime.mjs +4 -1
- package/src/source-server.mjs +17 -14
- package/src/targets/index.mjs +5 -2
- package/src/templates/workspace-template.mjs +13 -6
- package/src/testing-loader.mjs +7 -4
- package/src/testing.mjs +10 -7
- package/src/toolchain.mjs +13 -10
- package/src/update-check.mjs +9 -6
- package/src/workspace-operation-lock.mjs +14 -11
- package/src/workspace-runtime.mjs +4 -1
- package/src/workspace.mjs +17 -14
- package/runtime/arcane/modules/AIResponseLength.js +0 -32
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
2
|
+
const is=new Is(false);
|
|
3
|
+
|
|
1
4
|
import {createArcaneEventSource} from 'arcane-os/event-manager';
|
|
2
5
|
import TerminalSession from '../entities/TerminalSession.js';
|
|
3
6
|
|
|
@@ -47,17 +50,17 @@ function terminalEventReason(type){
|
|
|
47
50
|
|
|
48
51
|
function terminalPublicDetail(detail,type,reason){
|
|
49
52
|
const id=detail?.session?.id??detail?.sessionId;
|
|
50
|
-
const output=
|
|
53
|
+
const output=is.string(detail?.data)?detail.data:'';
|
|
51
54
|
const code=type==='error'
|
|
52
|
-
?
|
|
55
|
+
?is.string(detail?.code)&&detail.code
|
|
53
56
|
?detail.code
|
|
54
57
|
:TERMINAL_CLIENT_ERROR_CODES.sessionHostError
|
|
55
58
|
:null;
|
|
56
59
|
return {
|
|
57
|
-
...(
|
|
58
|
-
...(
|
|
59
|
-
...(
|
|
60
|
-
...(
|
|
60
|
+
...(is.string(id)&&id?{id}:{}),
|
|
61
|
+
...(is.string(detail?.stream)?{stream:detail.stream}:{}),
|
|
62
|
+
...(is.string(detail?.data)?{data:output}:{}),
|
|
63
|
+
...(is.string(detail?.session?.state)?{status:detail.session.state}:{}),
|
|
61
64
|
...(code?{code}:{}),
|
|
62
65
|
reason
|
|
63
66
|
};
|
|
@@ -93,8 +96,8 @@ export default class TerminalClient extends EventTarget{
|
|
|
93
96
|
type,
|
|
94
97
|
receiveTerminalHostEvent
|
|
95
98
|
);
|
|
96
|
-
if(
|
|
97
|
-
|
|
99
|
+
if(!is.function(unsubscribe)
|
|
100
|
+
&&!is.function(unsubscribe?.dispose)){
|
|
98
101
|
throw terminalClientError(
|
|
99
102
|
TERMINAL_CLIENT_ERROR_CODES.hostEventSubscriptionInvalid,
|
|
100
103
|
TERMINAL_CLIENT_REASONS.hostEventSubscriptionInvalid,
|
|
@@ -144,7 +147,7 @@ export default class TerminalClient extends EventTarget{
|
|
|
144
147
|
|
|
145
148
|
#assertCapability(method){
|
|
146
149
|
this.#assertOpen();
|
|
147
|
-
if(
|
|
150
|
+
if(!is.function(this.api?.[method])){
|
|
148
151
|
throw terminalClientError(
|
|
149
152
|
TERMINAL_CLIENT_ERROR_CODES.capabilityUnavailable,
|
|
150
153
|
TERMINAL_CLIENT_REASONS.capabilityUnavailable,
|
|
@@ -163,7 +166,7 @@ export default class TerminalClient extends EventTarget{
|
|
|
163
166
|
let firstError=null;
|
|
164
167
|
for(const subscription of this.unsubscribe){
|
|
165
168
|
try{
|
|
166
|
-
if(
|
|
169
|
+
if(is.function(subscription))subscription();
|
|
167
170
|
else subscription.dispose();
|
|
168
171
|
}catch(error){
|
|
169
172
|
firstError??=error;
|
|
@@ -179,7 +182,7 @@ export default class TerminalClient extends EventTarget{
|
|
|
179
182
|
const result=await this.api.start(options);
|
|
180
183
|
if(this.#destroyed||generation!==this.#generation){
|
|
181
184
|
let cleanupError=null;
|
|
182
|
-
if(
|
|
185
|
+
if(is.string(result?.id)&&is.function(this.api?.close)){
|
|
183
186
|
try{
|
|
184
187
|
await this.api.close(result.id);
|
|
185
188
|
}catch(error){
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
2
|
+
const is=new Is(false);
|
|
3
|
+
|
|
1
4
|
const COMMAND_PATTERN=/^(?:[a-z][a-z0-9:_-]{0,63}|\?)$/;
|
|
2
5
|
|
|
3
6
|
export function splitCommandLine(input=''){
|
|
@@ -28,7 +31,7 @@ export default class TerminalCommandRegistry{
|
|
|
28
31
|
register({name,aliases=[],description='',usage='',run}={}){
|
|
29
32
|
const normalized=String(name||'').trim().toLowerCase();
|
|
30
33
|
if(!COMMAND_PATTERN.test(normalized)) throw new TypeError('Terminal command names must use lowercase command syntax.');
|
|
31
|
-
if(
|
|
34
|
+
if(!is.function(run)) throw new TypeError(`Terminal command ${normalized} requires a run function.`);
|
|
32
35
|
const record=Object.freeze({name:normalized,aliases:Object.freeze(aliases.map(alias=>String(alias).toLowerCase())),description:String(description),usage:String(usage||normalized),run});
|
|
33
36
|
for(const key of [record.name,...record.aliases]){
|
|
34
37
|
if(!COMMAND_PATTERN.test(key)||this.commands.has(key)) throw new TypeError(`Duplicate or invalid terminal command: ${key}`);
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
2
|
+
const is=new Is(false);
|
|
3
|
+
|
|
1
4
|
import { arcaneLogging } from 'arcane-os/logging';
|
|
2
5
|
import {loadAndApplyTheme} from './ThemeManager.js';
|
|
3
6
|
import {createArcaneEventSource} from 'arcane-os/event-manager';
|
|
@@ -16,7 +19,7 @@ const themeBootstrapEvents=createArcaneEventSource(
|
|
|
16
19
|
|
|
17
20
|
function installAppearanceListener(ready){
|
|
18
21
|
const hostEvents=globalThis.Arcane?.events;
|
|
19
|
-
if(
|
|
22
|
+
if(!is.function(hostEvents?.on)||globalThis[listenerKey]){
|
|
20
23
|
return;
|
|
21
24
|
}
|
|
22
25
|
|
|
@@ -26,11 +29,11 @@ function installAppearanceListener(ready){
|
|
|
26
29
|
function forwardAppearanceChange(detail={}){
|
|
27
30
|
themeBootstrapOperationSequence+=1;
|
|
28
31
|
const forwarded={
|
|
29
|
-
scheme:
|
|
30
|
-
effectiveScheme:
|
|
32
|
+
scheme:is.string(detail?.scheme)?detail.scheme:null,
|
|
33
|
+
effectiveScheme:is.string(detail?.effectiveScheme)
|
|
31
34
|
?detail.effectiveScheme
|
|
32
35
|
:null,
|
|
33
|
-
source:
|
|
36
|
+
source:is.string(detail?.source)?detail.source:null,
|
|
34
37
|
reason:'host-appearance-changed'
|
|
35
38
|
};
|
|
36
39
|
themeBootstrapEvents.dispatch(
|
|
@@ -56,7 +59,7 @@ function installAppearanceListener(ready){
|
|
|
56
59
|
return false;
|
|
57
60
|
}
|
|
58
61
|
active=false;
|
|
59
|
-
if(
|
|
62
|
+
if(is.function(hostUnsubscribe)){
|
|
60
63
|
hostUnsubscribe();
|
|
61
64
|
}
|
|
62
65
|
if(globalThis[listenerKey]===dispose){
|
|
@@ -94,7 +97,7 @@ export function bootstrapArcaneTheme(options={}){
|
|
|
94
97
|
|
|
95
98
|
export function disposeArcaneThemeBootstrap(){
|
|
96
99
|
const dispose=globalThis[listenerKey];
|
|
97
|
-
return
|
|
100
|
+
return is.function(dispose)?dispose():false;
|
|
98
101
|
}
|
|
99
102
|
|
|
100
103
|
export const arcaneThemeReady=bootstrapArcaneTheme();
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
2
|
+
const is=new Is(false);
|
|
3
|
+
|
|
1
4
|
import Theme,{arcaneDarkThemeTokens,arcaneLightThemeTokens} from '../entities/Theme.js';
|
|
2
5
|
import PreferenceStore from './PreferenceStore.js';
|
|
3
6
|
import {applyAppearancePreferences,createAppearancePreferenceStore} from './AppearancePreferences.js';
|
|
@@ -135,8 +138,8 @@ export default class ThemeManager{
|
|
|
135
138
|
publicDetail:{mode:detail.mode,reason}
|
|
136
139
|
}
|
|
137
140
|
);
|
|
138
|
-
if(
|
|
139
|
-
&&
|
|
141
|
+
if(is.function(globalThis.CustomEvent)
|
|
142
|
+
&&is.function(globalThis.dispatchEvent)){
|
|
140
143
|
projectArcaneDOMEvent(globalThis,occurrence);
|
|
141
144
|
}
|
|
142
145
|
return occurrence;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
2
|
+
const is=new Is(false);
|
|
3
|
+
|
|
1
4
|
import { arcaneLogging } from 'arcane-os/logging';
|
|
2
5
|
function parseArguments(value,name=''){
|
|
3
6
|
let parsed=value;
|
|
4
|
-
if(
|
|
7
|
+
if(is.string(parsed)){
|
|
5
8
|
try{
|
|
6
9
|
parsed=JSON.parse(parsed);
|
|
7
10
|
}catch(error){
|
|
@@ -9,15 +12,15 @@ function parseArguments(value,name=''){
|
|
|
9
12
|
throw new Error(`Tool ${name} returned invalid JSON arguments.`);
|
|
10
13
|
}
|
|
11
14
|
}
|
|
12
|
-
const prototype=parsed&&
|
|
15
|
+
const prototype=parsed&&is.object(parsed)
|
|
13
16
|
?Object.getPrototypeOf(parsed)
|
|
14
17
|
:undefined;
|
|
15
18
|
if(
|
|
16
19
|
!parsed
|
|
17
|
-
|
|
18
|
-
||
|
|
20
|
+
||!is.object(parsed)
|
|
21
|
+
||is.array(parsed)
|
|
19
22
|
||(prototype!==Object.prototype&&prototype!==null)
|
|
20
|
-
|
|
23
|
+
||!is.string(parsed.message)
|
|
21
24
|
||!parsed.message.trim()
|
|
22
25
|
){
|
|
23
26
|
const error=new Error(
|
|
@@ -32,7 +35,7 @@ function parseArguments(value,name=''){
|
|
|
32
35
|
function getResponseCalls(response={}){
|
|
33
36
|
const calls=response?.choices?.[0]?.message?.tool_calls;
|
|
34
37
|
|
|
35
|
-
if(!
|
|
38
|
+
if(!is.array(calls)||!calls.length){
|
|
36
39
|
throw new Error('AI response did not contain a tool call.');
|
|
37
40
|
}
|
|
38
41
|
|
|
@@ -40,7 +43,7 @@ function getResponseCalls(response={}){
|
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
function dispatch(name='',argumentsValue='',handlers={}){
|
|
43
|
-
if(
|
|
46
|
+
if(!is.function(handlers[name])){
|
|
44
47
|
throw new Error(`No handler is registered for tool ${name}.`);
|
|
45
48
|
}
|
|
46
49
|
|
|
@@ -75,7 +78,7 @@ async function handleResponse(response={},handlers={}){
|
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
async function handleStreamedCalls(calls={},handlers={}){
|
|
78
|
-
if(!calls
|
|
81
|
+
if(!calls||!is.object(calls)||is.array(calls)){
|
|
79
82
|
throw new Error('Streamed tool calls must be an object.');
|
|
80
83
|
}
|
|
81
84
|
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
2
|
+
const is=new Is(false);
|
|
3
|
+
|
|
1
4
|
const componentWaitErrorCodes={
|
|
2
5
|
abortSignalInvalid:'ARCANE_COMPONENT_READINESS_ABORT_SIGNAL_INVALID',
|
|
3
6
|
elementRequired:'ARCANE_COMPONENT_READINESS_ELEMENT_REQUIRED',
|
|
@@ -34,7 +37,7 @@ export const COMPONENT_WAIT_ERROR_CODES={...componentWaitErrorCodes};
|
|
|
34
37
|
export const COMPONENT_WAIT_REASONS={...componentWaitReasons};
|
|
35
38
|
|
|
36
39
|
function defineComponentWaitError(error,code,reason,cause){
|
|
37
|
-
const priorCode=
|
|
40
|
+
const priorCode=is.string(error?.code)&&error.code
|
|
38
41
|
?error.code
|
|
39
42
|
:null;
|
|
40
43
|
try{
|
|
@@ -102,7 +105,7 @@ function componentWaitAbortError(reason){
|
|
|
102
105
|
}
|
|
103
106
|
|
|
104
107
|
function waitForComponent(element,options={}){
|
|
105
|
-
if(!options
|
|
108
|
+
if(!options||!is.object(options)||is.array(options)){
|
|
106
109
|
return Promise.reject(
|
|
107
110
|
componentWaitError(
|
|
108
111
|
'Component readiness wait options must be an object.',
|
|
@@ -121,13 +124,13 @@ function waitForComponent(element,options={}){
|
|
|
121
124
|
timeoutMs=0
|
|
122
125
|
}=options;
|
|
123
126
|
|
|
124
|
-
if(
|
|
125
|
-
||!
|
|
127
|
+
if(!is.string(errorEvent)
|
|
128
|
+
||!is.array(methods)
|
|
126
129
|
||methods.some(function invalidComponentMethod(method){
|
|
127
|
-
return
|
|
130
|
+
return !is.string(method)||method.trim().length<1;
|
|
128
131
|
})
|
|
129
|
-
|
|
130
|
-
|
|
132
|
+
||!is.string(property)
|
|
133
|
+
||!is.string(event)){
|
|
131
134
|
return Promise.reject(
|
|
132
135
|
componentWaitError(
|
|
133
136
|
'Component readiness event, errorEvent, property, and methods options are invalid.',
|
|
@@ -137,7 +140,7 @@ function waitForComponent(element,options={}){
|
|
|
137
140
|
)
|
|
138
141
|
);
|
|
139
142
|
}
|
|
140
|
-
if(!
|
|
143
|
+
if(!is.finite(timeoutMs)||timeoutMs<0){
|
|
141
144
|
return Promise.reject(
|
|
142
145
|
componentWaitError(
|
|
143
146
|
'timeoutMs must be a non-negative finite number.',
|
|
@@ -149,10 +152,10 @@ function waitForComponent(element,options={}){
|
|
|
149
152
|
}
|
|
150
153
|
if(signal!==null
|
|
151
154
|
&&(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
155
|
+
!is.object(signal)
|
|
156
|
+
||!is.boolean(signal.aborted)
|
|
157
|
+
||!is.function(signal.addEventListener)
|
|
158
|
+
||!is.function(signal.removeEventListener)
|
|
156
159
|
)){
|
|
157
160
|
return Promise.reject(
|
|
158
161
|
componentWaitError(
|
|
@@ -211,7 +214,7 @@ function waitForComponent(element,options={}){
|
|
|
211
214
|
}
|
|
212
215
|
|
|
213
216
|
return methods.every(function componentMethodAvailable(method){
|
|
214
|
-
return
|
|
217
|
+
return is.function(element[method]);
|
|
215
218
|
});
|
|
216
219
|
}
|
|
217
220
|
|
|
@@ -294,7 +297,7 @@ function waitForComponent(element,options={}){
|
|
|
294
297
|
const error=new Error(
|
|
295
298
|
detail?.message||'The component reported a loading error.'
|
|
296
299
|
);
|
|
297
|
-
const componentCode=
|
|
300
|
+
const componentCode=is.string(detail?.code)
|
|
298
301
|
&&detail.code.trim()
|
|
299
302
|
?detail.code
|
|
300
303
|
:null;
|
|
@@ -335,8 +338,8 @@ function waitForComponent(element,options={}){
|
|
|
335
338
|
}
|
|
336
339
|
if((event||errorEvent)
|
|
337
340
|
&&(
|
|
338
|
-
|
|
339
|
-
|
|
341
|
+
!is.function(element.addEventListener)
|
|
342
|
+
||!is.function(element.removeEventListener)
|
|
340
343
|
)){
|
|
341
344
|
fail(
|
|
342
345
|
componentWaitError(
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
2
|
+
const is=new Is(false);
|
|
3
|
+
|
|
1
4
|
const RAW_ID=/^[A-Za-z0-9_-]+$/;
|
|
2
5
|
export function parseYouTubeMedia(value){
|
|
3
6
|
const raw=String(value||'').trim();if(!raw)throw new TypeError('Enter a YouTube video or playlist URL.');let url;
|
|
@@ -14,4 +17,4 @@ export function parseYouTubeMedia(value){
|
|
|
14
17
|
if(playlist)return {type:'playlist',id:playlist};
|
|
15
18
|
throw new TypeError('The address does not contain a supported video or playlist id.');
|
|
16
19
|
}
|
|
17
|
-
export function youtubeEmbedUrl(locator,{privacyEnhanced=false}={}){const item=
|
|
20
|
+
export function youtubeEmbedUrl(locator,{privacyEnhanced=false}={}){const item=is.string(locator)?parseYouTubeMedia(locator):locator;const origin=privacyEnhanced?'https://www.youtube-nocookie.com':'https://www.youtube.com';if(item.type==='playlist')return `${origin}/embed?listType=playlist&list=${encodeURIComponent(item.id)}`;const url=new URL(`${origin}/embed/${encodeURIComponent(item.id)}`);if(item.playlist)url.searchParams.set('list',item.playlist);url.searchParams.set('playsinline','1');return url.href;}
|