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
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import {SDK_NAME,SDK_VERSION} from '../constants.mjs';
|
|
2
|
+
import {
|
|
3
|
+
SDK_BROWSER_RUNTIME_CONTENT_SHA256,
|
|
4
|
+
SDK_BROWSER_RUNTIME_MANIFEST_SHA256
|
|
5
|
+
} from '../sdk-browser-runtime.mjs';
|
|
2
6
|
|
|
3
7
|
function json(value){
|
|
4
8
|
return `${JSON.stringify(value,null,2)}\n`;
|
|
@@ -23,7 +27,9 @@ export function workspaceTemplate({
|
|
|
23
27
|
appId,
|
|
24
28
|
displayName,
|
|
25
29
|
runtimeRelease,
|
|
30
|
+
sdkBrowserRuntimeRelease,
|
|
26
31
|
appOnly=false,
|
|
32
|
+
namedImports=true,
|
|
27
33
|
minimumCoreVersion='0.8.12',
|
|
28
34
|
target='browser',
|
|
29
35
|
appIcon
|
|
@@ -42,6 +48,23 @@ export function workspaceTemplate({
|
|
|
42
48
|
const packageName=`arcane-${appId}`;
|
|
43
49
|
const runtimeContentSha256=runtimeRelease?.contentSha256;
|
|
44
50
|
const upstreamCommit=runtimeRelease?.source?.commit;
|
|
51
|
+
const browserManifestSha256=sdkBrowserRuntimeRelease?.manifestSha256;
|
|
52
|
+
const browserContentSha256=sdkBrowserRuntimeRelease?.contentSha256;
|
|
53
|
+
const browserSource=sdkBrowserRuntimeRelease?.source;
|
|
54
|
+
const expectedBrowserDependencies=[
|
|
55
|
+
{
|
|
56
|
+
name:'event-pubsub',
|
|
57
|
+
version:'6.1.0',
|
|
58
|
+
resolved:'https://registry.npmjs.org/event-pubsub/-/event-pubsub-6.1.0.tgz',
|
|
59
|
+
integrity:'sha512-FEMlhTxwqGM0hztTixG6FhVFXqp7Eq1ltk5mSreK6Mhy3xWWpLAzEUR6OMvMdNqT3jgSxA8JDhnhyAG3X4Xy7Q=='
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name:'strong-type',
|
|
63
|
+
version:'2.0.0',
|
|
64
|
+
resolved:'https://registry.npmjs.org/strong-type/-/strong-type-2.0.0.tgz',
|
|
65
|
+
integrity:'sha512-HHrY9qYC7yn+5mlewiI3k9RQM9gZqGQsqbomZcd10Ks0h4RlX01nnkWbCe4AsVPCI6KaFvpkWm1nHMD+Ykup6g=='
|
|
66
|
+
}
|
|
67
|
+
];
|
|
45
68
|
const packageInclude=[`${appId}.css`,'index.html'];
|
|
46
69
|
if(native)packageInclude.push('img/icon.png');
|
|
47
70
|
packageInclude.push('manifest.json','modules');
|
|
@@ -72,7 +95,36 @@ appropriate.
|
|
|
72
95
|
if(!appOnly&&(typeof upstreamCommit!=='string'||!/^[a-f0-9]{40}$/.test(upstreamCommit))){
|
|
73
96
|
throw new Error('The SDK runtime release does not contain a valid upstream commit.');
|
|
74
97
|
}
|
|
98
|
+
if(!appOnly&&(
|
|
99
|
+
browserManifestSha256!==SDK_BROWSER_RUNTIME_MANIFEST_SHA256
|
|
100
|
+
||browserContentSha256!==SDK_BROWSER_RUNTIME_CONTENT_SHA256
|
|
101
|
+
||sdkBrowserRuntimeRelease?.builder!=='arcane-sdk-browser-runtime-v1'
|
|
102
|
+
||sdkBrowserRuntimeRelease?.sdkVersion!==SDK_VERSION
|
|
103
|
+
||browserSource?.protocol!=='arcane-sdk-browser-runtime/1'
|
|
104
|
+
||browserSource?.authority!=='arcane-os-sdk'
|
|
105
|
+
||browserSource?.repository!=='https://github.com/TheWizardNexus/arcane-os-sdk.git'
|
|
106
|
+
||browserSource?.browserEntry!=='arcane-os/event-manager'
|
|
107
|
+
||!Array.isArray(browserSource?.dependencies)
|
|
108
|
+
||browserSource.dependencies.length!==expectedBrowserDependencies.length
|
|
109
|
+
||browserSource.dependencies.some((actual,index)=>{
|
|
110
|
+
const expected=expectedBrowserDependencies[index];
|
|
111
|
+
return !actual||Object.keys(actual).sort().join('\0')
|
|
112
|
+
!==['name','version','resolved','integrity'].sort().join('\0')
|
|
113
|
+
||actual.name!==expected.name||actual.version!==expected.version
|
|
114
|
+
||actual.resolved!==expected.resolved||actual.integrity!==expected.integrity;
|
|
115
|
+
})
|
|
116
|
+
)){
|
|
117
|
+
throw new Error('The SDK browser runtime release does not contain a valid trusted identity.');
|
|
118
|
+
}
|
|
75
119
|
|
|
120
|
+
const importMapMarkup=namedImports?` <script type="importmap" data-arcane-import-map>
|
|
121
|
+
{
|
|
122
|
+
"imports": {}
|
|
123
|
+
}
|
|
124
|
+
</script>
|
|
125
|
+
`:'';
|
|
126
|
+
const bootstrapMarkup=namedImports?'':
|
|
127
|
+
' <script type="module" src="./arcane/modules/ThemeBootstrap.js?v=1"></script>\n';
|
|
76
128
|
const files=new Map();
|
|
77
129
|
files.set('.gitignore',[
|
|
78
130
|
'node_modules/',
|
|
@@ -96,7 +148,7 @@ appropriate.
|
|
|
96
148
|
|
|
97
149
|
- Use plain JavaScript, HTML, and CSS; do not introduce TypeScript or TSX.
|
|
98
150
|
- Keep reusable mechanisms in Arcane OS and app-specific behavior under \`apps/${appId}/\`.
|
|
99
|
-
- Keep \`arcane/css/theme.css\` and \`ThemeBootstrap
|
|
151
|
+
- Keep \`arcane/css/theme.css\` before app styles and import \`arcane/ThemeBootstrap\` before app code runs.
|
|
100
152
|
- Use \`rgb(...)\` or \`rgba(...)\` for new CSS colors.
|
|
101
153
|
- Build one named app and one explicit target at a time. Native targets may be unavailable until their adapters are installed.
|
|
102
154
|
- Run \`npm run check\` before committing.
|
|
@@ -113,20 +165,32 @@ npm run doctor
|
|
|
113
165
|
npm run dev
|
|
114
166
|
\`\`\`
|
|
115
167
|
|
|
116
|
-
Open the loopback URL printed by the development server. The source server exposes this app and
|
|
168
|
+
Open the loopback URL printed by the development server. The source server exposes this app and its authenticated physical \`arcane/\` runtime; it does not expose an Ollama HTTP endpoint.
|
|
117
169
|
|
|
118
170
|
Commit the generated \`package-lock.json\` after dependency installation. CI intentionally uses \`npm ci\` and therefore requires that lock. Before the SDK is published, install a locally packed \`${SDK_NAME}\` \`.tgz\` with \`npm install --save-dev --save-exact <path-to-tarball>\`; keep that tarball at the lock file's relative path for repeatable local \`npm ci\` runs.
|
|
119
171
|
|
|
120
|
-
## Check and package
|
|
172
|
+
## Check and release the browser package
|
|
121
173
|
|
|
122
174
|
\`\`\`sh
|
|
123
175
|
npm run check
|
|
176
|
+
npm run import-map
|
|
124
177
|
npm run package
|
|
178
|
+
npm run verify
|
|
179
|
+
npm run bundle
|
|
125
180
|
npm run run
|
|
126
181
|
\`\`\`
|
|
127
182
|
|
|
128
|
-
The
|
|
129
|
-
|
|
183
|
+
The explicit \`import-map\` command refreshes
|
|
184
|
+
\`apps/${appId}/modules/arcane.importmap.json\` and the managed inline browser
|
|
185
|
+
import map in \`index.html\`. Development, package, and build refresh it
|
|
186
|
+
automatically. Named \`arcane/*\` imports resolve against the physical workspace
|
|
187
|
+
\`arcane/\` tree. Packaging copies the same authenticated bytes and specifier map
|
|
188
|
+
to \`dist/${appId}\`, \`verify\` authenticates that directory, \`bundle\` creates
|
|
189
|
+
its distributable archive, and \`run\` launches the verified packaged browser
|
|
190
|
+
release.
|
|
191
|
+
|
|
192
|
+
Native targets are provider-supplied and must be scaffolded and selected
|
|
193
|
+
explicitly; this browser workflow does not imply a standalone native executable.
|
|
130
194
|
${nativeGuide}
|
|
131
195
|
|
|
132
196
|
Every browser release also carries Arcane OS licensing material under \`licenses/arcane-os/\`. Review those terms before distribution.
|
|
@@ -140,11 +204,16 @@ Every browser release also carries Arcane OS licensing material under \`licenses
|
|
|
140
204
|
dev:'arcane dev',
|
|
141
205
|
test:'arcane test',
|
|
142
206
|
check:'arcane check',
|
|
207
|
+
'import-map':'arcane import-map',
|
|
143
208
|
package:'arcane package',
|
|
209
|
+
verify:'arcane verify',
|
|
210
|
+
bundle:'arcane bundle',
|
|
144
211
|
build:`arcane build --target ${buildTarget}`,
|
|
145
212
|
run:`arcane run --target ${runTarget}`,
|
|
146
|
-
|
|
147
|
-
|
|
213
|
+
...(native?{
|
|
214
|
+
'build:browser':'arcane build --target browser',
|
|
215
|
+
'run:browser':'arcane run --target browser'
|
|
216
|
+
}:{})
|
|
148
217
|
},
|
|
149
218
|
devDependencies:{
|
|
150
219
|
[SDK_NAME]:SDK_VERSION
|
|
@@ -158,15 +227,9 @@ Every browser release also carries Arcane OS licensing material under \`licenses
|
|
|
158
227
|
sharedPayloads:{
|
|
159
228
|
'browser-runtime':[
|
|
160
229
|
{
|
|
161
|
-
source:'
|
|
230
|
+
source:'arcane',
|
|
162
231
|
destination:'arcane',
|
|
163
|
-
include:['components','css','entities','img','modules','security'],
|
|
164
|
-
exclude:[]
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
source:'node_modules/arcane-os/runtime/strong-type',
|
|
168
|
-
destination:'node_modules/strong-type',
|
|
169
|
-
include:['index.js','licence','package.json'],
|
|
232
|
+
include:['components','css','dependencies','entities','img','modules','sdk','security'],
|
|
170
233
|
exclude:[]
|
|
171
234
|
},
|
|
172
235
|
{
|
|
@@ -186,6 +249,14 @@ Every browser release also carries Arcane OS licensing material under \`licenses
|
|
|
186
249
|
contentSha256:runtimeContentSha256,
|
|
187
250
|
upstreamCommit
|
|
188
251
|
},
|
|
252
|
+
sdkBrowserRuntime:{
|
|
253
|
+
manifest:'node_modules/arcane-os/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json',
|
|
254
|
+
manifestSha256:browserManifestSha256,
|
|
255
|
+
contentSha256:browserContentSha256,
|
|
256
|
+
builder:sdkBrowserRuntimeRelease?.builder,
|
|
257
|
+
sdkVersion:sdkBrowserRuntimeRelease?.sdkVersion,
|
|
258
|
+
source:sdkBrowserRuntimeRelease?.source
|
|
259
|
+
},
|
|
189
260
|
protocols:{
|
|
190
261
|
arcane:'arcane/1',
|
|
191
262
|
cliEvents:'arcane-cli-events/1',
|
|
@@ -288,15 +359,14 @@ jobs:
|
|
|
288
359
|
<meta charset="utf-8">
|
|
289
360
|
<meta name="arcane-app-id" content="${html(appId)}">
|
|
290
361
|
<base href="../../">
|
|
291
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
362
|
+
${importMapMarkup} <meta name="viewport" content="width=device-width, initial-scale=1">
|
|
292
363
|
<meta name="theme-color" content="rgb(23, 34, 56)">
|
|
293
364
|
<title>${html(name)}</title>
|
|
294
365
|
<link rel="manifest" href="./apps/${html(appId)}/manifest.json">
|
|
295
366
|
<link rel="stylesheet" href="./arcane/css/theme.css?v=1">
|
|
296
367
|
<link rel="stylesheet" href="./arcane/css/primitives.css?v=1">
|
|
297
368
|
<link rel="stylesheet" href="./apps/${html(appId)}/${html(appId)}.css?v=1">
|
|
298
|
-
|
|
299
|
-
</head>
|
|
369
|
+
${bootstrapMarkup}</head>
|
|
300
370
|
<body>
|
|
301
371
|
<main class="app-shell">
|
|
302
372
|
<section class="arcane-card" aria-labelledby="app-title">
|
|
@@ -337,12 +407,49 @@ jobs:
|
|
|
337
407
|
text-transform: uppercase;
|
|
338
408
|
}
|
|
339
409
|
`);
|
|
340
|
-
|
|
410
|
+
if(namedImports){
|
|
411
|
+
files.set(`apps/${appId}/modules/arcane.importmap.json`,json({imports:{}}));
|
|
412
|
+
}
|
|
413
|
+
const themeSpecifier=namedImports
|
|
414
|
+
?'arcane/ThemeBootstrap':'../../../arcane/modules/ThemeBootstrap.js';
|
|
415
|
+
const appDataSpecifier=namedImports
|
|
416
|
+
?'arcane/AppDataScope':'../../../arcane/modules/AppDataScope.js';
|
|
417
|
+
files.set(`apps/${appId}/modules/App.js`,`import arcaneThemeReady from '${themeSpecifier}';
|
|
418
|
+
import {
|
|
419
|
+
resolveApplicationId,
|
|
420
|
+
resolveApplicationLocalStorageKey
|
|
421
|
+
} from '${appDataSpecifier}';
|
|
422
|
+
|
|
423
|
+
const appName=${JSON.stringify(name)};
|
|
341
424
|
const action=document.querySelector('#app-action');
|
|
342
425
|
const status=document.querySelector('#app-status');
|
|
343
426
|
|
|
427
|
+
await arcaneThemeReady;
|
|
428
|
+
|
|
429
|
+
const appId=await resolveApplicationId();
|
|
430
|
+
const countKey=resolveApplicationLocalStorageKey('hello-count',{applicationId:appId});
|
|
431
|
+
|
|
432
|
+
function loadHelloCount(){
|
|
433
|
+
try{
|
|
434
|
+
const value=Number(globalThis.localStorage?.getItem(countKey)??0);
|
|
435
|
+
return Number.isSafeInteger(value)&&value>=0?value:0;
|
|
436
|
+
}catch{
|
|
437
|
+
return 0;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function saveHelloCount(value){
|
|
442
|
+
try{
|
|
443
|
+
globalThis.localStorage?.setItem(countKey,String(value));
|
|
444
|
+
}catch{
|
|
445
|
+
// The greeting still works when browser persistence is unavailable.
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
344
449
|
action?.addEventListener('click',()=>{
|
|
345
|
-
|
|
450
|
+
const count=loadHelloCount()+1;
|
|
451
|
+
saveHelloCount(count);
|
|
452
|
+
status.textContent=\`Hello from \${appName}! Greeting \${count}.\`;
|
|
346
453
|
});
|
|
347
454
|
`);
|
|
348
455
|
if(native){
|
|
@@ -355,17 +462,22 @@ import test from '${SDK_NAME}/testing';
|
|
|
355
462
|
const appRoot=new URL('../',import.meta.url);
|
|
356
463
|
|
|
357
464
|
test('application shell uses the shared Arcane theme in order',async()=>{
|
|
358
|
-
const source=await
|
|
465
|
+
const [source,appSource]=await Promise.all([
|
|
466
|
+
readFile(new URL('index.html',appRoot),'utf8'),
|
|
467
|
+
readFile(new URL('modules/App.js',appRoot),'utf8')
|
|
468
|
+
]);
|
|
359
469
|
const theme=source.indexOf('./arcane/css/theme.css');
|
|
360
470
|
const primitives=source.indexOf('./arcane/css/primitives.css');
|
|
361
471
|
const appStyle=source.indexOf('./apps/${appId}/${appId}.css');
|
|
362
|
-
const
|
|
472
|
+
const importMap=source.indexOf('${namedImports?'data-arcane-import-map':'./arcane/modules/ThemeBootstrap.js'}');
|
|
363
473
|
const appModule=source.indexOf('./apps/${appId}/modules/App.js');
|
|
364
474
|
|
|
365
475
|
assert.match(source,/<base href="\\.\\.\\/\\.\\.\\/">/);
|
|
366
476
|
assert.match(source,/<meta name="arcane-app-id" content="${appId}">/);
|
|
367
477
|
assert.ok(theme>=0&&primitives>theme&&appStyle>primitives);
|
|
368
|
-
assert.ok(
|
|
478
|
+
assert.ok(importMap>=0&&appModule>importMap);
|
|
479
|
+
assert.ok(appSource.includes("from '${themeSpecifier}'"));
|
|
480
|
+
assert.ok(appSource.includes("from '${appDataSpecifier}'"));
|
|
369
481
|
});
|
|
370
482
|
|
|
371
483
|
test('application package identity matches its directory',async()=>{
|