arcane-os 0.11.3 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/NOTICE +1 -0
- package/README.md +27 -13
- package/browser-runtime/pwa-install.mjs +242 -0
- package/browser-runtime/pwa.mjs +131 -0
- package/docs/architecture.md +28 -12
- package/docs/reference/cli.md +42 -16
- package/docs/reference/inventory/package-api.json +44 -2
- package/docs/reference/inventory/runtime-components.json +29 -1
- package/docs/reference/pwa.md +252 -24
- package/docs/reference/runtime-components.md +64 -0
- package/docs/reference/sdk-api.md +158 -28
- package/package.json +3 -2
- package/runtime/arcane/components/pwa-install.html +216 -0
- package/src/app-descriptor.mjs +43 -1
- package/src/cli/main.mjs +29 -13
- package/src/dev-server.mjs +387 -136
- package/src/pwa-worker.mjs +361 -137
- package/src/pwa.mjs +11 -2
- package/src/targets/index.mjs +5 -1
- package/src/toolchain.mjs +62 -12
package/docs/reference/cli.md
CHANGED
|
@@ -48,10 +48,11 @@ meaning and cardinality rules:
|
|
|
48
48
|
| `--workspace` | directory | Commands that select an external or integrated workspace; defaults to `.`. |
|
|
49
49
|
| `--app` | app id | Workspace/app operations except shared scope and `verify-bundle`; also the exact `mail serve` caller id. |
|
|
50
50
|
| `--arcane-root` | directory | `doctor`, native `build`/`run`, `native-doctor`, `native-prepare` |
|
|
51
|
-
| `--host` / `--port` | host / integer 0–65535 | Browser `dev`/`run` default to `127.0.0.1:8000`; `mail serve` defaults to `127.0.0.1:8025` and admits numeric loopback only. |
|
|
51
|
+
| `--host` / `--port` | host / integer 0–65535 | Browser `dev`/`run` default to HTTPS at `127.0.0.1:8000`; `mail serve` defaults to HTTP at `127.0.0.1:8025` and admits numeric loopback only. |
|
|
52
|
+
| `--http-port` | integer 0–65535 | Browser `dev`/`run` HTTP redirect listener; defaults to `0`, which selects an available port. |
|
|
52
53
|
| `--public` | flag | `dev`; serves HTTPS and binds to `0.0.0.0` unless `--host` explicitly selects another address. |
|
|
53
|
-
| `--https` | flag | `dev`;
|
|
54
|
-
| `--cert` / `--key` | PEM file paths | `dev`; supply both
|
|
54
|
+
| `--https` | flag | Browser `dev`/`run`; retained explicitly, while HTTPS is always enabled. |
|
|
55
|
+
| `--cert` / `--key` | PEM file paths | Browser `dev`/`run`; supply both for an explicit certificate chain and private key. Relative paths resolve from the workspace. |
|
|
55
56
|
| `--target` | target id | `new`, `init`, native diagnostics, `build`, `run` |
|
|
56
57
|
| `--format` / `--signing` | target-supported values | Native diagnostics, `build`, `run` |
|
|
57
58
|
| `--output-root` | directory | Native `build` and `run` |
|
|
@@ -311,7 +312,7 @@ npm exec -- arcane upgrade --workspace . --app hello-world
|
|
|
311
312
|
### Overview
|
|
312
313
|
|
|
313
314
|
Starts one development server for one selected app and maps the exact
|
|
314
|
-
workspace/runtime routes. It defaults to localhost; `--public` enables access
|
|
315
|
+
workspace/runtime routes. It defaults to HTTPS on localhost; `--public` enables access
|
|
315
316
|
from other devices on the network over HTTPS.
|
|
316
317
|
|
|
317
318
|
For an external workspace, the server exposes the selected projected
|
|
@@ -321,11 +322,19 @@ The explicit live-source SDK mapping remains unchanged and does not replace the
|
|
|
321
322
|
installed projection.
|
|
322
323
|
|
|
323
324
|
```text
|
|
324
|
-
arcane dev [--app <id>] [--public] [--https] [--cert <file> --key <file>] [--host <address>] [--port 8000]
|
|
325
|
+
arcane dev [--app <id>] [--public] [--https] [--cert <file> --key <file>] [--host <address>] [--port 8000] [--http-port 0]
|
|
325
326
|
```
|
|
326
327
|
|
|
327
328
|
### Lifecycle
|
|
328
329
|
|
|
330
|
+
Startup refreshes the selected authored `arcane-app.json` projection into
|
|
331
|
+
`arcane-package.json`, then refreshes its managed import maps under one
|
|
332
|
+
development-refresh operation lock. The lock is released before the server
|
|
333
|
+
starts. Package-only apps retain their existing manifest. This operation does
|
|
334
|
+
not package the app or produce `dist` output. With PWA enabled, the server
|
|
335
|
+
generates the installation and offline manifests directly; see
|
|
336
|
+
[PWA development and versioning](pwa.md#development-and-hosting).
|
|
337
|
+
|
|
329
338
|
The command reports acceptance before bind/start work, emits the final URL,
|
|
330
339
|
owns the server until cancellation, and restores failure to the process exit.
|
|
331
340
|
The default host is `127.0.0.1`. `--public` selects `0.0.0.0` (all IPv4
|
|
@@ -335,25 +344,33 @@ device, since `localhost` refers to that device and `0.0.0.0` is a bind address.
|
|
|
335
344
|
Network URLs come from one interface snapshot at startup and do not establish
|
|
336
345
|
remote reachability through the machine's firewall or network.
|
|
337
346
|
|
|
338
|
-
|
|
339
|
-
`--https`
|
|
340
|
-
`--
|
|
341
|
-
|
|
347
|
+
Every Arcane app uses HTTPS for development and packaged browser previews.
|
|
348
|
+
`--https` remains accepted but is no longer needed to select the transport.
|
|
349
|
+
`--port` selects the HTTPS application port. A second HTTP listener returns
|
|
350
|
+
`308` redirects to that HTTPS port, preserving the requested path and query.
|
|
351
|
+
`--http-port` selects its port; the default `0` lets the operating system choose
|
|
352
|
+
an available port. Both listeners use the selected host and must be ready
|
|
353
|
+
before startup completes. Cancellation or a listener failure closes both.
|
|
354
|
+
Human output prints `HTTP redirect: <url>` alongside the HTTPS application URL;
|
|
355
|
+
JSON/NDJSON server results include `httpPort`, `httpOrigin`, and `httpUrl` for
|
|
356
|
+
the redirect endpoint.
|
|
357
|
+
Supplying both `--cert` and `--key` selects an explicit PEM pair. The command
|
|
358
|
+
does not configure a firewall, router forwarding, or an internet tunnel.
|
|
342
359
|
|
|
343
360
|
### Development HTTPS setup
|
|
344
361
|
|
|
345
|
-
Before starting
|
|
346
|
-
chain at `.arcane/dev/server-cert.pem` and its PEM private key at
|
|
362
|
+
Before starting `arcane dev` or a packaged browser preview, place the server's
|
|
363
|
+
PEM certificate chain at `.arcane/dev/server-cert.pem` and its PEM private key at
|
|
347
364
|
`.arcane/dev/server-key.pem`, relative to the workspace. Alternatively, pass
|
|
348
|
-
`--cert <file> --key <file>` together. The certificate must cover the LAN IP
|
|
365
|
+
`--cert <file> --key <file>` together. The certificate must cover localhost or the LAN IP
|
|
349
366
|
address or hostname opened by each device. Certificate creation and renewal
|
|
350
367
|
belong to the developer's certificate tooling; the server does not generate a
|
|
351
368
|
CA or alter device trust stores. Keep `.arcane/dev/` ignored by Git and keep the
|
|
352
369
|
private key on the development computer.
|
|
353
370
|
|
|
354
|
-
The server reads the selected pair
|
|
355
|
-
|
|
356
|
-
|
|
371
|
+
The server reads the selected pair during startup, before binding.
|
|
372
|
+
Missing files or certificate/key parse errors produce a startup error;
|
|
373
|
+
Arcane never silently falls back to HTTP. Certificate/key contents are not
|
|
357
374
|
included in operation events or JSON/NDJSON output. Restart the server after
|
|
358
375
|
replacing its certificate pair; ordinary app source edits still appear on
|
|
359
376
|
refresh without restarting.
|
|
@@ -383,6 +400,9 @@ npm run dev -- --app hello-world --public
|
|
|
383
400
|
|
|
384
401
|
# Equivalent direct CLI invocation, with an optional port.
|
|
385
402
|
npm exec -- arcane dev --app hello-world --public --port 8000
|
|
403
|
+
|
|
404
|
+
# Select a stable HTTP entry that redirects to HTTPS on port 8000.
|
|
405
|
+
npm exec -- arcane dev --app hello-world --port 8000 --http-port 8080
|
|
386
406
|
```
|
|
387
407
|
|
|
388
408
|
## `arcane test`
|
|
@@ -617,11 +637,17 @@ npm exec -- arcane build \
|
|
|
617
637
|
|
|
618
638
|
For `--target browser`, starts the existing current `dist/<app>` release; it
|
|
619
639
|
does not package, rebuild, test, check, or verify that release automatically.
|
|
640
|
+
The preview always uses HTTPS with the workspace certificate pair. Supply
|
|
641
|
+
`--cert <file> --key <file>` together to use another pair; see
|
|
642
|
+
[development HTTPS setup](#development-https-setup).
|
|
643
|
+
`--port` selects the HTTPS application port, and `--http-port` selects the
|
|
644
|
+
paired HTTP `308` redirect port. The HTTP port defaults to an available port;
|
|
645
|
+
the CLI prints its actual redirect URL and reports both listener endpoints.
|
|
620
646
|
For a paired native target, it performs package, prepare, plan, build, launch,
|
|
621
647
|
readiness, and owned cancellation in one process.
|
|
622
648
|
|
|
623
649
|
```text
|
|
624
|
-
arcane run [--target <target>] [--app <id>] [--arcane-root <directory>] [--output-root <directory>] [--format <format>] [--signing <mode>]
|
|
650
|
+
arcane run [--target <target>] [--app <id>] [--cert <file> --key <file>] [--port 8000] [--http-port 0] [--arcane-root <directory>] [--output-root <directory>] [--format <format>] [--signing <mode>]
|
|
625
651
|
```
|
|
626
652
|
|
|
627
653
|
### Availability
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"minimumVersion": "22.23.2 for Node entrypoints",
|
|
7
7
|
"moduleSystem": "ESM"
|
|
8
8
|
},
|
|
9
|
-
"memberCount":
|
|
9
|
+
"memberCount": 208,
|
|
10
10
|
"members": [
|
|
11
11
|
{
|
|
12
12
|
"id": "root:APP_BUNDLE_DESCRIPTOR_NAME",
|
|
@@ -2991,11 +2991,53 @@
|
|
|
2991
2991
|
"entrypoints": ["arcane-os/pwa"],
|
|
2992
2992
|
"primaryImport": "arcane-os/pwa",
|
|
2993
2993
|
"group": "Progressive web applications",
|
|
2994
|
-
"summary": "Starts PWA registration without blocking
|
|
2994
|
+
"summary": "Starts PWA registration and DBOPFS-backed page-load resource checks without blocking rendering, returning an observable lifecycle owner.",
|
|
2995
2995
|
"availability": "Browser service workers; explicit unsupported state elsewhere",
|
|
2996
2996
|
"protocol": "Native registration, updatefound, statechange and controllerchange events",
|
|
2997
2997
|
"normalization": "Synchronous owner exposes ready, state, subscribe, update and dispose; current state replays by default, failures remain observable, disposal does not unregister the worker or delete saved data."
|
|
2998
2998
|
},
|
|
2999
|
+
{
|
|
3000
|
+
"id": "pwa:PWA_INSTALL_STATE_EVENT",
|
|
3001
|
+
"name": "PWA_INSTALL_STATE_EVENT",
|
|
3002
|
+
"displayName": "PWA_INSTALL_STATE_EVENT",
|
|
3003
|
+
"kind": "constant",
|
|
3004
|
+
"signature": "const PWA_INSTALL_STATE_EVENT",
|
|
3005
|
+
"entrypoints": ["arcane-os/pwa"],
|
|
3006
|
+
"primaryImport": "arcane-os/pwa",
|
|
3007
|
+
"group": "Progressive web applications",
|
|
3008
|
+
"summary": "Names the shared native installation availability and choice state event.",
|
|
3009
|
+
"availability": "Browser installation lifecycle; importable without starting observation",
|
|
3010
|
+
"protocol": "Existing Arcane event owner and native browser installation events",
|
|
3011
|
+
"normalization": "The exact event name is arcane.pwa.install.state."
|
|
3012
|
+
},
|
|
3013
|
+
{
|
|
3014
|
+
"id": "pwa:getPwaInstall",
|
|
3015
|
+
"name": "getPwaInstall",
|
|
3016
|
+
"displayName": "getPwaInstall()",
|
|
3017
|
+
"kind": "function",
|
|
3018
|
+
"signature": "getPwaInstall()",
|
|
3019
|
+
"entrypoints": ["arcane-os/pwa"],
|
|
3020
|
+
"primaryImport": "arcane-os/pwa",
|
|
3021
|
+
"group": "Progressive web applications",
|
|
3022
|
+
"summary": "Returns one shared page owner for native installation availability, prompt choices and session dismissal.",
|
|
3023
|
+
"availability": "Browser native installation events; waiting state while no prompt is available",
|
|
3024
|
+
"protocol": "Native beforeinstallprompt, appinstalled and display-mode change events",
|
|
3025
|
+
"normalization": "Synchronous owner exposes state, subscribe, prompt, dismiss and dispose; subscriptions replay current state, prompt invokes the native event directly in the user click and consumes it once, and session dismissal preserves a retained event for explicit inline installation."
|
|
3026
|
+
},
|
|
3027
|
+
{
|
|
3028
|
+
"id": "pwa:mountPwaInstallPrompt",
|
|
3029
|
+
"name": "mountPwaInstallPrompt",
|
|
3030
|
+
"displayName": "mountPwaInstallPrompt()",
|
|
3031
|
+
"kind": "function",
|
|
3032
|
+
"signature": "mountPwaInstallPrompt({appName = ''} = {})",
|
|
3033
|
+
"entrypoints": ["arcane-os/pwa"],
|
|
3034
|
+
"primaryImport": "arcane-os/pwa",
|
|
3035
|
+
"group": "Progressive web applications",
|
|
3036
|
+
"summary": "Starts shared installation observation and mounts one initially hidden, themed installation suggestion without delaying application rendering.",
|
|
3037
|
+
"availability": "Browser document and managed HTML import; resolves to null without a document",
|
|
3038
|
+
"protocol": "Shared native install owner and pwa-install.html component lifecycle",
|
|
3039
|
+
"normalization": "Repeated calls return the same mounting promise; the first appName initializes the component, success resolves to its ready html-import host, absence of a document or disposal before mounting resolves to null, and component loading failures reject. Removal or disposal during loading rejects with AbortError. A rejected mount permits another explicit attempt. Generated PWA bootstraps invoke it automatically."
|
|
3040
|
+
},
|
|
2999
3041
|
{
|
|
3000
3042
|
"id": "browser-speech:BROWSER_SPEECH_ARTIFACT_GRAPH_PROTOCOL",
|
|
3001
3043
|
"name": "BROWSER_SPEECH_ARTIFACT_GRAPH_PROTOCOL",
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"path": "runtime/arcane/components",
|
|
8
8
|
"sdkVersion": "0.7.2"
|
|
9
9
|
},
|
|
10
|
-
"componentCount":
|
|
10
|
+
"componentCount": 41,
|
|
11
11
|
"loader": "/arcane/modules/HTMLImport.js",
|
|
12
12
|
"artifacts": [
|
|
13
13
|
{
|
|
@@ -645,6 +645,34 @@
|
|
|
645
645
|
"transport": "HTMLImport + DOM; injected Arcane/provider modules where listed",
|
|
646
646
|
"normalization": "Normalized form values"
|
|
647
647
|
},
|
|
648
|
+
{
|
|
649
|
+
"file": "runtime/arcane/components/pwa-install.html",
|
|
650
|
+
"name": "pwa-install.html",
|
|
651
|
+
"purpose": "Presents a dismissible browser installation action with floating or inline placement.",
|
|
652
|
+
"methods": [
|
|
653
|
+
"configure()",
|
|
654
|
+
"install()",
|
|
655
|
+
"dismiss()",
|
|
656
|
+
"destroy()",
|
|
657
|
+
"state",
|
|
658
|
+
"ready"
|
|
659
|
+
],
|
|
660
|
+
"events": [
|
|
661
|
+
"pwa-install-ready",
|
|
662
|
+
"pwa-install-change",
|
|
663
|
+
"pwa-install-dismissed"
|
|
664
|
+
],
|
|
665
|
+
"slots": [],
|
|
666
|
+
"dependencies": [
|
|
667
|
+
"strong-type",
|
|
668
|
+
"arcane-os/pwa",
|
|
669
|
+
"arcane-os/event-manager",
|
|
670
|
+
"arcane-os/logging"
|
|
671
|
+
],
|
|
672
|
+
"availability": "Browser installation requires a browser-provided beforeinstallprompt event; otherwise hidden",
|
|
673
|
+
"transport": "HTMLImport + DOM; shared PWA installation owner and browser-native prompt",
|
|
674
|
+
"normalization": "Browser install availability and outcome supplied by the shared PWA owner"
|
|
675
|
+
},
|
|
648
676
|
{
|
|
649
677
|
"file": "runtime/arcane/components/record-timeline.html",
|
|
650
678
|
"name": "record-timeline.html",
|
package/docs/reference/pwa.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
An application supplies its installation identity and offline resource selection.
|
|
4
4
|
The SDK generates the Web App Manifest, offline inventory, service worker and
|
|
5
|
-
nonblocking registration module.
|
|
5
|
+
nonblocking registration module. Its shared installation owner and dismissible
|
|
6
|
+
component expose the browser's available install action. Native packages keep
|
|
7
|
+
their existing lifecycle.
|
|
6
8
|
|
|
7
9
|
## Application configuration
|
|
8
10
|
|
|
@@ -63,7 +65,7 @@ Browser packaging emits these files at the selected deployment root:
|
|
|
63
65
|
| `arcane.webmanifest` | Browser installation metadata. |
|
|
64
66
|
| `arcane-offline.json` | App ID/version, SDK version, deployment revision, resource URLs and explicit navigation aliases. |
|
|
65
67
|
| `arcane-sw.js` | Stable worker URL with the selected offline manifest embedded in its source. |
|
|
66
|
-
| `arcane-pwa.mjs` | Independent registration
|
|
68
|
+
| `arcane-pwa.mjs` | Independent registration and installation-component bootstrap importing the SDK client. |
|
|
67
69
|
|
|
68
70
|
Each packaged output gets one deployment revision shared by its offline
|
|
69
71
|
manifest and worker. It distinguishes separately generated outputs even when
|
|
@@ -74,6 +76,9 @@ It follows actual resource references to include meaningful query variants.
|
|
|
74
76
|
Generated application pages receive a manifest link and an `async` module
|
|
75
77
|
marked `data-arcane-pwa`. Existing application scripts retain their order.
|
|
76
78
|
PWA registration does not wait for models, storage, preferences or page rendering.
|
|
79
|
+
The same bootstrap starts one initially hidden `pwa-install.html` component with
|
|
80
|
+
the generated manifest's app name. Component loading and worker registration
|
|
81
|
+
proceed independently.
|
|
77
82
|
|
|
78
83
|
The selected PWA browser delivery removes `v` and `arcaneVersion` from actual
|
|
79
84
|
local resource references, including the managed import map. Other query fields,
|
|
@@ -83,31 +88,103 @@ the [existing asset version contract](asset-versioning.md).
|
|
|
83
88
|
|
|
84
89
|
## Development and hosting
|
|
85
90
|
|
|
91
|
+
Use the ordinary `arcane dev --app <id>` command after editing the selected
|
|
92
|
+
app's `arcane-app.json`. Startup refreshes that app's generated
|
|
93
|
+
`arcane-package.json` from the authored descriptor before refreshing its import
|
|
94
|
+
maps and starting the server. No packaging or `dist` output is required.
|
|
95
|
+
Package-only applications retain their existing descriptor workflow.
|
|
96
|
+
|
|
97
|
+
Add a file or directory to `package.include` to make it part of the app's
|
|
98
|
+
resources. A new file inside an already included directory needs no separate
|
|
99
|
+
entry. `package.include` is an application resource selection, not a file list
|
|
100
|
+
inside the Web App Manifest. `arcane.webmanifest` contains browser installation
|
|
101
|
+
metadata; `arcane-offline.json` contains the selected offline resource inventory.
|
|
102
|
+
If `package.pwa.offline.include` is nonempty, the resource must also
|
|
103
|
+
match that offline selection and must not match `offline.exclude`. Adding a
|
|
104
|
+
path only to the offline selection does not add it to the app's resources.
|
|
105
|
+
Restart after changing descriptor settings. Edits to selected source files are
|
|
106
|
+
picked up by the next due page-load check while the server remains running.
|
|
107
|
+
|
|
86
108
|
For an enabled application, `arcane dev` serves the generated PWA files at the
|
|
87
109
|
origin root and starts at the selected app page under `/apps/<id>/`. Use one
|
|
88
|
-
selected app per development origin.
|
|
89
|
-
and
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
110
|
+
selected app per development origin. The SDK uses `node-http-server` for source
|
|
111
|
+
and packaged-preview serving, including conditional resource responses.
|
|
112
|
+
Every Arcane development server and packaged browser preview serves HTTPS,
|
|
113
|
+
including localhost. Configure the workspace certificate pair before starting
|
|
114
|
+
the ordinary command; see [development HTTPS setup](cli.md#development-https-setup).
|
|
115
|
+
`--public` selects the IPv4 wildcard bind address; it does not enable PWA
|
|
116
|
+
configuration, change manifest metadata, or determine browser installability.
|
|
117
|
+
|
|
118
|
+
Source inventory work begins when the browser requests the worker or current
|
|
119
|
+
offline manifest, after the page can start. It traverses the selected route
|
|
120
|
+
inventory once for that request, follows page and runtime resource references
|
|
121
|
+
to retain selected query variants, and shares an in-flight traversal with
|
|
122
|
+
concurrent requests. Each referenced source file is read once per traversal;
|
|
97
123
|
document corpus bodies remain under their existing owner. It does not rebuild
|
|
98
|
-
the application.
|
|
99
|
-
bundle.
|
|
124
|
+
the application. Installation metadata and bootstrap requests reuse the current
|
|
125
|
+
generated bundle.
|
|
126
|
+
|
|
127
|
+
The SDK owns version information in `arcane-offline.json`:
|
|
128
|
+
|
|
129
|
+
| Field | Owner and update rule |
|
|
130
|
+
| --- | --- |
|
|
131
|
+
| `schemaVersion` | SDK offline-manifest format; currently `1`. |
|
|
132
|
+
| `appVersion` | The app descriptor's top-level `version`. |
|
|
133
|
+
| `sdkVersion` | The selected installed SDK or explicit live SDK source version. |
|
|
134
|
+
| `revision` | `development` for the source server; a fresh generated deployment ID for each packaged output. |
|
|
135
|
+
|
|
136
|
+
Do not hand-edit generated manifests or bump a version for every source edit.
|
|
137
|
+
`arcane.webmanifest` holds installation metadata and has no separate SDK-managed
|
|
138
|
+
release counter. Resource freshness uses each response's `Last-Modified` header.
|
|
139
|
+
|
|
140
|
+
On each page load, the SDK reads one `lastChecked` value for the app and worker
|
|
141
|
+
scope from DBOPFS in the background. When that value is missing or older than
|
|
142
|
+
the delivery mode's interval, it checks the current offline manifest and every
|
|
143
|
+
selected resource:
|
|
100
144
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
145
|
+
| Mode | Page-load check interval |
|
|
146
|
+
| --- | --- |
|
|
147
|
+
| Development | 120 seconds |
|
|
148
|
+
| Packaged browser delivery | 15 minutes |
|
|
149
|
+
|
|
150
|
+
These intervals schedule revalidation; they never expire a cached file. The
|
|
151
|
+
worker sends `GET` with `If-Modified-Since` using the cached response's
|
|
152
|
+
`Last-Modified`. A `304 Not Modified` retains the complete cached response. A
|
|
153
|
+
successful `200` replaces it after the new response is stored. Missing cached
|
|
154
|
+
resources are downloaded. Network and server failures retain an existing
|
|
155
|
+
offline copy and remain observable through SDK diagnostics. A host without
|
|
156
|
+
modification headers must send the current response because freshness cannot
|
|
157
|
+
be established from a missing header.
|
|
158
|
+
|
|
159
|
+
Complete resource responses remain in browser CacheStorage. DBOPFS stores one
|
|
160
|
+
successful whole-cycle timestamp, updated only after the manifest and every
|
|
161
|
+
selected resource have been checked successfully. A partial failure preserves
|
|
162
|
+
the previous timestamp so the next page load can retry. Each cached response
|
|
163
|
+
retains its own `Last-Modified` header, but there are no per-file check times.
|
|
164
|
+
The SDK imposes no age-based cache deletion and
|
|
165
|
+
retains resource bodies across app and SDK version changes. Requests for a page
|
|
166
|
+
do not wait for the complete resource inventory to finish checking. A file
|
|
167
|
+
already in the current resource cache also returns immediately when its own
|
|
168
|
+
conditional check is pending or in flight. That background check keeps its
|
|
169
|
+
existing owner and updates the stored response for subsequent requests.
|
|
170
|
+
The page receives the cached response's original status, commonly `200`, even
|
|
171
|
+
when the separate conditional network response is `304`. Status alone does
|
|
172
|
+
not identify a network transfer; use the browser's response source and timing
|
|
173
|
+
details to distinguish cache access from worker startup, queueing and network.
|
|
174
|
+
The SDK
|
|
175
|
+
uses at most four concurrent background resource requests and starts no timer
|
|
176
|
+
or polling loop between page loads.
|
|
177
|
+
|
|
178
|
+
During initial installation, selected resources are cached before the browser
|
|
179
|
+
activates the worker. Failures remain observable through native worker state
|
|
180
|
+
and SDK diagnostics. HTTP modification dates have second-level precision;
|
|
181
|
+
hosts must report changes to the served representation, including generated
|
|
182
|
+
output, rather than only the date of an unrelated source file.
|
|
107
183
|
|
|
108
184
|
The SDK development server sends `Cache-Control: no-cache` for PWA resources.
|
|
109
|
-
An independent static host
|
|
110
|
-
|
|
185
|
+
An independent static host should support `Last-Modified` and conditional GET
|
|
186
|
+
for stable HTML, module, style and import-map URLs, revalidate worker URLs, and
|
|
187
|
+
serve JavaScript with a JavaScript content type.
|
|
111
188
|
Keep the worker beside the deployment root it controls. The browser requires a
|
|
112
189
|
supported secure context, such as trusted HTTPS or localhost, to register it.
|
|
113
190
|
The SDK does not change certificates or browser permissions.
|
|
@@ -132,14 +209,165 @@ worker while they are open. Closing those pages allows activation; a refresh
|
|
|
132
209
|
can leave overlapping document clients and keep the update waiting.
|
|
133
210
|
|
|
134
211
|
The SDK does not call `skipWaiting`, claim the initial page, reload a page,
|
|
135
|
-
restart a model or poll for updates.
|
|
136
|
-
|
|
137
|
-
data and caches owned by other capabilities are untouched.
|
|
212
|
+
restart a model or poll for updates. Worker activation preserves cached
|
|
213
|
+
resources and the DBOPFS check history for the same app and registration scope.
|
|
214
|
+
Saved application data and caches owned by other capabilities are untouched.
|
|
215
|
+
|
|
216
|
+
When importing caches from an older SDK worker, the new worker fetches the
|
|
217
|
+
SDK-owned registration bootstrap and PWA client once so the page can use the
|
|
218
|
+
current cache-check protocol. Other cached resource bodies retain the normal
|
|
219
|
+
check cadence. This transition follows native worker installation and
|
|
220
|
+
activation without forcing a page reload.
|
|
138
221
|
|
|
139
222
|
Switching a server from a packaged release to live development does not replace
|
|
140
223
|
an already active release worker inside an open document. The same native
|
|
141
224
|
worker lifecycle applies.
|
|
142
225
|
|
|
226
|
+
## Installation component
|
|
227
|
+
|
|
228
|
+
Starting with SDK `0.13.0`, enabled PWA pages automatically mount the shared
|
|
229
|
+
[`pwa-install.html` component](runtime-components.md#pwa-installhtml). It appears
|
|
230
|
+
when the browser supplies an installation prompt, offers **Install** and a
|
|
231
|
+
clearly labeled close control, and does not move focus when it appears.
|
|
232
|
+
The floating suggestion has no automatic dismissal timer. Closing it remembers
|
|
233
|
+
the choice for the current tab session and manifest URL, so another page
|
|
234
|
+
load does not immediately show it again. A storage failure leaves the current
|
|
235
|
+
page's dismissal functional and reports the error through console diagnostics.
|
|
236
|
+
|
|
237
|
+
An application can also place the same component inline through `html-import`
|
|
238
|
+
with `data-presentation="inline"`. Both presentations share one page-owned
|
|
239
|
+
native installation event. Dismissing the floating suggestion does not consume
|
|
240
|
+
that event or disable an explicitly placed inline component. Closing an inline
|
|
241
|
+
instance hides only that instance. See the component reference for its
|
|
242
|
+
configuration, methods and events.
|
|
243
|
+
|
|
244
|
+
The browser controls the URL-bar installation indicator and native prompt.
|
|
245
|
+
The SDK cannot force either to appear. Without a captured
|
|
246
|
+
`beforeinstallprompt`, the component remains hidden; that waiting state does
|
|
247
|
+
not establish that installation is unsupported. The browser may still be
|
|
248
|
+
evaluating the app, may already have it installed, or may only support a
|
|
249
|
+
manual browser-menu installation path.
|
|
250
|
+
|
|
251
|
+
### Browser installation requirements
|
|
252
|
+
|
|
253
|
+
Inspect the loaded page's manifest link and the browser's manifest diagnostics
|
|
254
|
+
when an install action is missing. Confirm that the generated manifest has the
|
|
255
|
+
intended name, `start_url`, scope and app display mode, and that its icon URLs
|
|
256
|
+
resolve to actual images with the declared dimensions. For Chromium's manifest
|
|
257
|
+
install promotion, provide a `purpose: "any"` icon, or omit `purpose` to use
|
|
258
|
+
that default, in PNG, SVG or WebP format. Its strict installation icon selector
|
|
259
|
+
excludes JPEG even when the same image renders successfully on the page.
|
|
260
|
+
Do not change a file's extension or MIME declaration without converting the
|
|
261
|
+
actual image at the application's asset owner. See Chromium's
|
|
262
|
+
[icon selection implementation](https://raw.githubusercontent.com/chromium/chromium/main/third_party/blink/common/manifest/manifest_icon_selector.cc).
|
|
263
|
+
|
|
264
|
+
Providing 192-by-192 and 512-by-512 raster icons follows the
|
|
265
|
+
[browser guidance](https://web.dev/articles/add-manifest). Their absence alone
|
|
266
|
+
does not prove the failure: Chromium can select one larger supported icon.
|
|
267
|
+
Keep actual icon dimensions in `sizes`. Browser diagnostics about missing
|
|
268
|
+
`screenshots` concern the richer installation dialog; screenshots are optional
|
|
269
|
+
and are separate from a usable installation icon.
|
|
270
|
+
|
|
271
|
+
Browser installation requires HTTPS or the browser's localhost/loopback
|
|
272
|
+
exception. A device-facing LAN address is not loopback. Arcane's development
|
|
273
|
+
server still follows its own HTTPS serving contract above. Browser engagement,
|
|
274
|
+
installation state and platform support also affect whether native promotion
|
|
275
|
+
appears; worker cache readiness is not an installation UI prerequisite. See
|
|
276
|
+
[browser installation requirements](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Guides/Making_PWAs_installable).
|
|
277
|
+
|
|
278
|
+
Browsers without `beforeinstallprompt` can offer manual installation. For
|
|
279
|
+
example, current iPhone Safari uses Share, **Add to Home Screen**, **Open as
|
|
280
|
+
Web App**, then **Add**. A product may explain that browser-owned path in its
|
|
281
|
+
help, but should not present it as a programmatic SDK install action. The SDK
|
|
282
|
+
does not infer installation support from the user-agent string. See
|
|
283
|
+
[Apple's installation instructions](https://support.apple.com/guide/iphone/open-as-web-app-iphea86e5236/ios).
|
|
284
|
+
|
|
285
|
+
## getPwaInstall()
|
|
286
|
+
|
|
287
|
+
Import `getPwaInstall` and `PWA_INSTALL_STATE_EVENT` from `arcane-os/pwa`.
|
|
288
|
+
`getPwaInstall()` synchronously returns the shared page owner with `state`,
|
|
289
|
+
`subscribe`, `prompt`, `dismiss` and `dispose`. Call it early when owning a
|
|
290
|
+
separate install entry point so it can capture `beforeinstallprompt` before
|
|
291
|
+
loading the UI. The generated bootstrap already does this through
|
|
292
|
+
`mountPwaInstallPrompt()`.
|
|
293
|
+
|
|
294
|
+
`state` contains `status`, `available`, `dismissed`, `outcome` and `error`.
|
|
295
|
+
Status is `waiting`, `available`, `prompting`, `accepted`, `dismissed`,
|
|
296
|
+
`installed`, `running`, `error` or `disposed`. `available` means a native event
|
|
297
|
+
is retained; a dismissed floating suggestion can still have `available: true`.
|
|
298
|
+
`outcome` is the browser's `accepted` or `dismissed` choice, or `null` before a
|
|
299
|
+
choice. `error` carries the complete prompt error, or `null`.
|
|
300
|
+
|
|
301
|
+
`subscribe(listener, {emitCurrent: true, signal} = {})` immediately replays
|
|
302
|
+
state by default and returns an unsubscribe function. Later state travels
|
|
303
|
+
through the existing Arcane event owner using `PWA_INSTALL_STATE_EVENT`
|
|
304
|
+
(`arcane.pwa.install.state`). A subscription does not wait for worker
|
|
305
|
+
registration, storage initialization or model readiness.
|
|
306
|
+
|
|
307
|
+
Call `prompt()` directly from the user's install click, before any asynchronous
|
|
308
|
+
wait. It invokes the browser prompt in the same call stack, consumes the event
|
|
309
|
+
once, and returns a promise for the browser's choice. It resolves to `null`
|
|
310
|
+
when there is no retained event or the owner is disposed. Failure publishes
|
|
311
|
+
`error` state and rejects. A new native event is required for another prompt.
|
|
312
|
+
|
|
313
|
+
```javascript
|
|
314
|
+
import {getPwaInstall} from 'arcane-os/pwa';
|
|
315
|
+
|
|
316
|
+
const install = getPwaInstall();
|
|
317
|
+
const installButton = document.querySelector('#install');
|
|
318
|
+
|
|
319
|
+
install.subscribe(function showInstallAvailability(state) {
|
|
320
|
+
installButton.hidden = !state.available;
|
|
321
|
+
});
|
|
322
|
+
installButton.addEventListener('click', function requestInstallation() {
|
|
323
|
+
install.prompt().catch(function reportInstallFailure(error) {
|
|
324
|
+
console.error(error);
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
`dismiss()` remembers the session choice without consuming the retained event
|
|
330
|
+
and returns the current state. A browser-native dismissed choice is remembered
|
|
331
|
+
too. `appinstalled` clears the event and publishes `installed`; running in an
|
|
332
|
+
app display mode publishes `running` and suppresses the prompt. These states
|
|
333
|
+
do not establish offline readiness. On Android, `appinstalled` can arrive
|
|
334
|
+
before WebAPK creation finishes. See the
|
|
335
|
+
[browser lifecycle distinction](https://web.dev/learn/pwa/detection/).
|
|
336
|
+
|
|
337
|
+
`dispose()` removes the shared owner's native listeners and subscriptions.
|
|
338
|
+
Leaving the page disposes it automatically, except when the browser retains
|
|
339
|
+
the page in its back/forward cache.
|
|
340
|
+
Because the owner is shared, an individual component should dispose its own
|
|
341
|
+
subscription instead. A later `getPwaInstall()` creates a new owner after
|
|
342
|
+
disposal; it cannot recover a native event that was already consumed.
|
|
343
|
+
|
|
344
|
+
## mountPwaInstallPrompt()
|
|
345
|
+
|
|
346
|
+
`mountPwaInstallPrompt({appName = ''} = {})` starts native install observation
|
|
347
|
+
synchronously, then loads the shared HTML import and theme modules concurrently
|
|
348
|
+
and appends one initially hidden component when the document body is available.
|
|
349
|
+
It returns the same mounting promise on repeated calls; the first call supplies
|
|
350
|
+
the initial app name. The promise resolves to the ready `html-import` host, or
|
|
351
|
+
`null` without a document or when the owner is disposed before mounting. It
|
|
352
|
+
rejects if component loading fails, or with `AbortError` when the loading host
|
|
353
|
+
is removed or its owner disposed. A rejected mount releases its slot so an
|
|
354
|
+
explicit later call can try again. Observe the rejection without making page
|
|
355
|
+
rendering wait for it.
|
|
356
|
+
|
|
357
|
+
The generated PWA bootstrap calls this automatically using the manifest name.
|
|
358
|
+
Applications need not add another floating suggestion. A separate entry point
|
|
359
|
+
can call it explicitly:
|
|
360
|
+
|
|
361
|
+
```javascript
|
|
362
|
+
import {mountPwaInstallPrompt} from 'arcane-os/pwa';
|
|
363
|
+
|
|
364
|
+
mountPwaInstallPrompt({appName: 'Example Library'}).catch(
|
|
365
|
+
function reportInstallComponentFailure(error) {
|
|
366
|
+
console.error(error);
|
|
367
|
+
}
|
|
368
|
+
);
|
|
369
|
+
```
|
|
370
|
+
|
|
143
371
|
## registerPwa()
|
|
144
372
|
|
|
145
373
|
Import `registerPwa` and `PWA_STATE_EVENT` from `arcane-os/pwa` through the
|
|
@@ -82,6 +82,7 @@ appropriate.
|
|
|
82
82
|
| [`modal.html`](#modalhtml) | Generic modal with population, open/close, actions, and sequential task execution. | `populate()`<br>`open()`<br>`close()`<br>`runTasks()`<br>`destroy()` | `modal-ready`<br>`modal-opened`<br>`modal-closed`<br>`modal-action` | Modal state normalized; injected task results mixed |
|
|
83
83
|
| [`output-panel.html`](#output-panelhtml) | Presents status, output, body, coverage, actions, pending, error, and cleared states. | `configure()`<br>`setOutput()`<br>`setBody()`<br>`setCoverage()`<br>`setActions()`<br>`setPending()`<br>`setStatus()`<br>`setError()`<br>`clear()`<br>`destroy()` | `output-panel-ready`<br>`output-panel-state`<br>`output-panel-change`<br>`output-panel-action`<br>`output-panel-error`<br>`output-panel-cleared` | DOM-normalized |
|
|
84
84
|
| [`preferences-form.html`](#preferences-formhtml) | Builds a schema-driven preferences form with submit, reset, busy, and status behavior. | `configure()`<br>`getValues()`<br>`setValues()`<br>`setBusy()`<br>`setStatus()`<br>`destroy()` | `preferences-form-ready`<br>`preferences-change`<br>`preferences-submit`<br>`preferences-reset` | Normalized form values |
|
|
85
|
+
| [`pwa-install.html`](#pwa-installhtml) | Presents a dismissible browser installation action with floating or inline placement. | `configure()`<br>`install()`<br>`dismiss()`<br>`destroy()`<br>`state`<br>`ready` | `pwa-install-ready`<br>`pwa-install-change`<br>`pwa-install-dismissed` | Browser install availability and outcome supplied by the shared PWA owner |
|
|
85
86
|
| [`record-timeline.html`](#record-timelinehtml) | Displays complete chronological records/evidence and emits open actions. | `setItems()`<br>`populate()`<br>`destroy()` | `record-timeline-ready`<br>`record-timeline-open` | Complete item fields and inventories preserved |
|
|
86
87
|
| [`relationship-board.html`](#relationship-boardhtml) | Displays complete normalized relationship nodes/edges in graph and list forms. | `setGraph()`<br>`populate()`<br>`destroy()` | `relationship-board-ready`<br>`relationship-node-open`<br>`relationship-edge-open` | Complete graph inventories and fields preserved |
|
|
87
88
|
| [`screen-capture.html`](#screen-capturehtml) | Presents image, video, or GIF display-capture workflow. | `capture` (`ScreenCapture` instance)<br>`destroy()` | `screen-capture-ready`<br>`screen-capture-result` | State/result normalized; media permission/codec failures mixed |
|
|
@@ -1018,6 +1019,69 @@ Events: `preferences-form-ready`, `preferences-change`, `preferences-submit`, `p
|
|
|
1018
1019
|
</html-import>
|
|
1019
1020
|
```
|
|
1020
1021
|
|
|
1022
|
+
## pwa-install.html
|
|
1023
|
+
|
|
1024
|
+
### Overview
|
|
1025
|
+
|
|
1026
|
+
A compact installation suggestion using the shared [PWA installation owner](pwa.md).
|
|
1027
|
+
The default floating panel appears near the top right only when the browser offers
|
|
1028
|
+
installation. It has an Install action and an explicit close button, takes no
|
|
1029
|
+
focus automatically, and has no dismissal timer. It uses the Arcane theme and
|
|
1030
|
+
primitives, wraps complete labels and errors, and scrolls its own content when
|
|
1031
|
+
the available height is limited. The parent page loads `ThemeBootstrap.js` to
|
|
1032
|
+
apply the user's appearance preferences.
|
|
1033
|
+
|
|
1034
|
+
### Public surface
|
|
1035
|
+
|
|
1036
|
+
`configure({appName, installLabel, closeLabel, promptingLabel, description,
|
|
1037
|
+
presentation})` updates display configuration and returns its current record.
|
|
1038
|
+
Labels remain complete strings. `appName` initially uses `data-app-name` or
|
|
1039
|
+
`this app`; the default button label is `Install`. `presentation` is `floating`
|
|
1040
|
+
by default or `inline`, initially read from `data-presentation`. Inline placement
|
|
1041
|
+
uses the parent's layout. Set `description` to an empty string when a compact
|
|
1042
|
+
placement needs no supporting text; supplied descriptions remain visible.
|
|
1043
|
+
|
|
1044
|
+
`install()` calls the shared owner's native prompt synchronously and returns its
|
|
1045
|
+
promise of the browser outcome or `null` when no prompt is available. Call it
|
|
1046
|
+
directly from a user action. The component's Install button already does this.
|
|
1047
|
+
An explicit request's complete failure message remains visible until dismissed;
|
|
1048
|
+
the method rejects with the same error. The browser controls actual installation.
|
|
1049
|
+
Acceptance hides the suggestion without claiming installation has completed.
|
|
1050
|
+
|
|
1051
|
+
`dismiss()` closes the component. Floating dismissal also uses the owner's
|
|
1052
|
+
session dismissal; an explicit inline component ignores that shared dismissal
|
|
1053
|
+
and closes only its own instance. Closing retains any unused native prompt at
|
|
1054
|
+
the shared owner. `destroy()` removes the component's listeners and subscription,
|
|
1055
|
+
disposes its event source, hides its host, and marks `ready` false; it does not
|
|
1056
|
+
dispose the shared owner or change browser installation state. Both methods
|
|
1057
|
+
return true while active and false after destruction; `destroy()` is idempotent.
|
|
1058
|
+
|
|
1059
|
+
The readonly `state` property returns the shared owner's current install-state
|
|
1060
|
+
record; `ready` becomes true after methods and the state subscription are attached.
|
|
1061
|
+
`pwa-install-ready` carries `{ready, state}`; `pwa-install-change` carries
|
|
1062
|
+
`{state, visible}` for each observed owner update; `pwa-install-dismissed` carries
|
|
1063
|
+
`{presentation, state}`. These follow the canonical event projection contract.
|
|
1064
|
+
|
|
1065
|
+
### Availability and normalization
|
|
1066
|
+
|
|
1067
|
+
The component requires HTMLImport and a DOM renderer. Native installation
|
|
1068
|
+
availability comes from the browser's `beforeinstallprompt` event through
|
|
1069
|
+
`getPwaInstall()`. Without an available event, the suggestion stays hidden;
|
|
1070
|
+
absence does not identify why installation is unavailable. Installed-app events,
|
|
1071
|
+
accepted prompts, and an already running installed display mode hide it.
|
|
1072
|
+
|
|
1073
|
+
### Example
|
|
1074
|
+
|
|
1075
|
+
```html
|
|
1076
|
+
<html-import
|
|
1077
|
+
id="install-app"
|
|
1078
|
+
href="/arcane/components/pwa-install.html"
|
|
1079
|
+
data-app-name="Example Library"
|
|
1080
|
+
data-presentation="inline"
|
|
1081
|
+
hidden>
|
|
1082
|
+
</html-import>
|
|
1083
|
+
```
|
|
1084
|
+
|
|
1021
1085
|
## record-timeline.html
|
|
1022
1086
|
|
|
1023
1087
|
### Overview
|