arcane-os 0.11.2 → 0.12.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 +25 -0
- package/NOTICE +1 -0
- package/README.md +24 -13
- package/browser-runtime/ai/browser-wllama-runtime.mjs +7 -0
- package/browser-runtime/pwa.mjs +129 -0
- package/docs/architecture.md +28 -12
- package/docs/reference/ai/browser-wasm.md +5 -2
- package/docs/reference/cli.md +42 -16
- package/docs/reference/inventory/package-api.json +1 -1
- package/docs/reference/pwa.md +87 -22
- package/docs/reference/sdk-api.md +61 -27
- package/package.json +2 -1
- 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 +362 -136
- package/src/pwa.mjs +4 -1
- package/src/targets/index.mjs +5 -1
- package/src/toolchain.mjs +62 -12
package/docs/reference/pwa.md
CHANGED
|
@@ -83,31 +83,90 @@ the [existing asset version contract](asset-versioning.md).
|
|
|
83
83
|
|
|
84
84
|
## Development and hosting
|
|
85
85
|
|
|
86
|
+
Use the ordinary `arcane dev --app <id>` command after editing the selected
|
|
87
|
+
app's `arcane-app.json`. Startup refreshes that app's generated
|
|
88
|
+
`arcane-package.json` from the authored descriptor before refreshing its import
|
|
89
|
+
maps and starting the server. No packaging or `dist` output is required.
|
|
90
|
+
Package-only applications retain their existing descriptor workflow.
|
|
91
|
+
|
|
92
|
+
Add a file or directory to `package.include` to make it part of the app's
|
|
93
|
+
resources. A new file inside an already included directory needs no separate
|
|
94
|
+
entry. If `package.pwa.offline.include` is nonempty, the resource must also
|
|
95
|
+
match that offline selection and must not match `offline.exclude`. Adding a
|
|
96
|
+
path only to the offline selection does not add it to the app's resources.
|
|
97
|
+
Restart after changing descriptor settings. Edits to selected source files are
|
|
98
|
+
picked up by the next due page-load check while the server remains running.
|
|
99
|
+
|
|
86
100
|
For an enabled application, `arcane dev` serves the generated PWA files at the
|
|
87
101
|
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
|
-
|
|
102
|
+
selected app per development origin. The SDK uses `node-http-server` for source
|
|
103
|
+
and packaged-preview serving, including conditional resource responses.
|
|
104
|
+
Every Arcane development server and packaged browser preview serves HTTPS,
|
|
105
|
+
including localhost. Configure the workspace certificate pair before starting
|
|
106
|
+
the ordinary command; see [development HTTPS setup](cli.md#development-https-setup).
|
|
107
|
+
|
|
108
|
+
Source inventory work begins when the browser requests the worker or current
|
|
109
|
+
offline manifest, after the page can start. It traverses the selected route
|
|
110
|
+
inventory once for that request, follows page and runtime resource references
|
|
111
|
+
to retain selected query variants, and shares an in-flight traversal with
|
|
112
|
+
concurrent requests. Each referenced source file is read once per traversal;
|
|
97
113
|
document corpus bodies remain under their existing owner. It does not rebuild
|
|
98
|
-
the application.
|
|
99
|
-
bundle.
|
|
114
|
+
the application. Installation metadata and bootstrap requests reuse the current
|
|
115
|
+
generated bundle.
|
|
116
|
+
|
|
117
|
+
The SDK owns version information in `arcane-offline.json`:
|
|
118
|
+
|
|
119
|
+
| Field | Owner and update rule |
|
|
120
|
+
| --- | --- |
|
|
121
|
+
| `schemaVersion` | SDK offline-manifest format; currently `1`. |
|
|
122
|
+
| `appVersion` | The app descriptor's top-level `version`. |
|
|
123
|
+
| `sdkVersion` | The selected installed SDK or explicit live SDK source version. |
|
|
124
|
+
| `revision` | `development` for the source server; a fresh generated deployment ID for each packaged output. |
|
|
100
125
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
126
|
+
Do not hand-edit generated manifests or bump a version for every source edit.
|
|
127
|
+
`arcane.webmanifest` holds installation metadata and has no separate SDK-managed
|
|
128
|
+
release counter. Resource freshness uses each response's `Last-Modified` header.
|
|
129
|
+
|
|
130
|
+
On each page load, the SDK reads one `lastChecked` value for the app and worker
|
|
131
|
+
scope from DBOPFS in the background. When that value is missing or older than
|
|
132
|
+
the delivery mode's interval, it checks the current offline manifest and every
|
|
133
|
+
selected resource:
|
|
134
|
+
|
|
135
|
+
| Mode | Page-load check interval |
|
|
136
|
+
| --- | --- |
|
|
137
|
+
| Development | 120 seconds |
|
|
138
|
+
| Packaged browser delivery | 15 minutes |
|
|
139
|
+
|
|
140
|
+
These intervals schedule revalidation; they never expire a cached file. The
|
|
141
|
+
worker sends `GET` with `If-Modified-Since` using the cached response's
|
|
142
|
+
`Last-Modified`. A `304 Not Modified` retains the complete cached response. A
|
|
143
|
+
successful `200` replaces it after the new response is stored. Missing cached
|
|
144
|
+
resources are downloaded. Network and server failures retain an existing
|
|
145
|
+
offline copy and remain observable through SDK diagnostics. A host without
|
|
146
|
+
modification headers must send the current response because freshness cannot
|
|
147
|
+
be established from a missing header.
|
|
148
|
+
|
|
149
|
+
Complete resource responses remain in browser CacheStorage. DBOPFS stores one
|
|
150
|
+
successful whole-cycle timestamp, updated only after the manifest and every
|
|
151
|
+
selected resource have been checked successfully. A partial failure preserves
|
|
152
|
+
the previous timestamp so the next page load can retry. Each cached response
|
|
153
|
+
retains its own `Last-Modified` header, but there are no per-file check times.
|
|
154
|
+
The SDK imposes no age-based cache deletion and
|
|
155
|
+
retains resource bodies across app and SDK version changes. Requests for a page
|
|
156
|
+
do not wait for the complete resource inventory to finish checking. The SDK
|
|
157
|
+
uses at most four concurrent background resource requests and starts no timer
|
|
158
|
+
or polling loop between page loads.
|
|
159
|
+
|
|
160
|
+
During initial installation, selected resources are cached before the browser
|
|
161
|
+
activates the worker. Failures remain observable through native worker state
|
|
162
|
+
and SDK diagnostics. HTTP modification dates have second-level precision;
|
|
163
|
+
hosts must report changes to the served representation, including generated
|
|
164
|
+
output, rather than only the date of an unrelated source file.
|
|
107
165
|
|
|
108
166
|
The SDK development server sends `Cache-Control: no-cache` for PWA resources.
|
|
109
|
-
An independent static host
|
|
110
|
-
|
|
167
|
+
An independent static host should support `Last-Modified` and conditional GET
|
|
168
|
+
for stable HTML, module, style and import-map URLs, revalidate worker URLs, and
|
|
169
|
+
serve JavaScript with a JavaScript content type.
|
|
111
170
|
Keep the worker beside the deployment root it controls. The browser requires a
|
|
112
171
|
supported secure context, such as trusted HTTPS or localhost, to register it.
|
|
113
172
|
The SDK does not change certificates or browser permissions.
|
|
@@ -132,9 +191,15 @@ worker while they are open. Closing those pages allows activation; a refresh
|
|
|
132
191
|
can leave overlapping document clients and keep the update waiting.
|
|
133
192
|
|
|
134
193
|
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.
|
|
194
|
+
restart a model or poll for updates. Worker activation preserves cached
|
|
195
|
+
resources and the DBOPFS check history for the same app and registration scope.
|
|
196
|
+
Saved application data and caches owned by other capabilities are untouched.
|
|
197
|
+
|
|
198
|
+
When importing caches from an older SDK worker, the new worker fetches the
|
|
199
|
+
SDK-owned registration bootstrap and PWA client once so the page can use the
|
|
200
|
+
current cache-check protocol. Other cached resource bodies retain the normal
|
|
201
|
+
check cadence. This transition follows native worker installation and
|
|
202
|
+
activation without forcing a page reload.
|
|
138
203
|
|
|
139
204
|
Switching a server from a packaged release to live development does not replace
|
|
140
205
|
an already active release worker inside an open document. The same native
|
|
@@ -3459,6 +3459,15 @@ async function useselectApp(...arguments_) {
|
|
|
3459
3459
|
|
|
3460
3460
|
Starts one owned browser development server with exact runtime/app route mappings and a caller-selected bind address.
|
|
3461
3461
|
|
|
3462
|
+
HTTPS serving uses the published `node-http-server` module. The SDK
|
|
3463
|
+
selects source routes and supplies generated representations; the module owns
|
|
3464
|
+
static-file conditional GET/HEAD handling and response delivery. The SDK
|
|
3465
|
+
retains modification dates for its generated representations. Unchanged
|
|
3466
|
+
resources can return `304` with no body while changed resources return their
|
|
3467
|
+
complete current representation. PEM-path listeners use module deployment;
|
|
3468
|
+
explicit raw `tls` options retain native HTTPS transport with the same module
|
|
3469
|
+
response and static-file operations.
|
|
3470
|
+
|
|
3462
3471
|
### Signature, modes, and result
|
|
3463
3472
|
|
|
3464
3473
|
```text
|
|
@@ -3466,53 +3475,64 @@ async startDevServer(options={})
|
|
|
3466
3475
|
```
|
|
3467
3476
|
|
|
3468
3477
|
Import it from `arcane-os`. Source mode accepts
|
|
3469
|
-
`{workspaceRoot=process.cwd(), appId, mode='source', host='127.0.0.1', port=0,
|
|
3470
|
-
|
|
3478
|
+
`{workspaceRoot=process.cwd(), appId, mode='source', host='127.0.0.1', port=0, httpPort=0,
|
|
3479
|
+
certPath, keyPath, tls, signal, onEvent}` and serves one validated
|
|
3471
3480
|
workspace application plus its complete SDK or integrated runtime. Packaged mode uses
|
|
3472
|
-
`{mode:'packaged', releaseRoot, host, port,
|
|
3473
|
-
complete selected release files.
|
|
3481
|
+
`{mode:'packaged', releaseRoot, workspaceRoot, host, port, httpPort, certPath, keyPath, tls,
|
|
3482
|
+
signal, onEvent}` and serves the complete selected release files.
|
|
3483
|
+
`host` defaults to `127.0.0.1` and accepts an
|
|
3474
3484
|
explicit network address or hostname. Use `0.0.0.0` for all IPv4 interfaces or
|
|
3475
|
-
`::` for the platform's IPv6 wildcard
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
`
|
|
3485
|
+
`::` for the platform's IPv6 wildcard listeners. `port` selects the HTTPS
|
|
3486
|
+
application port, and `httpPort` selects the paired HTTP redirect port. Each
|
|
3487
|
+
defaults to `0`, which asks the operating system for an available port.
|
|
3488
|
+
The SDK request hook returns `308` for HTTP with a `Location` pointing to the
|
|
3489
|
+
actual HTTPS port while preserving the original request path and query. Both listeners
|
|
3490
|
+
use the selected host.
|
|
3491
|
+
|
|
3492
|
+
Every source server and packaged browser preview enforces HTTPS, including
|
|
3493
|
+
localhost. The legacy `https` option is accepted but cannot disable it.
|
|
3494
|
+
Startup reads `.arcane/dev/server-cert.pem` and
|
|
3479
3495
|
`.arcane/dev/server-key.pem` relative to `workspaceRoot` unless explicit
|
|
3480
|
-
`certPath` and `keyPath` are supplied together
|
|
3481
|
-
|
|
3482
|
-
direct `tls` object instead supplies Node HTTPS server options, including
|
|
3496
|
+
`certPath` and `keyPath` are supplied together; relative paths resolve from the
|
|
3497
|
+
workspace. A direct `tls` object instead supplies Node HTTPS server options, including
|
|
3483
3498
|
`cert` and `key`, without reading certificate files. Keep private material
|
|
3484
3499
|
server-side. Missing PEM files and Node certificate/key parse errors reject
|
|
3485
3500
|
startup without falling back to HTTP. Node owns TLS option handling and the
|
|
3486
3501
|
handshake; browser trust and address matching are evaluated when a client
|
|
3487
|
-
connects. The CLI's `--public` selects
|
|
3502
|
+
connects. The CLI's `--public` selects the wildcard bind;
|
|
3488
3503
|
the API's `host` option alone changes only the bind address.
|
|
3489
3504
|
|
|
3490
|
-
The promise settles after
|
|
3505
|
+
The promise settles after both listeners are ready and resolves to
|
|
3491
3506
|
`{server, protocol, mode, workspaceRoot, appId, host, port, origin, cleanUrl, url,
|
|
3492
|
-
networkUrls, close, closed, lifecycle}`. `server` is the raw Node
|
|
3493
|
-
server; `protocol` is `'
|
|
3507
|
+
networkUrls, httpPort, httpOrigin, httpUrl, close, closed, lifecycle}`. `server` is the raw Node HTTPS
|
|
3508
|
+
server; `protocol` is `'https:'`.
|
|
3494
3509
|
`url` and `cleanUrl` are the same application URL. Wildcard listeners use
|
|
3495
3510
|
`localhost` in that local URL; `host` retains the actual bound address.
|
|
3511
|
+
`httpPort` is the actual HTTP listener port, `httpOrigin` is its HTTP origin,
|
|
3512
|
+
and `httpUrl` combines that origin with the application start path. These
|
|
3513
|
+
fields identify the redirect endpoint; `origin`, `url`, `cleanUrl`, and
|
|
3514
|
+
`networkUrls` identify HTTPS application endpoints.
|
|
3496
3515
|
`networkUrls` lists application URLs for applicable non-loopback interface
|
|
3497
3516
|
addresses discovered once at startup. These URLs are connection candidates,
|
|
3498
3517
|
not evidence of reachability from another device. The server adds no session
|
|
3499
3518
|
capability or authentication. In packaged mode, `workspaceRoot` and `appId`
|
|
3500
3519
|
are `null`.
|
|
3501
3520
|
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
stores. Each client must trust the issuing CA and open an address covered by the
|
|
3521
|
+
PEM-path startup reads the selected pair. The server does not create
|
|
3522
|
+
certificates or modify trust stores. Each client must trust the issuing CA and open an address covered by the
|
|
3505
3523
|
server certificate. Lifecycle events and CLI summaries exclude TLS options and
|
|
3506
3524
|
private key contents. See [development HTTPS setup](cli.md#development-https-setup).
|
|
3507
3525
|
|
|
3508
|
-
Starting the server opens
|
|
3509
|
-
backpressured `server.starting` and `server.started` events.
|
|
3510
|
-
|
|
3526
|
+
Starting the server opens both selected listeners and emits awaited,
|
|
3527
|
+
backpressured `server.starting` and `server.started` events. `server.started`
|
|
3528
|
+
includes `httpPort`, `httpOrigin`, and `httpUrl` alongside the HTTPS endpoint.
|
|
3529
|
+
Request failures emit `server.request.failed`; shutdown emits `server.stopped` after owned
|
|
3511
3530
|
requests and event delivery drain. Call `await result.close()` in a `finally`
|
|
3512
3531
|
block, or abort `signal`; `close()` is idempotent and returns the
|
|
3513
|
-
same settlement represented by both `closed` and `lifecycle`.
|
|
3514
|
-
|
|
3515
|
-
|
|
3532
|
+
same settlement represented by both `closed` and `lifecycle`. Closing the
|
|
3533
|
+
operation closes both listeners. An error from either listener or an
|
|
3534
|
+
event-callback failure closes both and rejects the lifecycle. Invalid
|
|
3535
|
+
mode/host/port/httpPort, malformed workspace or release content, an occupied port,
|
|
3516
3536
|
or an already-aborted signal rejects startup.
|
|
3517
3537
|
|
|
3518
3538
|
### Availability and normalization
|
|
@@ -3907,9 +3927,16 @@ async function usedescribeTargets(...arguments_) {
|
|
|
3907
3927
|
Starts one owned browser development server for the selected application.
|
|
3908
3928
|
|
|
3909
3929
|
`https`, `certPath`, `keyPath`, and `tls` follow the
|
|
3910
|
-
[`startDevServer()` TLS contract](#startdevserver), alongside `host` and
|
|
3911
|
-
|
|
3912
|
-
|
|
3930
|
+
[`startDevServer()` TLS contract](#startdevserver), alongside `host`, `port`, and
|
|
3931
|
+
`httpPort`. `port` selects HTTPS and `httpPort` selects the HTTP `308` redirect
|
|
3932
|
+
listener; each defaults to an available port.
|
|
3933
|
+
The operation refreshes the selected authored descriptor's `arcane-package.json`
|
|
3934
|
+
projection and managed import maps under one development-refresh lock, then
|
|
3935
|
+
releases that lock before opening the HTTPS source listener and its HTTP
|
|
3936
|
+
redirect listener. It returns both endpoints and their shared shutdown
|
|
3937
|
+
lifecycle. Legacy package-only apps remain unchanged. The operation generates
|
|
3938
|
+
no packaged output; enabled PWA manifests
|
|
3939
|
+
are served directly from the selected source resources.
|
|
3913
3940
|
|
|
3914
3941
|
### Signature and result
|
|
3915
3942
|
|
|
@@ -6075,6 +6102,13 @@ registration and returns a synchronous owner with `ready`, `state`, `subscribe`,
|
|
|
6075
6102
|
`update` and `dispose`. It does not block page rendering or load models.
|
|
6076
6103
|
Unsupported environments receive an explicit unsupported state.
|
|
6077
6104
|
|
|
6105
|
+
The generated page bootstrap also starts the SDK's background resource check.
|
|
6106
|
+
It stores one `lastChecked` timestamp per app/cache in DBOPFS, advancing it only
|
|
6107
|
+
after the full resource check succeeds, and revalidates on page load after
|
|
6108
|
+
120 seconds in development or 15 minutes in packaged delivery. Complete
|
|
6109
|
+
responses remain cached without SDK expiration; `304` retains the response
|
|
6110
|
+
and a successful replacement updates it. See the [PWA guide](pwa.md).
|
|
6111
|
+
|
|
6078
6112
|
### Example
|
|
6079
6113
|
|
|
6080
6114
|
```javascript
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arcane-os",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.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",
|
|
@@ -105,6 +105,7 @@
|
|
|
105
105
|
},
|
|
106
106
|
"dependencies": {
|
|
107
107
|
"event-pubsub": "6.1.0",
|
|
108
|
+
"node-http-server": "9.1.1",
|
|
108
109
|
"strong-type": "2.0.1",
|
|
109
110
|
"vanilla-test": "2.1.3"
|
|
110
111
|
},
|
package/src/app-descriptor.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import Is from 'strong-type';
|
|
2
2
|
import {isDeepStrictEqual} from 'node:util';
|
|
3
|
-
import {readFile} from 'node:fs/promises';
|
|
3
|
+
import {readFile, writeFile} from 'node:fs/promises';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
+
import {throwIfAborted} from './errors.mjs';
|
|
5
6
|
import {normalizePwaConfig} from './pwa.mjs';
|
|
6
7
|
import {
|
|
7
8
|
ARCANE_MACHINE_BUNDLE_VERSION,
|
|
@@ -424,6 +425,47 @@ async function readJsonFile(filePath,label,{optional=false}={}){
|
|
|
424
425
|
}
|
|
425
426
|
}
|
|
426
427
|
|
|
428
|
+
export async function refreshAppPackageProjection({workspaceRoot, appId, signal, onEvent}) {
|
|
429
|
+
throwIfAborted(signal);
|
|
430
|
+
const appRoot = path.join(workspaceRoot, 'apps', appId);
|
|
431
|
+
const descriptorPath = path.join(appRoot, APP_DESCRIPTOR_NAME);
|
|
432
|
+
const authored = await readJsonFile(
|
|
433
|
+
descriptorPath,
|
|
434
|
+
`apps/${appId}/${APP_DESCRIPTOR_NAME}`,
|
|
435
|
+
{optional: true}
|
|
436
|
+
);
|
|
437
|
+
if (authored === null) return {updated: false};
|
|
438
|
+
|
|
439
|
+
validateAppDescriptor(
|
|
440
|
+
authored,
|
|
441
|
+
{appId}
|
|
442
|
+
);
|
|
443
|
+
const projection = projectPackageManifest(authored);
|
|
444
|
+
const packagePath = path.join(appRoot, 'arcane-package.json');
|
|
445
|
+
const packageManifest = await readJsonFile(
|
|
446
|
+
packagePath,
|
|
447
|
+
`apps/${appId}/arcane-package.json`
|
|
448
|
+
);
|
|
449
|
+
const packageProjection = packageManifest.pwa === undefined ? packageManifest : {
|
|
450
|
+
...packageManifest,
|
|
451
|
+
pwa: normalizePwaConfig(packageManifest.pwa)
|
|
452
|
+
};
|
|
453
|
+
if (isDeepStrictEqual(projection, packageProjection)) return {updated: false};
|
|
454
|
+
|
|
455
|
+
// Development updates the generated projection before strict workspace readers run.
|
|
456
|
+
throwIfAborted(signal);
|
|
457
|
+
await writeFile(packagePath, `${JSON.stringify(projection, null, 2)}\n`, 'utf8');
|
|
458
|
+
await onEvent?.(
|
|
459
|
+
{
|
|
460
|
+
type: 'workspace.application.projection.updated',
|
|
461
|
+
workspaceRoot,
|
|
462
|
+
appId,
|
|
463
|
+
path: packagePath
|
|
464
|
+
}
|
|
465
|
+
);
|
|
466
|
+
return {updated: true};
|
|
467
|
+
}
|
|
468
|
+
|
|
427
469
|
export async function loadAppDescriptor({workspaceRoot,appRoot,appId,packageManifest}){
|
|
428
470
|
const descriptorPath=path.join(appRoot,APP_DESCRIPTOR_NAME);
|
|
429
471
|
const authored=await readJsonFile(descriptorPath,`apps/${appId}/${APP_DESCRIPTOR_NAME}`,{optional:true});
|
package/src/cli/main.mjs
CHANGED
|
@@ -18,6 +18,7 @@ const VALUE_OPTIONS=new Set([
|
|
|
18
18
|
'arcane-root',
|
|
19
19
|
'host',
|
|
20
20
|
'port',
|
|
21
|
+
'http-port',
|
|
21
22
|
'cert',
|
|
22
23
|
'key',
|
|
23
24
|
'target',
|
|
@@ -64,7 +65,7 @@ Usage:
|
|
|
64
65
|
${CLI_NAME} upgrade [--workspace <directory>] [--app <id>]
|
|
65
66
|
${CLI_NAME} doctor [--workspace <directory>] [--arcane-root <directory>]
|
|
66
67
|
${CLI_NAME} import-map [--workspace <directory>] [--app <id>]
|
|
67
|
-
${CLI_NAME} dev [--app <id>] [--public] [--https] [--cert <pem>] [--key <pem>] [--host <address>] [--port 8000] [--sdk-runtime-source <sdk-root>]
|
|
68
|
+
${CLI_NAME} dev [--app <id>] [--public] [--https] [--cert <pem>] [--key <pem>] [--host <address>] [--port 8000] [--http-port 0] [--sdk-runtime-source <sdk-root>]
|
|
68
69
|
${CLI_NAME} test [--app <id>] [--scope app]
|
|
69
70
|
${CLI_NAME} test --scope shared --test-file <repo-relative.test.mjs>
|
|
70
71
|
${CLI_NAME} check [--app <id>] [--scope app] [--skip-tests]
|
|
@@ -76,7 +77,7 @@ Usage:
|
|
|
76
77
|
${CLI_NAME} native-doctor --target <native-target> --arcane-root <directory>
|
|
77
78
|
${CLI_NAME} native-prepare --target <native-target> --arcane-root <directory>
|
|
78
79
|
${CLI_NAME} build --target <target> [--arcane-root <directory>] [--output-root <directory>] [--format <format>] [--signing <mode>]
|
|
79
|
-
${CLI_NAME} run [--target <target>] [--app <id>] [--arcane-root <directory>] [--output-root <directory>] [--format <format>] [--signing <mode>]
|
|
80
|
+
${CLI_NAME} run [--target <target>] [--app <id>] [--cert <pem>] [--key <pem>] [--port 8000] [--http-port 0] [--arcane-root <directory>] [--output-root <directory>] [--format <format>] [--signing <mode>]
|
|
80
81
|
${CLI_NAME} update-check
|
|
81
82
|
${CLI_NAME} targets
|
|
82
83
|
${CLI_NAME} repo status|pull|push
|
|
@@ -88,9 +89,10 @@ Usage:
|
|
|
88
89
|
|
|
89
90
|
Development:
|
|
90
91
|
--public Serve HTTPS on all IPv4 interfaces (0.0.0.0) and print network URLs.
|
|
91
|
-
--https
|
|
92
|
+
--https Accepted for compatibility; Arcane browser serving always uses HTTPS.
|
|
92
93
|
--cert <pem> --key <pem> Use an existing certificate pair; paths are relative to the workspace.
|
|
93
94
|
--host <address> Override the bind address; takes precedence over --public.
|
|
95
|
+
--http-port <port> Browser dev/run HTTP redirect port; 0 selects an available port (default).
|
|
94
96
|
--sdk-runtime-source <sdk-root> Dev-only live SDK checkout; omitted preserves the workspace runtime mode.
|
|
95
97
|
|
|
96
98
|
Global:
|
|
@@ -456,9 +458,25 @@ function operationOptions(command,parsed,cwd){
|
|
|
456
458
|
if(flags.has('public')&&command!=='dev'){
|
|
457
459
|
usage('--public is supported only by dev.');
|
|
458
460
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
+
const browserServing = command === 'dev'
|
|
462
|
+
|| (command === 'run' && (values.target ?? 'browser') === 'browser');
|
|
463
|
+
if ((flags.has('https') || values.cert !== undefined || values.key !== undefined) && !browserServing) {
|
|
464
|
+
usage('--https, --cert, and --key are supported only by dev and run --target browser.');
|
|
461
465
|
}
|
|
466
|
+
if (values['http-port'] !== undefined && !browserServing) {
|
|
467
|
+
usage('--http-port is supported only by dev and run --target browser.');
|
|
468
|
+
}
|
|
469
|
+
if (browserServing && (values.cert === undefined) !== (values.key === undefined)) {
|
|
470
|
+
usage('Arcane HTTPS serving requires --cert and --key together.');
|
|
471
|
+
}
|
|
472
|
+
const browserServerOptions = browserServing ? {
|
|
473
|
+
https: true,
|
|
474
|
+
httpPort: readPort(values['http-port'], 0),
|
|
475
|
+
...(values.cert === undefined ? {} : {
|
|
476
|
+
certPath: path.resolve(workspaceRoot, values.cert),
|
|
477
|
+
keyPath: path.resolve(workspaceRoot, values.key)
|
|
478
|
+
})
|
|
479
|
+
} : {};
|
|
462
480
|
if(flags.has('overwrite')&&command!=='bundle'){
|
|
463
481
|
usage('--overwrite is supported only by bundle.');
|
|
464
482
|
}
|
|
@@ -518,18 +536,11 @@ function operationOptions(command,parsed,cwd){
|
|
|
518
536
|
}
|
|
519
537
|
if(command==='dev'){
|
|
520
538
|
noExtraPositionals(command,positionals);
|
|
521
|
-
if((values.cert===undefined)!==(values.key===undefined)){
|
|
522
|
-
usage('HTTPS development requires --cert and --key together.');
|
|
523
|
-
}
|
|
524
539
|
return {
|
|
525
540
|
...common,
|
|
541
|
+
...browserServerOptions,
|
|
526
542
|
host:values.host??(flags.has('public')?'0.0.0.0':'127.0.0.1'),
|
|
527
543
|
port:readPort(values.port,8000),
|
|
528
|
-
https:flags.has('public')||flags.has('https')||values.cert!==undefined,
|
|
529
|
-
...(values.cert===undefined?{}:{
|
|
530
|
-
certPath:path.resolve(workspaceRoot,values.cert),
|
|
531
|
-
keyPath:path.resolve(workspaceRoot,values.key)
|
|
532
|
-
}),
|
|
533
544
|
...(values['sdk-runtime-source']===undefined?{}:{
|
|
534
545
|
sdkRuntimeSourceRoot:path.resolve(cwd,values['sdk-runtime-source'])
|
|
535
546
|
})
|
|
@@ -609,6 +620,7 @@ function operationOptions(command,parsed,cwd){
|
|
|
609
620
|
noExtraPositionals(command,positionals);
|
|
610
621
|
return {
|
|
611
622
|
...common,
|
|
623
|
+
...browserServerOptions,
|
|
612
624
|
target:values.target??'browser',
|
|
613
625
|
arcaneRoot:values['arcane-root']?path.resolve(cwd,values['arcane-root']):undefined,
|
|
614
626
|
outputRoot:values['output-root']?path.resolve(cwd,values['output-root']):undefined,
|
|
@@ -853,6 +865,9 @@ function serverSummary(result){
|
|
|
853
865
|
host:result.host,
|
|
854
866
|
port:result.port,
|
|
855
867
|
url:result.url,
|
|
868
|
+
...(result.httpPort===undefined?{}:{httpPort:result.httpPort}),
|
|
869
|
+
...(result.httpOrigin===undefined?{}:{httpOrigin:result.httpOrigin}),
|
|
870
|
+
...(result.httpUrl===undefined?{}:{httpUrl:result.httpUrl}),
|
|
856
871
|
...(result.protocol===undefined?{}:{protocol:result.protocol}),
|
|
857
872
|
...(result.networkUrls===undefined?{}:{networkUrls:result.networkUrls}),
|
|
858
873
|
...(result.callerAuthentication
|
|
@@ -867,6 +882,7 @@ function serverSummary(result){
|
|
|
867
882
|
async function waitForServer(result,signal,reporter){
|
|
868
883
|
const readyMessage=[
|
|
869
884
|
`Development server ready at ${result.url}`,
|
|
885
|
+
...(result.httpUrl ? [`HTTP redirect: ${result.httpUrl}`] : []),
|
|
870
886
|
...(result.networkUrls??[]).map(function networkAddress(url){return `Network: ${url}`;})
|
|
871
887
|
].join('\n');
|
|
872
888
|
reporter.emit('server.ready',serverSummary(result),readyMessage);
|