arcane-os 0.40.0 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/NOTICE +3 -0
- package/README.md +1 -1
- package/browser-runtime/ai/browser-speech.mjs +4 -1
- package/browser-runtime/ai/digitalocean-speech.mjs +2 -468
- package/browser-runtime/ai/speech-worker-runtime.mjs +2 -3
- package/browser-runtime/ai/twin-cloud-speech.mjs +587 -0
- package/browser-runtime/dependencies/js-queue/licence.md +21 -0
- package/browser-runtime/dependencies/js-queue/package.json +100 -0
- package/browser-runtime/dependencies/js-queue/queue.js +78 -0
- package/docs/reference/ai/browser-speech.md +60 -14
- package/docs/reference/inventory/package-api.json +18 -4
- package/docs/reference/pwa.md +16 -1
- package/docs/reference/runtime-components.md +14 -4
- package/docs/reference/sdk-api.md +75 -17
- package/package.json +2 -1
- package/runtime/arcane/components/speech.html +17 -18
- package/src/dev-server.mjs +19 -11
- package/src/import-map.mjs +20 -1
- package/src/packager/core.mjs +8 -5
- package/src/toolchain.mjs +11 -1
|
@@ -518,7 +518,7 @@
|
|
|
518
518
|
requestUserMute();
|
|
519
519
|
} else {
|
|
520
520
|
pendingUnmute = true;
|
|
521
|
-
host.muted =
|
|
521
|
+
host.muted = false;
|
|
522
522
|
if (!settleSuccessfulUnmute()) {
|
|
523
523
|
synchronizeAIMutedState();
|
|
524
524
|
continuePendingUnmute();
|
|
@@ -567,21 +567,24 @@
|
|
|
567
567
|
if (sttBecameUnready) {
|
|
568
568
|
cancelSTTOperation('runtime-unready');
|
|
569
569
|
}
|
|
570
|
-
if (ttsBecameUnready) {
|
|
570
|
+
if (ttsBecameUnready && ttsRole.state !== 'error') {
|
|
571
571
|
pendingUnmute = false;
|
|
572
|
-
host.muted = true;
|
|
573
572
|
stopTTSPlayback();
|
|
574
573
|
}
|
|
575
|
-
if (ttsRole.state === 'error'
|
|
574
|
+
if (ttsRole.state === 'error') {
|
|
576
575
|
pendingUnmute = false;
|
|
577
|
-
host.muted = true;
|
|
578
|
-
stopTTSPlayback();
|
|
579
576
|
}
|
|
580
577
|
|
|
581
|
-
settleSuccessfulUnmute();
|
|
578
|
+
const unmuteSettled = settleSuccessfulUnmute();
|
|
582
579
|
continuePendingUnmute();
|
|
583
580
|
|
|
584
581
|
synchronizeAIMutedState();
|
|
582
|
+
if (!unmuteSettled
|
|
583
|
+
&& previousTTSRole.state !== 'ready'
|
|
584
|
+
&& ttsRole.state === 'ready'
|
|
585
|
+
&& !host.muted) {
|
|
586
|
+
resumeTTSPlayback();
|
|
587
|
+
}
|
|
585
588
|
renderControls();
|
|
586
589
|
renderStatus();
|
|
587
590
|
}
|
|
@@ -720,6 +723,9 @@
|
|
|
720
723
|
if (pendingTTSIntent === 'load') {
|
|
721
724
|
label = 'Cancel voice load';
|
|
722
725
|
description = 'Cancel loading the selected voice.';
|
|
726
|
+
} else if (!host.muted) {
|
|
727
|
+
label = 'Load voice';
|
|
728
|
+
description = 'Load the selected voice.';
|
|
723
729
|
}
|
|
724
730
|
} else if (ttsRole.state === 'error') {
|
|
725
731
|
disabled = !providerSelected;
|
|
@@ -960,7 +966,7 @@
|
|
|
960
966
|
return;
|
|
961
967
|
}
|
|
962
968
|
|
|
963
|
-
if (host.muted) {
|
|
969
|
+
if (host.muted || ['unloaded', 'error'].includes(ttsRole.state)) {
|
|
964
970
|
void requestUserUnmute();
|
|
965
971
|
} else {
|
|
966
972
|
requestUserMute();
|
|
@@ -976,7 +982,7 @@
|
|
|
976
982
|
}
|
|
977
983
|
const wasMuted = host.muted;
|
|
978
984
|
pendingUnmute = false;
|
|
979
|
-
const shouldUnload = !wasMuted
|
|
985
|
+
const shouldUnload = (!wasMuted && is.function(globalThis.ai?.setSpeechMuted))
|
|
980
986
|
|| pendingTTSIntent === 'load'
|
|
981
987
|
|| ['loading', 'ready', 'error'].includes(ttsRole.state);
|
|
982
988
|
host.muted = true;
|
|
@@ -1004,9 +1010,9 @@
|
|
|
1004
1010
|
) {
|
|
1005
1011
|
return false;
|
|
1006
1012
|
}
|
|
1013
|
+
host.muted = false;
|
|
1007
1014
|
if (!is.function(globalThis.ai?.setSpeechMuted)) {
|
|
1008
1015
|
pendingUnmute = true;
|
|
1009
|
-
host.muted = true;
|
|
1010
1016
|
renderControls();
|
|
1011
1017
|
renderStatus();
|
|
1012
1018
|
return false;
|
|
@@ -1021,8 +1027,7 @@
|
|
|
1021
1027
|
&& ['unloaded', 'loading', 'error'].includes(ttsRole.state)
|
|
1022
1028
|
);
|
|
1023
1029
|
if (!canRequestLoad) {
|
|
1024
|
-
|
|
1025
|
-
stopTTSPlayback();
|
|
1030
|
+
pendingUnmute = false;
|
|
1026
1031
|
reportTTSLifecycleError(
|
|
1027
1032
|
new Error('No selected speech provider is available to load.'),
|
|
1028
1033
|
'load'
|
|
@@ -1038,8 +1043,6 @@
|
|
|
1038
1043
|
}
|
|
1039
1044
|
if (!requested) {
|
|
1040
1045
|
pendingUnmute = false;
|
|
1041
|
-
host.muted = true;
|
|
1042
|
-
stopTTSPlayback();
|
|
1043
1046
|
renderControls();
|
|
1044
1047
|
renderStatus();
|
|
1045
1048
|
return false;
|
|
@@ -1117,8 +1120,6 @@
|
|
|
1117
1120
|
pendingTTSIntent = null;
|
|
1118
1121
|
if (action === 'load') {
|
|
1119
1122
|
pendingUnmute = false;
|
|
1120
|
-
host.muted = true;
|
|
1121
|
-
stopTTSPlayback();
|
|
1122
1123
|
}
|
|
1123
1124
|
reportTTSLifecycleError(error, action, operationId);
|
|
1124
1125
|
return false;
|
|
@@ -1211,8 +1212,6 @@
|
|
|
1211
1212
|
: 'synthesis';
|
|
1212
1213
|
const failure = failures[normalizedBoundary];
|
|
1213
1214
|
const message = visibleErrorMessage(error, failure.message);
|
|
1214
|
-
host.muted = true;
|
|
1215
|
-
stopTTSPlayback();
|
|
1216
1215
|
localStatus = {
|
|
1217
1216
|
message,
|
|
1218
1217
|
tone: 'error'
|
package/src/dev-server.mjs
CHANGED
|
@@ -13,7 +13,7 @@ import {APP_CONFIG_NAME, validateAppConfig} from './packager/core.mjs';
|
|
|
13
13
|
import {createEventQueue} from './event-queue.mjs';
|
|
14
14
|
import {
|
|
15
15
|
applyPwaEntryReferences,inspectImportMapHtml,MANAGED_IMPORT_MAP_ATTRIBUTE,
|
|
16
|
-
readWorkspaceAssetVersion,rewriteAssetReferences,versionAssetUrl
|
|
16
|
+
readWorkspaceAssetVersion,resolveAssetReference,rewriteAssetReferences,versionAssetUrl
|
|
17
17
|
} from './import-map.mjs';
|
|
18
18
|
import {createPwaArtifacts,selectPwaFiles} from './pwa.mjs';
|
|
19
19
|
|
|
@@ -658,14 +658,15 @@ async function sourcePwaAssets(routeSet, mappings, signal, resourceUrls, resourc
|
|
|
658
658
|
}
|
|
659
659
|
}
|
|
660
660
|
}
|
|
661
|
-
for (const
|
|
661
|
+
for (const reference of references) {
|
|
662
|
+
const {url, kind} = reference;
|
|
662
663
|
if (kind === 'import' && !/^(?:\.{1,2}\/|\/)/u.test(url)) continue;
|
|
663
664
|
let target;
|
|
664
|
-
let base;
|
|
665
665
|
try {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
666
|
+
target = resolveAssetReference(
|
|
667
|
+
{...reference, url: versionAssetUrl(url, null)},
|
|
668
|
+
{ownerUrl: current.url, documentUrl, managedMap}
|
|
669
|
+
);
|
|
669
670
|
} catch {
|
|
670
671
|
// Non-URL source values retain their authored behavior.
|
|
671
672
|
continue;
|
|
@@ -695,6 +696,11 @@ async function sourcePwaAssets(routeSet, mappings, signal, resourceUrls, resourc
|
|
|
695
696
|
return [...selectedUrls].sort();
|
|
696
697
|
}
|
|
697
698
|
|
|
699
|
+
export async function collectSourcePwaAssets({workspaceRoot,appId,signal,onEvent}={}){
|
|
700
|
+
const routes=await sourceRoutes(workspaceRoot,appId,{signal,onEvent});
|
|
701
|
+
return sourcePwaAssets(routes,routes.mappings,signal,new Set(),new Set());
|
|
702
|
+
}
|
|
703
|
+
|
|
698
704
|
function closeDevelopmentListeners(fileServer, tlsServer) {
|
|
699
705
|
const closeTls = tlsServer ? new Promise(
|
|
700
706
|
function closeRawTlsListener(resolve, reject) {
|
|
@@ -1236,13 +1242,16 @@ async function startOwnedDevServer({
|
|
|
1236
1242
|
.includes(request.headers['sec-fetch-dest']);
|
|
1237
1243
|
const rewrite=runtimeResource||entryDocument||browserResource||managedMap
|
|
1238
1244
|
||resourcePaths.has(target.path);
|
|
1239
|
-
const onReference = function observeServedResource(
|
|
1245
|
+
const onReference = function observeServedResource(reference) {
|
|
1246
|
+
const {url,kind,baseKind}=reference;
|
|
1240
1247
|
if (pwaEnabled && kind !== 'fetch'
|
|
1241
1248
|
&& !(kind === 'import' && !/^(?:\.{1,2}\/|\/)/u.test(url))) {
|
|
1242
1249
|
try {
|
|
1243
1250
|
const documentUrl = new URL(target.path, 'http://arcane.invalid');
|
|
1244
|
-
const
|
|
1245
|
-
|
|
1251
|
+
const resource = resolveAssetReference(
|
|
1252
|
+
{...reference,url:versionAssetUrl(url,null)},
|
|
1253
|
+
{ownerUrl:documentUrl}
|
|
1254
|
+
);
|
|
1246
1255
|
if (resource.origin === documentUrl.origin) {
|
|
1247
1256
|
pwaResourceUrls.add(`${resource.pathname}${resource.search}`);
|
|
1248
1257
|
}
|
|
@@ -1254,8 +1263,7 @@ async function startOwnedDevServer({
|
|
|
1254
1263
|
||(kind==='import'&&!/^(?:\.{1,2}\/|\/)/u.test(url)))return;
|
|
1255
1264
|
try{
|
|
1256
1265
|
const documentUrl=new URL(target.path,'http://arcane.invalid');
|
|
1257
|
-
const
|
|
1258
|
-
const resource=new URL(url,base);
|
|
1266
|
+
const resource=resolveAssetReference(reference,{ownerUrl:documentUrl});
|
|
1259
1267
|
if(resource.origin===documentUrl.origin
|
|
1260
1268
|
&&/\.(?:m?js|html?|css)$/iu.test(resource.pathname)){
|
|
1261
1269
|
resourcePaths.add(decodeURIComponent(resource.pathname));
|
package/src/import-map.mjs
CHANGED
|
@@ -1281,6 +1281,23 @@ export function rewriteAssetReferences(source,{filePath,version=SDK_VERSION,onRe
|
|
|
1281
1281
|
return source;
|
|
1282
1282
|
}
|
|
1283
1283
|
|
|
1284
|
+
export function resolveAssetReference({url,baseHref,baseKind},{ownerUrl,documentUrl=ownerUrl,managedMap=false}){
|
|
1285
|
+
if(baseKind==='component-runtime'&&url.startsWith('./arcane/')){
|
|
1286
|
+
const owner=new URL(ownerUrl);
|
|
1287
|
+
const marker='/arcane/components/';
|
|
1288
|
+
const componentIndex=owner.pathname.lastIndexOf(marker);
|
|
1289
|
+
if(componentIndex>=0){
|
|
1290
|
+
// HTMLImport resolves these component attributes against their
|
|
1291
|
+
// installed runtime, independently of the host document's base.
|
|
1292
|
+
const runtimeRoot=new URL(owner.pathname.slice(0,componentIndex+'/arcane/'.length),owner.origin);
|
|
1293
|
+
return new URL(url.slice('./arcane/'.length),runtimeRoot);
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
const base=baseHref?new URL(baseHref,ownerUrl)
|
|
1297
|
+
:managedMap||baseKind==='document'?documentUrl:ownerUrl;
|
|
1298
|
+
return new URL(url,base);
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1284
1301
|
function registerSpecifier(registry,specifier,target){
|
|
1285
1302
|
registry.set(specifier,{specifier,target});
|
|
1286
1303
|
}
|
|
@@ -2071,7 +2088,9 @@ function htmlReferenceEdits(source,version,onReference){
|
|
|
2071
2088
|
:element.tag==='link'&&relationships.includes('preload')
|
|
2072
2089
|
&&['script','worker','style'].includes(destination)?destination==='style'?'style':'script':'asset';
|
|
2073
2090
|
const view=htmlAttributeView(original);
|
|
2074
|
-
if(view)reportAssetReference(reportHtmlReference,view.decoded,kind
|
|
2091
|
+
if(view)reportAssetReference(reportHtmlReference,view.decoded,kind,
|
|
2092
|
+
(name==='href'||name==='src')&&view.decoded.startsWith('./arcane/')
|
|
2093
|
+
?'component-runtime':undefined);
|
|
2075
2094
|
const value=versionHtmlAttribute(original,version);
|
|
2076
2095
|
if(value===original)continue;
|
|
2077
2096
|
const position=attributes.positions.get(name);
|
package/src/packager/core.mjs
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
applyPwaEntryReferences,
|
|
20
20
|
inspectImportMapHtml,
|
|
21
21
|
readWorkspaceAssetVersion,
|
|
22
|
+
resolveAssetReference,
|
|
22
23
|
rewriteAssetReferences,
|
|
23
24
|
versionAssetUrl
|
|
24
25
|
} from '../import-map.mjs';
|
|
@@ -967,17 +968,19 @@ async function packageWithContext(context,options={}){
|
|
|
967
968
|
resource={references,...(pwaDocumentSources.has(relative)?{content}:{})};
|
|
968
969
|
resources.set(relative,resource);
|
|
969
970
|
}
|
|
970
|
-
for(const
|
|
971
|
+
for(const reference of resource.references){
|
|
972
|
+
const {url,kind,baseHref}=reference;
|
|
971
973
|
const traversable=kind!=='fetch'&&(kind!=='asset'||/\.css(?:[?#]|$)/iu.test(url))
|
|
972
974
|
&&(kind!=='import'||/^(?:\.{1,2}\/|\/)/u.test(url));
|
|
973
975
|
if(!pwaEnabled&&!traversable)continue;
|
|
974
976
|
if(kind==='import'&&!/^(?:\.{1,2}\/|\/)/u.test(url))continue;
|
|
975
977
|
try{
|
|
976
978
|
const ownerUrl=new URL(packageResourceUrl(relative),entryUrl.origin);
|
|
977
|
-
const
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
979
|
+
const target=resolveAssetReference(reference,{
|
|
980
|
+
ownerUrl,
|
|
981
|
+
documentUrl:current.documentUrl,
|
|
982
|
+
managedMap:path.posix.basename(relative)==='arcane.importmap.json'
|
|
983
|
+
});
|
|
981
984
|
if(target.origin===entryUrl.origin){
|
|
982
985
|
const file=decodeURIComponent(target.pathname).replace(/^\//u,'');
|
|
983
986
|
if(pwaEnabled&&offlineInventory.has(file)){
|
package/src/toolchain.mjs
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
validateWorkspace
|
|
12
12
|
} from './workspace.mjs';
|
|
13
13
|
import {loadArcaneIntegratedProvider} from './integrated-provider-loader.mjs';
|
|
14
|
-
import {startDevServer} from './dev-server.mjs';
|
|
14
|
+
import {collectSourcePwaAssets,startDevServer} from './dev-server.mjs';
|
|
15
15
|
import {applyPwaEntryReferences,generateImportMap,readApplicationTestImportMapContext} from './import-map.mjs';
|
|
16
16
|
import {createPwaArtifacts} from './pwa.mjs';
|
|
17
17
|
import {readInstalledSdkLayout} from './sdk-runtime-layout.mjs';
|
|
@@ -337,11 +337,21 @@ async function refreshRootApplicationFiles(prepared,inspected,importMap,{signal,
|
|
|
337
337
|
...inspected.files.filter(file=>file!=='index.html'||manifest.include.includes('index.html')),
|
|
338
338
|
importMap.artifactRelativePath
|
|
339
339
|
])];
|
|
340
|
+
const sourceOrigin='http://arcane.invalid';
|
|
341
|
+
const selectedPaths=new Set(files.map(function selectedStaticPath(file){
|
|
342
|
+
return new URL(`/${file.split('/').map(encodeURIComponent).join('/')}`,sourceOrigin).pathname;
|
|
343
|
+
}));
|
|
344
|
+
const assets=installed?.direct&&manifest.pwa?.enabled
|
|
345
|
+
?(await collectSourcePwaAssets({workspaceRoot,appId,signal,onEvent})).filter(function selectedStaticVariant(value){
|
|
346
|
+
const url=new URL(value,sourceOrigin);
|
|
347
|
+
return url.origin===sourceOrigin&&selectedPaths.has(url.pathname);
|
|
348
|
+
}):[];
|
|
340
349
|
const pwa=installed?.direct&&manifest.pwa?.enabled?createPwaArtifacts({
|
|
341
350
|
app:{id:appId,displayName:manifest.displayName,version:manifest.version,entry},
|
|
342
351
|
sdkVersion:installed.version,
|
|
343
352
|
pwa:manifest.pwa,
|
|
344
353
|
files,
|
|
354
|
+
assets,
|
|
345
355
|
basePath:'/',
|
|
346
356
|
appBase:'/',
|
|
347
357
|
installationId:`/apps/${appId}/`,
|