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.
@@ -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. Its worker uses network revalidation first
89
- and retains successful selected resource responses for offline use, so saved
90
- source edits remain visible on an ordinary online refresh.
91
-
92
- Source inventory work begins when the browser requests the worker update, after
93
- the page can start. It traverses the selected route inventory once for that
94
- request, follows application page and runtime resource references to retain
95
- selected query variants, and shares an in-flight traversal with concurrent
96
- manifest requests. Each referenced source file is read once per traversal;
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. Generated metadata and bootstrap requests reuse the current
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
- Packaged workers use their selected cache generation first. During installation,
102
- at most four resource requests run together; each response is fetched from the
103
- network with the browser's reload cache mode before it enters the candidate
104
- cache. The candidate must finish
105
- installation before the browser activates it. Failures retain the prior active
106
- worker and remain observable through native worker state and SDK diagnostics.
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 must also revalidate stable HTML, module, style,
110
- import-map and worker URLs, and serve JavaScript with a JavaScript content type.
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. Activation retires only obsolete resource
136
- caches belonging to that exact app and registration scope. Saved application
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
- https=false, certPath, keyPath, tls, signal, onEvent}` and serves one validated
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, signal, onEvent}` and serves the
3473
- complete selected release files. `host` defaults to `127.0.0.1` and accepts an
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 listener; port `0` asks the operating
3476
- system for an available port.
3477
-
3478
- `https:true` reads `.arcane/dev/server-cert.pem` and
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. The path pair also selects
3481
- HTTPS without `https:true`; relative paths resolve from the workspace. A
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 HTTPS and the wildcard bind;
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 the listener is ready and resolves to
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 HTTP or HTTPS
3493
- server; `protocol` is `'http:'` or `'https:'`.
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
- All returned application URLs use the selected transport's scheme. The server
3503
- reads one PEM pair per startup and does not create certificates or modify trust
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 the selected listener and emits awaited,
3509
- backpressured `server.starting` and `server.started` events. Request failures
3510
- emit `server.request.failed`; shutdown emits `server.stopped` after owned
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`. A listener error
3514
- or event-callback failure closes the server and rejects its lifecycle. Invalid
3515
- mode/host/port, malformed workspace or release content, an occupied port,
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 `port`.
3911
- The operation refreshes the selected app's managed import maps once, then owns
3912
- one source listener and returns its protocol, URLs, and shutdown lifecycle.
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.11.2",
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
  },
@@ -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 Use HTTPS with .arcane/dev/server-cert.pem and server-key.pem.
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
- if((flags.has('https')||values.cert!==undefined||values.key!==undefined)&&command!=='dev'){
460
- usage('--https, --cert, and --key are supported only by dev.');
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);