arcane-os 0.26.0 → 0.27.1
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 +27 -0
- package/README.md +9 -4
- package/browser-runtime/pwa-install.mjs +3 -3
- package/docs/architecture.md +19 -8
- package/docs/reference/cli.md +18 -7
- package/docs/reference/protocols.md +30 -8
- package/docs/reference/pwa.md +24 -0
- package/package.json +2 -2
- package/runtime/arcane/components/dashboard-config.html +2 -1
- package/runtime/arcane/components/data-view.html +2 -1
- package/runtime/arcane/components/file-manager.html +7 -6
- package/src/app-descriptor.mjs +3 -1
- package/src/app-layout.mjs +32 -0
- package/src/application-tests.mjs +3 -1
- package/src/cli/main.mjs +9 -12
- package/src/dev-server.mjs +82 -24
- package/src/import-map.mjs +26 -10
- package/src/packager/core.mjs +79 -21
- package/src/pwa-worker.mjs +18 -4
- package/src/pwa.mjs +55 -10
- package/src/scaffold.mjs +43 -7
- package/src/sdk-runtime-layout.mjs +28 -15
- package/src/templates/workspace-template.mjs +44 -36
- package/src/toolchain.mjs +76 -3
- package/src/workspace.mjs +46 -38
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.27.1
|
|
4
|
+
|
|
5
|
+
- Preserve the previous `apps/<id>/arcane-sw.js` and `arcane-offline.json`
|
|
6
|
+
endpoints when generating a root-layout PWA. Both use the canonical worker
|
|
7
|
+
and current root inventory, including navigation aliases and installed npm
|
|
8
|
+
resource paths; portable output also retains deployment-relative URLs.
|
|
9
|
+
- Serve those previous worker and inventory endpoints directly during SDK
|
|
10
|
+
development instead of redirecting worker-script requests. Retain ordinary
|
|
11
|
+
browser update/activation, caches, application identity and saved data.
|
|
12
|
+
- Keep root layout optional and existing multi-app and Node server behavior
|
|
13
|
+
unchanged. Installed-application execution remains consumer-owned.
|
|
14
|
+
|
|
15
|
+
## 0.27.0
|
|
16
|
+
|
|
17
|
+
- Add optional standalone `appsRoot: "."` discovery and `new`/`init --apps-root .`.
|
|
18
|
+
Preserve declared app IDs, existing multi-app/integrated layouts, nested pages,
|
|
19
|
+
and the selected native/portable package interface.
|
|
20
|
+
- Serve and package direct installed SDK URLs under `/node_modules/<dependency>/`.
|
|
21
|
+
Managed bare and relative imports select the same module instances, including
|
|
22
|
+
npm aliases; dynamic component resources resolve from their own installed URL.
|
|
23
|
+
- Generate root static PWA files and prior `/apps/<id>/` navigation pages through
|
|
24
|
+
the existing `arcane import-map` operation. Preserve authored installation IDs,
|
|
25
|
+
source/package defaults, query strings, fragments, and complete app content.
|
|
26
|
+
Ordinary static hosts need no additional SDK server or copied runtime.
|
|
27
|
+
- Keep existing physical and virtual browser routes, Node mail APIs, listener
|
|
28
|
+
configuration, and server-consumer entrypoints unchanged.
|
|
29
|
+
|
|
3
30
|
## 0.26.0
|
|
4
31
|
|
|
5
32
|
- Add explicit installed-package browser runtime routes. Source development,
|
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ version-locked SDK runtime, while an integrated Arcane checkout uses its live
|
|
|
19
19
|
`arcane/` runtime. Both profiles preserve the same app URLs, theme, packaging,
|
|
20
20
|
event, cancellation, and browser run contracts.
|
|
21
21
|
|
|
22
|
-
This checkout defines the `0.
|
|
22
|
+
This checkout defines the `0.27.1` SDK contract. Applications pin one exact npm
|
|
23
23
|
version and lockfile; registry state is deliberately not baked into application
|
|
24
24
|
artifacts.
|
|
25
25
|
|
|
@@ -27,9 +27,14 @@ External browser apps can use the installed npm package directly, without a
|
|
|
27
27
|
generated workspace `arcane/` directory or `arcane.lock.json`. Select the
|
|
28
28
|
[four installed-package routes](docs/reference/protocols.md#installed-package-browser-routes)
|
|
29
29
|
in `arcane-packager.json`: development, managed import maps, and PWA resources
|
|
30
|
-
read the installed SDK
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
read the installed SDK at real `/node_modules/arcane-os/...` browser URLs when
|
|
31
|
+
each destination equals its source. An alias uses its actual installed folder.
|
|
32
|
+
Select `appsRoot: "."` for a standalone root app, or scaffold one with
|
|
33
|
+
`arcane new my-app --apps-root .`. After npm installation, `arcane import-map`
|
|
34
|
+
refreshes managed maps and the root app's static PWA/navigation files for ordinary
|
|
35
|
+
static hosting. Portable app packages still contain their selected runtime.
|
|
36
|
+
Existing `apps/<id>`, virtual `/arcane` routes, and materialized workspaces remain
|
|
37
|
+
supported. Node services continue to
|
|
33
38
|
use the installed CLI or public imports such as `arcane-os/mail`.
|
|
34
39
|
|
|
35
40
|
The [mail gateway](docs/reference/mail.md) serves HTTPS with HTTP/2 on port 4433
|
|
@@ -273,8 +273,8 @@ export function mountPwaInstallPrompt({appName = ''} = {}) {
|
|
|
273
273
|
if (!globalThis.document) return null;
|
|
274
274
|
// Both modules may start independently; saved theme loading is not a barrier.
|
|
275
275
|
await Promise.all([
|
|
276
|
-
import(
|
|
277
|
-
import(
|
|
276
|
+
import('arcane/HTMLImport'),
|
|
277
|
+
import('arcane/ThemeBootstrap')
|
|
278
278
|
]);
|
|
279
279
|
if (owner.state.status === 'disposed') return null;
|
|
280
280
|
if (!document.body) {
|
|
@@ -295,7 +295,7 @@ export function mountPwaInstallPrompt({appName = ''} = {}) {
|
|
|
295
295
|
host.hidden = true;
|
|
296
296
|
host.dataset.appName = String(appName);
|
|
297
297
|
host.dataset.arcanePwaInstall = '';
|
|
298
|
-
host.setAttribute('href', new URL('../components/pwa-install.html', import.meta.
|
|
298
|
+
host.setAttribute('href', new URL('../components/pwa-install.html', import.meta.resolve('arcane/HTMLImport')).href);
|
|
299
299
|
return new Promise(function waitForInstallComponent(resolve, reject) {
|
|
300
300
|
const observer = new MutationObserver(function observeRemovedInstallComponent() {
|
|
301
301
|
if (!host.isConnected) cancelMount();
|
package/docs/architecture.md
CHANGED
|
@@ -87,10 +87,11 @@ app-scoped toolchain operation unchanged.
|
|
|
87
87
|
An external workspace can select `installed-v1` routes directly from its
|
|
88
88
|
`node_modules/arcane-os` installation, without a workspace `arcane/` tree or
|
|
89
89
|
`arcane.lock.json`. The SDK reads the installed package version and maps its
|
|
90
|
-
runtime, browser runtime, runtime dependency, and licenses to the
|
|
91
|
-
browser destinations.
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
runtime, browser runtime, runtime dependency, and licenses to the configured
|
|
91
|
+
browser destinations. Direct destinations are the real npm paths. Existing
|
|
92
|
+
`physical-v1` workspaces, virtual installed routes, and the explicit materializer
|
|
93
|
+
remain supported. Root scaffolding selects direct npm routes; the existing
|
|
94
|
+
multi-app scaffold retains its physical layout. See [installed-package routes](reference/protocols.md#installed-package-browser-routes)
|
|
94
95
|
for the configuration and npm-alias form.
|
|
95
96
|
|
|
96
97
|
An Arcane OS checkout is an integrated SDK consumer, not the owner
|
|
@@ -245,14 +246,24 @@ apps synthesize that descriptor from their schema-1 package plus the current
|
|
|
245
246
|
native registry during migration.
|
|
246
247
|
|
|
247
248
|
An external app can use four `installed-v1` shared routes in
|
|
248
|
-
`arcane-packager.json
|
|
249
|
-
|
|
250
|
-
`/arcane/
|
|
251
|
-
`/
|
|
249
|
+
`arcane-packager.json`. With each destination equal to its source, browser URLs
|
|
250
|
+
point directly into `/node_modules/arcane-os/runtime/arcane`,
|
|
251
|
+
`/node_modules/arcane-os/browser-runtime`, and
|
|
252
|
+
`/node_modules/arcane-os/runtime/strong-type`; the three package license files
|
|
253
|
+
remain in `/node_modules/arcane-os`. An alias uses its actual installed folder.
|
|
254
|
+
Source serving and import-map generation read those
|
|
252
255
|
installed files without creating a workspace runtime copy. Distribution copies
|
|
253
256
|
the selected routes completely inside the portable artifact, preserving the
|
|
254
257
|
same URLs. Existing physical `arcane/` routes retain their behavior.
|
|
255
258
|
|
|
259
|
+
`appsRoot: "."` places one standalone application at the workspace root while
|
|
260
|
+
retaining its declared ID and app-relative entries. The existing `apps` option
|
|
261
|
+
keeps multi-app and integrated layouts. Root static hosting consumes the same
|
|
262
|
+
npm URLs, managed maps, generated PWA files, and compatibility navigation pages
|
|
263
|
+
as SDK development. TWiN's ordinary static host needs no additional server;
|
|
264
|
+
separate Node API hosts such as Stripe keep their existing server and SDK mail
|
|
265
|
+
imports. Application location does not change their listeners or configuration.
|
|
266
|
+
|
|
256
267
|
Release schema 1 and builder identity `arcane-app-packager-v1` remain unchanged
|
|
257
268
|
because current Arcane native consumers treat them as public contracts. Native
|
|
258
269
|
builders consume the schema-2 descriptor as a separate build input while v1
|
package/docs/reference/cli.md
CHANGED
|
@@ -109,7 +109,7 @@ Creates one repository-shaped external application workspace and the selected
|
|
|
109
109
|
app. It never creates more than one app or silently installs a global SDK.
|
|
110
110
|
|
|
111
111
|
```text
|
|
112
|
-
arcane new <id> [--path <directory>] [--display-name <name>] [--target <target>] [--git]
|
|
112
|
+
arcane new <id> [--path <directory>] [--apps-root apps|.] [--display-name <name>] [--target <target>] [--git]
|
|
113
113
|
```
|
|
114
114
|
|
|
115
115
|
### Options and result
|
|
@@ -120,6 +120,12 @@ directory as a repository. Native target scaffolds also retain `browser` and
|
|
|
120
120
|
include the required icon. The result reports the workspace, app, descriptor,
|
|
121
121
|
target, and created paths.
|
|
122
122
|
|
|
123
|
+
`--apps-root .` creates a standalone root application using its installed npm
|
|
124
|
+
SDK directly. The default `--apps-root apps` preserves `apps/<id>`. Root setup
|
|
125
|
+
does not install dependencies or copy a runtime: run `npm install`, then
|
|
126
|
+
`npm run import-map`. Until installation, its result reports the import map as
|
|
127
|
+
pending with reason `sdk-install-required`.
|
|
128
|
+
|
|
123
129
|
### Example
|
|
124
130
|
|
|
125
131
|
```bash
|
|
@@ -135,7 +141,7 @@ initialization writes only the selected `apps/<id>/` boundary and does not add
|
|
|
135
141
|
an SDK dependency to the Arcane OS repository.
|
|
136
142
|
|
|
137
143
|
```text
|
|
138
|
-
arcane init [id] [--workspace <directory>] [--app <id>] [--display-name <name>] [--target <target>]
|
|
144
|
+
arcane init [id] [--workspace <directory>] [--app <id>] [--apps-root apps|.] [--display-name <name>] [--target <target>]
|
|
139
145
|
```
|
|
140
146
|
|
|
141
147
|
### Errors and safety
|
|
@@ -145,6 +151,10 @@ incompatible workspace fail rather than being overwritten. Initialization is
|
|
|
145
151
|
idempotent only for files whose existing content satisfies the scaffold
|
|
146
152
|
contract.
|
|
147
153
|
|
|
154
|
+
`--apps-root .` selects root setup for a standalone workspace. Omission retains
|
|
155
|
+
the configured layout, or `apps` for a new configuration. `init` never moves an
|
|
156
|
+
existing application or converts the integrated Arcane OS layout.
|
|
157
|
+
|
|
148
158
|
### Example
|
|
149
159
|
|
|
150
160
|
```bash
|
|
@@ -318,13 +328,14 @@ workspace/runtime routes. It defaults to HTTPS on localhost; `--public` enables
|
|
|
318
328
|
from other devices on the network, using HTTPS by default.
|
|
319
329
|
|
|
320
330
|
For an external workspace, the server exposes the selected SDK routes alongside
|
|
321
|
-
the application. `installed-v1`
|
|
322
|
-
|
|
323
|
-
|
|
331
|
+
the application. Direct `installed-v1` routes serve the real
|
|
332
|
+
`/node_modules/<dependency>/...` URLs without creating a workspace runtime
|
|
333
|
+
directory. Earlier virtual `/arcane` installed routes remain supported.
|
|
334
|
+
Existing `physical-v1` workspaces serve
|
|
324
335
|
their projected `arcane/` root. Integrated workspaces retain their configured
|
|
325
336
|
physical routes.
|
|
326
|
-
|
|
327
|
-
installed
|
|
337
|
+
An explicit live-source SDK mapping follows the selected browser destinations
|
|
338
|
+
while reading canonical SDK source; it never replaces installed files.
|
|
328
339
|
|
|
329
340
|
```text
|
|
330
341
|
arcane dev [--app <id>] [--public] [--http | --https] [--cert <file> --key <file>] [--host <address>] [--port 8000] [--http-port 0]
|
|
@@ -107,31 +107,31 @@ needed:
|
|
|
107
107
|
```json
|
|
108
108
|
{
|
|
109
109
|
"schemaVersion": 1,
|
|
110
|
-
"appsRoot": "
|
|
110
|
+
"appsRoot": ".",
|
|
111
111
|
"distRoot": "dist",
|
|
112
112
|
"sharedPayloads": {
|
|
113
113
|
"browser-runtime": [
|
|
114
114
|
{
|
|
115
115
|
"source": "node_modules/arcane-os/runtime/arcane",
|
|
116
|
-
"destination": "arcane",
|
|
116
|
+
"destination": "node_modules/arcane-os/runtime/arcane",
|
|
117
117
|
"include": ["components", "css", "entities", "img", "modules"],
|
|
118
118
|
"exclude": []
|
|
119
119
|
},
|
|
120
120
|
{
|
|
121
121
|
"source": "node_modules/arcane-os/browser-runtime",
|
|
122
|
-
"destination": "arcane/
|
|
122
|
+
"destination": "node_modules/arcane-os/browser-runtime",
|
|
123
123
|
"include": ["."],
|
|
124
124
|
"exclude": []
|
|
125
125
|
},
|
|
126
126
|
{
|
|
127
127
|
"source": "node_modules/arcane-os/runtime/strong-type",
|
|
128
|
-
"destination": "arcane/
|
|
128
|
+
"destination": "node_modules/arcane-os/runtime/strong-type",
|
|
129
129
|
"include": ["."],
|
|
130
130
|
"exclude": []
|
|
131
131
|
},
|
|
132
132
|
{
|
|
133
133
|
"source": "node_modules/arcane-os",
|
|
134
|
-
"destination": "
|
|
134
|
+
"destination": "node_modules/arcane-os",
|
|
135
135
|
"include": ["LICENSE", "COMMERCIAL-LICENSE.md", "NOTICE"],
|
|
136
136
|
"exclude": []
|
|
137
137
|
}
|
|
@@ -142,22 +142,44 @@ needed:
|
|
|
142
142
|
|
|
143
143
|
The first include list also accepts a final `security` entry. An npm alias such
|
|
144
144
|
as `arcane-sdk` substitutes `node_modules/arcane-sdk` for the package prefix in
|
|
145
|
-
all four source
|
|
145
|
+
all four source and destination paths. Package selection and SDK
|
|
146
146
|
version come from the installed dependency, not a generated runtime lock.
|
|
147
147
|
|
|
148
148
|
`arcane import-map`, `arcane dev`, packaging, and generated PWA inventories use
|
|
149
|
-
the same
|
|
149
|
+
the same actual npm destinations. For example, `arcane/HTMLImport` resolves to
|
|
150
|
+
`./node_modules/arcane-os/runtime/arcane/modules/HTMLImport.js`, and
|
|
151
|
+
`arcane-os/event-manager` resolves to
|
|
152
|
+
`./node_modules/arcane-os/browser-runtime/event-manager.mjs`. A normal static
|
|
153
|
+
server can serve those files directly. Source serving and map generation read installed
|
|
150
154
|
files without materializing them into the workspace. A selected portable
|
|
151
155
|
package copies its complete selected resources inside the artifact, preserving
|
|
152
156
|
the same browser URLs and saved managed import maps.
|
|
153
157
|
|
|
154
158
|
Existing `physical-v1` configurations whose first source is `arcane` remain
|
|
155
159
|
supported. The explicit materializer below still refreshes those projections,
|
|
156
|
-
and
|
|
160
|
+
and the default multi-app scaffold retains its existing physical layout. The
|
|
161
|
+
earlier installed routes with virtual `/arcane` destinations also remain
|
|
162
|
+
supported. Selecting `installed-v1`
|
|
157
163
|
does not delete any preexisting workspace files. The separate host-document
|
|
158
164
|
`generateDocumentImportMaps()` API continues to accept an already materialized
|
|
159
165
|
runtime; its input contract is unchanged.
|
|
160
166
|
|
|
167
|
+
### Optional standalone root application
|
|
168
|
+
|
|
169
|
+
`appsRoot: "."` selects one application whose `arcane-app.json`,
|
|
170
|
+
`arcane-package.json`, entry, and app-owned files occupy the workspace root.
|
|
171
|
+
The declared application ID remains unchanged. `appsRoot: "apps"` continues
|
|
172
|
+
to discover `apps/<id>` and supports the existing integrated and multi-app
|
|
173
|
+
layouts. Entries and include/exclude paths remain relative to the application.
|
|
174
|
+
|
|
175
|
+
Root HTML uses `<base href="./">`; nested navigable documents use their actual
|
|
176
|
+
depth back to the workspace. Managed bare imports remain the public interface;
|
|
177
|
+
their targets follow the selected npm routes. `arcane import-map` also writes
|
|
178
|
+
root-app navigation pages for the previous `/apps/<id>/` links, preserving
|
|
179
|
+
query strings and fragments. It preserves authored files at those destinations.
|
|
180
|
+
For a direct-installed root PWA it generates the static PWA records at the root,
|
|
181
|
+
so normal static hosting needs no SDK request handler or runtime copy.
|
|
182
|
+
|
|
161
183
|
## Installed SDK runtime materialization
|
|
162
184
|
|
|
163
185
|
`materializeInstalledSdkRuntime()` is the Node entrypoint for refreshing one
|
package/docs/reference/pwa.md
CHANGED
|
@@ -47,6 +47,30 @@ explicit `id` and `scope` values, resolve against `./apps/<id>/`; an icon such
|
|
|
47
47
|
as `img/library.png` therefore remains beneath the app directory. Absolute URL
|
|
48
48
|
fields retain their authored destination.
|
|
49
49
|
|
|
50
|
+
For `appsRoot: "."`, application URLs stay at the deployment root. Direct npm
|
|
51
|
+
routes keep runtime URLs under `/node_modules/<dependency>/...`. The public
|
|
52
|
+
`arcane import-map` operation generates static PWA files beside the root entry
|
|
53
|
+
and adds their links to the selected navigable documents. This works with an
|
|
54
|
+
ordinary static host; it does not copy the installed runtime into `arcane/`.
|
|
55
|
+
The source root defaults its installation ID to `/apps/<id>/` to preserve the
|
|
56
|
+
previous source identity while its start URL and scope move to the root. An
|
|
57
|
+
authored `manifest.id` remains authoritative. Packaged default identity remains
|
|
58
|
+
`./`. Existing `/apps/<id>/` navigation aliases retain query strings and
|
|
59
|
+
fragments and lead to the selected root document. No stored application data is
|
|
60
|
+
rewritten by changing the layout.
|
|
61
|
+
|
|
62
|
+
Root PWA generation also retains `apps/<id>/arcane-sw.js` and
|
|
63
|
+
`apps/<id>/arcane-offline.json`. These are ordinary generated files served at
|
|
64
|
+
their original URLs, including on a static host. The same canonical worker and
|
|
65
|
+
current inventory use root resource/navigation URLs, rebased for the previous
|
|
66
|
+
scope when deployed beneath a directory. An existing worker's inventory refresh
|
|
67
|
+
can learn the new navigation destinations; the browser can update the worker at
|
|
68
|
+
its retained script URL through normal update and activation. No cache deletion,
|
|
69
|
+
forced activation, user-data migration or application-owned server handler is
|
|
70
|
+
introduced. Offline clients require a later successful connection to receive
|
|
71
|
+
updated files; fixture coverage does not establish a particular installed app's
|
|
72
|
+
actual browser lifecycle.
|
|
73
|
+
|
|
50
74
|
`offline.include` and `offline.exclude` select literal paths or directory
|
|
51
75
|
prefixes from the selected emitted inventory. An omitted or empty include list
|
|
52
76
|
selects that inventory; exclusions subtract from it. App files use app-relative
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arcane-os",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.1",
|
|
4
4
|
"description": "Arcane OS JavaScript SDK, project-local CLI, browser runtime, and repository-portable application packager.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.mjs",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"test:release": "node ./bin/arcane-test.mjs test/npm-release.test.mjs",
|
|
85
85
|
"test:unit": "node ./bin/arcane-test.mjs test/app-descriptor.test.mjs test/app-schema.test.mjs test/app-selection.test.mjs test/contracts.test.mjs test/doctor.test.mjs test/mail-credentials.test.mjs test/mail-outbox.test.mjs test/mail-public-api.test.mjs test/mail-send.test.mjs test/mail-transport.test.mjs test/targets.test.mjs test/workspace-operation-lock.test.mjs",
|
|
86
86
|
"test:functional": "node ./bin/arcane-test.mjs test/browser-speech-providers.test.mjs test/browser-wasm-gpu-notice.test.mjs test/browser-wasm-download-resume.test.mjs test/cli.test.mjs test/dbopfs-document-library.test.mjs test/dev-server.test.mjs test/dev-pwa.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/import-map.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/modal.test.mjs test/packaging.test.mjs test/pwa-packaging.test.mjs test/pwa-client.test.mjs test/pwa-install.test.mjs test/pwa-worker.test.mjs test/persistent-ai-chat-session.test.mjs test/reference-completeness.test.mjs test/runtime-api-behavior.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/speech-playback.test.mjs test/site.test.mjs test/update-check.test.mjs",
|
|
87
|
-
"test:integration": "node ./bin/arcane-test.mjs test/installed-package-runtime.test.mjs test/integrated-shared.test.mjs test/integrated-workspace.test.mjs test/mail-browser.test.mjs test/native-plan.test.mjs test/native-provider-loader.test.mjs test/npm-release.test.mjs test/release-bundle.test.mjs test/release-capability-smoke.test.mjs test/shared-payload-batch.test.mjs test/tarball.test.mjs test/browser-wasm-cpu.test.mjs test/wllama-webgpu-runtime.test.mjs",
|
|
87
|
+
"test:integration": "node ./bin/arcane-test.mjs test/installed-package-runtime.test.mjs test/root-app-layout.test.mjs test/integrated-shared.test.mjs test/integrated-workspace.test.mjs test/mail-browser.test.mjs test/native-plan.test.mjs test/native-provider-loader.test.mjs test/npm-release.test.mjs test/release-bundle.test.mjs test/release-capability-smoke.test.mjs test/shared-payload-batch.test.mjs test/tarball.test.mjs test/browser-wasm-cpu.test.mjs test/wllama-webgpu-runtime.test.mjs",
|
|
88
88
|
"test:regression": "node ./bin/arcane-test.mjs test/channel-workflows.test.mjs test/html-import-registration.test.mjs test/logging-regression.test.mjs test/markdown-speech.test.mjs test/prepared-speech.test.mjs test/native-provider-generation.test.mjs test/speech-queue-regression.test.mjs test/testing.test.mjs test/test-sets.test.mjs",
|
|
89
89
|
"check": "node tools/check-source.mjs && npm test",
|
|
90
90
|
"check:release": "node tools/check-source.mjs --package-only && npm run test:release",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
const {arcaneLogging}=await import('arcane-os/logging');
|
|
17
17
|
|
|
18
18
|
const host=this;
|
|
19
|
+
const componentHref=new URL(host.getAttribute('href'),document.baseURI);
|
|
19
20
|
const {default:waitForComponent}=await import('../modules/WaitForComponent.js');
|
|
20
21
|
const {
|
|
21
22
|
effectiveDashboardVisibility,
|
|
@@ -232,7 +233,7 @@
|
|
|
232
233
|
const items=document.createElement('section');
|
|
233
234
|
|
|
234
235
|
styles.rel='stylesheet';
|
|
235
|
-
styles.href=new URL('
|
|
236
|
+
styles.href=new URL('../css/dashboard-config.css?v=2',componentHref).href;
|
|
236
237
|
heading.dataset.dashboardConfigHeading='';
|
|
237
238
|
message.dataset.dashboardConfigDescription='';
|
|
238
239
|
empty.className='dashboard-config-empty';
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
const {arcaneLogging}=await import('arcane-os/logging');
|
|
21
21
|
|
|
22
22
|
const host=this;
|
|
23
|
+
const componentHref=new URL(host.getAttribute('href'),document.baseURI);
|
|
23
24
|
const openButton=host.shadowRoot.querySelector('#openData');
|
|
24
25
|
const dataModal=host.shadowRoot.querySelector('#dataModal');
|
|
25
26
|
const {default:waitForComponent}=await import('../modules/WaitForComponent.js');
|
|
@@ -89,7 +90,7 @@
|
|
|
89
90
|
fileManager.dataset.layout=host.dataset.layout||'files';
|
|
90
91
|
fileManager.setAttribute(
|
|
91
92
|
'href',
|
|
92
|
-
'./
|
|
93
|
+
new URL('./file-manager.html?v=18',componentHref).href
|
|
93
94
|
);
|
|
94
95
|
|
|
95
96
|
content.append(heading,fileManager);
|
|
@@ -352,6 +352,7 @@
|
|
|
352
352
|
//importing Document at the end of the file to avoid blocking;
|
|
353
353
|
|
|
354
354
|
const host=this;
|
|
355
|
+
const componentHref=new URL(host.getAttribute('href'),document.baseURI);
|
|
355
356
|
const {default:waitForComponent}=await import('../modules/WaitForComponent.js');
|
|
356
357
|
const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
|
|
357
358
|
const events=createArcaneEventSource(host,{source:'arcane.component.file-manager',eventTypes:['file-manager-action','file-manager-select','file-manager-open','file-manager-ready']});
|
|
@@ -830,8 +831,8 @@
|
|
|
830
831
|
icon.className='tree-entry-icon';
|
|
831
832
|
icon.alt='';
|
|
832
833
|
icon.src=entry.kind==='directory'
|
|
833
|
-
?new URL('
|
|
834
|
-
:new URL('
|
|
834
|
+
?new URL('../img/folder.svg',componentHref).href
|
|
835
|
+
:new URL('../img/doc.svg',componentHref).href;
|
|
835
836
|
name.className='tree-entry-name';
|
|
836
837
|
name.innerText=entry.name;
|
|
837
838
|
count.className='tree-file-count';
|
|
@@ -1409,7 +1410,7 @@
|
|
|
1409
1410
|
deleteButton.innerText='Delete File';
|
|
1410
1411
|
deleteIcon.alt='';
|
|
1411
1412
|
deleteIcon.className='action-icon';
|
|
1412
|
-
deleteIcon.src=new URL('
|
|
1413
|
+
deleteIcon.src=new URL('../img/trash.svg',componentHref).href;
|
|
1413
1414
|
deleteButton.prepend(deleteIcon);
|
|
1414
1415
|
deleteButton.addEventListener(
|
|
1415
1416
|
'click',
|
|
@@ -1615,7 +1616,7 @@
|
|
|
1615
1616
|
|
|
1616
1617
|
fileIcon.alt='';
|
|
1617
1618
|
fileIcon.className='icon file-icon';
|
|
1618
|
-
fileIcon.src=new URL('
|
|
1619
|
+
fileIcon.src=new URL('../img/doc.svg',componentHref).href;
|
|
1619
1620
|
fileDetails.className='file-details';
|
|
1620
1621
|
fileLabel.className='file-name';
|
|
1621
1622
|
fileLabel.innerText=fileName;
|
|
@@ -1638,7 +1639,7 @@
|
|
|
1638
1639
|
|
|
1639
1640
|
deleteIcon.alt='';
|
|
1640
1641
|
deleteIcon.className='action-icon';
|
|
1641
|
-
deleteIcon.src=new URL('
|
|
1642
|
+
deleteIcon.src=new URL('../img/trash.svg',componentHref).href;
|
|
1642
1643
|
|
|
1643
1644
|
openButton.addEventListener(
|
|
1644
1645
|
'click',
|
|
@@ -1938,7 +1939,7 @@
|
|
|
1938
1939
|
directory.dataset.directory=tableName;
|
|
1939
1940
|
folder.className='file folder';
|
|
1940
1941
|
folderIcon.className='icon';
|
|
1941
|
-
folderIcon.src=new URL('
|
|
1942
|
+
folderIcon.src=new URL('../img/folder.svg',componentHref).href;
|
|
1942
1943
|
folderName.innerText=tableName;
|
|
1943
1944
|
fileCount.className='file-count';
|
|
1944
1945
|
fileCount.innerText=`${files.length} ${files.length===1?'file':'files'}`;
|
package/src/app-descriptor.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Is from 'strong-type';
|
|
2
|
+
import {resolveAppRoot} from './app-layout.mjs';
|
|
2
3
|
import {isDeepStrictEqual} from 'node:util';
|
|
3
4
|
import {readFile, writeFile} from 'node:fs/promises';
|
|
4
5
|
import path from 'node:path';
|
|
@@ -427,7 +428,8 @@ async function readJsonFile(filePath,label,{optional=false}={}){
|
|
|
427
428
|
|
|
428
429
|
export async function refreshAppPackageProjection({workspaceRoot, appId, signal, onEvent}) {
|
|
429
430
|
throwIfAborted(signal);
|
|
430
|
-
const
|
|
431
|
+
const rootConfig=await readJsonFile(path.join(workspaceRoot,'arcane-packager.json'),'arcane-packager.json');
|
|
432
|
+
const appRoot = resolveAppRoot(workspaceRoot,rootConfig,appId);
|
|
431
433
|
const descriptorPath = path.join(appRoot, APP_DESCRIPTOR_NAME);
|
|
432
434
|
const authored = await readJsonFile(
|
|
433
435
|
descriptorPath,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
|
|
3
|
+
// The app identity is independent of whether its files occupy a workspace root.
|
|
4
|
+
export function appRelativeRoot(config, appId) {
|
|
5
|
+
return config.appsRoot === '.' ? '' : `apps/${appId}`;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function resolveAppRoot(workspaceRoot, config, appId) {
|
|
9
|
+
return path.resolve(workspaceRoot, appRelativeRoot(config, appId));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function appBaseHref(workspaceRoot, appRoot, document = 'index.html') {
|
|
13
|
+
const directory = path.dirname(path.resolve(appRoot, document));
|
|
14
|
+
const relative = path.relative(directory, workspaceRoot).split(path.sep).join('/');
|
|
15
|
+
return relative ? `${relative}/` : './';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function rootAppNavigation(appId, entry, documents = []) {
|
|
19
|
+
const redirects=new Map();
|
|
20
|
+
for(const document of documents)redirects.set(`apps/${appId}/${document}`,document);
|
|
21
|
+
redirects.set(`apps/${appId}/index.html`,entry);
|
|
22
|
+
return [...redirects].map(([file,target])=>{
|
|
23
|
+
const relative=path.posix.relative(path.posix.dirname(file),target);
|
|
24
|
+
const destination=JSON.stringify(relative).replaceAll('<','\\u003c');
|
|
25
|
+
return {
|
|
26
|
+
path:file,target:`/${target}`,
|
|
27
|
+
content:'<!doctype html>\n<!-- Arcane root application navigation -->\n'
|
|
28
|
+
+'<meta charset="utf-8">\n<title>Opening application</title>\n'
|
|
29
|
+
+`<script>const target=new URL(${destination},location.href);target.search=location.search;target.hash=location.hash;location.replace(target.href);</script>\n`
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
}
|
|
@@ -124,7 +124,9 @@ async function selectedTestFiles({workspaceRoot,workspaceMode,appRoot,signal}){
|
|
|
124
124
|
if(workspaceMode==='external'){
|
|
125
125
|
await collectOptionalTests(path.join(workspaceRoot,'test'),workspaceRoot,files,signal);
|
|
126
126
|
}
|
|
127
|
-
if(appRoot
|
|
127
|
+
if(appRoot&&(workspaceMode!=='external'||!samePath(workspaceRoot,appRoot))){
|
|
128
|
+
await collectOptionalTests(path.join(appRoot,'test'),appRoot,files,signal);
|
|
129
|
+
}
|
|
128
130
|
return [...files].sort();
|
|
129
131
|
}
|
|
130
132
|
|
package/src/cli/main.mjs
CHANGED
|
@@ -14,6 +14,7 @@ const VALUE_OPTIONS=new Set([
|
|
|
14
14
|
'display-name',
|
|
15
15
|
'workspace',
|
|
16
16
|
'app',
|
|
17
|
+
'apps-root',
|
|
17
18
|
'sdk-runtime-source',
|
|
18
19
|
'arcane-root',
|
|
19
20
|
'host',
|
|
@@ -60,8 +61,8 @@ const MAX_NODE_TIMER_DELAY_MS=2_147_483_647;
|
|
|
60
61
|
export const HELP_TEXT=`Arcane OS application SDK ${SDK_VERSION}
|
|
61
62
|
|
|
62
63
|
Usage:
|
|
63
|
-
${CLI_NAME} new <id> [--path <directory>] [--display-name <name>] [--target <target>] [--git]
|
|
64
|
-
${CLI_NAME} init [id] [--workspace <directory>] [--display-name <name>] [--target <target>]
|
|
64
|
+
${CLI_NAME} new <id> [--path <directory>] [--apps-root apps|.] [--display-name <name>] [--target <target>] [--git]
|
|
65
|
+
${CLI_NAME} init [id] [--workspace <directory>] [--apps-root apps|.] [--display-name <name>] [--target <target>]
|
|
65
66
|
${CLI_NAME} upgrade [--workspace <directory>] [--app <id>]
|
|
66
67
|
${CLI_NAME} doctor [--workspace <directory>] [--arcane-root <directory>]
|
|
67
68
|
${CLI_NAME} import-map [--workspace <directory>] [--app <id>]
|
|
@@ -421,15 +422,6 @@ function readScope(value){
|
|
|
421
422
|
return scope;
|
|
422
423
|
}
|
|
423
424
|
|
|
424
|
-
function inferredAppId(workspaceRoot){
|
|
425
|
-
const id=path.basename(workspaceRoot)
|
|
426
|
-
.normalize('NFKD')
|
|
427
|
-
.toLowerCase()
|
|
428
|
-
.replace(/[^a-z0-9]+/gu,'-')
|
|
429
|
-
.replace(/^-+|-+$/gu,'');
|
|
430
|
-
return id||'arcane-app';
|
|
431
|
-
}
|
|
432
|
-
|
|
433
425
|
function noExtraPositionals(command,positionals,expected=0){
|
|
434
426
|
if(positionals.length>expected){
|
|
435
427
|
usage(`Unexpected argument for ${command}.`);
|
|
@@ -503,6 +495,9 @@ function operationOptions(command,parsed,cwd){
|
|
|
503
495
|
if(command!=='mail'&&flags.has('report-stdin')){
|
|
504
496
|
usage('--report-stdin is supported only by mail send.');
|
|
505
497
|
}
|
|
498
|
+
if(values['apps-root']!==undefined&&!['new','init'].includes(command)){
|
|
499
|
+
usage('--apps-root is supported only by new and init.');
|
|
500
|
+
}
|
|
506
501
|
|
|
507
502
|
if(command==='new'){
|
|
508
503
|
const appId=positionals[0];
|
|
@@ -511,6 +506,7 @@ function operationOptions(command,parsed,cwd){
|
|
|
511
506
|
return {
|
|
512
507
|
targetPath:path.resolve(cwd,values.path??appId),
|
|
513
508
|
appId,
|
|
509
|
+
appsRoot:values['apps-root']??'apps',
|
|
514
510
|
displayName:values['display-name'],
|
|
515
511
|
target:values.target??'browser',
|
|
516
512
|
initializeGit:flags.has('git')
|
|
@@ -520,7 +516,8 @@ function operationOptions(command,parsed,cwd){
|
|
|
520
516
|
noExtraPositionals(command,positionals,1);
|
|
521
517
|
return {
|
|
522
518
|
workspaceRoot,
|
|
523
|
-
appId:positionals[0]??values.app
|
|
519
|
+
appId:positionals[0]??values.app,
|
|
520
|
+
appsRoot:values['apps-root'],
|
|
524
521
|
displayName:values['display-name'],
|
|
525
522
|
target:values.target??'browser'
|
|
526
523
|
};
|