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,1423 @@
|
|
|
1
|
+
# Arcane API platform, installation, users, and system guides
|
|
2
|
+
|
|
3
|
+
These methods report or change host-level state. Feature-detect the public
|
|
4
|
+
member and use the capability and method inventory exposed by the current host
|
|
5
|
+
before presenting a control. A grant never replaces a method's input,
|
|
6
|
+
privilege, identity, freshness, or confirmation checks.
|
|
7
|
+
|
|
8
|
+
Core operations that return an `operation` record also emit future-only
|
|
9
|
+
`operation.started`, `operation.progress`, `operation.log`,
|
|
10
|
+
`operation.completed`, or `operation.failed` events. Subscribe before calling
|
|
11
|
+
the method, correlate by `operationId`, and release the returned unsubscribe
|
|
12
|
+
function. An operation result can complete with warnings; inspect
|
|
13
|
+
`warningCount` and the method-specific readiness fields.
|
|
14
|
+
|
|
15
|
+
## Arcane.platform.status()
|
|
16
|
+
|
|
17
|
+
### Overview
|
|
18
|
+
|
|
19
|
+
`Arcane.platform.status()` returns the host, execution-evidence, renderer,
|
|
20
|
+
permission, application, and effective-capability snapshot for the bound
|
|
21
|
+
session. It is a repeatable read with no side effect or event. It requires
|
|
22
|
+
`system.read` and is available on Core and Android.
|
|
23
|
+
|
|
24
|
+
### Result and platform differences
|
|
25
|
+
|
|
26
|
+
Core returns exactly `platform`, `rawPlatform`, `displayName`, `architecture`,
|
|
27
|
+
`release`, `desktop`, `sessionType`, `simulated`, `adapter`, `version`,
|
|
28
|
+
`protocol`, `application`, `renderer`, `permissions`, `capabilities`, and
|
|
29
|
+
`execution`. Microsoft NT uses `platform: "windows"` and
|
|
30
|
+
`rawPlatform: "win32"`; Linux uses `"linux"` for both. `hostname` is
|
|
31
|
+
deliberately omitted.
|
|
32
|
+
|
|
33
|
+
`execution` is exactly
|
|
34
|
+
`{hostPlatform, effectivePlatform, simulation, evidenceClass}`. Core uses
|
|
35
|
+
`evidenceClass: "real-host"` or `"simulation"`. Android reports
|
|
36
|
+
`platform/rawPlatform: "android"` and
|
|
37
|
+
`execution: {hostPlatform:"android", effectivePlatform:"android",
|
|
38
|
+
simulation:false, evidenceClass:"application-host"}`. Simulation and Android
|
|
39
|
+
application-host evidence are not publisher, signing, or release-candidate
|
|
40
|
+
attestations.
|
|
41
|
+
|
|
42
|
+
`renderer` contains `id`, `available`, and nullable `version`, with host-specific
|
|
43
|
+
`adapter` or `executable` metadata. `permissions` has the shape documented by
|
|
44
|
+
`Arcane.permissions.status()`. `capabilities` is exactly `{app, grants,
|
|
45
|
+
methods}` and is the Android replacement for the Core-only direct
|
|
46
|
+
`Arcane.capabilities.list()` method.
|
|
47
|
+
|
|
48
|
+
### Errors and recovery
|
|
49
|
+
|
|
50
|
+
`METHOD_NOT_ALLOWED` or `ANDROID_CAPABILITY_DENIED` means `system.read` is not
|
|
51
|
+
granted. `METHOD_CONTRACT_OUTPUT_INVALID` means the host status failed its
|
|
52
|
+
closed shape or internal-consistency checks; repair the matching host and app
|
|
53
|
+
package rather than inferring platform state from user-agent strings.
|
|
54
|
+
|
|
55
|
+
### Example
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
const status = await Arcane.platform.status();
|
|
59
|
+
|
|
60
|
+
console.log(status.displayName, status.architecture, status.release);
|
|
61
|
+
console.log(status.execution.evidenceClass);
|
|
62
|
+
console.log('Admitted methods', status.capabilities.methods);
|
|
63
|
+
```
|
|
64
|
+
## Arcane.permissions.status()
|
|
65
|
+
|
|
66
|
+
### Overview
|
|
67
|
+
|
|
68
|
+
`Arcane.permissions.status()` refreshes the Core host's permission/elevation
|
|
69
|
+
observation. It requires `system.read`, is Core-only, changes no privilege, and
|
|
70
|
+
emits no event. A true `canElevate` value describes the host mechanism; it does
|
|
71
|
+
not mean this read prompted for or obtained elevation.
|
|
72
|
+
|
|
73
|
+
### Result
|
|
74
|
+
|
|
75
|
+
The result is exactly `{elevated, level, canElevate, mechanism, detectedBy,
|
|
76
|
+
probes}`. `elevated` and `canElevate` are booleans; `mechanism` may be `null`;
|
|
77
|
+
`probes` contains bounded host-specific diagnostic records.
|
|
78
|
+
|
|
79
|
+
Microsoft NT normally reports `level` as `"standard"`, `"administrator"`, or
|
|
80
|
+
`"system"`, using UAC and an integrity-level probe. Linux reports `"standard"`
|
|
81
|
+
or `"root"` from the effective uid and also records whether its kernel peer
|
|
82
|
+
credential guard is available. Simulation returns explicitly simulated
|
|
83
|
+
mechanisms and probes. Never use a simulation result as evidence of real
|
|
84
|
+
administrator or root authority.
|
|
85
|
+
|
|
86
|
+
### Errors and recovery
|
|
87
|
+
|
|
88
|
+
`METHOD_NOT_ALLOWED` means the application lacks `system.read`. A failed probe
|
|
89
|
+
normally remains visible in `detectedBy` and `probes`; a rejected request or
|
|
90
|
+
transport failure should be surfaced as unknown permission state, never treated
|
|
91
|
+
as elevated.
|
|
92
|
+
|
|
93
|
+
### Example
|
|
94
|
+
|
|
95
|
+
```javascript
|
|
96
|
+
const permissions = await Arcane.permissions.status();
|
|
97
|
+
|
|
98
|
+
if (!permissions.elevated) {
|
|
99
|
+
console.log('This host session is not elevated.', permissions.level);
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Arcane.version.current()
|
|
104
|
+
|
|
105
|
+
### Overview
|
|
106
|
+
|
|
107
|
+
`Arcane.version.current()` returns the active Arcane OS host/bundle version for
|
|
108
|
+
this bridge session. It takes no parameters, needs no capability, and is
|
|
109
|
+
available on Core and Android. It is a repeatable read with no event or side
|
|
110
|
+
effect.
|
|
111
|
+
|
|
112
|
+
### Result
|
|
113
|
+
|
|
114
|
+
The result is one canonical semantic-version string no longer than 64
|
|
115
|
+
characters. It is the host release version, not an independently packaged
|
|
116
|
+
application's version; use `Arcane.app.current().version` for the latter. A
|
|
117
|
+
version string is not signer, integrity, update, or release-candidate evidence.
|
|
118
|
+
|
|
119
|
+
### Errors and recovery
|
|
120
|
+
|
|
121
|
+
`METHOD_CONTRACT_OUTPUT_INVALID` indicates that the host returned a value other
|
|
122
|
+
than its bound bundle version. Repair or update the host/package pair.
|
|
123
|
+
`ARCANE_TRANSPORT_UNAVAILABLE` means the page is not hosted by Arcane.
|
|
124
|
+
|
|
125
|
+
### Example
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
const hostVersion = await Arcane.version.current();
|
|
129
|
+
const application = await Arcane.app.current();
|
|
130
|
+
|
|
131
|
+
console.log('Host', hostVersion, 'Application', application.version);
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Arcane.version.installation()
|
|
135
|
+
|
|
136
|
+
### Overview
|
|
137
|
+
|
|
138
|
+
`Arcane.version.installation()` calls the same `installation.status` RPC as
|
|
139
|
+
`Arcane.installation.status()`. It does not return a version string and does not
|
|
140
|
+
mutate or repair the installation. The alias requires `installation.read` on a
|
|
141
|
+
Core host and emits no event.
|
|
142
|
+
|
|
143
|
+
### Result and availability
|
|
144
|
+
|
|
145
|
+
The exact installation-status object is documented under
|
|
146
|
+
`Arcane.installation.status()`. Its `installedVersion` can be `null`, while
|
|
147
|
+
`packageVersion` identifies the active Provisioner package. Use
|
|
148
|
+
`disposition`, `action`, integrity, and identity fields together; comparing the
|
|
149
|
+
two version strings alone is not an installation trust decision.
|
|
150
|
+
|
|
151
|
+
### Errors and recovery
|
|
152
|
+
|
|
153
|
+
`METHOD_NOT_ALLOWED` means the application lacks `installation.read`.
|
|
154
|
+
Installation identity or integrity errors must be shown with their supplied
|
|
155
|
+
resolution. This alias is not projected on Android.
|
|
156
|
+
|
|
157
|
+
### Example
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
const installation = await Arcane.version.installation();
|
|
161
|
+
|
|
162
|
+
console.log(
|
|
163
|
+
installation.installedVersion,
|
|
164
|
+
installation.packageVersion,
|
|
165
|
+
installation.disposition
|
|
166
|
+
);
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Arcane.machine.status()
|
|
170
|
+
|
|
171
|
+
### Overview
|
|
172
|
+
|
|
173
|
+
`Arcane.machine.status()` returns the Provisioner's combined machine-readiness
|
|
174
|
+
view. It requires `provisioning.manage`, an application of type `provisioner`,
|
|
175
|
+
and a Core host. It performs bounded status and verification reads but makes no
|
|
176
|
+
machine change and emits no event.
|
|
177
|
+
|
|
178
|
+
This result contains local account, filesystem-location, and installation
|
|
179
|
+
details. Keep it inside the trusted Provisioner UI; do not send or persist the
|
|
180
|
+
whole object as telemetry.
|
|
181
|
+
|
|
182
|
+
### Result
|
|
183
|
+
|
|
184
|
+
The exact top-level fields are `version`, `protocol`, `application`, `os`,
|
|
185
|
+
`nativeAdapter`, `identity`, `protectedUsername`, `protectedUsernames`,
|
|
186
|
+
`usernamePolicy`, `installation`, `requirements`, `permissions`, `renderer`,
|
|
187
|
+
`securityMode`, `publisherTrustSource`, `revocationStatus`,
|
|
188
|
+
`installedSecurityMode`, `paths`, `simulation`, `execution`, and `bundleRoot`.
|
|
189
|
+
|
|
190
|
+
`installation`, `requirements`, `permissions`, and `execution` use the same
|
|
191
|
+
shapes documented by their focused methods. `securityMode` and its evidence
|
|
192
|
+
describe the active host release; `installedSecurityMode` describes the
|
|
193
|
+
installed release or `"not-installed"`. Simulation remains labeled in both
|
|
194
|
+
`simulation` and `execution`.
|
|
195
|
+
|
|
196
|
+
### Errors and recovery
|
|
197
|
+
|
|
198
|
+
`METHOD_NOT_ALLOWED` means the caller is not the admitted Provisioner or lacks
|
|
199
|
+
`provisioning.manage`. Status can also fail closed on invalid installation,
|
|
200
|
+
account, or filesystem evidence. Preserve the error's diagnostic id and follow
|
|
201
|
+
its repair guidance; do not remove failing fields and reinterpret the remainder
|
|
202
|
+
as ready.
|
|
203
|
+
|
|
204
|
+
### Example
|
|
205
|
+
|
|
206
|
+
```javascript
|
|
207
|
+
const machine = await Arcane.machine.status();
|
|
208
|
+
|
|
209
|
+
console.log(machine.os.displayName, machine.installation.disposition);
|
|
210
|
+
console.log('Simulation', machine.execution.simulation);
|
|
211
|
+
console.log('Required work', machine.requirements.filter(
|
|
212
|
+
function findBlockingRequirement(requirement) {
|
|
213
|
+
return requirement.blocking;
|
|
214
|
+
}
|
|
215
|
+
));
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Arcane.user.current()
|
|
219
|
+
|
|
220
|
+
### Overview
|
|
221
|
+
|
|
222
|
+
`Arcane.user.current()` returns the privacy-minimized identity bound to the
|
|
223
|
+
current host session. It requires `identity.read` and is available on Core and
|
|
224
|
+
Android. It is a repeatable read with no event or side effect. It is not an
|
|
225
|
+
authentication token and cannot select another user.
|
|
226
|
+
|
|
227
|
+
### Result and platform differences
|
|
228
|
+
|
|
229
|
+
The exact result is `{identityKind, username, accountName, displayName,
|
|
230
|
+
source}`. Microsoft NT and Linux return `identityKind: "host-account"`,
|
|
231
|
+
nonempty `username`, `accountName`, and `displayName`, and `source` set to
|
|
232
|
+
`"windows"` or `"linux"`.
|
|
233
|
+
|
|
234
|
+
Android returns `identityKind: "local-session"`, `username: null`,
|
|
235
|
+
`accountName: null`, a bounded display name, and `source: "android"`. Do not
|
|
236
|
+
derive or synthesize an Android operating-system account identifier.
|
|
237
|
+
|
|
238
|
+
### Errors and recovery
|
|
239
|
+
|
|
240
|
+
`METHOD_NOT_ALLOWED` or `ANDROID_CAPABILITY_DENIED` means `identity.read` is not
|
|
241
|
+
granted. `METHOD_CONTRACT_OUTPUT_INVALID` means the identity violated the
|
|
242
|
+
privacy-minimized contract; treat identity as unavailable and repair the host.
|
|
243
|
+
|
|
244
|
+
### Example
|
|
245
|
+
|
|
246
|
+
```javascript
|
|
247
|
+
const identity = await Arcane.user.current();
|
|
248
|
+
const label = identity.identityKind === 'host-account'
|
|
249
|
+
? identity.displayName
|
|
250
|
+
: 'Local Android session';
|
|
251
|
+
|
|
252
|
+
console.log(label, identity.source);
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Arcane.requirements.list()
|
|
256
|
+
|
|
257
|
+
### Overview
|
|
258
|
+
|
|
259
|
+
`Arcane.requirements.list()` returns all current Core installation requirement
|
|
260
|
+
records. It requires `requirements.read`, takes no parameters, changes nothing,
|
|
261
|
+
and emits no event. The result is a bare array, not a wrapper object.
|
|
262
|
+
|
|
263
|
+
### Result
|
|
264
|
+
|
|
265
|
+
The array currently contains `ollama`, `renderer`, and `session-control`.
|
|
266
|
+
Renderer and session-control records have exactly `id`, `name`,
|
|
267
|
+
`minimumVersion`, `required`, `installable`, `description`, `ready`,
|
|
268
|
+
`blocking`, `status`, `version`, `executable`, `message`, `platform`, and
|
|
269
|
+
`adapter`.
|
|
270
|
+
|
|
271
|
+
The Ollama record additionally has `requiredFor`, `requiredScope`, `detection`,
|
|
272
|
+
and `globalInstall`. `detection` separates machine-wide and user-scoped
|
|
273
|
+
observations; `globalInstall` is exactly `{available, status, action,
|
|
274
|
+
requiresElevation, provider, reason}`. Ollama is optional for base Arcane OS,
|
|
275
|
+
but required before local AI. Paths and process observations are local machine
|
|
276
|
+
data and should not be logged wholesale.
|
|
277
|
+
|
|
278
|
+
### Errors and recovery
|
|
279
|
+
|
|
280
|
+
`METHOD_NOT_ALLOWED` means the app lacks `requirements.read`. A record whose
|
|
281
|
+
`ready` is false includes a human-facing `message`; only `blocking: true`
|
|
282
|
+
blocks base installation. Refresh the list after the operator resolves a
|
|
283
|
+
prerequisite rather than modifying the returned record.
|
|
284
|
+
|
|
285
|
+
### Example
|
|
286
|
+
|
|
287
|
+
```javascript
|
|
288
|
+
const requirements = await Arcane.requirements.list();
|
|
289
|
+
|
|
290
|
+
for (const requirement of requirements) {
|
|
291
|
+
console.log(
|
|
292
|
+
requirement.name,
|
|
293
|
+
requirement.status,
|
|
294
|
+
requirement.blocking
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## Arcane.requirements.ensure()
|
|
300
|
+
|
|
301
|
+
### Overview
|
|
302
|
+
|
|
303
|
+
`Arcane.requirements.ensure(requirementIds, options?)` checks and, only where an
|
|
304
|
+
approved installer is available, attempts to prepare selected requirements. It
|
|
305
|
+
requires `provisioning.manage`, the Provisioner application type, an elevated
|
|
306
|
+
Core worker, and the exclusive machine-mutation boundary.
|
|
307
|
+
|
|
308
|
+
Omitted, `null`, or empty `requirementIds` selects the required requirements
|
|
309
|
+
(`renderer` and `session-control`), not every listed optional requirement. A
|
|
310
|
+
nonempty array may contain each known id once and no more than the current
|
|
311
|
+
three-item inventory. Always pass an array deliberately: the JavaScript wrapper
|
|
312
|
+
normalizes a non-array first argument to the default selection.
|
|
313
|
+
|
|
314
|
+
`options` is either omitted or an exact plain object containing only
|
|
315
|
+
`userProcessInterruption`, set to `"deny"` or `"allow"`; the default is
|
|
316
|
+
`"deny"`. Use `"allow"` only after a separate, informed confirmation. The host
|
|
317
|
+
still re-verifies exact process and port identity and will not terminate an
|
|
318
|
+
unknown process.
|
|
319
|
+
|
|
320
|
+
### Result, side effects, and events
|
|
321
|
+
|
|
322
|
+
The exact result is `{requirements, operation, credentials}`. `requirements`
|
|
323
|
+
contains fresh records only for the selected ids. `credentials` is an array and
|
|
324
|
+
is normally empty. `operation` is the completed tracked-operation record with
|
|
325
|
+
`id`, `type`, `status`, timestamps, `progress`, `currentStep`,
|
|
326
|
+
`progressDetails`, `credentials`, `error`, and `warningCount`.
|
|
327
|
+
|
|
328
|
+
The operation can perform disk, network, process, or installation work and
|
|
329
|
+
emits the standard operation lifecycle events. Simulation changes only
|
|
330
|
+
simulation state and is not real readiness evidence.
|
|
331
|
+
|
|
332
|
+
### Errors and recovery
|
|
333
|
+
|
|
334
|
+
Invalid ids or options use `INVALID_REQUIREMENTS_ENSURE_REQUEST`; invalid
|
|
335
|
+
wrapper options throw `TypeError` before dispatch. Common host failures include
|
|
336
|
+
`ADMIN_REQUIRED`, `OPERATION_BUSY`, `REQUIREMENT_NOT_INSTALLABLE`,
|
|
337
|
+
`REQUIREMENT_VERIFY_FAILED`, and lease-release failures. Wait for a busy
|
|
338
|
+
operation, keep interruption denied unless separately approved, and follow the
|
|
339
|
+
specific requirement's recovery message.
|
|
340
|
+
|
|
341
|
+
### Example
|
|
342
|
+
|
|
343
|
+
```javascript
|
|
344
|
+
async function ensureBlockingRequirementsAfterConfirmation(confirmChange) {
|
|
345
|
+
const requirements = await Arcane.requirements.list();
|
|
346
|
+
const selected = requirements.filter(
|
|
347
|
+
function selectBlockingRequirement(requirement) {
|
|
348
|
+
return requirement.required && !requirement.ready;
|
|
349
|
+
}
|
|
350
|
+
).map(function selectRequirementId(requirement) {
|
|
351
|
+
return requirement.id;
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
if (selected.length === 0 || !confirmChange(selected)) {
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return Arcane.requirements.ensure(selected, {
|
|
359
|
+
userProcessInterruption: 'deny'
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## Arcane.installation.status()
|
|
365
|
+
|
|
366
|
+
### Overview
|
|
367
|
+
|
|
368
|
+
`Arcane.installation.status()` reads the relationship between the active
|
|
369
|
+
Provisioner package and the installed Arcane OS state. It requires
|
|
370
|
+
`installation.read` on Core, makes no change, and emits no event. Status is
|
|
371
|
+
evidence for deciding what to present; it does not authorize a later mutation.
|
|
372
|
+
|
|
373
|
+
### Result
|
|
374
|
+
|
|
375
|
+
The exact fields are `present`, `installedVersion`, `packageVersion`, `blocked`,
|
|
376
|
+
`blockedReason`, `repairRequired`, `repairReason`, `disposition`, `action`,
|
|
377
|
+
`installRoot`, `stateRoot`, `manifest`, `installedPayloadMode`,
|
|
378
|
+
`installedIntegrity`, `installedIdentity`, `identityRepairRequired`,
|
|
379
|
+
`payloadRepairRequired`, `developmentTrustRepairRequired`,
|
|
380
|
+
`developmentMachineTrust`, `candidatePayloadDiffers`, and `payload`.
|
|
381
|
+
|
|
382
|
+
`disposition` is `"missing"`, `"downgrade-blocked"`, `"repair-required"`,
|
|
383
|
+
`"update-available"`, or `"current"`; `action` is `"install"`, `"blocked"`,
|
|
384
|
+
`"repair"`, `"update"`, or `"current"`. `payload` is exactly `{mode,
|
|
385
|
+
releaseReady, installable, description, missingRelease}`. The manifest and
|
|
386
|
+
integrity/identity evidence are structured host records and may contain local
|
|
387
|
+
paths; keep them inside the Provisioner boundary.
|
|
388
|
+
|
|
389
|
+
### Errors and recovery
|
|
390
|
+
|
|
391
|
+
`METHOD_NOT_ALLOWED` means the caller lacks `installation.read`. A blocked,
|
|
392
|
+
repair, or invalid-identity state is normally returned as data so the UI can
|
|
393
|
+
present the exact next action. If the read itself rejects, preserve its
|
|
394
|
+
diagnostic and repair guidance rather than using version comparison alone.
|
|
395
|
+
|
|
396
|
+
### Example
|
|
397
|
+
|
|
398
|
+
```javascript
|
|
399
|
+
const installation = await Arcane.installation.status();
|
|
400
|
+
|
|
401
|
+
console.log(installation.disposition, installation.action);
|
|
402
|
+
if (installation.blocked || installation.repairRequired) {
|
|
403
|
+
console.warn(installation.blockedReason || installation.repairReason);
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## Arcane.installation.ensure()
|
|
408
|
+
|
|
409
|
+
### Overview
|
|
410
|
+
|
|
411
|
+
`Arcane.installation.ensure()` installs, updates, repairs, or verifies Arcane OS
|
|
412
|
+
as required. It is a privileged, exclusive, non-idempotent Provisioner
|
|
413
|
+
operation requiring `provisioning.manage` on Core. It can write protected
|
|
414
|
+
files, register platform integration, and change machine configuration. Never
|
|
415
|
+
start it without a visible status and separate user confirmation.
|
|
416
|
+
|
|
417
|
+
The host rejects an installed Provisioner attempting to replace its own active
|
|
418
|
+
installation; updates and repairs run from a verified external release. It
|
|
419
|
+
blocks downgrades and re-verifies installation identity and postconditions.
|
|
420
|
+
|
|
421
|
+
### Result, side effects, and events
|
|
422
|
+
|
|
423
|
+
The exact result is `{manifest, installation, requirements, model, ready,
|
|
424
|
+
warningCount, operation, credentials}`. `model` is exactly `{status, reason,
|
|
425
|
+
requiredBefore, created}` and deliberately reports local-model setup as
|
|
426
|
+
deferred from base installation. `ready: true` requires a present, current,
|
|
427
|
+
nonblocked installation with accepted identity, integrity, and required
|
|
428
|
+
requirements. A completed result can have `ready: false` and warnings when
|
|
429
|
+
warn-first policy is active.
|
|
430
|
+
|
|
431
|
+
The method emits the standard operation lifecycle events. Simulation mutates
|
|
432
|
+
only deterministic development state and does not prove a real installation.
|
|
433
|
+
|
|
434
|
+
### Errors and recovery
|
|
435
|
+
|
|
436
|
+
Important failures include `ADMIN_REQUIRED`, `OPERATION_BUSY`,
|
|
437
|
+
`EXTERNAL_PROVISIONER_REQUIRED`, `DOWNGRADE_BLOCKED`,
|
|
438
|
+
`INSTALL_IDENTITY_INVALID`, payload or integrity failures, and installation
|
|
439
|
+
lease/stage cleanup failures. Do not retry automatically after an ambiguous
|
|
440
|
+
failure: preserve the diagnostic, inspect fresh `installation.status()`, and
|
|
441
|
+
follow its recovery action.
|
|
442
|
+
|
|
443
|
+
### Example
|
|
444
|
+
|
|
445
|
+
```javascript
|
|
446
|
+
async function ensureInstallationAfterConfirmation(confirmChange) {
|
|
447
|
+
const status = await Arcane.installation.status();
|
|
448
|
+
if (status.action === 'current' || status.action === 'blocked') {
|
|
449
|
+
return status;
|
|
450
|
+
}
|
|
451
|
+
if (!confirmChange(status.action, status)) {
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
return Arcane.installation.ensure();
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
## Arcane.installation.openUninstaller()
|
|
459
|
+
|
|
460
|
+
### Overview
|
|
461
|
+
|
|
462
|
+
`Arcane.installation.openUninstaller()` opens the globally installed Arcane OS
|
|
463
|
+
uninstaller controller. It is available only to a Provisioner with
|
|
464
|
+
`provisioning.manage` on a Microsoft NT Core host. The method does not uninstall
|
|
465
|
+
anything itself: the controller separately performs UAC, read-only preflight,
|
|
466
|
+
scope review, and typed confirmation.
|
|
467
|
+
|
|
468
|
+
### Result and side effect
|
|
469
|
+
|
|
470
|
+
The exact result is `{opened: true}`. It means Microsoft NT accepted creation
|
|
471
|
+
of the installed uninstaller process, not that UAC was approved or an uninstall
|
|
472
|
+
completed. The method emits no operation event. It will not run a checkout-local
|
|
473
|
+
or caller-selected executable.
|
|
474
|
+
|
|
475
|
+
### Errors and recovery
|
|
476
|
+
|
|
477
|
+
`UNINSTALLER_NOT_SUPPORTED` means the current platform is not Microsoft NT.
|
|
478
|
+
`UNINSTALLER_UNAVAILABLE` and related integrity errors mean the global
|
|
479
|
+
installation must be repaired. `UNINSTALLER_OPEN_FAILED` means process creation
|
|
480
|
+
was not confirmed. Use the operating system's Installed apps interface when the
|
|
481
|
+
verified controller cannot be opened.
|
|
482
|
+
|
|
483
|
+
### Example
|
|
484
|
+
|
|
485
|
+
```javascript
|
|
486
|
+
async function openUninstallerAfterConfirmation(confirmOpen) {
|
|
487
|
+
if (!confirmOpen()) {
|
|
488
|
+
return null;
|
|
489
|
+
}
|
|
490
|
+
return Arcane.installation.openUninstaller();
|
|
491
|
+
}
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
## Arcane.users.list()
|
|
495
|
+
|
|
496
|
+
### Overview
|
|
497
|
+
|
|
498
|
+
`Arcane.users.list()` returns local accounts that use the exact Arcane shell or
|
|
499
|
+
have a protected Arcane recovery record. It requires `users.manage`, an
|
|
500
|
+
application of type `provisioner`, and a Core host. It is a read and emits no
|
|
501
|
+
operation event. On Microsoft NT an elevated read can temporarily load and
|
|
502
|
+
unload a signed-out profile to verify both protected shell bindings; it does not
|
|
503
|
+
persistently change the account.
|
|
504
|
+
|
|
505
|
+
### Result
|
|
506
|
+
|
|
507
|
+
The exact top-level result is `{users, policy, protectedUsernames}`. `policy` is
|
|
508
|
+
exactly `{platform, minimumLength, maximumLength, description, example}`.
|
|
509
|
+
`protectedUsernames` contains accounts the Provisioner must not convert.
|
|
510
|
+
|
|
511
|
+
Every `users` record contains host account and shell observations plus the
|
|
512
|
+
Arcane recovery fields `managedByArcane`, `createdByArcane`, `passwordStatus`,
|
|
513
|
+
`provisionedAt`, `passwordChangedAt`, prior-shell values and presence flags,
|
|
514
|
+
recorded binding/security metadata, `canRestoreShell`,
|
|
515
|
+
`restoreRequiresElevatedVerification`, `shellMutationPhase`,
|
|
516
|
+
`shellRecoveryPrepared`, `accountMutationPhase`, and `activationRequired`.
|
|
517
|
+
|
|
518
|
+
Microsoft NT records include `username`, `sid`, `enabled`, `profile`, `shell`,
|
|
519
|
+
both policy and legacy shell values/presence flags, `shellAssigned`,
|
|
520
|
+
`shellBindingVersion`, `assignmentMode`, `verification`, and `source`. Linux
|
|
521
|
+
records include `username`, optional `uid`, `enabled`, `profile`, `shell`,
|
|
522
|
+
`shellAssigned`, `verification`, and `source`. Nullable or recorded-only values
|
|
523
|
+
must remain unknown; do not coerce them to false.
|
|
524
|
+
|
|
525
|
+
### Errors and recovery
|
|
526
|
+
|
|
527
|
+
`METHOD_NOT_ALLOWED` means this is not the admitted Provisioner. Host account,
|
|
528
|
+
profile, registry, passwd, or recovery-record failures should be surfaced with
|
|
529
|
+
their diagnostic. Refresh only after resolving the cause; do not drop a
|
|
530
|
+
recorded-only entry, because it may represent an interrupted transaction that
|
|
531
|
+
needs recovery.
|
|
532
|
+
|
|
533
|
+
### Example
|
|
534
|
+
|
|
535
|
+
```javascript
|
|
536
|
+
const result = await Arcane.users.list();
|
|
537
|
+
|
|
538
|
+
for (const user of result.users) {
|
|
539
|
+
console.log(
|
|
540
|
+
user.username,
|
|
541
|
+
user.shellAssigned,
|
|
542
|
+
user.activationRequired,
|
|
543
|
+
user.verification
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
## Arcane.users.validate()
|
|
549
|
+
|
|
550
|
+
### Overview
|
|
551
|
+
|
|
552
|
+
`Arcane.users.validate(usernames)` validates one username or an array without
|
|
553
|
+
creating or changing an account. The wrapper always sends an array. The method
|
|
554
|
+
requires `users.manage`, the Provisioner application type, and Core; it is a
|
|
555
|
+
read with no event.
|
|
556
|
+
|
|
557
|
+
Microsoft NT permits 1–20 letters, numbers, periods, underscores, or hyphens,
|
|
558
|
+
beginning with a letter or number and not ending in a period. Linux permits
|
|
559
|
+
1–32 lower-case letters, numbers, underscores, or hyphens, beginning with a
|
|
560
|
+
lower-case letter or underscore. Both reject reserved, privileged, and current
|
|
561
|
+
protected accounts.
|
|
562
|
+
|
|
563
|
+
### Result
|
|
564
|
+
|
|
565
|
+
The exact result is `{valid, users, errors, policy}`. `valid` is true only when
|
|
566
|
+
at least one input is valid and there are no errors. Each successful item is
|
|
567
|
+
exactly `{input, username, valid: true, exists}`. Each failed item includes
|
|
568
|
+
`input`, `valid: false`, and the normalized Arcane error fields, including code,
|
|
569
|
+
message, and recovery guidance. `policy` is the five-field platform username
|
|
570
|
+
policy returned by `users.list()`.
|
|
571
|
+
|
|
572
|
+
### Errors and recovery
|
|
573
|
+
|
|
574
|
+
Individual invalid values are normally returned in `errors` as
|
|
575
|
+
`INVALID_USERNAME` or `CURRENT_USER_PROTECTED`; the whole call need not reject.
|
|
576
|
+
Use the returned policy and per-item resolution. Validate again immediately
|
|
577
|
+
before a confirmed add because account existence can change after this read.
|
|
578
|
+
|
|
579
|
+
### Example
|
|
580
|
+
|
|
581
|
+
```javascript
|
|
582
|
+
const validation = await Arcane.users.validate(['arcane-user']);
|
|
583
|
+
|
|
584
|
+
if (!validation.valid) {
|
|
585
|
+
for (const error of validation.errors) {
|
|
586
|
+
console.warn(error.code, error.message, error.resolution);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
## Arcane.users.add()
|
|
592
|
+
|
|
593
|
+
### Overview
|
|
594
|
+
|
|
595
|
+
`Arcane.users.add(usernames)` ensures the installation, then creates or
|
|
596
|
+
configures one or more local standard accounts with the verified Arcane login
|
|
597
|
+
shell. It requires `users.manage`, the Provisioner type, elevation, and the
|
|
598
|
+
exclusive Core mutation boundary. The wrapper accepts one username or an array;
|
|
599
|
+
the host validates every value and de-duplicates platform-equivalent names.
|
|
600
|
+
|
|
601
|
+
This is a consequential, non-idempotent account mutation. Existing accounts
|
|
602
|
+
keep their password while receiving a recoverable shell assignment. A newly
|
|
603
|
+
created account is staged disabled, with an exact OS identity and prior-shell
|
|
604
|
+
record, until its returned temporary credential has been delivered and
|
|
605
|
+
`users.activate()` succeeds. The host attempts fail-closed rollback after an
|
|
606
|
+
interruption; recorded partial state must be recovered, not guessed away.
|
|
607
|
+
|
|
608
|
+
### Result, credentials, and events
|
|
609
|
+
|
|
610
|
+
The exact result is `{users, machineUsers, installation, operation,
|
|
611
|
+
credentials}`. `users` contains per-request native results plus
|
|
612
|
+
`passwordStatus` and `activationRequired`; `machineUsers` uses the record shape
|
|
613
|
+
from `users.list()`. `installation` is a fresh installation-status object.
|
|
614
|
+
|
|
615
|
+
For each new account, `credentials` contains exactly `{username,
|
|
616
|
+
temporaryPassword, mustChangeAtNextSignIn: true, reason: "new-account",
|
|
617
|
+
activationRequired: true}`. Save and present the secret once through protected
|
|
618
|
+
UI; never log, copy to telemetry, or persist it in ordinary app storage. The
|
|
619
|
+
standard operation lifecycle events are emitted, and
|
|
620
|
+
`operation.completed.credentials` is equally sensitive.
|
|
621
|
+
|
|
622
|
+
### Errors and recovery
|
|
623
|
+
|
|
624
|
+
Important failures include `ADMIN_REQUIRED`, `OPERATION_BUSY`, username and
|
|
625
|
+
protected-account errors, `RELEASE_SECURITY_UNVERIFIED`,
|
|
626
|
+
`PARTIAL_ACCOUNT_RECOVERY_REQUIRED`, shell backup/change failures, and
|
|
627
|
+
platform user-provisioning failures. Do not repeat an ambiguous add. Refresh
|
|
628
|
+
`users.list()`, preserve any credential already shown, and follow the recorded
|
|
629
|
+
transaction recovery.
|
|
630
|
+
|
|
631
|
+
### Example
|
|
632
|
+
|
|
633
|
+
```javascript
|
|
634
|
+
async function addUserAfterValidation(username, confirmAccountChange) {
|
|
635
|
+
const validation = await Arcane.users.validate([username]);
|
|
636
|
+
if (!validation.valid || !confirmAccountChange(validation.users[0])) {
|
|
637
|
+
return null;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
const result = await Arcane.users.add([validation.users[0].username]);
|
|
641
|
+
// Present result.credentials through protected, non-logging UI.
|
|
642
|
+
return result;
|
|
643
|
+
}
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
## Arcane.users.activate()
|
|
647
|
+
|
|
648
|
+
### Overview
|
|
649
|
+
|
|
650
|
+
`Arcane.users.activate(username)` enables only a newly created, disabled Arcane
|
|
651
|
+
account whose durable staged identity is in `activation-pending`. It requires
|
|
652
|
+
`users.manage`, the Provisioner type, elevation, and the exclusive Core
|
|
653
|
+
mutation boundary. Call it only after the operator has safely received the
|
|
654
|
+
temporary credential returned by `users.add()`.
|
|
655
|
+
|
|
656
|
+
Activation re-verifies the exact SID or uid and Arcane shell assignment before
|
|
657
|
+
enabling the account. It does not activate an existing account or a name-only
|
|
658
|
+
match. The account must change its temporary password at next sign-in.
|
|
659
|
+
|
|
660
|
+
### Result, side effects, and events
|
|
661
|
+
|
|
662
|
+
The exact result is `{user, operation, credentials}`; `credentials` is empty.
|
|
663
|
+
`user` contains the native `username`, stable `sid` or `uid`, `enabled: true`,
|
|
664
|
+
`activated: true`, `activationRequired: false`, and
|
|
665
|
+
`passwordStatus: "temporary-issued"`, with host-specific profile/shell or
|
|
666
|
+
reconciliation fields where applicable. Standard operation events are emitted.
|
|
667
|
+
|
|
668
|
+
### Errors and recovery
|
|
669
|
+
|
|
670
|
+
`STAGED_ACCOUNT_NOT_FOUND` means no exact disabled staged identity is eligible.
|
|
671
|
+
`SHELL_CHANGED_EXTERNALLY`, `INVALID_STAGED_ACCOUNT`, or a changed SID/uid
|
|
672
|
+
blocks activation. Platform failures leave or restore the account disabled
|
|
673
|
+
where possible. Refresh the user inventory and follow the protected recovery
|
|
674
|
+
record; never enable a same-named account manually based only on its name.
|
|
675
|
+
|
|
676
|
+
### Example
|
|
677
|
+
|
|
678
|
+
```javascript
|
|
679
|
+
async function activateStagedUserAfterCredentialDelivery(
|
|
680
|
+
username,
|
|
681
|
+
confirmCredentialDelivered
|
|
682
|
+
) {
|
|
683
|
+
if (!confirmCredentialDelivered(username)) {
|
|
684
|
+
return null;
|
|
685
|
+
}
|
|
686
|
+
return Arcane.users.activate(username);
|
|
687
|
+
}
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
## Arcane.users.resetPassword()
|
|
691
|
+
|
|
692
|
+
### Overview
|
|
693
|
+
|
|
694
|
+
`Arcane.users.resetPassword(username)` prepares a new temporary password for an
|
|
695
|
+
active, recorded Arcane user. Despite its name, this step does not change the
|
|
696
|
+
operating-system password. It requires `users.manage`, the Provisioner type,
|
|
697
|
+
and the exclusive Core operation boundary; the actual privileged change occurs
|
|
698
|
+
only in `users.applyPassword()`.
|
|
699
|
+
|
|
700
|
+
### Result and credential handling
|
|
701
|
+
|
|
702
|
+
The exact result is `{user, operation, credentials}`. `user` is exactly
|
|
703
|
+
`{username, passwordReset: false, applyPasswordRequired: true,
|
|
704
|
+
passwordStatus}`. `credentials` contains one exact object:
|
|
705
|
+
`{username, temporaryPassword, mustChangeAtNextSignIn: true,
|
|
706
|
+
reason: "password-reset", applyPasswordRequired: true}`.
|
|
707
|
+
|
|
708
|
+
The standard operation lifecycle events are emitted. Treat the credential in
|
|
709
|
+
both the response and `operation.completed` event as sensitive, show it through
|
|
710
|
+
protected UI, and do not log or durably store it.
|
|
711
|
+
|
|
712
|
+
### Errors and recovery
|
|
713
|
+
|
|
714
|
+
`USER_NOT_FOUND` means the account is absent or not registered with Arcane.
|
|
715
|
+
`STAGED_ACCOUNT_NOT_ACTIVE` requires completing the staged activation first.
|
|
716
|
+
`NOT_ARCANE_USER` means the protected record does not show an active Arcane
|
|
717
|
+
shell assignment. Since this method has not changed the OS password, a lost
|
|
718
|
+
prepared credential can be discarded and prepared again.
|
|
719
|
+
|
|
720
|
+
### Example
|
|
721
|
+
|
|
722
|
+
```javascript
|
|
723
|
+
async function preparePasswordResetAfterConfirmation(username, confirmReset) {
|
|
724
|
+
if (!confirmReset(username)) {
|
|
725
|
+
return null;
|
|
726
|
+
}
|
|
727
|
+
const prepared = await Arcane.users.resetPassword(username);
|
|
728
|
+
// Pass prepared.credentials[0] only to protected credential UI.
|
|
729
|
+
return prepared;
|
|
730
|
+
}
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
## Arcane.users.applyPassword()
|
|
734
|
+
|
|
735
|
+
### Overview
|
|
736
|
+
|
|
737
|
+
`Arcane.users.applyPassword(username, temporaryPassword)` applies the exact
|
|
738
|
+
temporary password produced by the current Provisioner workflow. It is a
|
|
739
|
+
privileged, exclusive, non-idempotent Core mutation requiring `users.manage`
|
|
740
|
+
and the Provisioner type. It changes the local operating-system password and
|
|
741
|
+
forces a change at the next sign-in.
|
|
742
|
+
|
|
743
|
+
Do not construct a password yourself. The accepted handoff has the generated
|
|
744
|
+
`A!` prefix, 16 base64url characters, and `9z` suffix. Keep it in memory only
|
|
745
|
+
long enough to show and apply it; never place it in a URL, log, diagnostic, or
|
|
746
|
+
ordinary storage.
|
|
747
|
+
|
|
748
|
+
### Result, side effects, and events
|
|
749
|
+
|
|
750
|
+
The exact result is `{user, operation, credentials}` with an empty credentials
|
|
751
|
+
array. `user` contains `username`, `passwordReset: true`,
|
|
752
|
+
`mustChangeAtNextSignIn: true`, `applyPasswordRequired: false`, and
|
|
753
|
+
`passwordStatus: "temporary-issued"`, plus `sid`/`uid` or `enabled` where the
|
|
754
|
+
native host reports it. Standard operation events are emitted with redacted
|
|
755
|
+
command diagnostics.
|
|
756
|
+
|
|
757
|
+
### Errors and recovery
|
|
758
|
+
|
|
759
|
+
`INVALID_TEMPORARY_PASSWORD` rejects anything outside the exact generated
|
|
760
|
+
handoff. `USER_NOT_FOUND` and `NOT_ARCANE_USER` block a changed or inactive
|
|
761
|
+
account. Platform reset failures retain redacted diagnostics. After an
|
|
762
|
+
ambiguous failure, do not generate a different secret immediately: refresh the
|
|
763
|
+
account state and follow the error's reconciliation guidance, because the first
|
|
764
|
+
password may already have been accepted.
|
|
765
|
+
|
|
766
|
+
### Example
|
|
767
|
+
|
|
768
|
+
```javascript
|
|
769
|
+
async function applyPreparedPassword(prepared) {
|
|
770
|
+
const credential = prepared?.credentials?.[0];
|
|
771
|
+
if (!credential || credential.applyPasswordRequired !== true) {
|
|
772
|
+
throw new Error('A current prepared credential is required.');
|
|
773
|
+
}
|
|
774
|
+
return Arcane.users.applyPassword(
|
|
775
|
+
credential.username,
|
|
776
|
+
credential.temporaryPassword
|
|
777
|
+
);
|
|
778
|
+
}
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
## Arcane.users.verifyShell()
|
|
782
|
+
|
|
783
|
+
### Overview
|
|
784
|
+
|
|
785
|
+
`Arcane.users.verifyShell(username)` performs an administrator-backed,
|
|
786
|
+
read-only verification of the recorded account's exact Arcane shell binding.
|
|
787
|
+
It requires `users.manage`, the Provisioner type, and privileged Core access,
|
|
788
|
+
but it does not change the shell. Microsoft NT verifies both protected per-user
|
|
789
|
+
bindings; Linux verifies the protected login-shell field.
|
|
790
|
+
|
|
791
|
+
### Result and events
|
|
792
|
+
|
|
793
|
+
The exact result is `{user, operation, credentials}` with empty credentials.
|
|
794
|
+
`user` is the current host-specific `users.list()` record plus
|
|
795
|
+
`administratorVerified: true` and an `administratorVerifiedAt` timestamp.
|
|
796
|
+
Inspect `user.shellAssigned`; administrative verification can successfully
|
|
797
|
+
complete while reporting a mismatch. Standard operation events are emitted.
|
|
798
|
+
|
|
799
|
+
### Errors and recovery
|
|
800
|
+
|
|
801
|
+
`NOT_ARCANE_USER` means no managed recovery record exists. `USER_NOT_FOUND`
|
|
802
|
+
means the recorded account is gone. Profile, registry, passwd, SID, or uid
|
|
803
|
+
verification errors require administrator review. Do not call
|
|
804
|
+
`restoreShell()` merely because verification failed to run; restore only after
|
|
805
|
+
reviewing a valid mismatch and the recorded baseline.
|
|
806
|
+
|
|
807
|
+
### Example
|
|
808
|
+
|
|
809
|
+
```javascript
|
|
810
|
+
const verification = await Arcane.users.verifyShell('arcane-user');
|
|
811
|
+
|
|
812
|
+
if (!verification.user.shellAssigned) {
|
|
813
|
+
console.warn('The recorded Arcane shell binding does not match.');
|
|
814
|
+
}
|
|
815
|
+
```
|
|
816
|
+
|
|
817
|
+
## Arcane.users.restoreShell()
|
|
818
|
+
|
|
819
|
+
### Overview
|
|
820
|
+
|
|
821
|
+
`Arcane.users.restoreShell(username)` restores the exact prior shell values
|
|
822
|
+
captured before Arcane assigned its login shell. It requires `users.manage`, the
|
|
823
|
+
Provisioner type, elevation, and the exclusive Core mutation boundary. It does
|
|
824
|
+
not delete the account or change its password, but it materially changes what
|
|
825
|
+
starts at the user's next sign-in.
|
|
826
|
+
|
|
827
|
+
Microsoft NT restores both prior policy and legacy shell bindings, including
|
|
828
|
+
their recorded absence. Linux restores the recorded login shell after checking
|
|
829
|
+
the exact uid and ensuring the prior executable still exists. The host refuses
|
|
830
|
+
to overwrite a value changed outside the recorded transaction.
|
|
831
|
+
|
|
832
|
+
### Result, side effects, and events
|
|
833
|
+
|
|
834
|
+
The exact result is `{user, operation, credentials}` with empty credentials.
|
|
835
|
+
`user` contains `username`, `restored: true`, the restored nullable `shell`,
|
|
836
|
+
`shellAssigned: false`, and `verification`, plus Microsoft NT binding fields or
|
|
837
|
+
Linux `profile` and `uid`. Recovery can also report `alreadyRestored: true`.
|
|
838
|
+
Standard operation events are emitted.
|
|
839
|
+
|
|
840
|
+
### Errors and recovery
|
|
841
|
+
|
|
842
|
+
`SHELL_BACKUP_NOT_FOUND` means there is no safe baseline. A staged account must
|
|
843
|
+
be activated or recovered before restore. `SHELL_CHANGED_EXTERNALLY`, changed
|
|
844
|
+
SID/uid errors, or `PREVIOUS_SHELL_MISSING` block mutation rather than guessing.
|
|
845
|
+
Review the account and protected recovery record manually; do not substitute a
|
|
846
|
+
default shell silently.
|
|
847
|
+
|
|
848
|
+
### Example
|
|
849
|
+
|
|
850
|
+
```javascript
|
|
851
|
+
async function restoreShellAfterVerification(username, confirmRestore) {
|
|
852
|
+
const verification = await Arcane.users.verifyShell(username);
|
|
853
|
+
if (!confirmRestore(verification.user)) {
|
|
854
|
+
return null;
|
|
855
|
+
}
|
|
856
|
+
return Arcane.users.restoreShell(username);
|
|
857
|
+
}
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
## Arcane.system.lock()
|
|
861
|
+
|
|
862
|
+
### Overview
|
|
863
|
+
|
|
864
|
+
`Arcane.system.lock()` asks the operating system to lock the current desktop
|
|
865
|
+
session. It requires `session.control`, an application of type `shell`, and a
|
|
866
|
+
Core host. It is an exclusive, non-idempotent session-control request and does
|
|
867
|
+
not merely hide or close Arcane.
|
|
868
|
+
|
|
869
|
+
Microsoft NT dispatches the native workstation-lock command. Linux selects the
|
|
870
|
+
first available supported controller from `loginctl`, GNOME Screensaver, or
|
|
871
|
+
the XDG screensaver command. Simulation records only an explicitly simulated
|
|
872
|
+
request.
|
|
873
|
+
|
|
874
|
+
### Result and side effect
|
|
875
|
+
|
|
876
|
+
On a real host the result is exactly `{requested: true, accepted: true,
|
|
877
|
+
simulated: false, command, pid}`. In simulation it is exactly `{requested:
|
|
878
|
+
true, accepted: true, simulated: true, command, args}`. Acceptance means the
|
|
879
|
+
session controller process started; it is not a later proof that the desktop is
|
|
880
|
+
visibly locked. No Arcane operation or completion event is emitted.
|
|
881
|
+
|
|
882
|
+
### Errors and recovery
|
|
883
|
+
|
|
884
|
+
`SESSION_COMMAND_UNAVAILABLE` means no supported controller exists.
|
|
885
|
+
`SESSION_COMMAND_DISPATCH_FAILED` or `SESSION_COMMAND_DISPATCH_TIMEOUT` means
|
|
886
|
+
the host could not confirm process creation. `METHOD_NOT_ALLOWED` means the
|
|
887
|
+
caller is not the admitted Shell or lacks `session.control`. Do not retry in a
|
|
888
|
+
tight loop after an ambiguous timeout.
|
|
889
|
+
|
|
890
|
+
### Example
|
|
891
|
+
|
|
892
|
+
```javascript
|
|
893
|
+
async function lockSessionAfterConfirmation(confirmLock) {
|
|
894
|
+
if (!confirmLock()) {
|
|
895
|
+
return null;
|
|
896
|
+
}
|
|
897
|
+
return Arcane.system.lock();
|
|
898
|
+
}
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
## Arcane.system.ping()
|
|
902
|
+
|
|
903
|
+
### Overview
|
|
904
|
+
|
|
905
|
+
`Arcane.system.ping()` confirms that the bound Arcane bridge admitted and
|
|
906
|
+
answered one request. It requires no capability and is available on Core and
|
|
907
|
+
Android. It uses a 10-second client timeout, has no side effect, and emits no
|
|
908
|
+
event.
|
|
909
|
+
|
|
910
|
+
### Result and limits
|
|
911
|
+
|
|
912
|
+
The exact result is `{ok: true}`. Success does not prove installation health,
|
|
913
|
+
network reachability, renderer readiness, dependency readiness, elevation,
|
|
914
|
+
publisher trust, signing, or release-candidate status. Use the focused status
|
|
915
|
+
method for each of those questions.
|
|
916
|
+
|
|
917
|
+
### Errors and recovery
|
|
918
|
+
|
|
919
|
+
`ARCANE_TRANSPORT_UNAVAILABLE` means no host is connected.
|
|
920
|
+
`ARCANE_REQUEST_TIMEOUT` means the bridge did not complete before the client
|
|
921
|
+
deadline. Android can reject duplicate or invalid bridge frames. Treat any
|
|
922
|
+
failure as an unknown bridge state and reconnect; do not turn it into a broader
|
|
923
|
+
health diagnosis without evidence.
|
|
924
|
+
|
|
925
|
+
### Example
|
|
926
|
+
|
|
927
|
+
```javascript
|
|
928
|
+
const reply = await Arcane.system.ping();
|
|
929
|
+
console.log('Bridge replied', reply.ok);
|
|
930
|
+
```
|
|
931
|
+
|
|
932
|
+
## Arcane.system.metrics()
|
|
933
|
+
|
|
934
|
+
### Overview
|
|
935
|
+
|
|
936
|
+
`Arcane.system.metrics()` reads a bounded machine resource snapshot. It
|
|
937
|
+
requires `system.metrics.read` on a Core host, changes nothing, and emits no
|
|
938
|
+
event. Metrics are local-machine data; retain only what the UI needs and do not
|
|
939
|
+
use them as a stable device fingerprint.
|
|
940
|
+
|
|
941
|
+
### Result
|
|
942
|
+
|
|
943
|
+
The exact result is `{architecture, logicalProcessors, loadAverage, memory,
|
|
944
|
+
uptimeSeconds}`. `loadAverage` is the operating system's load-average array
|
|
945
|
+
rounded to three decimals. `memory` is exactly `{totalBytes, freeBytes,
|
|
946
|
+
usedBytes}`, with `usedBytes` computed as the nonnegative difference. Uptime is
|
|
947
|
+
the whole number of seconds reported by the OS.
|
|
948
|
+
|
|
949
|
+
This is an observation, not an admission decision. Local-model APIs apply their
|
|
950
|
+
own hardware and memory policy; do not infer model eligibility from these
|
|
951
|
+
values.
|
|
952
|
+
|
|
953
|
+
### Errors and recovery
|
|
954
|
+
|
|
955
|
+
`METHOD_NOT_ALLOWED` means the application lacks `system.metrics.read`.
|
|
956
|
+
Transport failure means the snapshot is unavailable; keep the last value
|
|
957
|
+
visibly stale or clear it rather than reporting zero resources.
|
|
958
|
+
|
|
959
|
+
### Example
|
|
960
|
+
|
|
961
|
+
```javascript
|
|
962
|
+
const metrics = await Arcane.system.metrics();
|
|
963
|
+
const freeGiB = metrics.memory.freeBytes / (1024 ** 3);
|
|
964
|
+
|
|
965
|
+
console.log(metrics.logicalProcessors, `${freeGiB.toFixed(1)} GiB free`);
|
|
966
|
+
```
|
|
967
|
+
|
|
968
|
+
## Arcane.system.failurePolicy()
|
|
969
|
+
|
|
970
|
+
### Overview
|
|
971
|
+
|
|
972
|
+
`Arcane.system.failurePolicy()` reads the user-wide verification behavior used
|
|
973
|
+
by tracked Core operations. It requires `preferences.read`, app id `settings`,
|
|
974
|
+
and a Core host. It has no side effect or event.
|
|
975
|
+
|
|
976
|
+
### Result and behavior
|
|
977
|
+
|
|
978
|
+
The exact result is `{failFast: boolean}`. The default is `false` (warn-first)
|
|
979
|
+
when no saved policy exists. Warn-first lets specifically classified
|
|
980
|
+
verification warnings complete visibly; it never authorizes unverified bytes or
|
|
981
|
+
bypasses a hard identity, privilege, capability, or transaction boundary.
|
|
982
|
+
`true` turns eligible warnings into operation failures.
|
|
983
|
+
|
|
984
|
+
If Core cannot read a corrupt policy, it logs the problem internally and safely
|
|
985
|
+
returns `{failFast: false}` for that process. Settings should present that value
|
|
986
|
+
without claiming the saved file was healthy.
|
|
987
|
+
|
|
988
|
+
### Errors and recovery
|
|
989
|
+
|
|
990
|
+
`METHOD_NOT_ALLOWED` means the caller is not Settings or lacks
|
|
991
|
+
`preferences.read`. Transport failures leave the policy unknown. Use
|
|
992
|
+
`saveFailurePolicy()` for an intentional change; do not mutate the returned
|
|
993
|
+
object.
|
|
994
|
+
|
|
995
|
+
### Example
|
|
996
|
+
|
|
997
|
+
```javascript
|
|
998
|
+
const policy = await Arcane.system.failurePolicy();
|
|
999
|
+
console.log(policy.failFast ? 'Fail fast' : 'Warn first');
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
## Arcane.system.saveFailurePolicy()
|
|
1003
|
+
|
|
1004
|
+
### Overview
|
|
1005
|
+
|
|
1006
|
+
`Arcane.system.saveFailurePolicy(settings)` persists the user-wide verification
|
|
1007
|
+
behavior. It requires `preferences.write`, app id `settings`, and the exclusive
|
|
1008
|
+
Core mutation boundary. `settings` must be an exact object containing only the
|
|
1009
|
+
boolean `failFast` field; values are not coerced.
|
|
1010
|
+
|
|
1011
|
+
The change affects subsequently created tracked operations. It does not change
|
|
1012
|
+
an already running operation and cannot weaken hard trust, authority,
|
|
1013
|
+
privilege, or integrity checks.
|
|
1014
|
+
|
|
1015
|
+
### Result and side effect
|
|
1016
|
+
|
|
1017
|
+
The exact result is `{failFast: boolean}` with the saved value. A real host
|
|
1018
|
+
durably replaces the protected user-wide policy record; simulation changes only
|
|
1019
|
+
simulation state. The method emits no standard operation event.
|
|
1020
|
+
|
|
1021
|
+
### Errors and recovery
|
|
1022
|
+
|
|
1023
|
+
`INVALID_FAILURE_POLICY` rejects missing, nonboolean, or extra fields.
|
|
1024
|
+
`METHOD_NOT_ALLOWED` means the caller is not admitted Settings. `OPERATION_BUSY`
|
|
1025
|
+
means another exclusive mutation is active; wait, re-read the policy, and let
|
|
1026
|
+
the operator confirm the still-desired value.
|
|
1027
|
+
|
|
1028
|
+
### Example
|
|
1029
|
+
|
|
1030
|
+
```javascript
|
|
1031
|
+
async function saveFailurePolicyAfterConfirmation(failFast, confirmChange) {
|
|
1032
|
+
if (!confirmChange(failFast)) {
|
|
1033
|
+
return null;
|
|
1034
|
+
}
|
|
1035
|
+
return Arcane.system.saveFailurePolicy({failFast});
|
|
1036
|
+
}
|
|
1037
|
+
```
|
|
1038
|
+
|
|
1039
|
+
## Arcane.network.status()
|
|
1040
|
+
|
|
1041
|
+
### Overview
|
|
1042
|
+
|
|
1043
|
+
`Arcane.network.status()` reports whether the host sees at least one network
|
|
1044
|
+
interface with a non-loopback address. It requires `network.status.read` and is
|
|
1045
|
+
available on Core and Android. It performs no network request, changes nothing,
|
|
1046
|
+
and emits no event.
|
|
1047
|
+
|
|
1048
|
+
### Result and limits
|
|
1049
|
+
|
|
1050
|
+
The exact result is `{online, interfaceCount}`. `interfaceCount` is a safe
|
|
1051
|
+
integer from 0 through 64, and `online` is exactly
|
|
1052
|
+
`interfaceCount > 0`. It does not prove Internet, DNS, route, captive-portal,
|
|
1053
|
+
mail-gateway, or application-service reachability.
|
|
1054
|
+
|
|
1055
|
+
Use this result only as a coarse UI hint. A network operation still needs its
|
|
1056
|
+
own bounded timeout and surfaced error; do not suppress a retry solely because
|
|
1057
|
+
this snapshot says offline.
|
|
1058
|
+
|
|
1059
|
+
### Errors and recovery
|
|
1060
|
+
|
|
1061
|
+
`METHOD_NOT_ALLOWED` or `ANDROID_CAPABILITY_DENIED` means the grant is absent.
|
|
1062
|
+
`NETWORK_STATUS_UNAVAILABLE` means Core observed more interfaces than its
|
|
1063
|
+
bounded contract accepts. `METHOD_CONTRACT_OUTPUT_INVALID` rejects a
|
|
1064
|
+
contradictory Android or Core result.
|
|
1065
|
+
|
|
1066
|
+
### Example
|
|
1067
|
+
|
|
1068
|
+
```javascript
|
|
1069
|
+
const network = await Arcane.network.status();
|
|
1070
|
+
|
|
1071
|
+
console.log(
|
|
1072
|
+
network.online ? 'Interface present' : 'No non-loopback interface',
|
|
1073
|
+
network.interfaceCount
|
|
1074
|
+
);
|
|
1075
|
+
```
|
|
1076
|
+
|
|
1077
|
+
## Arcane.firewall.status()
|
|
1078
|
+
|
|
1079
|
+
### Overview
|
|
1080
|
+
|
|
1081
|
+
`Arcane.firewall.status()` returns the canonical global-deny policy identity,
|
|
1082
|
+
Arcane-owned native projection state, bounded audit count, coverage limits, and
|
|
1083
|
+
action readiness. It requires `firewall.read`, app id `firewall`, and a Core
|
|
1084
|
+
host. It is a repeatable read with no side effect or event.
|
|
1085
|
+
|
|
1086
|
+
The current lifecycle implementation is development-only. Deterministic
|
|
1087
|
+
simulation can report `supported: true` but always reports
|
|
1088
|
+
`coverage.machineWide: false`. A non-simulated host reports lifecycle mutation
|
|
1089
|
+
unsupported until Core can authenticate its native-host caller. Never present
|
|
1090
|
+
simulation as live traffic enforcement.
|
|
1091
|
+
|
|
1092
|
+
### Result
|
|
1093
|
+
|
|
1094
|
+
The exact top-level result is `{schemaVersion, platform, backend, simulation,
|
|
1095
|
+
supported, coverage, policy, state, projection, auditCount,
|
|
1096
|
+
supportedOperations, warnings}` with `schemaVersion: 1` and
|
|
1097
|
+
`supportedOperations` exactly `['install','enable','disable','rollback',
|
|
1098
|
+
'recover']`.
|
|
1099
|
+
|
|
1100
|
+
`coverage` is exactly `{machineWide, ingress, egress, limitations}`. `policy`
|
|
1101
|
+
is exactly `{schemaVersion, generation, sha256, domainRuleCount,
|
|
1102
|
+
networkRuleCount}`. `state` is exactly `{generation, installed, enabled,
|
|
1103
|
+
installReady, enableReady, recoveryRequired, activePolicyGeneration,
|
|
1104
|
+
activePolicySha256, lastOperation, lastChangedAt}`. `projection` is exactly
|
|
1105
|
+
`{sha256, createdAt, expiresAt, addressCount, directRuleCount,
|
|
1106
|
+
domainRuleCount}`.
|
|
1107
|
+
|
|
1108
|
+
Use `state.installReady` and `state.enableReady` as fail-closed UI gates, then
|
|
1109
|
+
bind any confirmed mutation to `policy.generation` and `state.generation`.
|
|
1110
|
+
Warnings include coverage, expiry, projection, and live-host limitations and
|
|
1111
|
+
must remain visible.
|
|
1112
|
+
|
|
1113
|
+
### Errors and recovery
|
|
1114
|
+
|
|
1115
|
+
`METHOD_NOT_ALLOWED` means the current app is not Arcane Firewall or lacks
|
|
1116
|
+
`firewall.read`. Invalid policy/state or native inspection evidence is reflected
|
|
1117
|
+
as warnings and `recoveryRequired` where safe; a closed-contract failure uses
|
|
1118
|
+
`METHOD_CONTRACT_OUTPUT_INVALID`. Do not enable controls by recomputing
|
|
1119
|
+
readiness in the renderer.
|
|
1120
|
+
|
|
1121
|
+
### Example
|
|
1122
|
+
|
|
1123
|
+
```javascript
|
|
1124
|
+
const status = await Arcane.firewall.status();
|
|
1125
|
+
|
|
1126
|
+
console.log(status.platform, status.backend, status.simulation);
|
|
1127
|
+
console.log('Install ready', status.state.installReady);
|
|
1128
|
+
console.log('Enable ready', status.state.enableReady);
|
|
1129
|
+
for (const warning of status.warnings) {
|
|
1130
|
+
console.warn(warning);
|
|
1131
|
+
}
|
|
1132
|
+
```
|
|
1133
|
+
|
|
1134
|
+
## Arcane.firewall.audit()
|
|
1135
|
+
|
|
1136
|
+
### Overview
|
|
1137
|
+
|
|
1138
|
+
`Arcane.firewall.audit(options?)` returns bounded Arcane Firewall lifecycle and
|
|
1139
|
+
owned-state metadata. It requires `firewall.read`, app id `firewall`, and Core.
|
|
1140
|
+
It does not return packet payloads, full per-packet attribution, credentials, or
|
|
1141
|
+
unbounded history and has no side effect or event.
|
|
1142
|
+
|
|
1143
|
+
`options` is optional. `limit` defaults to 100 and must be a safe integer from
|
|
1144
|
+
1 through 200; invalid values throw `TypeError` before dispatch.
|
|
1145
|
+
|
|
1146
|
+
### Result
|
|
1147
|
+
|
|
1148
|
+
The exact result is `{records, total, truncated, coverage, warning}`.
|
|
1149
|
+
`warning` is a string or `null`. Records are newest first and each is exactly
|
|
1150
|
+
`{id, time, type, operation, stateGeneration, result, direction, ruleId,
|
|
1151
|
+
message}`. `type` is `"lifecycle"` or `"blocked"`; `operation` is one of
|
|
1152
|
+
`install`, `enable`, `disable`, `rollback`, `recover`, or `block`; `direction`
|
|
1153
|
+
and `ruleId` may be `null`.
|
|
1154
|
+
|
|
1155
|
+
`total` is the retained audit count, capped at 500. `truncated` says the chosen
|
|
1156
|
+
limit omitted retained records; it does not claim Arcane captured every network
|
|
1157
|
+
decision.
|
|
1158
|
+
|
|
1159
|
+
### Errors and recovery
|
|
1160
|
+
|
|
1161
|
+
`METHOD_NOT_ALLOWED` means the Firewall read boundary is absent.
|
|
1162
|
+
`METHOD_CONTRACT_INPUT_INVALID` indicates a malformed native request; use the
|
|
1163
|
+
public wrapper and documented limit. A damaged state record can return an empty
|
|
1164
|
+
audit with its failure in `warning`, allowing the UI to offer Recovery without
|
|
1165
|
+
claiming that no history exists.
|
|
1166
|
+
|
|
1167
|
+
### Example
|
|
1168
|
+
|
|
1169
|
+
```javascript
|
|
1170
|
+
const audit = await Arcane.firewall.audit({limit: 50});
|
|
1171
|
+
|
|
1172
|
+
for (const record of audit.records) {
|
|
1173
|
+
console.log(record.time, record.operation, record.result, record.message);
|
|
1174
|
+
}
|
|
1175
|
+
if (audit.warning) {
|
|
1176
|
+
console.warn(audit.warning);
|
|
1177
|
+
}
|
|
1178
|
+
```
|
|
1179
|
+
|
|
1180
|
+
## Arcane.firewall.install()
|
|
1181
|
+
|
|
1182
|
+
### Overview
|
|
1183
|
+
|
|
1184
|
+
`Arcane.firewall.install(expectation)` resolves and stages the reviewed
|
|
1185
|
+
canonical deny-policy projection. It requires `firewall.manage`, app id
|
|
1186
|
+
`firewall`, elevated Core authority, the exclusive mutation boundary, and a
|
|
1187
|
+
separate user confirmation. It is non-idempotent and currently succeeds only in
|
|
1188
|
+
deterministic development simulation; live mutation fails explicitly.
|
|
1189
|
+
|
|
1190
|
+
`expectation` must be an exact plain object containing the current positive
|
|
1191
|
+
`expectedPolicyGeneration` and nonnegative `expectedStateGeneration` from one
|
|
1192
|
+
fresh `firewall.status()` result. Unknown, missing, stale, fractional, or
|
|
1193
|
+
negative values are rejected.
|
|
1194
|
+
|
|
1195
|
+
Install may use bounded system DNS to project domain rules to addresses. One
|
|
1196
|
+
projection admits at most 4,096 domain rules. It stages Arcane-owned state with
|
|
1197
|
+
enforcement disabled; an enabled generation must be disabled first.
|
|
1198
|
+
|
|
1199
|
+
### Result, side effects, and events
|
|
1200
|
+
|
|
1201
|
+
Every firewall mutation resolves to exactly `{status, receipt, operation}`.
|
|
1202
|
+
`status` is the full fresh status object. `receipt` is exactly `{schemaVersion,
|
|
1203
|
+
operation, ownedNamespace, backend, policyGeneration, projectionSha256,
|
|
1204
|
+
completedAt, transactionId}`. `operation` is the completed standard operation
|
|
1205
|
+
record; its type is `"firewall.install"`, progress is 100, credentials is empty,
|
|
1206
|
+
and error is null. Standard operation events are emitted.
|
|
1207
|
+
|
|
1208
|
+
### Errors and recovery
|
|
1209
|
+
|
|
1210
|
+
Bad JavaScript input throws `TypeError`; stale snapshots use
|
|
1211
|
+
`FIREWALL_POLICY_GENERATION_STALE` or `FIREWALL_STATE_GENERATION_STALE`.
|
|
1212
|
+
`FIREWALL_HOST_AUTHENTICATION_UNAVAILABLE` identifies the current live-host
|
|
1213
|
+
boundary. Other important failures include `FIREWALL_MUTATION_BUSY`,
|
|
1214
|
+
`OPERATION_BUSY`, `FIREWALL_RECOVERY_REQUIRED`, `FIREWALL_DISABLE_REQUIRED`,
|
|
1215
|
+
bounded DNS/projection failures, and cancellation. Refresh status after any
|
|
1216
|
+
failure; do not reuse old generations.
|
|
1217
|
+
|
|
1218
|
+
### Example
|
|
1219
|
+
|
|
1220
|
+
```javascript
|
|
1221
|
+
async function installFirewallAfterConfirmation(confirmInstall) {
|
|
1222
|
+
const status = await Arcane.firewall.status();
|
|
1223
|
+
if (!status.simulation || !status.supported || !status.state.installReady) {
|
|
1224
|
+
return null;
|
|
1225
|
+
}
|
|
1226
|
+
if (!confirmInstall(status)) {
|
|
1227
|
+
return null;
|
|
1228
|
+
}
|
|
1229
|
+
return Arcane.firewall.install({
|
|
1230
|
+
expectedPolicyGeneration: status.policy.generation,
|
|
1231
|
+
expectedStateGeneration: status.state.generation
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
```
|
|
1235
|
+
|
|
1236
|
+
## Arcane.firewall.enable()
|
|
1237
|
+
|
|
1238
|
+
### Overview
|
|
1239
|
+
|
|
1240
|
+
`Arcane.firewall.enable(expectation)` enables only the exact installed,
|
|
1241
|
+
unexpired projection for the current canonical policy. It requires
|
|
1242
|
+
`firewall.manage`, app id `firewall`, elevated Core authority, exclusive
|
|
1243
|
+
mutation, and separate confirmation. It does not resolve domains or silently
|
|
1244
|
+
replace a stale projection. Current success is simulation-only and never proves
|
|
1245
|
+
machine-wide enforcement.
|
|
1246
|
+
|
|
1247
|
+
Pass the two exact current generations from a status whose
|
|
1248
|
+
`state.enableReady` is true. The host repeats all generation, recovery,
|
|
1249
|
+
prerequisite, policy hash, installation, and projection-expiry checks after
|
|
1250
|
+
dispatch.
|
|
1251
|
+
|
|
1252
|
+
### Result, side effects, and events
|
|
1253
|
+
|
|
1254
|
+
The exact result is `{status, receipt, operation}` with the receipt fields
|
|
1255
|
+
documented under `firewall.install()`. The receipt operation is `"enable"`, and
|
|
1256
|
+
the tracked operation type is `"firewall.enable"`. The returned status has a
|
|
1257
|
+
new state generation and reports the resulting simulated enabled state.
|
|
1258
|
+
Standard operation events are emitted.
|
|
1259
|
+
|
|
1260
|
+
### Errors and recovery
|
|
1261
|
+
|
|
1262
|
+
In addition to stale, busy, recovery, and live-host errors, enable can reject
|
|
1263
|
+
with `FIREWALL_NATIVE_PREREQUISITE_REQUIRED`, `FIREWALL_ALREADY_ENABLED`,
|
|
1264
|
+
`FIREWALL_INSTALL_REQUIRED`, or `FIREWALL_PROJECTION_EXPIRED`. Refresh status;
|
|
1265
|
+
an expired or mismatched projection requires a newly confirmed Install, not an
|
|
1266
|
+
automatic enable retry.
|
|
1267
|
+
|
|
1268
|
+
### Example
|
|
1269
|
+
|
|
1270
|
+
```javascript
|
|
1271
|
+
async function enableFirewallAfterConfirmation(confirmEnable) {
|
|
1272
|
+
const status = await Arcane.firewall.status();
|
|
1273
|
+
if (!status.simulation || !status.supported || !status.state.enableReady) {
|
|
1274
|
+
return null;
|
|
1275
|
+
}
|
|
1276
|
+
if (!confirmEnable(status)) {
|
|
1277
|
+
return null;
|
|
1278
|
+
}
|
|
1279
|
+
return Arcane.firewall.enable({
|
|
1280
|
+
expectedPolicyGeneration: status.policy.generation,
|
|
1281
|
+
expectedStateGeneration: status.state.generation
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
```
|
|
1285
|
+
|
|
1286
|
+
## Arcane.firewall.disable()
|
|
1287
|
+
|
|
1288
|
+
### Overview
|
|
1289
|
+
|
|
1290
|
+
`Arcane.firewall.disable(expectation)` disables only Arcane-owned firewall
|
|
1291
|
+
state. It requires `firewall.manage`, app id `firewall`, elevated Core
|
|
1292
|
+
authority, exclusive mutation, fresh generations, and separate confirmation.
|
|
1293
|
+
It does not disable or rewrite firewall rules owned by another product. Current
|
|
1294
|
+
success affects only deterministic simulation state.
|
|
1295
|
+
|
|
1296
|
+
### Result, side effects, and events
|
|
1297
|
+
|
|
1298
|
+
The exact result is `{status, receipt, operation}`. The receipt operation is
|
|
1299
|
+
`"disable"`, the tracked operation type is `"firewall.disable"`, and the fresh
|
|
1300
|
+
status reports `enabled: false` with an incremented state generation. Standard
|
|
1301
|
+
operation events are emitted. Request acceptance is not a live enforcement
|
|
1302
|
+
claim; check the returned labeled status.
|
|
1303
|
+
|
|
1304
|
+
### Errors and recovery
|
|
1305
|
+
|
|
1306
|
+
`FIREWALL_NOT_INSTALLED` means there is no Arcane-owned installed generation to
|
|
1307
|
+
disable. Recovery-required, stale-generation, busy, and live-host-authentication
|
|
1308
|
+
errors fail without guessing ownership. Refresh status and confirm again; use
|
|
1309
|
+
Recovery only when the returned state explicitly requires reconciliation.
|
|
1310
|
+
|
|
1311
|
+
### Example
|
|
1312
|
+
|
|
1313
|
+
```javascript
|
|
1314
|
+
async function disableFirewallAfterConfirmation(confirmDisable) {
|
|
1315
|
+
const status = await Arcane.firewall.status();
|
|
1316
|
+
if (!status.simulation || !status.supported || !status.state.enabled) {
|
|
1317
|
+
return null;
|
|
1318
|
+
}
|
|
1319
|
+
if (!confirmDisable(status)) {
|
|
1320
|
+
return null;
|
|
1321
|
+
}
|
|
1322
|
+
return Arcane.firewall.disable({
|
|
1323
|
+
expectedPolicyGeneration: status.policy.generation,
|
|
1324
|
+
expectedStateGeneration: status.state.generation
|
|
1325
|
+
});
|
|
1326
|
+
}
|
|
1327
|
+
```
|
|
1328
|
+
|
|
1329
|
+
## Arcane.firewall.rollback()
|
|
1330
|
+
|
|
1331
|
+
### Overview
|
|
1332
|
+
|
|
1333
|
+
`Arcane.firewall.rollback(expectation)` restores one retained Arcane-owned
|
|
1334
|
+
projection only when it belongs to the same canonical policy, remains
|
|
1335
|
+
unexpired, and preserves every deny in the current projection. It requires
|
|
1336
|
+
`firewall.manage`, app id `firewall`, elevated Core authority, exclusive
|
|
1337
|
+
mutation, fresh generations, and separate confirmation. Current success is
|
|
1338
|
+
simulation-only.
|
|
1339
|
+
|
|
1340
|
+
Rollback never means “use any previous policy.” The host refuses a different
|
|
1341
|
+
policy generation/hash or a projection that would weaken current deny coverage.
|
|
1342
|
+
It reapplies the retained projection in the current installed/enabled mode.
|
|
1343
|
+
|
|
1344
|
+
### Result, side effects, and events
|
|
1345
|
+
|
|
1346
|
+
The exact result is `{status, receipt, operation}`. The tracked operation type
|
|
1347
|
+
is `"firewall.rollback"` and returned status records `lastOperation:
|
|
1348
|
+
"rollback"`. The native receipt's `operation` is `"install"` or `"enable"`
|
|
1349
|
+
because that is the concrete reapplication performed; there is intentionally no
|
|
1350
|
+
`"rollback"` receipt operation. Standard operation events are emitted.
|
|
1351
|
+
|
|
1352
|
+
### Errors and recovery
|
|
1353
|
+
|
|
1354
|
+
Rollback-specific failures are `FIREWALL_ROLLBACK_UNAVAILABLE`,
|
|
1355
|
+
`FIREWALL_ROLLBACK_POLICY_MISMATCH`,
|
|
1356
|
+
`FIREWALL_ROLLBACK_PROJECTION_EXPIRED`, `FIREWALL_CURRENT_POLICY_STALE`, and
|
|
1357
|
+
`FIREWALL_ROLLBACK_WOULD_WEAKEN_POLICY`. Keep the current state on rejection.
|
|
1358
|
+
Use a separately confirmed Disable, Install, and Enable sequence when the
|
|
1359
|
+
retained projection cannot be safely reused.
|
|
1360
|
+
|
|
1361
|
+
### Example
|
|
1362
|
+
|
|
1363
|
+
```javascript
|
|
1364
|
+
async function rollbackFirewallAfterConfirmation(confirmRollback) {
|
|
1365
|
+
const status = await Arcane.firewall.status();
|
|
1366
|
+
if (!status.simulation || !status.supported || status.state.recoveryRequired) {
|
|
1367
|
+
return null;
|
|
1368
|
+
}
|
|
1369
|
+
if (!confirmRollback(status)) {
|
|
1370
|
+
return null;
|
|
1371
|
+
}
|
|
1372
|
+
return Arcane.firewall.rollback({
|
|
1373
|
+
expectedPolicyGeneration: status.policy.generation,
|
|
1374
|
+
expectedStateGeneration: status.state.generation
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
```
|
|
1378
|
+
|
|
1379
|
+
## Arcane.firewall.recover()
|
|
1380
|
+
|
|
1381
|
+
### Overview
|
|
1382
|
+
|
|
1383
|
+
`Arcane.firewall.recover(expectation)` explicitly reconciles and removes only
|
|
1384
|
+
Arcane-owned firewall state when consistency or native inspection indicates
|
|
1385
|
+
recovery is required. It requires `firewall.manage`, app id `firewall`,
|
|
1386
|
+
elevated Core authority, exclusive mutation, fresh generations, and separate
|
|
1387
|
+
confirmation. Current success changes deterministic simulation state only.
|
|
1388
|
+
|
|
1389
|
+
Recovery is not a general firewall reset. The backend is constrained to its
|
|
1390
|
+
Arcane-owned namespace; unrelated firewall state is outside the operation.
|
|
1391
|
+
|
|
1392
|
+
### Result, side effects, and events
|
|
1393
|
+
|
|
1394
|
+
The exact result is `{status, receipt, operation}`. The receipt operation is
|
|
1395
|
+
`"recover"`, the tracked operation type is `"firewall.recover"`, and successful
|
|
1396
|
+
status returns the Arcane state to its default noninstalled, disabled,
|
|
1397
|
+
non-recovery state at a new generation. Standard operation events are emitted.
|
|
1398
|
+
|
|
1399
|
+
### Errors and recovery
|
|
1400
|
+
|
|
1401
|
+
Stale generation, busy operation, privilege, and live-host-authentication
|
|
1402
|
+
failures still apply. Recovery may read a damaged consistency record, but it
|
|
1403
|
+
does not bypass policy identity or ownership. Preserve a failed transaction's
|
|
1404
|
+
diagnostic and avoid parallel retries; refresh status only after the exclusive
|
|
1405
|
+
operation has finished.
|
|
1406
|
+
|
|
1407
|
+
### Example
|
|
1408
|
+
|
|
1409
|
+
```javascript
|
|
1410
|
+
async function recoverFirewallAfterConfirmation(confirmRecovery) {
|
|
1411
|
+
const status = await Arcane.firewall.status();
|
|
1412
|
+
if (!status.simulation || !status.supported || !status.state.recoveryRequired) {
|
|
1413
|
+
return null;
|
|
1414
|
+
}
|
|
1415
|
+
if (!confirmRecovery(status)) {
|
|
1416
|
+
return null;
|
|
1417
|
+
}
|
|
1418
|
+
return Arcane.firewall.recover({
|
|
1419
|
+
expectedPolicyGeneration: status.policy.generation,
|
|
1420
|
+
expectedStateGeneration: status.state.generation
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
```
|