@deepseek-ai/dsh-client-modules 0.1.5-rc.2 → 0.1.6-alpha.2

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.
@@ -28,6 +28,8 @@
28
28
  * {@link ClientModuleSystem}. The package root is the host-side service that
29
29
  * composes the wire.
30
30
  */
31
+ import type { DshClientManifest } from '@deepseek-ai/dsh-package-manifest';
32
+ import type { ClientEntries } from './entries.ts';
31
33
  import type { ClientModuleSystem } from './system.ts';
32
34
  declare module '@deepseek-ai/cordis' {
33
35
  interface Context {
@@ -57,22 +59,22 @@ export interface WebBootEntry {
57
59
  /** Non-baseline module specifiers this row requests; omitted when it requests none. */
58
60
  external?: string[];
59
61
  }
60
- /** Initial scheduling phase for one content-addressed combo script. */
62
+ /** Initial scheduling phase for one revisioned combo script. */
61
63
  export type WebBootBatchPhase = 'bootstrap' | 'application';
62
64
  /** One initial combo script; a scheduling phase may span several descriptors. */
63
65
  export interface WebBootBatch {
64
66
  /** Parser-blocking bootstrap or preloaded application scheduling. */
65
67
  phase: WebBootBatchPhase;
66
- /** Content-addressed combo script endpoint. */
68
+ /** Revisioned combo script endpoint. */
67
69
  url: string;
68
- /** Revision over the combined plugin script bytes and indexed source map. */
70
+ /** Revision derived from the ordered entry revisions. */
69
71
  rev: string;
70
72
  /** Graph entry ids whose factories the script registers, in execution order. */
71
73
  entries: string[];
72
74
  }
73
75
  /** The composed client entry graph the host injects as `window.__DSH_BOOT__`. */
74
76
  export interface WebBootGraph {
75
- /** Consistency anchor over the whole graph (content + bundle hashes). */
77
+ /** Consistency anchor over the current entry and batch descriptors. */
76
78
  rev: string;
77
79
  /**
78
80
  * Composed entries in module-graph order — a dynamic package row precedes
@@ -89,7 +91,7 @@ export interface BootModuleRow {
89
91
  id: string;
90
92
  /** Revisioned single-resource combo endpoint used after HMR invalidation. */
91
93
  url: string;
92
- /** Content-addressed combo endpoint used before the first HMR invalidation. */
94
+ /** Revisioned combo endpoint used before the first HMR invalidation. */
93
95
  initialUrl: string;
94
96
  /** Opaque plugin-artifact revision used after HMR invalidation. */
95
97
  rev: string;
@@ -126,6 +128,23 @@ export interface BootManifest {
126
128
  * @throws {Error} when the value is present but is not an array of strings.
127
129
  */
128
130
  export declare function optionalStringArray(subject: string, field: string, value: unknown): string[] | undefined;
131
+ /**
132
+ * Narrow an unknown parsed JSON value to the `dsh.client` declaration. Shared
133
+ * by the node half's Loader scan and the roster generator, so both read a
134
+ * package's browser declaration through one validator.
135
+ * @param pkgName - package name used as the diagnostic prefix.
136
+ * @param value - the raw `dsh.client` field of the package manifest.
137
+ * @returns the validated declaration, or undefined when the field is absent.
138
+ * @throws {Error} when the field is present but any member is malformed.
139
+ */
140
+ export declare function parseDshClient(pkgName: string, value: unknown): DshClientManifest | undefined;
141
+ /**
142
+ * The bare package-root specifier `specifier` names, or undefined for a subpath, a path, or any scheme-qualified
143
+ * specifier (`cordis:` builtins, `node:` modules, URLs).
144
+ * @param specifier - Loader row name.
145
+ * @returns the package name, or undefined.
146
+ */
147
+ export declare function exactPackageSpecifier(specifier: string): string | undefined;
129
148
  /**
130
149
  * Normalize a module specifier onto the graph row that owns it: a plugin bundle
131
150
  * IS its package's client half, so `<id>/client` (the exports subpath external
@@ -144,16 +163,25 @@ export declare function stripClientSuffix(spec: string): string;
144
163
  * @returns the manifest with optional plugin-view fields normalized.
145
164
  */
146
165
  export declare function parseBootManifest(wire: unknown): BootManifest;
166
+ /** Module resolver passed into a registered Client bundle factory. */
167
+ export interface ClientBundleRequire {
168
+ /** Resolve a module-table dependency synchronously. */
169
+ (specifier: string): unknown;
170
+ /** Load and resolve a package-local dynamic chunk asynchronously. */
171
+ async(specifier: string): Promise<unknown>;
172
+ }
147
173
  /** One client bundle's factory registration submitted through `window.__ModuleLoader__.load`. */
148
174
  export interface ClientBundleRegistration {
149
175
  /** Plugin id (package name) — the registration key; must match the graph row being executed. */
150
176
  id: string;
177
+ /** Package-local chunk filename; absent for the package's `client.js` entry. */
178
+ chunk?: string;
151
179
  /**
152
- * Closure factory holding the whole bundle body: receives the synchronous
153
- * require bound to the module table and returns the bundle's exports. Runs
154
- * once, at materialization.
180
+ * Closure factory holding the whole bundle body: receives the module-table
181
+ * require whose `async` operation loads generated chunks, and returns the
182
+ * bundle's exports. The factory runs once, at materialization.
155
183
  */
156
- factory: (require: (spec: string) => unknown) => Record<string, unknown>;
184
+ factory: (require: ClientBundleRequire) => Record<string, unknown>;
157
185
  }
158
186
  /** Inputs passed by the web entry when it creates the client module system. */
159
187
  export interface ClientModuleCreateOptions {
@@ -208,9 +236,11 @@ export interface ClientModuleRecord {
208
236
  export interface ClientModuleLoader {
209
237
  /** Discriminant against Node's internal loader shapes ('v1'/'v2'). */
210
238
  version: 'client';
211
- /** Parsed Host boot graph shared with the web entry after module-system creation. */
239
+ /** Latest parsed Host graph, updated by live entry reconciliation. */
212
240
  manifest: BootManifest;
213
- /** Materialized-module registry: id record. The governance-side read API for entry exports. */
241
+ /** Page-owned entry reconciliation, shared by boot, graph updates and HMR. */
242
+ entries: ClientEntries;
243
+ /** Materialized-module registry: entry or package-local chunk id → record. */
214
244
  loadCache: Map<string, ClientModuleRecord>;
215
245
  /**
216
246
  * Internal contract consumed by the vendored Loader's `tree.import`. Resolves
@@ -234,8 +264,8 @@ export interface ClientModuleLoader {
234
264
  */
235
265
  prefetch(id: string): Promise<void>;
236
266
  /**
237
- * Full reset of one non-bootstrap module: drop its registered factory and
238
- * materialized record so the next prefetch/import loads its one-resource
267
+ * Full reset of one non-bootstrap package: drop its entry and chunk factories
268
+ * and materialized records so the next prefetch/import loads its one-resource
239
269
  * combo script rather than the initial multi-resource request. The bootstrap
240
270
  * module remains materialized.
241
271
  * @param id - entry name to invalidate.
@@ -246,7 +276,7 @@ export interface ClientModuleLoader {
246
276
  }
247
277
  /** Internal construction inputs assembled by the modules bundle's bootstrap export. */
248
278
  export interface ClientModuleSystemOptions {
249
- /** Parsed boot graph owned by the resulting module system. */
279
+ /** Boot graph validated by {@link parseBootManifest}, owned by the resulting module system. */
250
280
  manifest: BootManifest;
251
281
  /** Module-table seed: platform-singleton specifier → shell instance. */
252
282
  staticModules: Record<string, unknown>;
@@ -1,3 +1,4 @@
1
+ import { ClientEntries } from './entries.ts';
1
2
  import type { BootManifest, ClientModuleLoader, ClientModuleRecord, ClientModuleSystemOptions } from './manifest.ts';
2
3
  /**
3
4
  * The client module system: state tables plus the arrival/materialization
@@ -8,15 +9,18 @@ import type { BootManifest, ClientModuleLoader, ClientModuleRecord, ClientModule
8
9
  */
9
10
  export declare class ClientModuleSystem implements ClientModuleLoader {
10
11
  readonly version = "client";
11
- readonly manifest: BootManifest;
12
+ manifest: BootManifest;
13
+ readonly entries: ClientEntries;
12
14
  readonly loadCache: Map<string, ClientModuleRecord>;
13
15
  private readonly seed;
14
16
  private readonly factories;
15
17
  private readonly bootstrapIds;
16
18
  /** In-flight script transport per URL; every row in one batch shares it. */
17
19
  private readonly pendingArrival;
20
+ /** Owner generation captured by in-flight chunk requests and advanced on invalidation. */
21
+ private readonly generations;
18
22
  /** Single-resource combo URL selected by HMR after invalidating one row. */
19
- private readonly reloadUrls;
23
+ private readonly reloadTargets;
20
24
  /** Materialization re-entrancy guard: factory-form CJS cannot deliver partial exports, so a cycle is fatal. */
21
25
  private readonly materializing;
22
26
  private readonly graphRows;
@@ -34,15 +38,16 @@ export declare class ClientModuleSystem implements ClientModuleLoader {
34
38
  private arriveGraphRow;
35
39
  /** Materialize a registered factory (synchronous; memoized in loadCache). */
36
40
  private materialize;
37
- /**
38
- * The synchronous require answered to factories: seed → memoized record →
39
- * registered factory. Fetching is async and therefore unreachable
40
- * from here; an external dynamic package must have arrived before its
41
- * consumer materializes.
42
- */
41
+ /** Build the synchronous module-table require and its asynchronous chunk operation. */
43
42
  private makeRequire;
43
+ /** Load, register, and materialize one package-local dynamic chunk. */
44
+ private importChunk;
44
45
  import(specifier: string): Promise<unknown>;
45
46
  prefetch(id: string): Promise<void>;
47
+ /** Refresh descriptors and unowned factory revisions before any entry imports its dependencies. */
48
+ private updateManifest;
49
+ /** Retain live Loader modules and their transitive requests before evicting unreferenced graph records. */
50
+ private prune;
46
51
  invalidate(id: string, rev?: string): void;
47
52
  }
48
53
  //# sourceMappingURL=system.d.ts.map
@@ -6,7 +6,7 @@
6
6
  * combo scripts plus their source maps,
7
7
  * contributes the registration facade, application preloads, bootstrap scripts,
8
8
  * and graph to the webserver's index injection table, and provides the
9
- * `clientModuleHost` service (the HMR node half's registration/notification
9
+ * `clientModules` service (the HMR node half's registration/notification
10
10
  * face).
11
11
  *
12
12
  * Scanning is incremental per package — there is no full-rescan code path.
@@ -91,6 +91,7 @@ export declare class ClientModuleRegistry extends Service {
91
91
  private composed;
92
92
  /**
93
93
  * Build the service: subscribe, seed, and run the activation flush.
94
+ * Bundle routes follow the optional Web carrier's injected lifecycle.
94
95
  * @param ctx - plugin context carrying Loader and an optional Web carrier.
95
96
  */
96
97
  constructor(ctx: Context);
@@ -108,11 +109,12 @@ export declare class ClientModuleRegistry extends Service {
108
109
  /**
109
110
  * Serve an advertised revisioned bundle or source map without a Web server.
110
111
  * Unknown URLs return 404, unsupported methods return 405, and `HEAD`
111
- * returns the same immutable headers without a body.
112
+ * returns the same immutable headers without materializing a body. Each body
113
+ * is built once on its first `GET`; script construction never reads maps.
112
114
  * @param request - shell-carrier request for a `/plugins` resource.
113
115
  * @returns the exact response also exposed by the optional Web route.
114
116
  */
115
- fetchBundle(request: Request): Response;
117
+ fetchBundle(request: Request): Promise<Response>;
116
118
  /**
117
119
  * Filesystem baseline captured before an entry's current bytes were read.
118
120
  * HMR compares it with the live files when installing a watch, so a write
@@ -123,8 +125,8 @@ export declare class ClientModuleRegistry extends Service {
123
125
  */
124
126
  artifactBaseline(id: string): ClientArtifactBaseline | undefined;
125
127
  /**
126
- * Re-hash one bundle (the HMR watch's registration hook — the only entry
127
- * point through which bundle content changes reach the graph).
128
+ * Publish one completed bundle generation (the HMR watch's registration
129
+ * hook — the only entry point through which build changes reach the graph).
128
130
  * @param id - entry id (package name).
129
131
  * @returns the new rev, or undefined for an unknown id.
130
132
  */
@@ -164,20 +166,24 @@ export declare class ClientModuleRegistry extends Service {
164
166
  /** Allocate an opaque initial row revision without inspecting artifact bytes. */
165
167
  private allocateInitialRevision;
166
168
  /**
167
- * Read the activation-time bundle and optional source-map snapshots.
169
+ * Read the activation-time bundle snapshot.
168
170
  * @param pkgName - package that declares the client bundle.
169
171
  * @param clientPath - absolute path of the built client artifact.
170
172
  * @returns the immutable bytes plus the pre-read filesystem baseline.
171
173
  * @throws {MissingClientBundleError} when the read fails with `ENOENT`; other filesystem errors are rethrown unchanged.
172
174
  */
173
175
  private initialBundleSnapshot;
174
- /** Treat a missing, torn, or malformed development map as an identity-mapped artifact revision. */
175
- private readSourceMapSnapshot;
176
+ /** Treat a missing, torn, or malformed development map as an identity section. */
177
+ private readonly readSourceMap;
176
178
  /** Reconcile one entry name against the live Loader sources. @returns whether the table changed. */
177
179
  private processOne;
178
180
  private resolveSource;
179
181
  private reconcilePackage;
180
182
  private flush;
183
+ /** Match an exact current-revision package-local chunk URL without reading its file. */
184
+ private chunkRequest;
185
+ /** Build a package-local chunk response only when its URL is requested. */
186
+ private chunkResponse;
181
187
  private bundleResource;
182
188
  private readonly serveBundle;
183
189
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-modules",
3
3
  "description": "Client module system, dual-face: node half composes the __DSH_BOOT__ entry graph (incremental dsh.client scan, bundle route, index tap, webPlugins service); browser half is the lazy-CJS module table the vendored cordis Loader consumes as its internal seam",
4
- "version": "0.1.5-rc.2",
4
+ "version": "0.1.6-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -38,11 +38,12 @@
38
38
  },
39
39
  "license": "MIT",
40
40
  "devDependencies": {
41
+ "@deepseek-ai/dsh-host-webserver": "^0.1.6-alpha.2",
42
+ "@deepseek-ai/dsh-invariants": "^0.1.6-alpha.2",
41
43
  "@deepseek-ai/cordis-plugin-loader": "^1.0.3",
42
- "@deepseek-ai/dsh-host-webserver": "^0.1.5-rc.2",
43
- "@deepseek-ai/dsh-invariants": "^0.1.5-rc.2",
44
44
  "@deepseek-ai/cordis": "^4.0.2",
45
- "@deepseek-ai/dsh-package-manifest": "^0.1.5-rc.2"
45
+ "@deepseek-ai/dsh-package-manifest": "^0.1.6-alpha.2",
46
+ "@deepseek-ai/dsh-client-store": "^0.1.6-alpha.2"
46
47
  },
47
48
  "files": [
48
49
  "lib/index.js",