arcane-os 0.52.0 → 0.53.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 +37 -0
- package/README.md +1 -1
- package/docs/architecture.md +26 -3
- package/docs/reference/cli.md +30 -2
- package/docs/reference/inventory/package-api.json +15 -1
- package/docs/reference/protocols.md +23 -4
- package/docs/reference/pwa.md +44 -2
- package/docs/reference/sdk-api.md +158 -1
- package/package.json +3 -2
- package/src/dev-server.mjs +68 -25
- package/src/index.mjs +1 -0
- package/src/packager/core.mjs +10 -5
- package/src/pwa-worker.mjs +4 -2
- package/src/toolchain.mjs +23 -6
- package/src/websocket.mjs +479 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.53.0
|
|
4
|
+
|
|
5
|
+
- Add `acceptWebSocket` through `arcane-os/websocket` and the Node root export.
|
|
6
|
+
Accept a caller-selected native HTTP/1.1 Upgrade and exchange complete text
|
|
7
|
+
and binary messages with fragmentation, Ping/Pong, ordered writable
|
|
8
|
+
backpressure, close/abort handling and observable connection settlement.
|
|
9
|
+
Buffered Upgrade input reaches synchronously registered listeners in order.
|
|
10
|
+
- Preserve valid text, leading Unicode markers and binary view boundaries.
|
|
11
|
+
Text that cannot be represented exactly as UTF-8 reports an explicit error
|
|
12
|
+
before transmission or a close-state change. Browser clients use native
|
|
13
|
+
`WebSocket`; existing HTTP/TLS listeners, routes and application messages
|
|
14
|
+
remain caller-owned.
|
|
15
|
+
- No third-party WebSocket runtime, client sharing, reconnect, application
|
|
16
|
+
envelope, storage, HTTP/2 extended CONNECT or extension negotiation is added.
|
|
17
|
+
Existing SDK behavior and dependencies remain unchanged. Ordinary consumers
|
|
18
|
+
update through their public package workflow; optional server integration
|
|
19
|
+
belongs to the consuming application.
|
|
20
|
+
|
|
21
|
+
## 0.52.1
|
|
22
|
+
|
|
23
|
+
- Preserve an authored host `index.html` at `/` independently of application
|
|
24
|
+
entry and offline selection. Root import-map/PWA generation no longer aliases
|
|
25
|
+
that public homepage to the app entry. Existing app-only roots retain their
|
|
26
|
+
launcher behavior; excluded homepage content and assets stay outside the
|
|
27
|
+
application's managed documents and offline inventory.
|
|
28
|
+
- Source development follows root-file creation/removal without a descriptor
|
|
29
|
+
edit, serves an unselected host root unchanged, and avoids stale conditional
|
|
30
|
+
responses when generated aliases change within one HTTP second. Ordinary
|
|
31
|
+
selected routes, startup entry, manifest identity and worker lifecycle remain
|
|
32
|
+
unchanged.
|
|
33
|
+
- Packaged authored roots carry optional generated `app.rootDocument` metadata
|
|
34
|
+
so preview serves them at `/`; older and app-only packages retain their
|
|
35
|
+
existing redirects and queries. Worker directory navigation uses only indexes
|
|
36
|
+
already selected in its current offline inventory, with exact-query priority.
|
|
37
|
+
No dependency, configuration option, saved-data migration or cache reset is
|
|
38
|
+
introduced. Consumers regenerate their normal public SDK outputs after update.
|
|
39
|
+
|
|
3
40
|
## 0.52.0
|
|
4
41
|
|
|
5
42
|
- Add optional `package.documents` to select managed application HTML separately
|
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ selected SDK projection or an explicit live SDK source mount. Both profiles
|
|
|
20
20
|
share the theme, packaging, event, cancellation,
|
|
21
21
|
and browser run contracts while retaining their selected application layout.
|
|
22
22
|
|
|
23
|
-
This checkout defines the `0.
|
|
23
|
+
This checkout defines the `0.53.0` SDK contract. Applications pin one exact npm
|
|
24
24
|
version and lockfile; registry state is deliberately not baked into application
|
|
25
25
|
artifacts.
|
|
26
26
|
|
package/docs/architecture.md
CHANGED
|
@@ -145,6 +145,19 @@ one metadata task; unchanged files reuse their parsed selection. Shared runtime
|
|
|
145
145
|
requests do not wait for that refresh. Full offline inventories are enumerated
|
|
146
146
|
only for worker/offline-manifest requests, with separate state for each selected
|
|
147
147
|
app snapshot so an older inventory cannot overwrite newer generated metadata.
|
|
148
|
+
|
|
149
|
+
Authored host-root `index.html` presence is refreshed independently of descriptor
|
|
150
|
+
edits. Development serves that host index at `/` instead of redirecting to the
|
|
151
|
+
app entry and suppresses the root PWA alias. An index outside the selected app
|
|
152
|
+
mapping uses an unchanged exact-root response; `/index.html` and other resource
|
|
153
|
+
URLs retain their existing selection rules. A selected index keeps its existing
|
|
154
|
+
document classification. This broadens no app or offline inventory and adds no
|
|
155
|
+
managed maps or bootstrap. With no host index, the app-entry redirect remains.
|
|
156
|
+
A worker serves a directory's cached index body only when that index is already
|
|
157
|
+
in its current offline selection; otherwise the host owns the unchanged request.
|
|
158
|
+
The selected app launch and installation identity remain independent of this
|
|
159
|
+
host-root navigation.
|
|
160
|
+
|
|
148
161
|
Changed resource requests return the complete current saved source without
|
|
149
162
|
packaging, copying files into `dist`, or restarting the server. Conditional
|
|
150
163
|
requests for unchanged resources return `304`. Enabled PWAs check on page load
|
|
@@ -253,9 +266,12 @@ separate. See the [complete output contract](reference/protocols.md#app-selected
|
|
|
253
266
|
|
|
254
267
|
Packaging keeps standalone app files at the release root and places an explicitly
|
|
255
268
|
nested app beneath `apps/<id>/`. It preserves every shared route destination.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
269
|
+
A selected authored output-root `index.html` is preserved and suppresses the
|
|
270
|
+
deployment-root PWA navigation alias. When selected content supplies no root
|
|
271
|
+
index, the SDK generates a launcher and retains the selected app-entry alias;
|
|
272
|
+
an excluded source-host index does not alter that package result. Authored
|
|
273
|
+
document bases, app URLs, relative module imports and shared runtime paths
|
|
274
|
+
therefore resolve through the same layout in
|
|
259
275
|
source development and packaged delivery. Packaging consumes the saved source
|
|
260
276
|
and managed import maps; use `arcane import-map` to refresh those maps, or the
|
|
261
277
|
ordinary `arcane dev` startup that performs that refresh.
|
|
@@ -266,6 +282,13 @@ entry, or `./apps/hello-world/index.html` for a nested app. Its complete `files`
|
|
|
266
282
|
inventory follows the selected layout and includes the root `index.html`.
|
|
267
283
|
Packaged browser serving opens `app.start`; a previously generated flat release without `app.start` retains
|
|
268
284
|
its `app.entry` launch path.
|
|
285
|
+
Only selected records supplying an authored output-root index add the optional
|
|
286
|
+
generated `app.rootDocument: "./index.html"` release field. Preview serves that
|
|
287
|
+
document at `/` without inferring ownership from HTML content. When the field is
|
|
288
|
+
absent, older releases and generated-launcher packages retain their existing
|
|
289
|
+
`302` root redirect to `app.start` or the older `app.entry` fallback, preserving
|
|
290
|
+
the request query. This release fact adds no app configuration or API option and
|
|
291
|
+
does not change `app.start`.
|
|
269
292
|
|
|
270
293
|
The authored schema-2 descriptor is canonical for new apps and projects an
|
|
271
294
|
exact schema-1 `arcane-package.json` for current consumers. Existing Arcane
|
package/docs/reference/cli.md
CHANGED
|
@@ -245,6 +245,12 @@ files remain unchanged. The same layout applies to `arcane dev` and
|
|
|
245
245
|
`arcane package`. Generated and offline app files are committed; GitHub Actions
|
|
246
246
|
consume those committed files. See [root generated output](pwa.md#root-generated-output).
|
|
247
247
|
|
|
248
|
+
An existing authored source-host `index.html` suppresses the generated `/`
|
|
249
|
+
navigation alias even when the page is outside the application or offline
|
|
250
|
+
selection. It is not automatically added to either inventory or given managed
|
|
251
|
+
maps or PWA bootstrap. The selected app entry and installation identity remain
|
|
252
|
+
unchanged; see [authored host roots](pwa.md#authored-host-root-and-app-entry).
|
|
253
|
+
|
|
248
254
|
The supported physical layout preserves its route count and ordered include
|
|
249
255
|
list. External and modern integrated physical routes require `components`, `css`,
|
|
250
256
|
`dependencies`, `entities`, `img`, `modules`, and `sdk`; a physical workspace
|
|
@@ -373,6 +379,16 @@ not package the app or produce `dist` output. With PWA enabled, the server
|
|
|
373
379
|
generates the installation and offline manifests directly; see
|
|
374
380
|
[PWA development and versioning](pwa.md#development-and-hosting).
|
|
375
381
|
|
|
382
|
+
The startup URL remains the selected app entry. At `/`, the server serves an
|
|
383
|
+
existing authored host-root `index.html` and suppresses the app-entry redirect
|
|
384
|
+
and PWA alias. A root outside the selected app mapping is served unchanged only
|
|
385
|
+
through this exact-root route; `/index.html` and other resource URLs retain their
|
|
386
|
+
existing selection rules. A selected root follows its existing document
|
|
387
|
+
classification. Root presence does not expand either inventory or cause
|
|
388
|
+
bootstrap injection. With no host index, the app-entry redirect remains.
|
|
389
|
+
Root-file creation or removal is reflected in subsequent root-navigation and
|
|
390
|
+
generated-PWA requests without a restart or a descriptor edit.
|
|
391
|
+
|
|
376
392
|
The command reports acceptance before bind/start work, emits the final URL,
|
|
377
393
|
owns the server until cancellation, and restores failure to the process exit.
|
|
378
394
|
The default host is `127.0.0.1`. `--public` selects `0.0.0.0` (all IPv4
|
|
@@ -550,8 +566,11 @@ defaulting to `dist/<id>/`, and preserves the prior output until the replacement
|
|
|
550
566
|
is complete. It consumes saved source and managed
|
|
551
567
|
import maps, keeps standalone app files at the output root, and retains the
|
|
552
568
|
configured shared route destinations. Explicit multi-app workspaces retain
|
|
553
|
-
their selected app beneath `apps/<id>/`.
|
|
554
|
-
`index.html
|
|
569
|
+
their selected app beneath `apps/<id>/`. A selected authored output-root
|
|
570
|
+
`index.html` is preserved and suppresses the deployment-root PWA navigation
|
|
571
|
+
alias. When selected content supplies no root index, the SDK generates a launcher
|
|
572
|
+
and retains the app-entry alias. An excluded source-host root does not change
|
|
573
|
+
that package selection.
|
|
555
574
|
Source document bases and resource URLs therefore retain their development
|
|
556
575
|
layout. Packaging does not run tests or checks automatically.
|
|
557
576
|
|
|
@@ -584,6 +603,10 @@ The result includes the release root, manifest, and complete selected inventory.
|
|
|
584
603
|
the package launch URL in `app.start`: `./index.html` for a root app with that
|
|
585
604
|
entry, or `./apps/hello-world/index.html` for a nested app. The complete file
|
|
586
605
|
inventory follows the selected layout and includes the root `index.html`.
|
|
606
|
+
Only selected records supplying an authored output-root index add
|
|
607
|
+
`app.rootDocument: "./index.html"`. This optional generated release fact selects
|
|
608
|
+
root-document serving in preview; it is not an app configuration or CLI option
|
|
609
|
+
and does not change `app.start`.
|
|
587
610
|
`--dry-run` plans the package without refreshing source, running tests, or
|
|
588
611
|
replacing output.
|
|
589
612
|
|
|
@@ -749,6 +772,11 @@ For `--target browser`, starts the existing release in the app's configured
|
|
|
749
772
|
does not package, rebuild, test, check, or verify that release automatically.
|
|
750
773
|
It opens the release manifest's `app.start` URL. Older flat releases without
|
|
751
774
|
that field continue to open their `app.entry` path.
|
|
775
|
+
Requests to `/` serve the explicit `app.rootDocument` when that generated
|
|
776
|
+
release field is present. With no field, including older releases and app-only
|
|
777
|
+
packages with a generated launcher, `/` retains its `302` redirect to
|
|
778
|
+
`app.start` or the older `app.entry` fallback, preserving the request query.
|
|
779
|
+
Preview does not infer root ownership from HTML content.
|
|
752
780
|
The preview always uses HTTPS with the workspace certificate pair. Supply
|
|
753
781
|
`--cert <file> --key <file>` together to use another pair; see
|
|
754
782
|
[development HTTPS setup](#development-https-setup).
|
|
@@ -6,12 +6,26 @@
|
|
|
6
6
|
"minimumVersion": "22.23.2 for Node entrypoints",
|
|
7
7
|
"moduleSystem": "ESM"
|
|
8
8
|
},
|
|
9
|
-
"memberCount":
|
|
9
|
+
"memberCount": 224,
|
|
10
10
|
"runtimeSubpathPatterns": {
|
|
11
11
|
"arcane-os/modules/*": "./runtime/arcane/modules/*",
|
|
12
12
|
"arcane-os/entities/*": "./runtime/arcane/entities/*"
|
|
13
13
|
},
|
|
14
14
|
"members": [
|
|
15
|
+
{
|
|
16
|
+
"id": "root:acceptWebSocket",
|
|
17
|
+
"name": "acceptWebSocket",
|
|
18
|
+
"displayName": "acceptWebSocket()",
|
|
19
|
+
"kind": "function",
|
|
20
|
+
"signature": "acceptWebSocket({request,socket,head,protocol,signal})",
|
|
21
|
+
"entrypoints": ["arcane-os", "arcane-os/websocket"],
|
|
22
|
+
"primaryImport": "arcane-os/websocket",
|
|
23
|
+
"group": "WebSocket protocol",
|
|
24
|
+
"summary": "Accept one caller-selected HTTP/1.1 Upgrade and exchange complete native WebSocket messages.",
|
|
25
|
+
"availability": "Node; interoperates with browser native WebSocket clients",
|
|
26
|
+
"protocol": "RFC6455 version 13, without extensions or HTTP/2 extended CONNECT",
|
|
27
|
+
"normalization": "Native EventTarget message/error/close events and owned send/close promises; no application envelopes or storage"
|
|
28
|
+
},
|
|
15
29
|
{
|
|
16
30
|
"id": "root:APP_BUNDLE_DESCRIPTOR_NAME",
|
|
17
31
|
"name": "APP_BUNDLE_DESCRIPTOR_NAME",
|
|
@@ -251,15 +251,34 @@ The declared application ID remains unchanged. `appsRoot: "apps"` continues
|
|
|
251
251
|
to discover `apps/<id>` and supports the existing integrated and multi-app
|
|
252
252
|
layouts. Entries and include/exclude paths remain relative to the application.
|
|
253
253
|
|
|
254
|
-
|
|
255
|
-
depth back to the workspace. Managed bare imports remain the
|
|
256
|
-
their targets follow the selected npm routes. `arcane import-map`
|
|
257
|
-
enabled static PWA records at the app root, so normal static hosting needs no
|
|
254
|
+
SDK-managed root HTML uses `<base href="./">`; nested navigable documents use
|
|
255
|
+
their actual depth back to the workspace. Managed bare imports remain the
|
|
256
|
+
public interface; their targets follow the selected npm routes. `arcane import-map`
|
|
257
|
+
generates enabled static PWA records at the app root, so normal static hosting needs no
|
|
258
258
|
SDK request handler or runtime copy. Managed refresh, development serving,
|
|
259
259
|
inspection, dry run and packaging add no nested `apps/<id>/` navigation pages,
|
|
260
260
|
redirects, or duplicate PWA worker/inventory files. There is no output-retention
|
|
261
261
|
switch for those retired records.
|
|
262
262
|
|
|
263
|
+
An authored source-host `index.html` suppresses the root app-entry redirect and
|
|
264
|
+
generated PWA navigation alias even when that file is outside the application's
|
|
265
|
+
include or offline selection. Development serves that host index at `/`. An
|
|
266
|
+
index outside the selected app mapping uses an unchanged exact-root response;
|
|
267
|
+
`/index.html` and other resource URLs retain their existing selection rules.
|
|
268
|
+
A selected index follows the existing document classification. Root presence
|
|
269
|
+
adds no page, assets, managed maps, or PWA bootstrap to the application. With no
|
|
270
|
+
host index, development retains the app-entry redirect. In a package, only a
|
|
271
|
+
selected authored output-root index suppresses the alias; an absent or excluded
|
|
272
|
+
root retains the generated launcher and app-entry alias. Selected records that
|
|
273
|
+
supply an authored output-root index add the optional generated release field
|
|
274
|
+
`app.rootDocument: "./index.html"`. Preview serves that document at `/`; absence
|
|
275
|
+
retains the existing `302` to `app.start` or the older `app.entry` fallback with
|
|
276
|
+
the request query preserved. This is a release fact, not an app setting or HTML
|
|
277
|
+
content inference, and `app.start` remains unchanged. The worker can answer a
|
|
278
|
+
directory navigation from an index only when that index already belongs to its
|
|
279
|
+
current offline selection and has a cached response; otherwise the unchanged
|
|
280
|
+
request remains host-owned. See [authored host roots](pwa.md#authored-host-root-and-app-entry).
|
|
281
|
+
|
|
263
282
|
Application identity, stored data, the existing default installation ID and an
|
|
264
283
|
authored `pwa.manifest.id` remain unchanged. Authored resources continue to
|
|
265
284
|
follow the app's include/exclude selection; generation does not delete existing
|
package/docs/reference/pwa.md
CHANGED
|
@@ -102,6 +102,38 @@ committed files rather than generating them. Actual multi-app workspaces keep
|
|
|
102
102
|
their explicit `appsRoot: "apps"` layout. This source/package contract does not
|
|
103
103
|
establish any particular installed application's browser lifecycle.
|
|
104
104
|
|
|
105
|
+
### Authored host root and app entry
|
|
106
|
+
|
|
107
|
+
An authored `index.html` at the source host root keeps `/` separate from the
|
|
108
|
+
selected application entry. Root import-map generation and development PWA
|
|
109
|
+
generation omit the `/`-to-entry navigation alias whenever that file exists,
|
|
110
|
+
including when it is outside `package.include` or the offline selection.
|
|
111
|
+
Development serving answers `/` with that host index. An index outside the app's
|
|
112
|
+
selected source mapping is served unchanged through this exact-root route;
|
|
113
|
+
`/index.html` and other resource URLs retain their existing selection rules.
|
|
114
|
+
A selected index follows its existing managed-document classification. Root
|
|
115
|
+
presence alone adds no page or assets to the application or offline inventory
|
|
116
|
+
and adds no managed maps or PWA bootstrap. The host owns a root response outside
|
|
117
|
+
the worker's selected offline resources. With no host index, development retains
|
|
118
|
+
its app-entry redirect.
|
|
119
|
+
|
|
120
|
+
Packaging considers the selected output instead of unrelated source-host files.
|
|
121
|
+
A selected authored output-root `index.html` is preserved and suppresses the
|
|
122
|
+
deployment-root navigation alias. When selected content supplies no output-root
|
|
123
|
+
index, the package retains its generated launcher and app-entry alias. An
|
|
124
|
+
authored source root excluded from the package does not replace that launcher.
|
|
125
|
+
Only when selected records supply an authored output-root index does packaging
|
|
126
|
+
write `app.rootDocument: "./index.html"` in `ARCANE_APP_RELEASE.json`.
|
|
127
|
+
Packaged preview uses that generated field to serve the authored document at
|
|
128
|
+
`/`; it does not inspect HTML to infer root ownership. Without the field,
|
|
129
|
+
including older releases and generated-launcher packages, preview retains its
|
|
130
|
+
`302` redirect to `app.start` (or the older `app.entry` fallback), preserving the
|
|
131
|
+
request query. The startup URL remains the selected app launch URL.
|
|
132
|
+
|
|
133
|
+
This behavior requires no new setting. The application entry, default install
|
|
134
|
+
start URL, manifest identity and scope, worker registration scope, cache
|
|
135
|
+
identity, and saved application data keep their existing contracts.
|
|
136
|
+
|
|
105
137
|
### Offline resource selection
|
|
106
138
|
|
|
107
139
|
`offline.include` and `offline.exclude` select literal paths or directory
|
|
@@ -304,8 +336,10 @@ therefore matters even when an offline cache exists. Updating files in place
|
|
|
304
336
|
while installation fetches them is not an atomic release snapshot; the host owns
|
|
305
337
|
consistent deployment of the selected output.
|
|
306
338
|
|
|
307
|
-
|
|
308
|
-
document URL used to resolve relative modules and styles.
|
|
339
|
+
Where an app-entry navigation alias remains, it redirects to the selected entry
|
|
340
|
+
page, preserving the document URL used to resolve relative modules and styles.
|
|
341
|
+
An authored host root suppresses that alias as described above; merely retaining
|
|
342
|
+
an old cached root resource does not add it to the current offline selection.
|
|
309
343
|
|
|
310
344
|
For a same-origin navigation to a selected static `.html` or `.htm` document,
|
|
311
345
|
the worker can reuse that document's cached body while leaving the complete
|
|
@@ -319,6 +353,14 @@ document. This does not change query matching for assets, API calls, ordinary
|
|
|
319
353
|
fetch requests, unselected documents or other origins. Cache refresh and the
|
|
320
354
|
Update prompt keep their existing lifecycle.
|
|
321
355
|
|
|
356
|
+
For a same-origin directory navigation without an app-entry alias, the worker
|
|
357
|
+
can likewise reuse that directory's `index.html` body only when the index is
|
|
358
|
+
already in the current offline selection and has a retained cached response.
|
|
359
|
+
The directory URL and its query remain unchanged, including beneath a deployment
|
|
360
|
+
subpath. An exact query-specific selected resource takes precedence. Otherwise,
|
|
361
|
+
the original request passes to the host unchanged. This adds no page or asset to
|
|
362
|
+
the inventory and does not save a host response over the selected index.
|
|
363
|
+
|
|
322
364
|
Browser storage eviction can remove an offline cache. A missing release cache
|
|
323
365
|
entry falls back to the network, so offline availability still depends on the
|
|
324
366
|
browser retaining the selected resources.
|
|
@@ -41,6 +41,7 @@ runtime layouts.
|
|
|
41
41
|
| `arcane-os` | Complete high-level SDK surface. |
|
|
42
42
|
| `arcane-os/toolchain` | Headless application operations. |
|
|
43
43
|
| `arcane-os/events` | CLI/event reporter. |
|
|
44
|
+
| `arcane-os/websocket` | Node HTTP/1.1 WebSocket Upgrade, complete messages and connection lifecycle. Browser clients use native `WebSocket`. |
|
|
44
45
|
| `arcane-os/testing` | Isolated test registration and execution. |
|
|
45
46
|
| `arcane-os/targets` | Target adapters and dispatch. |
|
|
46
47
|
| `arcane-os/native` | Native plan and builder protocol. |
|
|
@@ -130,6 +131,7 @@ The remaining data-only subpaths are eight JSON Schemas and package metadata.
|
|
|
130
131
|
|
|
131
132
|
| Member | Kind | Import | Group | Availability |
|
|
132
133
|
| --- | --- | --- | --- | --- |
|
|
134
|
+
| `acceptWebSocket()` | function | `arcane-os`, `arcane-os/websocket` | WebSocket protocol | Node; browser-native client interoperability |
|
|
133
135
|
| `fetchRequest()` | function | `arcane-os/ai/twin-cloud` | TWiN Cloud requests | Node and Browser; remote HTTPS provider |
|
|
134
136
|
| `fetchSystemOneRequest()` | function | `arcane-os/ai/twin-cloud` | TWiN Cloud state-and-questions requests | Node and Browser; remote HTTPS provider |
|
|
135
137
|
| `generateImages()` | function | `arcane-os/ai/twin-cloud` | TWiN Cloud image generation | Node and Browser with Fetch and Blob; remote HTTPS provider |
|
|
@@ -882,7 +884,14 @@ generates one that opens the selected app page. The result
|
|
|
882
884
|
contains `outputRoot`, `manifest`, and the complete `files` inventory.
|
|
883
885
|
`manifest.app.entry` stays app-relative, while `manifest.app.start`
|
|
884
886
|
is the package launch URL, such as `./index.html` for a root app or
|
|
885
|
-
`./apps/hello-world/index.html` for a nested app.
|
|
887
|
+
`./apps/hello-world/index.html` for a nested app. Only when selected records
|
|
888
|
+
supply an authored output-root index does the release add
|
|
889
|
+
`manifest.app.rootDocument: "./index.html"`. Preview serves that explicit
|
|
890
|
+
document at `/`; without the field, older releases and generated-launcher
|
|
891
|
+
packages retain the `302` redirect to `app.start` or the older `app.entry`
|
|
892
|
+
fallback with the request query preserved. This generated release fact adds no
|
|
893
|
+
app configuration or API option, changes no `app.start`, and requires no HTML
|
|
894
|
+
content inference. Release
|
|
886
895
|
schema `1`, kind `arcane-app-release`, and packager identity
|
|
887
896
|
`arcane-app-packager-v1` remain unchanged. A dry run returns the planned output
|
|
888
897
|
and file inventory without writing source or output.
|
|
@@ -3746,6 +3755,154 @@ async function useselectApp(...arguments_) {
|
|
|
3746
3755
|
}
|
|
3747
3756
|
```
|
|
3748
3757
|
|
|
3758
|
+
## acceptWebSocket()
|
|
3759
|
+
|
|
3760
|
+
### Overview
|
|
3761
|
+
|
|
3762
|
+
Accepts one caller-selected RFC6455 HTTP/1.1 Upgrade using Node's native
|
|
3763
|
+
duplex stream. The caller owns HTTP routing, TLS, listeners, application
|
|
3764
|
+
messages and shutdown. Use the raw `server` returned by `startDevServer`, or
|
|
3765
|
+
the public `.server` / `.secureServer` of `node-http-server`. There is no
|
|
3766
|
+
listener creation, default port, application envelope, message persistence,
|
|
3767
|
+
client sharing, reconnect loop or third-party WebSocket runtime.
|
|
3768
|
+
|
|
3769
|
+
Browser clients use native `WebSocket` directly. Node's global `WebSocket` is
|
|
3770
|
+
also a client, not a server. This server adapter supports version 13 over an
|
|
3771
|
+
HTTP/1.1 `upgrade` event, including HTTP/1.1 negotiated on an HTTPS listener.
|
|
3772
|
+
It does not implement HTTP/2 extended CONNECT or negotiate extensions such as
|
|
3773
|
+
compression. TLS setup remains with the existing server owner.
|
|
3774
|
+
|
|
3775
|
+
### Signature, modes, and result
|
|
3776
|
+
|
|
3777
|
+
```text
|
|
3778
|
+
acceptWebSocket({request,socket,head,protocol,signal})
|
|
3779
|
+
```
|
|
3780
|
+
|
|
3781
|
+
Import from `arcane-os/websocket` or `arcane-os`. Supply the exact `request`,
|
|
3782
|
+
`socket` and `head` from the selected Node `upgrade` event. Do not substitute
|
|
3783
|
+
`request.socket` for that event's stream. `head` defaults to an empty buffer.
|
|
3784
|
+
Optional `protocol` is one exact client-offered token; the default empty string
|
|
3785
|
+
selects no subprotocol. A browser that offers subprotocols expects one to be
|
|
3786
|
+
selected. Optional `signal` owns this connection's lifetime.
|
|
3787
|
+
|
|
3788
|
+
The synchronous result is a native `EventTarget` with:
|
|
3789
|
+
|
|
3790
|
+
| Member | Contract |
|
|
3791
|
+
| --- | --- |
|
|
3792
|
+
| `readyState` | `1` open, `2` closing, `3` closed. Acceptance queues the handshake before any messages. |
|
|
3793
|
+
| `protocol` | Selected subprotocol, or the empty string. |
|
|
3794
|
+
| `send(data)` | `Promise<void>` for a complete string, `ArrayBuffer`, or view. A view sends only its selected region. Input is snapshotted at submission; writes stay in submission order. The promise waits for the native write callback and any required drain; it is not a peer/application acknowledgement. |
|
|
3795
|
+
| `close(code=1000,reason='')` | Starts the close handshake after already accepted sends; returns `closed`. Repeated calls return the same promise. A peer Close rejects unsent application messages and retains the close reply. |
|
|
3796
|
+
| `terminate(reason?)` | Destroys only this connection's stream immediately, rejects pending sends and returns `closed`. An optional reason is reported as an error. |
|
|
3797
|
+
| `closed` | Resolves once the stream closes to `{code,reason,wasClean,error}`. It never rejects. Code/reason come from the peer Close; without one, code is `1006`. An empty peer Close reports `1005`. `wasClean` requires both close frames and no recorded failure. |
|
|
3798
|
+
|
|
3799
|
+
Register listeners synchronously after acceptance. The handshake write and
|
|
3800
|
+
initial `head` processing begin in a microtask so those listeners receive
|
|
3801
|
+
buffered messages. `head` is processed once, before later stream chunks.
|
|
3802
|
+
|
|
3803
|
+
| Native event | Payload |
|
|
3804
|
+
| --- | --- |
|
|
3805
|
+
| `message` | `MessageEvent.data`: complete text as a string, or complete binary as `Uint8Array`. Fragment boundaries never replace message boundaries. |
|
|
3806
|
+
| `error` | `CustomEvent.detail`: the complete original transport Error or coded protocol/abort Error. |
|
|
3807
|
+
| `close` | `CustomEvent.detail`: the same result as `closed`. |
|
|
3808
|
+
|
|
3809
|
+
These are transport-local native events, not an application bus or retained
|
|
3810
|
+
event history. Native `EventTarget` owns listener exceptions; an async listener
|
|
3811
|
+
must observe its own promises. Listen for errors or inspect `closed.error`.
|
|
3812
|
+
Ping receives a matching Pong internally; Pong is not an application message.
|
|
3813
|
+
Text decoding preserves a leading U+FEFF and validates UTF-8 across the complete
|
|
3814
|
+
fragmented message. Binary data is never interpreted or wrapped as JSON.
|
|
3815
|
+
|
|
3816
|
+
### Errors and cancellation
|
|
3817
|
+
|
|
3818
|
+
Before changing the socket, an invalid handshake throws
|
|
3819
|
+
`ARCANE_WEBSOCKET_HANDSHAKE_INVALID` with `statusCode:400,headers:{}`;
|
|
3820
|
+
an unsupported WebSocket version throws `ARCANE_WEBSOCKET_VERSION_UNSUPPORTED`
|
|
3821
|
+
with `statusCode:426` and `headers:{'Sec-WebSocket-Version':'13'}`. The host
|
|
3822
|
+
owns sending that HTTP response and ending the rejected stream. Invalid socket,
|
|
3823
|
+
data or close arguments report `TypeError` / `RangeError`; a failed `send`
|
|
3824
|
+
rejects its promise without changing the payload.
|
|
3825
|
+
An unpaired UTF-16 surrogate cannot be represented as UTF-8: sending such text
|
|
3826
|
+
rejects with `ARCANE_WEBSOCKET_TEXT_INVALID`, and using it as a close reason
|
|
3827
|
+
throws that error before changing connection state. Valid strings remain exact.
|
|
3828
|
+
|
|
3829
|
+
After acceptance, invalid framing reports `ARCANE_WEBSOCKET_PROTOCOL_INVALID`
|
|
3830
|
+
and close status `1002`; invalid text reports `ARCANE_WEBSOCKET_TEXT_INVALID`
|
|
3831
|
+
and `1007`. Complete platform errors remain observable. Framing lengths,
|
|
3832
|
+
masking, the handshake's SHA-1 accept calculation and control-frame bounds are
|
|
3833
|
+
RFC transport requirements only. There are no application message limits,
|
|
3834
|
+
byte progress, content identities, or optional security controls.
|
|
3835
|
+
|
|
3836
|
+
A pre-aborted signal throws before taking ownership. Later abort destroys the
|
|
3837
|
+
stream with an `AbortError` coded `ARCANE_WEBSOCKET_ABORTED`, preserving the
|
|
3838
|
+
signal reason as its cause. Closing rejects new sends with
|
|
3839
|
+
`ARCANE_WEBSOCKET_CONNECTION_CLOSED` (or the existing failure).
|
|
3840
|
+
No timer silently terminates a slow close handshake; use the caller's signal or
|
|
3841
|
+
`terminate()` when that owner decides to stop. Server listener closure alone,
|
|
3842
|
+
including Node `closeAllConnections()`, does not own upgraded sockets. Track
|
|
3843
|
+
connections or provide a shared lifetime signal, then await their `closed`
|
|
3844
|
+
promises separately. None of this changes chat storage or `persist:false`.
|
|
3845
|
+
|
|
3846
|
+
### Example
|
|
3847
|
+
|
|
3848
|
+
This example attaches to an already-owned listener and returns a separate
|
|
3849
|
+
connection cleanup function. Its route and echo policy belong to the caller.
|
|
3850
|
+
Call it with `publicServer.server`, `publicServer.secureServer`, or an SDK
|
|
3851
|
+
development server's returned `server`; it creates no additional HTTP server.
|
|
3852
|
+
|
|
3853
|
+
```javascript
|
|
3854
|
+
import {acceptWebSocket} from 'arcane-os/websocket';
|
|
3855
|
+
|
|
3856
|
+
function attachEcho(server,signal){
|
|
3857
|
+
const connections=new Set();
|
|
3858
|
+
function upgrade(request,socket,head){
|
|
3859
|
+
if(request.url!=='/socket'){
|
|
3860
|
+
socket.end('HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n');
|
|
3861
|
+
return;
|
|
3862
|
+
}
|
|
3863
|
+
let connection;
|
|
3864
|
+
try{connection=acceptWebSocket({request,socket,head,signal});}
|
|
3865
|
+
catch(error){
|
|
3866
|
+
console.error(error);
|
|
3867
|
+
const status=error.statusCode??400;
|
|
3868
|
+
const version=status===426?'Sec-WebSocket-Version: 13\r\n':'';
|
|
3869
|
+
socket.end(`HTTP/1.1 ${status} Upgrade rejected\r\n${version}Connection: close\r\n\r\n`);
|
|
3870
|
+
return;
|
|
3871
|
+
}
|
|
3872
|
+
connections.add(connection);
|
|
3873
|
+
connection.addEventListener('error',function failed(event){console.error(event.detail);});
|
|
3874
|
+
connection.addEventListener('message',function echo(event){
|
|
3875
|
+
connection.send(event.data).catch(function sendFailed(error){console.error(error);});
|
|
3876
|
+
});
|
|
3877
|
+
connection.addEventListener('close',function remove(){connections.delete(connection);});
|
|
3878
|
+
}
|
|
3879
|
+
server.on('upgrade',upgrade);
|
|
3880
|
+
return async function detach(){
|
|
3881
|
+
server.off('upgrade',upgrade);
|
|
3882
|
+
await Promise.all([...connections].map(function stop(connection){return connection.terminate();}));
|
|
3883
|
+
};
|
|
3884
|
+
}
|
|
3885
|
+
|
|
3886
|
+
// In browser code, after the host has selected its ws: or wss: URL:
|
|
3887
|
+
function connectEcho(url){
|
|
3888
|
+
const client=new WebSocket(url);
|
|
3889
|
+
client.addEventListener('open',function greet(){client.send('The moon needs a coffee break.');});
|
|
3890
|
+
client.addEventListener('message',function received(event){console.log(event.data);});
|
|
3891
|
+
return client;
|
|
3892
|
+
}
|
|
3893
|
+
```
|
|
3894
|
+
|
|
3895
|
+
Protocol references: [RFC6455](https://www.rfc-editor.org/rfc/rfc6455.html),
|
|
3896
|
+
[Node upgrade event](https://nodejs.org/api/http.html#event-upgrade), and
|
|
3897
|
+
[native browser WebSocket](https://websockets.spec.whatwg.org/).
|
|
3898
|
+
Work is connection-local and linear in actual framing/content. Input is
|
|
3899
|
+
assembled once per complete message; advertised lengths do not preallocate
|
|
3900
|
+
payloads. Outbound framing snapshots each submitted message and uses native
|
|
3901
|
+
writable backpressure. Callers await `send` when producing a sustained stream.
|
|
3902
|
+
There is no history scan, app loop, diagnostic payload store or automatic retry.
|
|
3903
|
+
The authored `test/websocket.test.mjs` fixtures cover this boundary; source
|
|
3904
|
+
inspection is distinct from executing them or verifying a browser deployment.
|
|
3905
|
+
|
|
3749
3906
|
## startDevServer()
|
|
3750
3907
|
|
|
3751
3908
|
### Overview
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arcane-os",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.53.0",
|
|
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",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
".": "./src/index.mjs",
|
|
13
13
|
"./toolchain": "./src/toolchain.mjs",
|
|
14
14
|
"./events": "./src/events.mjs",
|
|
15
|
+
"./websocket": "./src/websocket.mjs",
|
|
15
16
|
"./event-manager": "./src/event-manager.mjs",
|
|
16
17
|
"./modules/*": "./runtime/arcane/modules/*",
|
|
17
18
|
"./entities/*": "./runtime/arcane/entities/*",
|
|
@@ -86,7 +87,7 @@
|
|
|
86
87
|
"test": "npm run test:unit && npm run test:functional && npm run test:integration && npm run test:regression",
|
|
87
88
|
"test:release": "node ./bin/arcane-test.mjs test/npm-release.test.mjs",
|
|
88
89
|
"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/conversation-closing-report.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",
|
|
89
|
-
"test:functional": "node ./bin/arcane-test.mjs test/ai-request-model.test.mjs test/ai-request-retry.test.mjs test/ai-stream-cancellation.test.mjs test/browser-speech-providers.test.mjs test/browser-wasm-gpu-notice.test.mjs test/browser-wasm-download-resume.test.mjs test/chat-input.test.mjs test/chat-stream-speech.test.mjs test/chat-transcript-scroll.test.mjs test/chat-transient-retention.test.mjs test/cli.test.mjs test/continuous-voice-capture.test.mjs test/dbopfs-document-library.test.mjs test/dbopfs-png.test.mjs test/dbopfs.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/file-preview.test.mjs test/import-map.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/markdown-editor.test.mjs test/markdown-media.test.mjs test/markdown-source-map.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/rendered-print.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/theme-manager.test.mjs test/twin-cloud-images.test.mjs test/twin-cloud.test.mjs test/update-check.test.mjs test/user-explicit-updates.test.mjs",
|
|
90
|
+
"test:functional": "node ./bin/arcane-test.mjs test/ai-request-model.test.mjs test/ai-request-retry.test.mjs test/ai-stream-cancellation.test.mjs test/browser-speech-providers.test.mjs test/browser-wasm-gpu-notice.test.mjs test/browser-wasm-download-resume.test.mjs test/chat-input.test.mjs test/chat-stream-speech.test.mjs test/chat-transcript-scroll.test.mjs test/chat-transient-retention.test.mjs test/cli.test.mjs test/continuous-voice-capture.test.mjs test/dbopfs-document-library.test.mjs test/dbopfs-png.test.mjs test/dbopfs.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/file-preview.test.mjs test/import-map.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/markdown-editor.test.mjs test/markdown-media.test.mjs test/markdown-source-map.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/rendered-print.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/theme-manager.test.mjs test/twin-cloud-images.test.mjs test/twin-cloud.test.mjs test/websocket.test.mjs test/update-check.test.mjs test/user-explicit-updates.test.mjs",
|
|
90
91
|
"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",
|
|
91
92
|
"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",
|
|
92
93
|
"check": "node tools/check-source.mjs && npm test",
|