arcane-os 0.1.0-dev.5 → 0.1.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.
@@ -1,42 +1,34 @@
1
- # Development publication
2
-
3
- ## Current branch stage
4
-
5
- Until the first official SDK release, `main` is the single canonical working,
6
- integration, publication, and documentation branch. Pull requests and pushes
7
- target `main`, and the complete Node/platform matrix runs there. Do not use a
8
- separate development branch during this prerelease stage.
9
-
10
- After the first official release, ordinary work will move to a long-lived
11
- `dev` branch while `main` remains the canonical released line. That transition
12
- must be made as one explicit release change that updates branch protections,
13
- checks, trusted publication rules, documentation channels, and contributor
14
- instructions together. The future branch name alone grants no authority.
15
-
16
- ## Development npm publication
17
-
18
- The current development npm version is `0.1.0-dev.5` and `publishConfig.tag` is
19
- `dev`, so a development publication does not become the default `latest`
20
- release. Query `npm view arcane-os@dev version` for current registry
21
- availability; immutable package documentation does not assert mutable registry
22
- state. npm is the canonical SDK distribution: application repositories add an
23
- exact `arcane-os` project dependency and invoke its local CLI with
24
- `npm exec -- arcane`. A separate global installer, standalone SDK executable,
25
- NuGet package, Homebrew formula, or OS package is not part of this release
26
- surface. Vanilla Test's C# and Rust lifecycles do not turn this JavaScript SDK
27
- into a .NET or Rust package.
28
-
29
- `Check` first runs the development suite, then one unprivileged producer packs
30
- one `.tgz` under pinned Node and npm versions. The producer writes a canonical
1
+ # npm publication
2
+
3
+ ## Canonical main and npm channels
4
+
5
+ `main` is the single canonical working and publication branch before and after
6
+ the first release. Do not create a development branch. `-dev` versions select
7
+ the npm `dev` dist-tag, while bare numeric stable versions select
8
+ `latest`. These are registry channels, not Git branches.
9
+
10
+ ## Stable and development npm publication
11
+
12
+ The package version and `publishConfig.tag` must agree exactly: `-dev` uses
13
+ `dev`, and a bare numeric stable version uses `latest`. npm is the canonical
14
+ SDK distribution: application repositories add an exact `arcane-os` project
15
+ dependency and invoke its local CLI with `npm exec -- arcane`. A separate
16
+ global installer, standalone SDK executable, NuGet package, Homebrew formula,
17
+ or OS package is not part of this release surface.
18
+
19
+ `Check` validates the source once, then one unprivileged producer packs one
20
+ `.tgz` under pinned Node and npm versions. The producer writes a canonical
31
21
  manifest containing the source SHA, clean-checkout flag, package inventory,
32
22
  byte length, SHA-256, npm SHA-1 shasum, and SHA-512 integrity. Windows x64,
33
23
  Linux x64, and a real macOS arm64 runner use the declared Node `22.23.2` floor
34
24
  and each download that same Actions
35
25
  artifact by immutable artifact id. They never repack it. Each runner verifies
36
26
  the receipt, installs the tarball into a disposable project, exercises
37
- `npm exec --offline -- arcane`, and runs a test imported from
38
- `arcane-os/testing` through the installed package's `arcane-test.mjs`. A final
39
- readiness job fails unless the producer and the complete native matrix pass.
27
+ `npm exec --offline -- arcane`, and runs one small capability contract through
28
+ the installed package's `arcane-test.mjs`. A final readiness job verifies the
29
+ same artifact's identity, integrity, shasum, license inventory, and content
30
+ boundary once. Browser/process simulations, Pages, Examples, and presentation
31
+ work are post-registry follow-through rather than npm publication gates.
40
32
 
41
33
  `publish-dev.yml` can run only when manually dispatched from `main` in
42
34
  `TheWizardNexus/arcane-os-sdk`. Dispatch requires an authorized npm content
@@ -49,14 +41,19 @@ promotion. Direct trusted publishing is not permitted for that class.
49
41
 
50
42
  For the standard path, the workflow authenticates a successful `Check` push
51
43
  run for that exact `main` SHA, downloads its immutable package artifact,
52
- reverifies the manifest and bytes, and publishes the downloaded `.tgz`. It
44
+ reverifies the manifest and bytes, derives `dev` or `latest` from the strict
45
+ version, and publishes the downloaded `.tgz`. It
53
46
  never invokes `npm pack` or `npm publish .` under publication authority. A
54
47
  repository-wide concurrency group prevents simultaneous publication jobs;
55
48
  GitHub may replace an older pending dispatch, and each surviving dispatch is
56
- safe to rerun. Preflight rejects byte mismatches, a backward `dev` move, or any
57
- dist-tag other than `dev`; an already-published matching version is an
58
- idempotent success. Post-publication
59
- verification tolerates npm's publish-time scanning for up to 15 minutes. If
49
+ safe to rerun. Preflight rejects byte mismatches, tag rollback, malformed
50
+ registry state, or any dist-tag other than `dev` and `latest`; an
51
+ already-published matching version is an idempotent success. The historical
52
+ first-version state where both tags identify `0.1.0-dev.5` is accepted only
53
+ with its recorded integrity and shasum and only while no stable version exists.
54
+ Post-publication verification preserves the other channel, checks integrity
55
+ and shasum, and validates trusted-publisher provenance. It tolerates npm's
56
+ publish-time scanning for up to 15 minutes. If
60
57
  scanning or manual review remains pending, the workflow reports that state and
61
58
  a rerun safely resumes verification without republishing immutable bytes.
62
59
 
@@ -73,7 +70,7 @@ integrity. Arcane separately requires the installed package to identify exactly
73
70
  as `arcane-os@0.1.0-dev.5` and verifies the locked runtime. A local directory
74
71
  `file:` install is intentionally unsupported because it may be linked.
75
72
 
76
- Before the first development publish, or while the registry package is absent:
73
+ The first-version bootstrap established these permanent audit boundaries:
77
74
 
78
75
  1. Push the intended clean `main` commit and require the complete Check workflow,
79
76
  including the exact-artifact Windows/Linux/macOS matrix, to pass.
@@ -93,12 +90,10 @@ Before the first development publish, or while the registry package is absent:
93
90
  tarball. Do not rebuild or repack it for this bootstrap. After the package
94
91
  exists, standard releases may publish directly through OIDC, while dual-use
95
92
  releases must use `npm stage publish` and human 2FA promotion.
96
- 5. Allow for npm publish-time scanning, then verify the registry's
97
- `dist.integrity` equals the manifest, verify `dev` is
98
- the only dist-tag, add a second appropriate owner, and configure npm trusted
99
- publishing for the exact `publish-dev.yml` workflow and `npm` environment.
100
- For a dual-use classification, grant stage-only trust instead of direct
101
- publish authority.
93
+ 5. Verify the registry's `dist.integrity` and shasum. npm's required bootstrap
94
+ state has both `dev` and `latest` at the immutable `0.1.0-dev.5` bytes
95
+ until the first stable publish moves only `latest`. The sole trusted
96
+ publisher is the exact `publish-dev.yml` workflow and `npm` environment.
102
97
  6. Later standard development versions may use the workflow's direct OIDC
103
98
  authority. A dual-use version must be staged and promoted with human 2FA.
104
99
  Any missing policy decision, package bootstrap, environment, publisher
@@ -170,12 +165,12 @@ internal checksums alone do not grant authority.
170
165
  Stable versioning, the npm `latest` tag, and an official GitHub release remain a
171
166
  separate explicit release decision. Current `main` development does not
172
167
  silently convert a `-dev` package into an official release. A stable release
173
- must publish the same matrix-tested `.tgz` under `latest`; only after registry
168
+ must publish the same source-validated and platform-smoked `.tgz` under
169
+ `latest`; only after registry
174
170
  integrity matches may GitHub attach that `.tgz`, manifest, and checksum. Its Git
175
171
  tag and GitHub release title must both be the same bare numeric
176
- `MAJOR.MINOR.PATCH`. The first stable change must also activate the documented
177
- `dev`/`main` branch transition and protections; prerelease versions do not get a
178
- misleading numeric GitHub release.
172
+ `MAJOR.MINOR.PATCH`. Prerelease versions do not get a misleading numeric
173
+ GitHub release, and no release creates a Git branch for an npm dist-tag.
179
174
 
180
175
  ## Documentation publication
181
176
 
@@ -188,16 +183,14 @@ It does not rerun the SDK test suite or execute repository build code.
188
183
 
189
184
  The deployment job holds only the read, Pages, and OIDC permissions required by
190
185
  that single checked artifact. The `github-pages` environment remains the final
191
- deployment authority. A separate `/dev/` documentation channel is deferred to
192
- the same explicit post-release branch transition described above.
186
+ deployment authority. Documentation channels are post-registry presentation
187
+ work and do not change the canonical source branch.
193
188
 
194
189
  ## Work-amplification record
195
190
 
196
- The prerelease branch cardinality is one checked `main` SHA, one npm release
197
- candidate, one static site, and one Pages artifact. Four source-check jobs cover
198
- two supported Node lines on Windows and Linux. One producer creates the npm
199
- tarball once; three native consumers execute those exact bytes on Windows,
200
- Linux, and macOS; one readiness gate aggregates them. Development publication
201
- and Pages authenticate and reuse that successful exact-SHA evidence. Neither
202
- rebuilds the SDK package or reruns the suite, and Pages does not create a second
203
- site placement.
191
+ The release graph is one checked `main` SHA and one npm release candidate. One
192
+ source-validation job runs the suite once; one producer creates the tarball;
193
+ three small installed-package consumers execute those exact bytes on Windows,
194
+ Linux, and macOS; and one readiness job verifies identity and legal inventory.
195
+ OIDC publication reuses that successful exact-SHA artifact without rebuilding.
196
+ Pages and broader presentation work follow registry verification separately.
@@ -235,11 +235,11 @@ Seeking never rewrites DOM, storage, native state, processes, or network state.
235
235
 
236
236
  ```javascript
237
237
  await events.playback({
238
- stack=null,
239
- fromSequence=1,
240
- toSequence=Number.MAX_SAFE_INTEGER,
241
- speed=0,
242
- mode='review',
238
+ stack:null,
239
+ fromSequence:1,
240
+ toSequence:Number.MAX_SAFE_INTEGER,
241
+ speed:0,
242
+ mode:'review',
243
243
  signal,
244
244
  onRecord
245
245
  });
@@ -50,9 +50,10 @@ format, or signing loop and does not produce app output.
50
50
 
51
51
  - Scaffold: approximately 15-25 files, less than 100 KiB, target under one
52
52
  second before an optional dependency installation.
53
- - Shared browser payload: 158 files / 3,359,960 bytes, comprising the exact
54
- 155-file / 3,320,994-byte dev.4 runtime receipt plus three SDK licensing files
55
- / 38,966 bytes, verified once per exact SDK installation state.
53
+ - Shared browser payload: 166 files / 3,478,345 bytes, comprising the exact
54
+ 155-file / 3,320,994-byte Arcane-upstream runtime receipt, the separate
55
+ 8-file / 118,385-byte SDK browser-runtime receipt, and three SDK licensing
56
+ files / 38,966 bytes, verified once per exact SDK installation state.
56
57
  - Small browser package: app bytes plus the shared runtime, copied and inventoried
57
58
  once into an atomic staging directory.
58
59
  - Portable build: one explicitly selected app and one host platform request. In
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "arcane-os",
3
- "version": "0.1.0-dev.5",
4
- "description": "Arcane OS application SDK, CLI, browser runtime, and cross-platform build toolchain.",
3
+ "version": "0.1.0",
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",
7
7
  "bin": {
@@ -33,6 +33,7 @@
33
33
  },
34
34
  "files": [
35
35
  "bin/",
36
+ "browser-runtime/",
36
37
  "src/",
37
38
  "runtime/",
38
39
  "schemas/",
@@ -45,11 +46,14 @@
45
46
  ],
46
47
  "scripts": {
47
48
  "test": "npm run test:unit && npm run test:functional && npm run test:integration && npm run test:regression",
48
- "test:unit": "node ./bin/arcane-test.mjs test/app-descriptor.test.mjs test/app-schema.test.mjs test/contracts.test.mjs test/doctor.test.mjs test/targets.test.mjs",
49
- "test:functional": "node ./bin/arcane-test.mjs test/cli.test.mjs test/dev-server.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/packaging.test.mjs test/reference-completeness.test.mjs test/runtime-api-behavior.test.mjs test/runtime-sync.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/site.test.mjs test/update-check.test.mjs",
50
- "test:integration": "node ./bin/arcane-test.mjs test/integrated-shared.test.mjs test/integrated-workspace.test.mjs test/native-plan.test.mjs test/native-provider-loader.test.mjs test/npm-release.test.mjs test/release-bundle.test.mjs test/shared-payload-batch.test.mjs test/tarball.test.mjs",
49
+ "test:release": "npm run test:unit && npm run test:functional:release && npm run test:integration && npm run test:regression",
50
+ "test:unit": "node ./bin/arcane-test.mjs test/app-descriptor.test.mjs test/app-schema.test.mjs test/contracts.test.mjs test/doctor.test.mjs test/targets.test.mjs test/workspace-operation-lock.test.mjs",
51
+ "test:functional": "node ./bin/arcane-test.mjs test/cli.test.mjs test/dev-server.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/import-map.test.mjs test/packaging.test.mjs test/reference-completeness.test.mjs test/runtime-api-behavior.test.mjs test/runtime-sync.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/site.test.mjs test/update-check.test.mjs",
52
+ "test:functional:release": "node ./bin/arcane-test.mjs test/cli.test.mjs test/dev-server.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/import-map.test.mjs test/packaging.test.mjs test/runtime-api-behavior.test.mjs test/runtime-sync.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/update-check.test.mjs",
53
+ "test:integration": "node ./bin/arcane-test.mjs test/integrated-shared.test.mjs test/integrated-workspace.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",
51
54
  "test:regression": "node ./bin/arcane-test.mjs test/channel-workflows.test.mjs test/native-provider-generation.test.mjs test/testing.test.mjs test/test-sets.test.mjs",
52
- "check": "node tools/check-source.mjs && node tools/runtime-manifest.mjs --verify && npm test",
55
+ "check": "node tools/check-source.mjs && node tools/runtime-manifest.mjs --verify && node tools/sdk-browser-runtime-manifest.mjs --verify && npm test",
56
+ "check:release": "node tools/check-source.mjs && node tools/runtime-manifest.mjs --verify && node tools/sdk-browser-runtime-manifest.mjs --verify && npm run test:release",
53
57
  "runtime:verify": "node tools/runtime-manifest.mjs --verify",
54
58
  "runtime:sync": "node tools/sync-runtime.mjs",
55
59
  "pack:local": "npm pack --ignore-scripts",
@@ -81,7 +85,7 @@
81
85
  "publishConfig": {
82
86
  "access": "public",
83
87
  "registry": "https://registry.npmjs.org/",
84
- "tag": "dev"
88
+ "tag": "latest"
85
89
  },
86
90
  "dependencies": {
87
91
  "event-pubsub": "6.1.0",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "builder": "arcane-sdk-runtime-v1",
4
- "sdkVersion": "0.1.0-dev.5",
4
+ "sdkVersion": "0.1.0",
5
5
  "source": {
6
6
  "repository": "https://github.com/TheWizardNexus/ARCANE-OS.git",
7
7
  "commit": "567ad110bf57a1c2d4a3daa22ae93716cc5f4d7e",
@@ -9,6 +9,7 @@
9
9
  "schemaVersion",
10
10
  "sdk",
11
11
  "runtime",
12
+ "sdkBrowserRuntime",
12
13
  "protocols"
13
14
  ],
14
15
  "properties": {
@@ -27,7 +28,7 @@
27
28
  "const": "arcane-os"
28
29
  },
29
30
  "version": {
30
- "const": "0.1.0-dev.5"
31
+ "const": "0.1.0"
31
32
  }
32
33
  }
33
34
  },
@@ -52,6 +53,90 @@
52
53
  }
53
54
  }
54
55
  },
56
+ "sdkBrowserRuntime": {
57
+ "type": "object",
58
+ "additionalProperties": false,
59
+ "required": [
60
+ "manifest",
61
+ "manifestSha256",
62
+ "contentSha256",
63
+ "builder",
64
+ "sdkVersion",
65
+ "source"
66
+ ],
67
+ "properties": {
68
+ "manifest": {
69
+ "const": "node_modules/arcane-os/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json"
70
+ },
71
+ "manifestSha256": {
72
+ "const": "43baaec850291c28795f6c194001deb5febab88ccab1b033bce6597dd6f6f08f"
73
+ },
74
+ "contentSha256": {
75
+ "const": "0caa302bc07d4a45f5290504ec62ddce98fdf5e3412f916c10aae3d51b1e5f7c"
76
+ },
77
+ "builder": {
78
+ "const": "arcane-sdk-browser-runtime-v1"
79
+ },
80
+ "sdkVersion": {
81
+ "const": "0.1.0"
82
+ },
83
+ "source": {
84
+ "type": "object",
85
+ "additionalProperties": false,
86
+ "required": [
87
+ "authority",
88
+ "repository",
89
+ "protocol",
90
+ "browserEntry",
91
+ "dependencies"
92
+ ],
93
+ "properties": {
94
+ "authority": {
95
+ "const": "arcane-os-sdk"
96
+ },
97
+ "repository": {
98
+ "const": "https://github.com/TheWizardNexus/arcane-os-sdk.git"
99
+ },
100
+ "protocol": {
101
+ "const": "arcane-sdk-browser-runtime/1"
102
+ },
103
+ "browserEntry": {
104
+ "const": "arcane-os/event-manager"
105
+ },
106
+ "dependencies": {
107
+ "type": "array",
108
+ "minItems": 2,
109
+ "maxItems": 2,
110
+ "prefixItems": [
111
+ {
112
+ "type": "object",
113
+ "additionalProperties": false,
114
+ "required": ["name", "version", "resolved", "integrity"],
115
+ "properties": {
116
+ "name": {"const": "event-pubsub"},
117
+ "version": {"const": "6.1.0"},
118
+ "resolved": {"const": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-6.1.0.tgz"},
119
+ "integrity": {"const": "sha512-FEMlhTxwqGM0hztTixG6FhVFXqp7Eq1ltk5mSreK6Mhy3xWWpLAzEUR6OMvMdNqT3jgSxA8JDhnhyAG3X4Xy7Q=="}
120
+ }
121
+ },
122
+ {
123
+ "type": "object",
124
+ "additionalProperties": false,
125
+ "required": ["name", "version", "resolved", "integrity"],
126
+ "properties": {
127
+ "name": {"const": "strong-type"},
128
+ "version": {"const": "2.0.0"},
129
+ "resolved": {"const": "https://registry.npmjs.org/strong-type/-/strong-type-2.0.0.tgz"},
130
+ "integrity": {"const": "sha512-HHrY9qYC7yn+5mlewiI3k9RQM9gZqGQsqbomZcd10Ks0h4RlX01nnkWbCe4AsVPCI6KaFvpkWm1nHMD+Ykup6g=="}
131
+ }
132
+ }
133
+ ],
134
+ "items": false
135
+ }
136
+ }
137
+ }
138
+ }
139
+ },
55
140
  "protocols": {
56
141
  "type": "object",
57
142
  "additionalProperties": false,
package/src/cli/main.mjs CHANGED
@@ -39,6 +39,7 @@ Usage:
39
39
  ${CLI_NAME} new <id> [--path <directory>] [--display-name <name>] [--target <target>] [--git]
40
40
  ${CLI_NAME} init [id] [--workspace <directory>] [--display-name <name>] [--target <target>]
41
41
  ${CLI_NAME} doctor [--workspace <directory>] [--arcane-root <directory>]
42
+ ${CLI_NAME} import-map [--workspace <directory>] [--app <id>]
42
43
  ${CLI_NAME} dev [--app <id>] [--host 127.0.0.1] [--port 8000]
43
44
  ${CLI_NAME} test [--app <id>] [--scope app]
44
45
  ${CLI_NAME} test --scope shared --test-file <repo-relative.test.mjs>
@@ -220,6 +221,10 @@ function operationOptions(command,parsed,cwd){
220
221
  requireLocalAI:flags.has('require-local-ai')
221
222
  };
222
223
  }
224
+ if(command==='import-map'){
225
+ noExtraPositionals(command,positionals);
226
+ return common;
227
+ }
223
228
  if(command==='dev'){
224
229
  noExtraPositionals(command,positionals);
225
230
  return {
@@ -9,10 +9,12 @@ import {
9
9
  RELEASE_MANIFEST_NAME
10
10
  } from './packager/core.mjs';
11
11
  import {
12
- authenticateRuntimeReceipt,
13
- readVerifiedRuntimeFile,
14
- verifyRuntime
15
- } from './runtime.mjs';
12
+ authenticateWorkspaceRuntimeReceipt,
13
+ readVerifiedWorkspaceRuntimeFile,
14
+ verifyWorkspaceRuntime
15
+ } from './workspace-runtime.mjs';
16
+ import {verifyRuntime} from './runtime.mjs';
17
+ import {verifySdkBrowserRuntime} from './sdk-browser-runtime.mjs';
16
18
  import {resolveWorkspace} from './workspace.mjs';
17
19
  import {createEventQueue} from './event-queue.mjs';
18
20
 
@@ -147,6 +149,31 @@ function identityMap(identities,prefix=''){
147
149
  return result;
148
150
  }
149
151
 
152
+ function routePrefixKey(prefix){
153
+ return prefix.map(segment=>segment.normalize('NFC').toLowerCase()).join('/');
154
+ }
155
+
156
+ function deterministicMappings(mappings){
157
+ const seen=new Map();
158
+ for(const mapping of mappings){
159
+ const key=routePrefixKey(mapping.prefix);
160
+ const prior=seen.get(key);
161
+ if(prior){
162
+ fail(
163
+ `Development server routes collide after case/NFC normalization: `
164
+ +`/${prior.prefix.join('/')} and /${mapping.prefix.join('/')}.`
165
+ );
166
+ }
167
+ seen.set(key,mapping);
168
+ }
169
+ return [...mappings].sort((left,right)=>{
170
+ if(left.prefix.length!==right.prefix.length)return right.prefix.length-left.prefix.length;
171
+ const leftKey=routePrefixKey(left.prefix);
172
+ const rightKey=routePrefixKey(right.prefix);
173
+ return leftKey<rightKey?-1:leftKey>rightKey?1:0;
174
+ });
175
+ }
176
+
150
177
  function createFileWorkLimiter(){
151
178
  let active=0;
152
179
  const pending=[];
@@ -318,7 +345,7 @@ function sharedPathAllowed(relative,route){
318
345
  });
319
346
  }
320
347
 
321
- async function sourceRoutes(workspaceRoot,appId,{runtimeReceipt,signal,onEvent}){
348
+ async function sourceRoutes(workspaceRoot,appId,{workspaceRuntimeReceipt,signal}){
322
349
  const resolved=await resolveWorkspace({workspaceRoot,appId});
323
350
  if(resolved.config.workspaceMode==='integrated'){
324
351
  return {
@@ -340,16 +367,43 @@ async function sourceRoutes(workspaceRoot,appId,{runtimeReceipt,signal,onEvent})
340
367
  ]
341
368
  };
342
369
  }
343
- const runtimeRoot=path.join(
344
- resolved.workspaceRoot,
345
- 'node_modules',
346
- 'arcane-os',
347
- 'runtime'
348
- );
349
- const verified=runtimeReceipt??await verifyRuntime({runtimeRoot,signal,onEvent});
350
- await authenticateRuntimeReceipt(verified,{runtimeRoot});
351
- const arcaneIdentities=identityMap(verified.identities,'arcane');
352
- const strongTypeIdentities=identityMap(verified.identities,'strong-type');
370
+ const runtimeRoot=path.join(resolved.workspaceRoot,'arcane');
371
+ let verified=workspaceRuntimeReceipt;
372
+ if(!verified){
373
+ const sdkRuntimeRoot=path.join(
374
+ resolved.workspaceRoot,
375
+ 'node_modules',
376
+ 'arcane-os',
377
+ 'runtime'
378
+ );
379
+ const sdkRuntimeReceipt=await verifyRuntime({
380
+ runtimeRoot:sdkRuntimeRoot,
381
+ signal
382
+ });
383
+ const sdkBrowserRuntimeRoot=path.join(
384
+ resolved.workspaceRoot,
385
+ 'node_modules',
386
+ 'arcane-os',
387
+ 'browser-runtime'
388
+ );
389
+ const sdkBrowserRuntimeReceipt=await verifySdkBrowserRuntime({
390
+ browserRuntimeRoot:sdkBrowserRuntimeRoot,
391
+ signal
392
+ });
393
+ verified=await verifyWorkspaceRuntime({
394
+ workspaceRoot:resolved.workspaceRoot,
395
+ runtimeRoot:sdkRuntimeRoot,
396
+ runtimeReceipt:sdkRuntimeReceipt,
397
+ browserRuntimeRoot:sdkBrowserRuntimeRoot,
398
+ sdkBrowserRuntimeReceipt,
399
+ signal
400
+ });
401
+ }
402
+ verified=await authenticateWorkspaceRuntimeReceipt(verified,{
403
+ workspaceRoot:resolved.workspaceRoot,
404
+ signal
405
+ });
406
+ const arcaneIdentities=identityMap(verified.identities);
353
407
  return {
354
408
  workspaceRoot:resolved.workspaceRoot,
355
409
  workspaceMode:'external',
@@ -363,25 +417,14 @@ async function sourceRoutes(workspaceRoot,appId,{runtimeReceipt,signal,onEvent})
363
417
  },
364
418
  {
365
419
  prefix:['arcane'],
366
- root:path.join(runtimeRoot,'arcane'),
420
+ root:runtimeRoot,
367
421
  identities:arcaneIdentities,
368
- read:relative=>readVerifiedRuntimeFile(verified,{
369
- runtimeRoot,
370
- relativePath:`arcane/${relative.join('/')}`,
422
+ read:relative=>readVerifiedWorkspaceRuntimeFile(verified,{
423
+ workspaceRoot:resolved.workspaceRoot,
424
+ relativePath:relative.join('/'),
371
425
  signal
372
426
  }),
373
427
  allow:relative=>arcaneIdentities.has(inventoryKey(relative.join('/')))
374
- },
375
- {
376
- prefix:['node_modules','strong-type'],
377
- root:path.join(runtimeRoot,'strong-type'),
378
- identities:strongTypeIdentities,
379
- read:relative=>readVerifiedRuntimeFile(verified,{
380
- runtimeRoot,
381
- relativePath:`strong-type/${relative.join('/')}`,
382
- signal
383
- }),
384
- allow:relative=>strongTypeIdentities.has(inventoryKey(relative.join('/')))
385
428
  }
386
429
  ]
387
430
  };
@@ -461,7 +504,7 @@ async function startOwnedDevServer({
461
504
  host='127.0.0.1',
462
505
  port=0,
463
506
  signal,
464
- runtimeReceipt,
507
+ workspaceRuntimeReceipt,
465
508
  releaseReceipt
466
509
  }={},events,releaseSignal){
467
510
  throwIfAborted(signal);
@@ -473,12 +516,13 @@ async function startOwnedDevServer({
473
516
  await events.send({type:'server.starting',mode,host,port,appId});
474
517
  const routeSet=mode==='source'
475
518
  ?await sourceRoutes(workspaceRoot,appId,{
476
- runtimeReceipt,
519
+ workspaceRuntimeReceipt,
477
520
  signal,
478
521
  onEvent:event=>events.send(event)
479
522
  })
480
523
  :await packagedRoutes(releaseRoot,releaseReceipt,{signal});
481
- for(const mapping of routeSet.mappings){
524
+ const mappings=deterministicMappings(routeSet.mappings);
525
+ for(const mapping of mappings){
482
526
  const info=await lstat(mapping.root);
483
527
  if(info.isSymbolicLink()||!info.isDirectory())fail(`Server route root must be a real directory: ${mapping.root}.`);
484
528
  mapping.root=await realpath(mapping.root);
@@ -533,7 +577,7 @@ async function startOwnedDevServer({
533
577
  response.end();
534
578
  return;
535
579
  }
536
- const mapping=routeSet.mappings.find(route=>
580
+ const mapping=mappings.find(route=>
537
581
  route.prefix.every((segment,index)=>segments[index]===segment)
538
582
  );
539
583
  if(!mapping){deny(response,404,'Not found.');return;}