sh3-core 0.2.0 → 0.3.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/dist/artifact.d.ts +32 -0
- package/dist/artifact.js +1 -0
- package/dist/build.d.ts +20 -0
- package/dist/build.js +78 -1
- package/dist/createShell.d.ts +7 -14
- package/dist/createShell.js +15 -46
- package/dist/index.d.ts +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static manifest file included in every SH3 artifact directory.
|
|
3
|
+
* Generated at build time from the shard/app manifest in code.
|
|
4
|
+
* This is the single source of truth for package metadata —
|
|
5
|
+
* registries, servers, and install tools read this instead of
|
|
6
|
+
* requiring manual metadata entry.
|
|
7
|
+
*/
|
|
8
|
+
export interface ArtifactManifest {
|
|
9
|
+
/** Unique package identifier. Matches the shard/app manifest id. */
|
|
10
|
+
id: string;
|
|
11
|
+
/** Whether this is a shard or app (or both via combo bundle). */
|
|
12
|
+
type: 'shard' | 'app' | 'combo';
|
|
13
|
+
/** Human-readable display name. */
|
|
14
|
+
label: string;
|
|
15
|
+
/** Version string (semver). */
|
|
16
|
+
version: string;
|
|
17
|
+
/** SH3 contract version this artifact was built against. */
|
|
18
|
+
contractVersion: number;
|
|
19
|
+
/** Relative path to the client bundle within the artifact directory. Omit if server-only. */
|
|
20
|
+
client?: string;
|
|
21
|
+
/** Relative path to the server bundle within the artifact directory. Omit if client-only. */
|
|
22
|
+
server?: string;
|
|
23
|
+
/** Short description (one or two sentences). */
|
|
24
|
+
description?: string;
|
|
25
|
+
/** Author name. */
|
|
26
|
+
author?: string;
|
|
27
|
+
/** Package dependencies. */
|
|
28
|
+
requires?: Array<{
|
|
29
|
+
id: string;
|
|
30
|
+
versionRange: string;
|
|
31
|
+
}>;
|
|
32
|
+
}
|
package/dist/artifact.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/build.d.ts
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* });
|
|
18
18
|
*/
|
|
19
19
|
import type { Plugin } from 'vite';
|
|
20
|
+
import type { ArtifactManifest } from './artifact';
|
|
20
21
|
/**
|
|
21
22
|
* Vite plugin that inlines extracted CSS into the JS bundle.
|
|
22
23
|
*
|
|
@@ -27,3 +28,22 @@ import type { Plugin } from 'vite';
|
|
|
27
28
|
* as a self-executing `<style>` injector, and delete the CSS files.
|
|
28
29
|
*/
|
|
29
30
|
export declare function sh3CssInline(): Plugin;
|
|
31
|
+
/**
|
|
32
|
+
* Options for the sh3Artifact plugin.
|
|
33
|
+
*/
|
|
34
|
+
export interface Sh3ArtifactOptions {
|
|
35
|
+
/** Path to pre-built server bundle. If provided, gets copied as server.js. */
|
|
36
|
+
serverEntry?: string;
|
|
37
|
+
/** Override manifest fields not extractable from code (description, author, requires). */
|
|
38
|
+
manifest?: Partial<Pick<ArtifactManifest, 'description' | 'author' | 'requires'>>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Vite plugin that produces a distributable artifact directory after build.
|
|
42
|
+
*
|
|
43
|
+
* After Vite's lib build completes, this plugin:
|
|
44
|
+
* 1. Finds the entry chunk and renames it to client.js
|
|
45
|
+
* 2. Optionally copies a pre-built server bundle as server.js
|
|
46
|
+
* 3. Extracts manifest fields (id, label, version, type) from the source
|
|
47
|
+
* 4. Writes manifest.json alongside the bundles
|
|
48
|
+
*/
|
|
49
|
+
export declare function sh3Artifact(options?: Sh3ArtifactOptions): Plugin;
|
package/dist/build.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* },
|
|
17
17
|
* });
|
|
18
18
|
*/
|
|
19
|
-
import { readFileSync, writeFileSync, unlinkSync, readdirSync } from 'node:fs';
|
|
19
|
+
import { readFileSync, writeFileSync, unlinkSync, readdirSync, copyFileSync, existsSync } from 'node:fs';
|
|
20
20
|
import { join } from 'node:path';
|
|
21
21
|
/**
|
|
22
22
|
* Vite plugin that inlines extracted CSS into the JS bundle.
|
|
@@ -83,3 +83,80 @@ export function sh3CssInline() {
|
|
|
83
83
|
},
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Vite plugin that produces a distributable artifact directory after build.
|
|
88
|
+
*
|
|
89
|
+
* After Vite's lib build completes, this plugin:
|
|
90
|
+
* 1. Finds the entry chunk and renames it to client.js
|
|
91
|
+
* 2. Optionally copies a pre-built server bundle as server.js
|
|
92
|
+
* 3. Extracts manifest fields (id, label, version, type) from the source
|
|
93
|
+
* 4. Writes manifest.json alongside the bundles
|
|
94
|
+
*/
|
|
95
|
+
export function sh3Artifact(options = {}) {
|
|
96
|
+
let outDir = '';
|
|
97
|
+
let entryFileName = '';
|
|
98
|
+
return {
|
|
99
|
+
name: 'sh3-artifact',
|
|
100
|
+
apply: 'build',
|
|
101
|
+
enforce: 'post',
|
|
102
|
+
configResolved(config) {
|
|
103
|
+
outDir = config.build.outDir;
|
|
104
|
+
},
|
|
105
|
+
generateBundle(_outputOptions, bundle) {
|
|
106
|
+
// Find the entry chunk — the one Rollup marks as isEntry.
|
|
107
|
+
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
108
|
+
if (chunk.type === 'chunk' && chunk.isEntry) {
|
|
109
|
+
entryFileName = fileName;
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
async closeBundle() {
|
|
115
|
+
var _a;
|
|
116
|
+
if (!entryFileName)
|
|
117
|
+
return;
|
|
118
|
+
const clientSrc = join(outDir, entryFileName);
|
|
119
|
+
const clientDest = join(outDir, 'client.js');
|
|
120
|
+
// Read source before potentially overwriting.
|
|
121
|
+
let source = '';
|
|
122
|
+
try {
|
|
123
|
+
source = readFileSync(clientSrc, 'utf-8');
|
|
124
|
+
}
|
|
125
|
+
catch (_b) {
|
|
126
|
+
console.warn('[sh3-artifact] Could not read entry chunk:', clientSrc);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
// Rename entry chunk to client.js (only if names differ).
|
|
130
|
+
if (clientSrc !== clientDest) {
|
|
131
|
+
writeFileSync(clientDest, source);
|
|
132
|
+
unlinkSync(clientSrc);
|
|
133
|
+
}
|
|
134
|
+
// --- Extract manifest fields via regex ---
|
|
135
|
+
const extract = (pattern) => {
|
|
136
|
+
const m = source.match(pattern);
|
|
137
|
+
return m ? m[1] : '';
|
|
138
|
+
};
|
|
139
|
+
const id = extract(/\bid\s*:\s*["']([^"']+)["']/);
|
|
140
|
+
const label = extract(/\blabel\s*:\s*["']([^"']+)["']/);
|
|
141
|
+
const version = extract(/\bversion\s*:\s*["']([^"']+)["']/);
|
|
142
|
+
const hasShard = /\bviews\s*:\s*\[/.test(source);
|
|
143
|
+
const hasApp = /\brequiredShards\s*:\s*\[/.test(source);
|
|
144
|
+
const type = hasShard && hasApp ? 'combo' : hasApp ? 'app' : 'shard';
|
|
145
|
+
// --- Optional server bundle ---
|
|
146
|
+
let hasServer = false;
|
|
147
|
+
if (options.serverEntry && existsSync(options.serverEntry)) {
|
|
148
|
+
copyFileSync(options.serverEntry, join(outDir, 'server.js'));
|
|
149
|
+
hasServer = true;
|
|
150
|
+
}
|
|
151
|
+
// --- Write manifest.json ---
|
|
152
|
+
const manifest = Object.assign(Object.assign({ id: id || 'unknown', type, label: label || id || 'unknown', version: version || '0.0.0', contractVersion: 1, client: 'client.js' }, (hasServer ? { server: 'server.js' } : {})), ((_a = options.manifest) !== null && _a !== void 0 ? _a : {}));
|
|
153
|
+
writeFileSync(join(outDir, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\n');
|
|
154
|
+
// --- Log summary ---
|
|
155
|
+
const files = ['manifest.json', 'client.js'];
|
|
156
|
+
if (hasServer)
|
|
157
|
+
files.push('server.js');
|
|
158
|
+
console.log(`[sh3-artifact] ${manifest.id}@${manifest.version} (${manifest.type}) → ${outDir}`);
|
|
159
|
+
console.log(`[sh3-artifact] files: ${files.join(', ')}`);
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
package/dist/createShell.d.ts
CHANGED
|
@@ -9,21 +9,14 @@ export interface ShellConfig {
|
|
|
9
9
|
/** Additional apps to register */
|
|
10
10
|
apps?: App[];
|
|
11
11
|
/**
|
|
12
|
-
* Packages
|
|
13
|
-
*
|
|
14
|
-
* (e.g. a registry host pre-includes sh3-registry).
|
|
12
|
+
* Packages discovered by the server at boot.
|
|
13
|
+
* The frontend fetches this list from /api/packages and passes it here.
|
|
15
14
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
/** Package metadata for the install record. */
|
|
22
|
-
meta: {
|
|
23
|
-
id: string;
|
|
24
|
-
type: 'shard' | 'app';
|
|
25
|
-
version: string;
|
|
26
|
-
};
|
|
15
|
+
discoveredPackages?: Array<{
|
|
16
|
+
id: string;
|
|
17
|
+
type: string;
|
|
18
|
+
version: string;
|
|
19
|
+
bundleUrl: string;
|
|
27
20
|
}>;
|
|
28
21
|
/** Mount target — CSS selector or element (defaults to '#app') */
|
|
29
22
|
target?: string | HTMLElement;
|
package/dist/createShell.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { mount } from 'svelte';
|
|
10
10
|
import { Shell } from './index';
|
|
11
|
-
import { registerShard, registerApp, bootstrap, __setBackend, setLocalOwner,
|
|
11
|
+
import { registerShard, registerApp, bootstrap, __setBackend, setLocalOwner, } from './host';
|
|
12
12
|
import { resolvePlatform } from './platform/index';
|
|
13
13
|
export async function createShell(config) {
|
|
14
14
|
var _a, _b;
|
|
@@ -23,57 +23,26 @@ export async function createShell(config) {
|
|
|
23
23
|
if (platform.localOwner) {
|
|
24
24
|
setLocalOwner();
|
|
25
25
|
}
|
|
26
|
-
// 1b.
|
|
27
|
-
if ((_a = config === null || config === void 0 ? void 0 : config.
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
for (const pkg of config.preinstall) {
|
|
31
|
-
if (installedIds.has(pkg.meta.id))
|
|
32
|
-
continue;
|
|
26
|
+
// 1b. Load server-discovered packages (fetched by frontend from /api/packages).
|
|
27
|
+
if ((_a = config === null || config === void 0 ? void 0 : config.discoveredPackages) === null || _a === void 0 ? void 0 : _a.length) {
|
|
28
|
+
const { loadBundleModule } = await import('./registry/loader');
|
|
29
|
+
for (const pkg of config.discoveredPackages) {
|
|
33
30
|
try {
|
|
34
|
-
const res = await fetch(pkg.
|
|
31
|
+
const res = await fetch(pkg.bundleUrl);
|
|
35
32
|
if (!res.ok) {
|
|
36
|
-
console.warn(`[sh3]
|
|
33
|
+
console.warn(`[sh3] Failed to fetch discovered package "${pkg.id}": HTTP ${res.status}`);
|
|
37
34
|
continue;
|
|
38
35
|
}
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
integrity: '',
|
|
47
|
-
hasServerBundle: !!pkg.serverPath,
|
|
48
|
-
});
|
|
49
|
-
if (!result.success) {
|
|
50
|
-
console.warn(`[sh3] Pre-install failed for "${pkg.meta.id}":`, result.error);
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
// Push server bundle if present
|
|
54
|
-
if (pkg.serverPath) {
|
|
55
|
-
try {
|
|
56
|
-
const serverRes = await fetch(pkg.serverPath);
|
|
57
|
-
if (serverRes.ok) {
|
|
58
|
-
const serverBytes = await serverRes.arrayBuffer();
|
|
59
|
-
const form = new FormData();
|
|
60
|
-
form.append('shardId', pkg.meta.id);
|
|
61
|
-
form.append('bundle', new Blob([serverBytes], { type: 'application/javascript' }), 'bundle.js');
|
|
62
|
-
form.append('manifest', JSON.stringify(pkg.meta));
|
|
63
|
-
await fetch('/api/server-shards/install', {
|
|
64
|
-
method: 'POST',
|
|
65
|
-
body: form,
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
catch (_c) {
|
|
70
|
-
console.warn(`[sh3] Server bundle push failed for pre-install "${pkg.meta.id}"`);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
console.log(`[sh3] Pre-installed: ${pkg.meta.id}`);
|
|
36
|
+
const bytes = await res.arrayBuffer();
|
|
37
|
+
const loaded = await loadBundleModule(bytes);
|
|
38
|
+
for (const s of loaded.shards)
|
|
39
|
+
registerShard(s);
|
|
40
|
+
for (const a of loaded.apps)
|
|
41
|
+
registerApp(a);
|
|
42
|
+
console.log(`[sh3] Loaded discovered package: ${pkg.id}`);
|
|
74
43
|
}
|
|
75
44
|
catch (err) {
|
|
76
|
-
console.warn(`[sh3]
|
|
45
|
+
console.warn(`[sh3] Failed to load discovered package "${pkg.id}":`, err);
|
|
77
46
|
}
|
|
78
47
|
}
|
|
79
48
|
}
|
package/dist/index.d.ts
CHANGED