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.
- package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +86 -0
- package/browser-runtime/dependencies/event-pubsub/index.js +141 -0
- package/browser-runtime/dependencies/event-pubsub/licence +21 -0
- package/browser-runtime/dependencies/event-pubsub/package.json +59 -0
- package/browser-runtime/dependencies/strong-type/index.js +1151 -0
- package/browser-runtime/dependencies/strong-type/licence +21 -0
- package/browser-runtime/dependencies/strong-type/package.json +61 -0
- package/browser-runtime/dom-event-instrumentation.mjs +594 -0
- package/browser-runtime/event-manager.mjs +1342 -0
- package/docs/publishing.md +52 -59
- package/docs/reference/event-manager.md +5 -5
- package/docs/work-amplification.md +4 -3
- package/package.json +11 -7
- package/runtime/ARCANE_RUNTIME_RELEASE.json +1 -1
- package/schemas/arcane-lock.schema.json +86 -1
- package/src/cli/main.mjs +5 -0
- package/src/dev-server.mjs +78 -34
- package/src/doctor.mjs +77 -3
- package/src/import-map.mjs +2328 -0
- package/src/packager/core.mjs +607 -29
- package/src/scaffold.mjs +122 -5
- package/src/sdk-browser-runtime.mjs +585 -0
- package/src/targets/index.mjs +31 -4
- package/src/templates/workspace-template.mjs +135 -23
- package/src/toolchain.mjs +288 -55
- package/src/workspace-operation-lock.mjs +716 -0
- package/src/workspace-runtime.mjs +841 -0
- package/src/workspace.mjs +286 -37
package/docs/publishing.md
CHANGED
|
@@ -1,42 +1,34 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
##
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
`
|
|
20
|
-
|
|
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
|
|
38
|
-
|
|
39
|
-
|
|
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,
|
|
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,
|
|
57
|
-
dist-tag other than `dev
|
|
58
|
-
idempotent success.
|
|
59
|
-
|
|
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
|
-
|
|
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.
|
|
97
|
-
`
|
|
98
|
-
the
|
|
99
|
-
|
|
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
|
|
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`.
|
|
177
|
-
|
|
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.
|
|
192
|
-
|
|
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
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
and
|
|
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
|
|
239
|
-
fromSequence
|
|
240
|
-
toSequence
|
|
241
|
-
speed
|
|
242
|
-
mode
|
|
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:
|
|
54
|
-
155-file / 3,320,994-byte
|
|
55
|
-
/
|
|
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
|
|
4
|
-
"description": "Arcane OS
|
|
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:
|
|
49
|
-
"test:
|
|
50
|
-
"test:
|
|
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": "
|
|
88
|
+
"tag": "latest"
|
|
85
89
|
},
|
|
86
90
|
"dependencies": {
|
|
87
91
|
"event-pubsub": "6.1.0",
|
|
@@ -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
|
|
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 {
|
package/src/dev-server.mjs
CHANGED
|
@@ -9,10 +9,12 @@ import {
|
|
|
9
9
|
RELEASE_MANIFEST_NAME
|
|
10
10
|
} from './packager/core.mjs';
|
|
11
11
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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,{
|
|
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
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
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:
|
|
420
|
+
root:runtimeRoot,
|
|
367
421
|
identities:arcaneIdentities,
|
|
368
|
-
read:relative=>
|
|
369
|
-
|
|
370
|
-
relativePath
|
|
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
|
-
|
|
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
|
-
|
|
519
|
+
workspaceRuntimeReceipt,
|
|
477
520
|
signal,
|
|
478
521
|
onEvent:event=>events.send(event)
|
|
479
522
|
})
|
|
480
523
|
:await packagedRoutes(releaseRoot,releaseReceipt,{signal});
|
|
481
|
-
|
|
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=
|
|
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;}
|