arcane-os 0.1.0-dev.5
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 +154 -0
- package/COMMERCIAL-LICENSE.md +13 -0
- package/LICENSE +661 -0
- package/NOTICE +70 -0
- package/README.md +448 -0
- package/bin/arcane-test.mjs +741 -0
- package/bin/arcane.mjs +5 -0
- package/docs/architecture.md +234 -0
- package/docs/compatibility.md +36 -0
- package/docs/event-manager.md +166 -0
- package/docs/platform-targets.md +108 -0
- package/docs/publishing.md +203 -0
- package/docs/reference/README.md +117 -0
- package/docs/reference/arcane-ollama.md +288 -0
- package/docs/reference/availability-and-normalization.md +123 -0
- package/docs/reference/behavioral-testing.md +86 -0
- package/docs/reference/cli.md +569 -0
- package/docs/reference/core/README.md +62 -0
- package/docs/reference/core/arcane-ai-contracts.md +873 -0
- package/docs/reference/core/arcane-api.md +601 -0
- package/docs/reference/core/arcane-entities.md +65 -0
- package/docs/reference/core/arcane-events.md +134 -0
- package/docs/reference/core/ollama-module.md +181 -0
- package/docs/reference/core/reference/arcane-api/ai-and-ollama.md +1909 -0
- package/docs/reference/core/reference/arcane-api/applications-terminal-capabilities.md +1057 -0
- package/docs/reference/core/reference/arcane-api/core-and-events.md +320 -0
- package/docs/reference/core/reference/arcane-api/filesystem-storage-preferences-appearance.md +610 -0
- package/docs/reference/core/reference/arcane-api/namespaces.md +1157 -0
- package/docs/reference/core/reference/arcane-api/platform-installation-users-system.md +1423 -0
- package/docs/reference/core/reference/arcane-api/session-provisioning-diagnostics-development.md +315 -0
- package/docs/reference/event-manager.md +957 -0
- package/docs/reference/inventory/package-api.json +2632 -0
- package/docs/reference/inventory/runtime-components.json +934 -0
- package/docs/reference/inventory/runtime-entities.json +26 -0
- package/docs/reference/inventory/runtime-modules.json +1249 -0
- package/docs/reference/protocols.md +242 -0
- package/docs/reference/runtime-components.md +1098 -0
- package/docs/reference/runtime-entities.md +303 -0
- package/docs/reference/runtime-modules.md +2010 -0
- package/docs/reference/sdk-api.md +4901 -0
- package/docs/roadmap.md +79 -0
- package/docs/work-amplification.md +124 -0
- package/node_modules/event-pubsub/CHANGELOG.md +55 -0
- package/node_modules/event-pubsub/MIGRATION.md +70 -0
- package/node_modules/event-pubsub/README.md +363 -0
- package/node_modules/event-pubsub/SECURITY.md +37 -0
- package/node_modules/event-pubsub/index.js +141 -0
- package/node_modules/event-pubsub/licence +21 -0
- package/node_modules/event-pubsub/package.json +59 -0
- package/node_modules/strong-type/README.md +408 -0
- package/node_modules/strong-type/assets/strong-type-header.png +0 -0
- package/node_modules/strong-type/index.js +1151 -0
- package/node_modules/strong-type/licence +21 -0
- package/node_modules/strong-type/node.js +125 -0
- package/node_modules/strong-type/package.json +61 -0
- package/package.json +95 -0
- package/runtime/ARCANE_RUNTIME_RELEASE.json +791 -0
- package/runtime/arcane/components/app-bar.html +468 -0
- package/runtime/arcane/components/assistant-panel.html +715 -0
- package/runtime/arcane/components/calculator.html +8 -0
- package/runtime/arcane/components/chart.html +655 -0
- package/runtime/arcane/components/chat.html +1225 -0
- package/runtime/arcane/components/conversation-view.html +13 -0
- package/runtime/arcane/components/dashboard-config.html +341 -0
- package/runtime/arcane/components/data-maintenance.html +112 -0
- package/runtime/arcane/components/data-view.html +92 -0
- package/runtime/arcane/components/directory-picker.html +197 -0
- package/runtime/arcane/components/document-inspector.html +252 -0
- package/runtime/arcane/components/file-drop.html +264 -0
- package/runtime/arcane/components/file-inspector.html +293 -0
- package/runtime/arcane/components/file-manager.html +1715 -0
- package/runtime/arcane/components/header.html +142 -0
- package/runtime/arcane/components/integration-settings.html +14 -0
- package/runtime/arcane/components/local-ai-status.html +360 -0
- package/runtime/arcane/components/markdown-document.html +1048 -0
- package/runtime/arcane/components/markdown-editor.html +360 -0
- package/runtime/arcane/components/media-embed.html +8 -0
- package/runtime/arcane/components/modal.html +402 -0
- package/runtime/arcane/components/output-panel.html +259 -0
- package/runtime/arcane/components/preferences-form.html +135 -0
- package/runtime/arcane/components/record-timeline.html +105 -0
- package/runtime/arcane/components/relationship-board.html +116 -0
- package/runtime/arcane/components/screen-capture.html +8 -0
- package/runtime/arcane/components/source-code-viewer.html +441 -0
- package/runtime/arcane/components/source-explanation.html +124 -0
- package/runtime/arcane/components/speech.html +365 -0
- package/runtime/arcane/components/summary-strip.html +177 -0
- package/runtime/arcane/components/table.html +77 -0
- package/runtime/arcane/components/task-progress.html +282 -0
- package/runtime/arcane/components/terminal-workspace.html +65 -0
- package/runtime/arcane/components/theme-editor.html +41 -0
- package/runtime/arcane/components/theme-switcher.html +46 -0
- package/runtime/arcane/components/unified-inbox.html +20 -0
- package/runtime/arcane/components/voice-transcription.html +476 -0
- package/runtime/arcane/components/weather-widget.html +8 -0
- package/runtime/arcane/components/web-navigator.html +239 -0
- package/runtime/arcane/css/communications.css +1 -0
- package/runtime/arcane/css/dashboard-config.css +45 -0
- package/runtime/arcane/css/document-site.css +981 -0
- package/runtime/arcane/css/layout.css +438 -0
- package/runtime/arcane/css/primitives.css +321 -0
- package/runtime/arcane/css/theme.css +112 -0
- package/runtime/arcane/css/utility-workspace.css +1 -0
- package/runtime/arcane/entities/ApiModelRecord.js +20 -0
- package/runtime/arcane/entities/Calculation.js +13 -0
- package/runtime/arcane/entities/Chat.js +581 -0
- package/runtime/arcane/entities/CommunicationMessage.js +29 -0
- package/runtime/arcane/entities/CommunicationThread.js +21 -0
- package/runtime/arcane/entities/Document.js +10 -0
- package/runtime/arcane/entities/File.js +143 -0
- package/runtime/arcane/entities/Image.js +135 -0
- package/runtime/arcane/entities/IntentEnvelope.js +834 -0
- package/runtime/arcane/entities/Preference.js +83 -0
- package/runtime/arcane/entities/TWiNPolicyDecision.js +1092 -0
- package/runtime/arcane/entities/TerminalSession.js +46 -0
- package/runtime/arcane/entities/Theme.js +107 -0
- package/runtime/arcane/entities/User.js +1046 -0
- package/runtime/arcane/entities/Weather.js +23 -0
- package/runtime/arcane/img/arcane-os-everywhere.png +0 -0
- package/runtime/arcane/img/arrow-left.png +0 -0
- package/runtime/arcane/img/arrow-right.png +0 -0
- package/runtime/arcane/img/doc.svg +5 -0
- package/runtime/arcane/img/folder.svg +4 -0
- package/runtime/arcane/img/image.svg +5 -0
- package/runtime/arcane/img/refresh.png +0 -0
- package/runtime/arcane/img/send.svg +9 -0
- package/runtime/arcane/img/trash.svg +5 -0
- package/runtime/arcane/img/upload.svg +5 -0
- package/runtime/arcane/modules/AI.js +2048 -0
- package/runtime/arcane/modules/AIPreferenceRuntime.js +32 -0
- package/runtime/arcane/modules/AIPreferenceTuple.js +92 -0
- package/runtime/arcane/modules/AIResponseLength.js +42 -0
- package/runtime/arcane/modules/AIResponseURLPolicy.js +626 -0
- package/runtime/arcane/modules/AnsiText.js +53 -0
- package/runtime/arcane/modules/ApiModelDatabase.js +25 -0
- package/runtime/arcane/modules/AppDataScope.js +245 -0
- package/runtime/arcane/modules/AppearancePreferences.js +28 -0
- package/runtime/arcane/modules/ArcaneCommunicationBridge.js +22 -0
- package/runtime/arcane/modules/ArcaneNavigationPolicy.js +135 -0
- package/runtime/arcane/modules/ArcaneNetworkPolicy.js +255 -0
- package/runtime/arcane/modules/AsyncBoundary.js +161 -0
- package/runtime/arcane/modules/BrowserTestSuite.js +326 -0
- package/runtime/arcane/modules/CalculatorEngine.js +20 -0
- package/runtime/arcane/modules/CaseEvidenceIndexer.js +134 -0
- package/runtime/arcane/modules/ChartLibrary.js +35 -0
- package/runtime/arcane/modules/ChatRecords.js +13 -0
- package/runtime/arcane/modules/CommunicationAppController.js +43 -0
- package/runtime/arcane/modules/CommunicationHub.js +16 -0
- package/runtime/arcane/modules/CommunicationPreferences.js +13 -0
- package/runtime/arcane/modules/CommunicationProviderRegistry.js +16 -0
- package/runtime/arcane/modules/ComponentContracts.js +586 -0
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +288 -0
- package/runtime/arcane/modules/ConversationActionItems.js +488 -0
- package/runtime/arcane/modules/ConversationClosingReport.js +274 -0
- package/runtime/arcane/modules/ConversationTimebox.js +527 -0
- package/runtime/arcane/modules/CoreLocalModelCatalog.js +255 -0
- package/runtime/arcane/modules/DBLS.js +171 -0
- package/runtime/arcane/modules/DBOPFS.js +1154 -0
- package/runtime/arcane/modules/DBOPFSWorker.js +116 -0
- package/runtime/arcane/modules/DataMaintenance.js +91 -0
- package/runtime/arcane/modules/DevelopmentWorkspace.js +74 -0
- package/runtime/arcane/modules/DirectoryPicker.js +109 -0
- package/runtime/arcane/modules/DocumentNavigation.js +223 -0
- package/runtime/arcane/modules/Errors.js +1025 -0
- package/runtime/arcane/modules/GifEncoder.js +29 -0
- package/runtime/arcane/modules/HTMLImport.js +114 -0
- package/runtime/arcane/modules/InMemoryCommunicationProvider.js +14 -0
- package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +275 -0
- package/runtime/arcane/modules/LocalAIReadiness.js +870 -0
- package/runtime/arcane/modules/LocalAIReadinessController.js +156 -0
- package/runtime/arcane/modules/MD.js +111 -0
- package/runtime/arcane/modules/Mail.js +352 -0
- package/runtime/arcane/modules/MailTransport.mjs +180 -0
- package/runtime/arcane/modules/Marked.min.js +71 -0
- package/runtime/arcane/modules/MemoryRecords.js +44 -0
- package/runtime/arcane/modules/MessageAdvisory.js +38 -0
- package/runtime/arcane/modules/ModelDefinition.js +189 -0
- package/runtime/arcane/modules/Ollama.js +74 -0
- package/runtime/arcane/modules/OllamaModelIdentifier.js +21 -0
- package/runtime/arcane/modules/OllamaSettings.js +24 -0
- package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +14 -0
- package/runtime/arcane/modules/PreferenceStore.js +109 -0
- package/runtime/arcane/modules/QRCode.min.js +1 -0
- package/runtime/arcane/modules/Questionnaire.js +61 -0
- package/runtime/arcane/modules/RecordLinkIndex.js +24 -0
- package/runtime/arcane/modules/RecordPassageIndex.js +222 -0
- package/runtime/arcane/modules/RecordReviewStore.js +94 -0
- package/runtime/arcane/modules/RevocableProjectionLedger.js +1623 -0
- package/runtime/arcane/modules/RiskSignalAnalyzer.js +37 -0
- package/runtime/arcane/modules/ScamRiskPolicy.js +62 -0
- package/runtime/arcane/modules/ScopedOPFSCache.js +183 -0
- package/runtime/arcane/modules/ScreenCapture.js +20 -0
- package/runtime/arcane/modules/SpeechPlayback.js +581 -0
- package/runtime/arcane/modules/StaticDocumentCatalog.js +1248 -0
- package/runtime/arcane/modules/SystemAppearance.js +20 -0
- package/runtime/arcane/modules/SystemPlatformPresentation.js +51 -0
- package/runtime/arcane/modules/SystemToolRegistry.js +28 -0
- package/runtime/arcane/modules/TerminalClient.js +52 -0
- package/runtime/arcane/modules/TerminalCommandRegistry.js +50 -0
- package/runtime/arcane/modules/ThemeBootstrap.js +26 -0
- package/runtime/arcane/modules/ThemeManager.js +131 -0
- package/runtime/arcane/modules/TimeGuard.js +149 -0
- package/runtime/arcane/modules/ToolCallRouter.js +83 -0
- package/runtime/arcane/modules/WaitForComponent.js +102 -0
- package/runtime/arcane/modules/YouTubeMedia.js +16 -0
- package/runtime/arcane/modules/uPlot.LICENSE.txt +21 -0
- package/runtime/arcane/modules/uPlot.iife.min.js +2 -0
- package/runtime/arcane/modules/uPlot.min.css +1 -0
- package/runtime/arcane/security/arcane-network-policy.json +6 -0
- package/runtime/strong-type/index.js +352 -0
- package/runtime/strong-type/licence +21 -0
- package/runtime/strong-type/package.json +45 -0
- package/schemas/arcane-app-bundle.schema.json +125 -0
- package/schemas/arcane-app.schema.json +329 -0
- package/schemas/arcane-lock.schema.json +86 -0
- package/schemas/arcane-package.schema.json +224 -0
- package/schemas/cli-event.schema.json +122 -0
- package/schemas/event-stack.schema.json +152 -0
- package/schemas/native-build-plan.schema.json +176 -0
- package/schemas/target-adapter.schema.json +117 -0
- package/src/app-descriptor.mjs +500 -0
- package/src/cli/main.mjs +561 -0
- package/src/constants.mjs +31 -0
- package/src/dev-server.mjs +718 -0
- package/src/doctor.mjs +315 -0
- package/src/dom-event-instrumentation.mjs +594 -0
- package/src/errors.mjs +75 -0
- package/src/event-manager.mjs +1342 -0
- package/src/event-queue.mjs +138 -0
- package/src/events.mjs +219 -0
- package/src/index.mjs +177 -0
- package/src/integrated-provider-loader.mjs +432 -0
- package/src/native-plan.mjs +698 -0
- package/src/native-provider-loader.mjs +1126 -0
- package/src/packager/core.mjs +2691 -0
- package/src/process.mjs +353 -0
- package/src/release-bundle.mjs +2523 -0
- package/src/repository.mjs +90 -0
- package/src/runtime.mjs +452 -0
- package/src/scaffold.mjs +380 -0
- package/src/targets/index.mjs +436 -0
- package/src/templates/assets/app-icon.png +0 -0
- package/src/templates/workspace-template.mjs +388 -0
- package/src/testing-loader.mjs +9 -0
- package/src/testing.mjs +427 -0
- package/src/toolchain.mjs +1335 -0
- package/src/update-check.mjs +307 -0
- package/src/workspace.mjs +449 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
const APPLICATION_ID_PATTERN=/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
2
|
+
const APPLICATION_ID_MAX_LENGTH=64;
|
|
3
|
+
const APP_DATA_DIRECTORY='apps';
|
|
4
|
+
const APP_LOCAL_STORAGE_PREFIX='arcane.apps.';
|
|
5
|
+
|
|
6
|
+
function scopeError(code,message){
|
|
7
|
+
const error=new Error(message);
|
|
8
|
+
error.code=code;
|
|
9
|
+
return error;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Validates the canonical application identifier used by Arcane packages,
|
|
14
|
+
* the native host, and application-owned data folders.
|
|
15
|
+
*
|
|
16
|
+
* @param {*} value
|
|
17
|
+
* @param {string} label
|
|
18
|
+
* @returns {string}
|
|
19
|
+
*/
|
|
20
|
+
export function canonicalApplicationId(value,label='applicationId'){
|
|
21
|
+
if(typeof value!=='string'
|
|
22
|
+
||value.length<1
|
|
23
|
+
||value.length>APPLICATION_ID_MAX_LENGTH
|
|
24
|
+
||!APPLICATION_ID_PATTERN.test(value)){
|
|
25
|
+
throw scopeError(
|
|
26
|
+
'APP_DATA_SCOPE_INVALID',
|
|
27
|
+
`${label} must be a canonical Arcane application identifier.`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Reads the immutable application declaration from a document. Application
|
|
36
|
+
* pages declare this before storage modules run so standalone browser builds
|
|
37
|
+
* do not depend on their mount path for identity.
|
|
38
|
+
*
|
|
39
|
+
* @param {Document|Object|null} documentObject
|
|
40
|
+
* @returns {string|null}
|
|
41
|
+
*/
|
|
42
|
+
export function declaredApplicationId(documentObject=globalThis.document){
|
|
43
|
+
const metaValue=documentObject
|
|
44
|
+
?.querySelector?.('meta[name="arcane-app-id"]')
|
|
45
|
+
?.getAttribute?.('content');
|
|
46
|
+
const rootValue=documentObject?.documentElement?.dataset?.arcaneAppId;
|
|
47
|
+
const declarations=[metaValue,rootValue]
|
|
48
|
+
.filter(value=>value!==null&&value!==undefined&&value!=='')
|
|
49
|
+
.map((value,index)=>canonicalApplicationId(
|
|
50
|
+
value,
|
|
51
|
+
index===0?'arcane-app-id metadata':'document application id'
|
|
52
|
+
));
|
|
53
|
+
|
|
54
|
+
if(new Set(declarations).size>1){
|
|
55
|
+
throw scopeError(
|
|
56
|
+
'APP_DATA_SCOPE_MISMATCH',
|
|
57
|
+
'The document contains conflicting Arcane application identities.'
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return declarations[0]||null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Resolves the synchronous browser declaration used by storage mechanisms
|
|
66
|
+
* such as localStorage. Native-capable asynchronous callers must use
|
|
67
|
+
* resolveApplicationId so the host-bound identity remains authoritative.
|
|
68
|
+
*
|
|
69
|
+
* @param {Object} options
|
|
70
|
+
* @param {string|null} options.applicationId
|
|
71
|
+
* @param {Document|Object|null} options.documentObject
|
|
72
|
+
* @returns {string}
|
|
73
|
+
*/
|
|
74
|
+
export function resolveBrowserApplicationId({
|
|
75
|
+
applicationId=null,
|
|
76
|
+
documentObject=globalThis.document
|
|
77
|
+
}={}){
|
|
78
|
+
const explicit=applicationId===null||applicationId===undefined||applicationId===''
|
|
79
|
+
?null
|
|
80
|
+
:canonicalApplicationId(applicationId);
|
|
81
|
+
const declared=declaredApplicationId(documentObject);
|
|
82
|
+
|
|
83
|
+
if(explicit&&declared&&explicit!==declared){
|
|
84
|
+
throw scopeError(
|
|
85
|
+
'APP_DATA_SCOPE_MISMATCH',
|
|
86
|
+
'The configured and declared Arcane application identities do not match.'
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if(explicit||declared){
|
|
91
|
+
return explicit||declared;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
throw scopeError(
|
|
95
|
+
'APP_DATA_SCOPE_REQUIRED',
|
|
96
|
+
'Arcane application data cannot open without a declared application identity.'
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Resolves a logical local-storage key beneath the current browser app scope.
|
|
102
|
+
* Callers retain their domain namespace while the shared mechanism supplies
|
|
103
|
+
* the canonical `arcane.apps.<id>:` ownership prefix.
|
|
104
|
+
*
|
|
105
|
+
* @param {*} logicalKey
|
|
106
|
+
* @param {Object} options
|
|
107
|
+
* @returns {string}
|
|
108
|
+
*/
|
|
109
|
+
export function resolveApplicationLocalStorageKey(logicalKey='',options={}){
|
|
110
|
+
const applicationId=resolveBrowserApplicationId(options);
|
|
111
|
+
return `${APP_LOCAL_STORAGE_PREFIX}${applicationId}:${String(logicalKey)}`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function nativeApplicationId(arcane=globalThis.Arcane){
|
|
115
|
+
if(typeof arcane?.app?.current!=='function'){
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const descriptor=await arcane.app.current();
|
|
120
|
+
|
|
121
|
+
if(!descriptor||typeof descriptor!=='object'){
|
|
122
|
+
throw scopeError(
|
|
123
|
+
'APP_DATA_SCOPE_INVALID',
|
|
124
|
+
'Arcane returned an invalid bound application descriptor.'
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return canonicalApplicationId(
|
|
129
|
+
descriptor.id,
|
|
130
|
+
'bound application id'
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Resolves one application identity for persistent data. The native host is
|
|
136
|
+
* authoritative when present. Browser-only applications must declare their
|
|
137
|
+
* package id in `meta[name="arcane-app-id"]` (or the equivalent root data
|
|
138
|
+
* attribute). A mismatch fails closed before a data directory is opened.
|
|
139
|
+
*
|
|
140
|
+
* @param {Object} options
|
|
141
|
+
* @param {string|null} options.applicationId Explicit identity for adapters
|
|
142
|
+
* and synthetic tests. Application pages should use document metadata.
|
|
143
|
+
* @param {Document|Object|null} options.documentObject
|
|
144
|
+
* @param {Object|null} options.arcane
|
|
145
|
+
* @returns {Promise<string>}
|
|
146
|
+
*/
|
|
147
|
+
export async function resolveApplicationId({
|
|
148
|
+
applicationId=null,
|
|
149
|
+
documentObject=globalThis.document,
|
|
150
|
+
arcane=globalThis.Arcane
|
|
151
|
+
}={}){
|
|
152
|
+
let browserIdentity=null;
|
|
153
|
+
try{
|
|
154
|
+
browserIdentity=resolveBrowserApplicationId({
|
|
155
|
+
applicationId,
|
|
156
|
+
documentObject
|
|
157
|
+
});
|
|
158
|
+
}catch(error){
|
|
159
|
+
if(error?.code!=='APP_DATA_SCOPE_REQUIRED'){
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const nativeIdentity=await nativeApplicationId(arcane);
|
|
164
|
+
|
|
165
|
+
if(nativeIdentity&&browserIdentity&&nativeIdentity!==browserIdentity){
|
|
166
|
+
throw scopeError(
|
|
167
|
+
'APP_DATA_SCOPE_MISMATCH',
|
|
168
|
+
'The document identity does not match the application bound by Arcane.'
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if(nativeIdentity||browserIdentity){
|
|
173
|
+
return nativeIdentity||browserIdentity;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
throw scopeError(
|
|
177
|
+
'APP_DATA_SCOPE_REQUIRED',
|
|
178
|
+
'Arcane application data cannot open without a bound application identity.'
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Opens `<OPFS root>/apps/<application-id>` and returns only that app-owned
|
|
184
|
+
* directory. This is an organizational boundary for browser-only same-origin
|
|
185
|
+
* code; the native host additionally supplies a separate WebView profile and
|
|
186
|
+
* authoritative application identity.
|
|
187
|
+
*
|
|
188
|
+
* @param {Object} options
|
|
189
|
+
* @param {StorageManager|Object} options.storage
|
|
190
|
+
* @param {string|null} options.applicationId
|
|
191
|
+
* @param {Document|Object|null} options.documentObject
|
|
192
|
+
* @param {Object|null} options.arcane
|
|
193
|
+
* @param {boolean} options.create
|
|
194
|
+
* @returns {Promise<{applicationId:string,directory:FileSystemDirectoryHandle|Object,path:string}>}
|
|
195
|
+
*/
|
|
196
|
+
export async function openApplicationDataDirectory({
|
|
197
|
+
storage=globalThis.navigator?.storage,
|
|
198
|
+
applicationId=null,
|
|
199
|
+
documentObject=globalThis.document,
|
|
200
|
+
arcane=globalThis.Arcane,
|
|
201
|
+
create=true
|
|
202
|
+
}={}){
|
|
203
|
+
if(!storage||typeof storage.getDirectory!=='function'){
|
|
204
|
+
throw scopeError(
|
|
205
|
+
'APP_DATA_STORAGE_UNAVAILABLE',
|
|
206
|
+
'Origin Private File System storage is unavailable in this browser.'
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const id=await resolveApplicationId({
|
|
211
|
+
applicationId,
|
|
212
|
+
documentObject,
|
|
213
|
+
arcane
|
|
214
|
+
});
|
|
215
|
+
const root=await storage.getDirectory();
|
|
216
|
+
|
|
217
|
+
if(!root||typeof root.getDirectoryHandle!=='function'){
|
|
218
|
+
throw scopeError(
|
|
219
|
+
'APP_DATA_STORAGE_UNAVAILABLE',
|
|
220
|
+
'Arcane could not open the Origin Private File System root.'
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const applications=await root.getDirectoryHandle(
|
|
225
|
+
APP_DATA_DIRECTORY,
|
|
226
|
+
{create:Boolean(create)}
|
|
227
|
+
);
|
|
228
|
+
const directory=await applications.getDirectoryHandle(
|
|
229
|
+
id,
|
|
230
|
+
{create:Boolean(create)}
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
return {
|
|
234
|
+
applicationId:id,
|
|
235
|
+
directory,
|
|
236
|
+
path:`${APP_DATA_DIRECTORY}/${id}`
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export {
|
|
241
|
+
APPLICATION_ID_MAX_LENGTH,
|
|
242
|
+
APPLICATION_ID_PATTERN,
|
|
243
|
+
APP_DATA_DIRECTORY,
|
|
244
|
+
APP_LOCAL_STORAGE_PREFIX
|
|
245
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import PreferenceStore from './PreferenceStore.js';
|
|
2
|
+
|
|
3
|
+
export const appearancePreferenceSchema=Object.freeze([
|
|
4
|
+
{key:'appearance.colorScheme',type:'select',label:'Color scheme',description:'Use the device preference or choose a consistent light or dark appearance.',defaultValue:'system',options:[{label:'Use device setting',value:'system'},{label:'Light',value:'light'},{label:'Dark',value:'dark'}]},
|
|
5
|
+
{key:'appearance.density',type:'select',label:'Layout density',description:'Choose comfortable spacing or fit more information on screen.',defaultValue:'comfortable',options:[{label:'Comfortable',value:'comfortable'},{label:'Compact',value:'compact'}]},
|
|
6
|
+
{key:'accessibility.reduceMotion',type:'boolean',label:'Reduce motion',description:'Limit non-essential animation and transitions.',defaultValue:false},
|
|
7
|
+
{key:'accessibility.largeText',type:'boolean',label:'Larger text',description:'Increase the base text size in compatible Arcane applications.',defaultValue:false}
|
|
8
|
+
]);
|
|
9
|
+
|
|
10
|
+
export function createAppearancePreferenceStore(options={}){
|
|
11
|
+
return new PreferenceStore({namespace:'arcane',schema:appearancePreferenceSchema,...options});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function applyAppearancePreferences(values={},root=document.documentElement){
|
|
15
|
+
const scheme=values['appearance.colorScheme'];
|
|
16
|
+
if(scheme==='light'||scheme==='dark') root.dataset.colorScheme=scheme; else root.removeAttribute('data-color-scheme');
|
|
17
|
+
root.dataset.density=values['appearance.density']||'comfortable';
|
|
18
|
+
root.dataset.reduceMotion=String(Boolean(values['accessibility.reduceMotion']));
|
|
19
|
+
root.style.fontSize=values['accessibility.largeText']?'18px':'';
|
|
20
|
+
return values;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function loadAndApplyAppearancePreferences(options={}){
|
|
24
|
+
const store=options.store||createAppearancePreferenceStore(options);
|
|
25
|
+
const values=await store.load();
|
|
26
|
+
applyAppearancePreferences(values,options.root||document.documentElement);
|
|
27
|
+
return {store,values};
|
|
28
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import CommunicationMessage from '../entities/CommunicationMessage.js';
|
|
2
|
+
import CommunicationThread from '../entities/CommunicationThread.js';
|
|
3
|
+
|
|
4
|
+
function cleanEndpoint(value){const url=new URL(String(value||'http://127.0.0.1:8020'));if(!['http:','https:'].includes(url.protocol)) throw new TypeError('Bridge URL must use HTTP or HTTPS.');return url.href.replace(/\/$/,'');}
|
|
5
|
+
|
|
6
|
+
export default class ArcaneCommunicationBridge{
|
|
7
|
+
constructor({id,label,channels,endpoint='http://127.0.0.1:8020',fetchImpl=globalThis.fetch}={}){
|
|
8
|
+
this.id=String(id||'arcane-bridge');this.label=String(label||'Arcane communications bridge');this.channels=Array.from(channels||['other']);this.endpoint=cleanEndpoint(endpoint);this.fetchImpl=fetchImpl;
|
|
9
|
+
}
|
|
10
|
+
async request(path,options={}){
|
|
11
|
+
if(typeof this.fetchImpl!=='function') throw new Error('Network access is unavailable.');
|
|
12
|
+
const response=await this.fetchImpl(`${this.endpoint}${path}`,{...options,headers:{Accept:'application/json',...(options.body?{'Content-Type':'application/json'}:{}),...options.headers}});
|
|
13
|
+
const text=await response.text();let body={};if(text){try{body=JSON.parse(text);}catch{throw new Error('The communications bridge returned invalid JSON.');}}
|
|
14
|
+
if(!response.ok) throw new Error(body.error||`Communications bridge request failed (${response.status}).`);
|
|
15
|
+
return body;
|
|
16
|
+
}
|
|
17
|
+
async listThreads(){const body=await this.request(`/v1/providers/${encodeURIComponent(this.id)}/threads`);return Array.from(body.threads||[],value=>new CommunicationThread({...value,providerId:this.id}));}
|
|
18
|
+
async getMessages(threadId){const body=await this.request(`/v1/providers/${encodeURIComponent(this.id)}/threads/${encodeURIComponent(threadId)}/messages`);return Array.from(body.messages||[],value=>new CommunicationMessage({...value,threadId,providerId:this.id}));}
|
|
19
|
+
async send(input={}){const body=await this.request(`/v1/providers/${encodeURIComponent(this.id)}/messages`,{method:'POST',body:JSON.stringify(input)});return new CommunicationMessage({...body.message,providerId:this.id,threadId:body.message?.threadId||input.threadId,direction:'outbound'});}
|
|
20
|
+
async connect(){return this.request(`/v1/providers/${encodeURIComponent(this.id)}/connect`,{method:'POST'});}
|
|
21
|
+
async disconnect(){return this.request(`/v1/providers/${encodeURIComponent(this.id)}/disconnect`,{method:'POST'});}
|
|
22
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import * as ArcaneNetworkPolicy from './ArcaneNetworkPolicy.js?v=3';
|
|
2
|
+
|
|
3
|
+
function boundedText(value,fallback,maximum=500){
|
|
4
|
+
const text=typeof value==='string'?value.trim():'';
|
|
5
|
+
if(!text)return fallback;
|
|
6
|
+
return text.replace(/[\u0000-\u001f\u007f]/g,' ').slice(0,maximum);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function decisionId(){
|
|
10
|
+
if(typeof globalThis.crypto?.randomUUID==='function')return globalThis.crypto.randomUUID();
|
|
11
|
+
return `navigation-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function destinationContext(value){
|
|
15
|
+
const url=new URL(String(value));
|
|
16
|
+
if(!['http:','https:'].includes(url.protocol))throw new TypeError('Arcane navigation policy accepts only HTTP or HTTPS destinations.');
|
|
17
|
+
const defaultPort=url.protocol==='https:'?443:80;
|
|
18
|
+
const hostname=url.hostname;
|
|
19
|
+
const ipLiteral=isIpLiteralHostname(hostname);
|
|
20
|
+
return Object.freeze({
|
|
21
|
+
url:url.href,
|
|
22
|
+
hostname,
|
|
23
|
+
canonicalHostname:ipLiteral?hostname.replace(/^\[|\]$/g,''):ArcaneNetworkPolicy.canonicalNetworkHostname(hostname),
|
|
24
|
+
ipLiteral,
|
|
25
|
+
protocol:'tcp',
|
|
26
|
+
remotePort:url.port?Number(url.port):defaultPort
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function isIpLiteralHostname(hostname){
|
|
31
|
+
const value=String(hostname||'').replace(/^\[|\]$/g,'');
|
|
32
|
+
if(value.includes(':'))return /^[0-9a-f:.]+$/i.test(value);
|
|
33
|
+
const parts=value.split('.');
|
|
34
|
+
return parts.length===4&&parts.every(function validIpv4Part(part){
|
|
35
|
+
return /^(?:0|[1-9]\d{0,2})$/.test(part)&&Number(part)<=255;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function blockedDecision(rule,target,policyGeneration,ruleType){
|
|
40
|
+
return Object.freeze({
|
|
41
|
+
blocked:true,
|
|
42
|
+
decisionId:decisionId(),
|
|
43
|
+
decidedAt:new Date().toISOString(),
|
|
44
|
+
policyGeneration,
|
|
45
|
+
ruleId:boundedText(rule?.id,'unknown-rule',80),
|
|
46
|
+
ruleType,
|
|
47
|
+
target:target.url,
|
|
48
|
+
matchedValue:ruleType==='domain'?boundedText(rule?.domain,target.hostname,253):boundedText(rule?.cidr,target.hostname,160),
|
|
49
|
+
reason:Object.freeze({
|
|
50
|
+
code:boundedText(rule?.reason?.code,'global-deny',80),
|
|
51
|
+
title:boundedText(rule?.reason?.title,'Blocked by the global deny policy',120),
|
|
52
|
+
description:boundedText(rule?.reason?.description,'Arcane stopped this navigation before sending a request.')
|
|
53
|
+
}),
|
|
54
|
+
source:Object.freeze({
|
|
55
|
+
id:boundedText(rule?.source?.id,'arcane-policy',80),
|
|
56
|
+
label:boundedText(rule?.source?.label,'Arcane global policy',120),
|
|
57
|
+
reference:boundedText(rule?.source?.reference,'',500)||null
|
|
58
|
+
})
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function unavailableDecision(target,error){
|
|
63
|
+
return Object.freeze({
|
|
64
|
+
blocked:true,
|
|
65
|
+
decisionId:decisionId(),
|
|
66
|
+
decidedAt:new Date().toISOString(),
|
|
67
|
+
policyGeneration:null,
|
|
68
|
+
ruleId:'policy-unavailable',
|
|
69
|
+
ruleType:'policy',
|
|
70
|
+
target:target.url,
|
|
71
|
+
matchedValue:target.hostname,
|
|
72
|
+
reason:Object.freeze({
|
|
73
|
+
code:'policy-unavailable',
|
|
74
|
+
title:'Navigation paused because policy is unavailable',
|
|
75
|
+
description:'Arcane could not verify the current global deny policy, so it did not send this request.'
|
|
76
|
+
}),
|
|
77
|
+
source:Object.freeze({
|
|
78
|
+
id:'arcane-runtime',
|
|
79
|
+
label:'Arcane policy safety boundary',
|
|
80
|
+
reference:boundedText(error?.code||'','',120)||null
|
|
81
|
+
})
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function requireNetworkMatcher(networkMatcher){
|
|
86
|
+
if(typeof networkMatcher==='function')return networkMatcher;
|
|
87
|
+
const error=new Error('Arcane cannot evaluate literal-IP navigation because the canonical network matcher is unavailable.');
|
|
88
|
+
error.code='ARCANE_NETWORK_POLICY_MATCHER_UNAVAILABLE';
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function createArcaneNavigationGuard({
|
|
93
|
+
loadPolicy=ArcaneNetworkPolicy.loadArcaneNetworkPolicy,
|
|
94
|
+
onDecision=null,
|
|
95
|
+
networkMatcher=ArcaneNetworkPolicy.findDeniedNetworkRule
|
|
96
|
+
}={}){
|
|
97
|
+
return async function guardArcaneNavigation(value,context={}){
|
|
98
|
+
const target=destinationContext(value);
|
|
99
|
+
let decision;
|
|
100
|
+
try{
|
|
101
|
+
if(!target.ipLiteral&&(!target.canonicalHostname||target.canonicalHostname!==target.hostname)){
|
|
102
|
+
const error=new TypeError('Arcane navigation policy requires a canonical hostname without a trailing root dot.');
|
|
103
|
+
error.code='ARCANE_NETWORK_POLICY_HOSTNAME_NONCANONICAL';
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
const policy=await loadPolicy();
|
|
107
|
+
const domainRule=ArcaneNetworkPolicy.findDeniedDomainRule(policy,target.canonicalHostname);
|
|
108
|
+
let networkRule=null;
|
|
109
|
+
if(!domainRule&&target.ipLiteral){
|
|
110
|
+
const findDeniedNetworkRule=requireNetworkMatcher(networkMatcher);
|
|
111
|
+
networkRule=findDeniedNetworkRule(policy,target.canonicalHostname,{
|
|
112
|
+
protocol:target.protocol,
|
|
113
|
+
remotePort:target.remotePort
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
decision=domainRule
|
|
117
|
+
?blockedDecision(domainRule,target,policy.generation,'domain')
|
|
118
|
+
:networkRule
|
|
119
|
+
?blockedDecision(networkRule,target,policy.generation,'network')
|
|
120
|
+
:Object.freeze({
|
|
121
|
+
blocked:false,
|
|
122
|
+
decisionId:decisionId(),
|
|
123
|
+
decidedAt:new Date().toISOString(),
|
|
124
|
+
policyGeneration:policy.generation,
|
|
125
|
+
target:target.url
|
|
126
|
+
});
|
|
127
|
+
}catch(error){
|
|
128
|
+
decision=unavailableDecision(target,error);
|
|
129
|
+
}
|
|
130
|
+
if(typeof onDecision==='function'){
|
|
131
|
+
await onDecision(decision,Object.freeze({intent:boundedText(context.intent,'embedded',32)}));
|
|
132
|
+
}
|
|
133
|
+
return decision;
|
|
134
|
+
};
|
|
135
|
+
}
|