devframe 0.1.21 → 0.1.22
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/README.md +41 -18
- package/dist/{_shared-iZy45oG3.mjs → _shared-DcJX9-Az.mjs} +2 -2
- package/dist/adapters/build.d.mts +5 -5
- package/dist/adapters/build.mjs +13 -12
- package/dist/adapters/cli.d.mts +2 -2
- package/dist/adapters/cli.mjs +5 -5
- package/dist/adapters/dev.d.mts +18 -9
- package/dist/adapters/dev.mjs +1 -1
- package/dist/adapters/embedded.d.mts +5 -5
- package/dist/adapters/embedded.mjs +2 -2
- package/dist/adapters/mcp.d.mts +3 -3
- package/dist/adapters/mcp.mjs +5 -5
- package/dist/adapters/vite.d.mts +45 -12
- package/dist/adapters/vite.mjs +81 -18
- package/dist/chunk-e9Ob2GDo.mjs +26 -0
- package/dist/client/index.d.mts +10 -5
- package/dist/client/index.mjs +19 -10
- package/dist/colors-Bl4W18Mh.mjs +123 -0
- package/dist/{context-internal-saIAfNVw.d.mts → context-DBd794Rn.d.mts} +2 -2
- package/dist/{context-BJ4r2SmR.mjs → context-DUibxhrR.mjs} +14 -31
- package/dist/{dev-CdAy400a.mjs → dev-BGpTpYiR.mjs} +19 -20
- package/dist/{devtool-CNvLs2_Y.d.mts → devframe-DulcIxwu.d.mts} +49 -58
- package/dist/{diagnostics-DxPnRoXO.mjs → diagnostics-BFhNNmST.mjs} +7 -2
- package/dist/hash-BHZbo80D.mjs +126 -0
- package/dist/{human-id-BLoGo_e5.mjs → human-id-adtUWQLr.mjs} +12 -3
- package/dist/{index-CuLRIMto.d.mts → index-DB2Ie0Or.d.mts} +2 -3
- package/dist/index.d.mts +4 -5
- package/dist/index.mjs +2 -5
- package/dist/launch-editor-KA_21J1T.mjs +581 -0
- package/dist/node/auth.d.mts +44 -0
- package/dist/node/auth.mjs +55 -0
- package/dist/node/index.d.mts +10 -51
- package/dist/node/index.mjs +6 -62
- package/dist/{internal/index.d.mts → node/internal.d.mts} +5 -5
- package/dist/node/internal.mjs +50 -0
- package/dist/{open-Dede_w9r.mjs → open-DmFp0qZA.mjs} +12 -3
- package/dist/recipes/open-helpers.d.mts +4 -9
- package/dist/recipes/open-helpers.mjs +7 -12
- package/dist/revoke-DIMz1r7-.mjs +35 -0
- package/dist/rpc/index.d.mts +3 -3
- package/dist/rpc/index.mjs +4 -4
- package/dist/rpc/transports/ws-client.d.mts +1 -1
- package/dist/rpc/transports/ws-client.mjs +2 -1
- package/dist/rpc/transports/ws-server.d.mts +1 -1
- package/dist/rpc/transports/ws-server.mjs +2 -1
- package/dist/{rpc-INbWfHoX.mjs → rpc-CkZuoz-m.mjs} +3 -2
- package/dist/{serialization-DwKi05Pn.mjs → serialization-CwO31axa.mjs} +1 -2
- package/dist/{server-CBsxXIH5.mjs → server-ma8-ZVyX.mjs} +1 -1
- package/dist/{server-BAqOajx_.d.mts → server-zKEDxgqD.d.mts} +4 -3
- package/dist/shared-state-DCDs0e7y.mjs +928 -0
- package/dist/{static-dump-D5VH8Iqk.mjs → static-dump-D7AvjrgL.mjs} +1 -1
- package/dist/{context-internal-Dx_NoSv1.mjs → storage-CNC38eU-.mjs} +4 -86
- package/dist/structured-clone-DcDc2Dds.mjs +221 -0
- package/dist/types/index.d.mts +4 -4
- package/dist/types/index.mjs +11 -2
- package/dist/utils/colors.d.mts +28 -0
- package/dist/utils/colors.mjs +2 -0
- package/dist/utils/events.d.mts +1 -1
- package/dist/utils/hash.d.mts +7 -0
- package/dist/utils/hash.mjs +2 -0
- package/dist/utils/human-id.d.mts +6 -8
- package/dist/utils/human-id.mjs +1 -2
- package/dist/utils/launch-editor.d.mts +13 -0
- package/dist/utils/launch-editor.mjs +2 -0
- package/dist/utils/open.d.mts +16 -0
- package/dist/utils/open.mjs +2 -0
- package/dist/utils/serve-static.d.mts +30 -0
- package/dist/utils/serve-static.mjs +152 -0
- package/dist/utils/shared-state.d.mts +1 -1
- package/dist/utils/shared-state.mjs +1 -35
- package/dist/utils/streaming-channel.d.mts +1 -1
- package/dist/utils/structured-clone.d.mts +21 -0
- package/dist/utils/structured-clone.mjs +2 -0
- package/dist/utils/when.d.mts +32 -49
- package/dist/utils/when.mjs +20 -2
- package/dist/{ws-client-CjPuPFbA.d.mts → ws-client-Bavoya6-.d.mts} +1 -1
- package/dist/{ws-server-C7LnhOHi.d.mts → ws-server-DjvlwLuM.d.mts} +1 -1
- package/package.json +23 -10
- package/skills/devframe/SKILL.md +45 -23
- package/skills/devframe/templates/{counter-devtool.ts → counter-devframe.ts} +4 -4
- package/skills/devframe/templates/{spa-devtool.ts → spa-devframe.ts} +3 -3
- package/skills/devframe/templates/vite-client.ts +2 -2
- package/dist/internal/index.mjs +0 -3
- package/dist/utils/state.d.mts +0 -50
- package/dist/utils/state.mjs +0 -26
- package/dist/{define-Bb4zh-Dc.mjs → define-CW9gLnyG.mjs} +0 -0
- package/dist/{host-h3-9jeHcltx.mjs → host-h3-Dz8YnFgu.mjs} +1 -1
- /package/dist/{transports-DSV5_5QM.mjs → transports-BnCs4rj9.mjs} +0 -0
- /package/dist/{types-C5OVe4AC.d.mts → types-4rdUEi2R.d.mts} +0 -0
|
@@ -1,36 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { nanoid } from "./nanoid.mjs";
|
|
3
|
-
import { applyPatches, enablePatches, produce, produceWithPatches } from "immer";
|
|
4
|
-
//#region src/utils/shared-state.ts
|
|
5
|
-
function createSharedState(options) {
|
|
6
|
-
const { enablePatches: enablePatches$1 = false } = options;
|
|
7
|
-
const events = createEventEmitter();
|
|
8
|
-
let state = options.initialValue;
|
|
9
|
-
const syncIds = /* @__PURE__ */ new Set();
|
|
10
|
-
return {
|
|
11
|
-
on: events.on,
|
|
12
|
-
value: () => state,
|
|
13
|
-
patch: (patches, syncId = nanoid()) => {
|
|
14
|
-
if (syncIds.has(syncId)) return;
|
|
15
|
-
enablePatches();
|
|
16
|
-
state = applyPatches(state, patches);
|
|
17
|
-
syncIds.add(syncId);
|
|
18
|
-
events.emit("updated", state, void 0, syncId);
|
|
19
|
-
},
|
|
20
|
-
mutate: (fn, syncId = nanoid()) => {
|
|
21
|
-
if (syncIds.has(syncId)) return;
|
|
22
|
-
syncIds.add(syncId);
|
|
23
|
-
if (enablePatches$1) {
|
|
24
|
-
const [newState, patches] = produceWithPatches(state, fn);
|
|
25
|
-
state = newState;
|
|
26
|
-
events.emit("updated", state, patches, syncId);
|
|
27
|
-
} else {
|
|
28
|
-
state = produce(state, fn);
|
|
29
|
-
events.emit("updated", state, void 0, syncId);
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
syncIds
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
//#endregion
|
|
1
|
+
import { t as createSharedState } from "../shared-state-DCDs0e7y.mjs";
|
|
36
2
|
export { createSharedState };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { A as CreateStreamSinkOptions, F as createStreamReader, I as createStreamSink, M as StreamReader, N as StreamSink, O as BufferedChunk, P as StreamSinkEvents, j as StreamErrorPayload, k as CreateStreamReaderOptions } from "../devframe-DulcIxwu.mjs";
|
|
2
2
|
export { BufferedChunk, CreateStreamReaderOptions, CreateStreamSinkOptions, StreamErrorPayload, StreamReader, StreamSink, StreamSinkEvents, createStreamReader, createStreamSink };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/utils/structured-clone.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Serialize a structured-cloneable value (`Map`, `Set`, `Date`, `BigInt`,
|
|
4
|
+
* cycles, class instances, …) into a JSON-safe records array.
|
|
5
|
+
*/
|
|
6
|
+
declare function structuredCloneSerialize(value: unknown): unknown[];
|
|
7
|
+
/**
|
|
8
|
+
* Inverse of {@link structuredCloneSerialize}.
|
|
9
|
+
*/
|
|
10
|
+
declare function structuredCloneDeserialize<T = unknown>(value: unknown[]): T;
|
|
11
|
+
/**
|
|
12
|
+
* Serialize a structured-cloneable value to a single string. Equivalent
|
|
13
|
+
* to `JSON.stringify(structuredCloneSerialize(value))`.
|
|
14
|
+
*/
|
|
15
|
+
declare function structuredCloneStringify(value: unknown): string;
|
|
16
|
+
/**
|
|
17
|
+
* Inverse of {@link structuredCloneStringify}.
|
|
18
|
+
*/
|
|
19
|
+
declare function structuredCloneParse<T = unknown>(value: string): T;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { structuredCloneDeserialize, structuredCloneParse, structuredCloneSerialize, structuredCloneStringify };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { i as structuredCloneStringify, n as structuredCloneParse, r as structuredCloneSerialize, t as structuredCloneDeserialize } from "../structured-clone-DcDc2Dds.mjs";
|
|
2
|
+
export { structuredCloneDeserialize, structuredCloneParse, structuredCloneSerialize, structuredCloneStringify };
|
package/dist/utils/when.d.mts
CHANGED
|
@@ -325,50 +325,8 @@ type ValidateExpression<S extends string, T> = string extends S ? S : Tokenize<S
|
|
|
325
325
|
* defineCommand({ name: 'x', title: 'X', when: 'typo' })
|
|
326
326
|
* // ^^^^^ type error
|
|
327
327
|
*/
|
|
328
|
-
type WhenExpression<T, S extends string> = S & ValidateExpression<S, T>; //#endregion
|
|
328
|
+
type WhenExpression$1<T, S extends string> = S & ValidateExpression<S, T>; //#endregion
|
|
329
329
|
//#region src/index.d.ts
|
|
330
|
-
interface EvaluateOptions {
|
|
331
|
-
/**
|
|
332
|
-
* If `true`, throw when the expression references a context key that does
|
|
333
|
-
* not exist. Defaults to `false`, where unknown keys evaluate to `undefined`.
|
|
334
|
-
*/
|
|
335
|
-
strict?: boolean;
|
|
336
|
-
}
|
|
337
|
-
/**
|
|
338
|
-
* Evaluate a when-clause expression string against a context object.
|
|
339
|
-
* Equivalent to `evaluate(parse(expression), ctx, options)`.
|
|
340
|
-
*
|
|
341
|
-
* Supports a JS-expression subset:
|
|
342
|
-
* - Literals: booleans, numbers, strings (quoted with `"` or `'`)
|
|
343
|
-
* - Identifiers: bare keys, including namespaced (`vite.mode`, `vite:buildMode`)
|
|
344
|
-
* - Logical: `&&`, `||`, `!`
|
|
345
|
-
* - Equality: `==`, `!=` (string comparison, bare identifier RHS treated as string),
|
|
346
|
-
* `===`, `!==` (JS strict equality with full expression RHS)
|
|
347
|
-
* - Relational: `<`, `<=`, `>`, `>=`
|
|
348
|
-
* - Arithmetic: `+`, `-`, `*`, `/`, `%`, unary `-` / `+`
|
|
349
|
-
* - Grouping: `(` … `)`
|
|
350
|
-
*
|
|
351
|
-
* When `ctx` has a specific type with known keys, the expression string is
|
|
352
|
-
* **statically validated** — unknown context keys and syntax errors surface
|
|
353
|
-
* as TypeScript errors at the call site. Pass `ctx` typed as
|
|
354
|
-
* `Record<string, unknown>`, or the expression as `string`, to opt out of
|
|
355
|
-
* static checking (e.g. for dynamic expressions).
|
|
356
|
-
*
|
|
357
|
-
* With `{ strict: true }`, referencing an unknown context key at runtime
|
|
358
|
-
* throws. Short-circuit evaluation still applies — keys not reached are not
|
|
359
|
-
* checked.
|
|
360
|
-
*/
|
|
361
|
-
declare function evaluateWhen<T extends object, const E extends string>(expression: E & ValidateExpression<E, T>, ctx: T, options?: EvaluateOptions): boolean;
|
|
362
|
-
/**
|
|
363
|
-
* Resolve a context value by key. Supports namespaced keys with `.` or `:` separators.
|
|
364
|
-
*
|
|
365
|
-
* Lookup order:
|
|
366
|
-
* 1. Exact match — `ctx['plugin.mode']` or `ctx['plugin:mode']`
|
|
367
|
-
* 2. Nested path — e.g. `plugin.mode` falls back to `ctx.plugin?.mode`
|
|
368
|
-
*
|
|
369
|
-
* Returns `undefined` for unknown keys.
|
|
370
|
-
*/
|
|
371
|
-
declare function resolveContextValue<T extends Record<string, unknown>>(key: string, ctx: T): unknown; //#endregion
|
|
372
330
|
//#endregion
|
|
373
331
|
//#region src/utils/when.d.ts
|
|
374
332
|
/**
|
|
@@ -383,11 +341,9 @@ declare function resolveContextValue<T extends Record<string, unknown>>(key: str
|
|
|
383
341
|
* Plugins can add namespaced variables using dot or colon separators:
|
|
384
342
|
* - `vite.mode`, `vite:mode` — stored as `{ 'vite.mode': 'development' }` or nested `{ vite: { mode: 'development' } }`
|
|
385
343
|
*
|
|
386
|
-
*
|
|
387
|
-
*
|
|
388
|
-
*
|
|
389
|
-
* (`===`/`!==`), relational (`<`/`<=`/`>`/`>=`), arithmetic (`+ - * / %`), and
|
|
390
|
-
* number/string literals are supported.
|
|
344
|
+
* Supported operators: `!`, `==`, `!=`, `===`, `!==`, `<`, `<=`, `>`, `>=`,
|
|
345
|
+
* `&&`, `||`, `+`, `-`, `*`, `/`, `%`. Parentheses, number and string literals
|
|
346
|
+
* are also supported.
|
|
391
347
|
*/
|
|
392
348
|
interface WhenContext {
|
|
393
349
|
clientType: 'embedded' | 'standalone';
|
|
@@ -397,5 +353,32 @@ interface WhenContext {
|
|
|
397
353
|
/** Allow custom context variables from plugins */
|
|
398
354
|
[key: string]: unknown;
|
|
399
355
|
}
|
|
356
|
+
/**
|
|
357
|
+
* A statically-validated `when` expression string. Used inside `define*`
|
|
358
|
+
* helpers to surface unknown context keys and syntax errors as TypeScript
|
|
359
|
+
* errors at the call site.
|
|
360
|
+
*/
|
|
361
|
+
type WhenExpression<T, S extends string> = WhenExpression$1<T, S>;
|
|
362
|
+
/** Options for `evaluateWhen`. */
|
|
363
|
+
interface EvaluateWhenOptions {
|
|
364
|
+
/**
|
|
365
|
+
* Throw when the expression references a context key that does not exist.
|
|
366
|
+
*
|
|
367
|
+
* @default false
|
|
368
|
+
*/
|
|
369
|
+
strict?: boolean;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Evaluate a when-clause expression string against a context object.
|
|
373
|
+
*
|
|
374
|
+
* @example
|
|
375
|
+
* evaluateWhen('dockOpen && clientType == embedded', ctx)
|
|
376
|
+
*/
|
|
377
|
+
declare function evaluateWhen<T extends object, const E extends string>(expression: E & WhenExpression$1<T, E>, context: T, options?: EvaluateWhenOptions): boolean;
|
|
378
|
+
/**
|
|
379
|
+
* Resolve a context value by key. Supports namespaced keys with `.` or `:`
|
|
380
|
+
* separators. Returns `undefined` for unknown keys.
|
|
381
|
+
*/
|
|
382
|
+
declare function resolveContextValue<T extends Record<string, unknown>>(key: string, context: T): unknown;
|
|
400
383
|
//#endregion
|
|
401
|
-
export { WhenContext, type WhenExpression, evaluateWhen, resolveContextValue };
|
|
384
|
+
export { EvaluateWhenOptions, WhenContext, type WhenExpression, evaluateWhen, resolveContextValue };
|
package/dist/utils/when.mjs
CHANGED
|
@@ -369,7 +369,7 @@ function runBinary(node, ctx, strict) {
|
|
|
369
369
|
* throws. Short-circuit evaluation still applies — keys not reached are not
|
|
370
370
|
* checked.
|
|
371
371
|
*/
|
|
372
|
-
function evaluateWhen(expression, ctx, options) {
|
|
372
|
+
function evaluateWhen$1(expression, ctx, options) {
|
|
373
373
|
return evaluate(parse(expression), ctx, options);
|
|
374
374
|
}
|
|
375
375
|
/**
|
|
@@ -381,7 +381,7 @@ function evaluateWhen(expression, ctx, options) {
|
|
|
381
381
|
*
|
|
382
382
|
* Returns `undefined` for unknown keys.
|
|
383
383
|
*/
|
|
384
|
-
function resolveContextValue(key, ctx) {
|
|
384
|
+
function resolveContextValue$1(key, ctx) {
|
|
385
385
|
return resolve(key, ctx).value;
|
|
386
386
|
}
|
|
387
387
|
function lookup(key, ctx, strict) {
|
|
@@ -421,4 +421,22 @@ function resolve(key, ctx) {
|
|
|
421
421
|
};
|
|
422
422
|
}
|
|
423
423
|
//#endregion
|
|
424
|
+
//#region src/utils/when.ts
|
|
425
|
+
/**
|
|
426
|
+
* Evaluate a when-clause expression string against a context object.
|
|
427
|
+
*
|
|
428
|
+
* @example
|
|
429
|
+
* evaluateWhen('dockOpen && clientType == embedded', ctx)
|
|
430
|
+
*/
|
|
431
|
+
function evaluateWhen(expression, context, options) {
|
|
432
|
+
return evaluateWhen$1(expression, context, options);
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Resolve a context value by key. Supports namespaced keys with `.` or `:`
|
|
436
|
+
* separators. Returns `undefined` for unknown keys.
|
|
437
|
+
*/
|
|
438
|
+
function resolveContextValue(key, context) {
|
|
439
|
+
return resolveContextValue$1(key, context);
|
|
440
|
+
}
|
|
441
|
+
//#endregion
|
|
424
442
|
export { evaluateWhen, resolveContextValue };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { g as RpcFunctionDefinitionAny } from "./types-
|
|
1
|
+
import { g as RpcFunctionDefinitionAny } from "./types-4rdUEi2R.mjs";
|
|
2
2
|
import { BirpcGroup, ChannelOptions } from "birpc";
|
|
3
3
|
import { ServerOptions } from "node:https";
|
|
4
4
|
import { WebSocket, WebSocketServer } from "ws";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devframe",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.22",
|
|
5
5
|
"description": "Framework for building generic DevTools",
|
|
6
6
|
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -28,8 +28,9 @@
|
|
|
28
28
|
"./adapters/vite": "./dist/adapters/vite.mjs",
|
|
29
29
|
"./client": "./dist/client/index.mjs",
|
|
30
30
|
"./constants": "./dist/constants.mjs",
|
|
31
|
-
"./internal": "./dist/internal/index.mjs",
|
|
32
31
|
"./node": "./dist/node/index.mjs",
|
|
32
|
+
"./node/auth": "./dist/node/auth.mjs",
|
|
33
|
+
"./node/internal": "./dist/node/internal.mjs",
|
|
33
34
|
"./recipes/open-helpers": "./dist/recipes/open-helpers.mjs",
|
|
34
35
|
"./rpc": "./dist/rpc/index.mjs",
|
|
35
36
|
"./rpc/client": "./dist/rpc/client.mjs",
|
|
@@ -37,13 +38,18 @@
|
|
|
37
38
|
"./rpc/transports/ws-client": "./dist/rpc/transports/ws-client.mjs",
|
|
38
39
|
"./rpc/transports/ws-server": "./dist/rpc/transports/ws-server.mjs",
|
|
39
40
|
"./types": "./dist/types/index.mjs",
|
|
41
|
+
"./utils/colors": "./dist/utils/colors.mjs",
|
|
40
42
|
"./utils/events": "./dist/utils/events.mjs",
|
|
43
|
+
"./utils/hash": "./dist/utils/hash.mjs",
|
|
41
44
|
"./utils/human-id": "./dist/utils/human-id.mjs",
|
|
45
|
+
"./utils/launch-editor": "./dist/utils/launch-editor.mjs",
|
|
42
46
|
"./utils/nanoid": "./dist/utils/nanoid.mjs",
|
|
47
|
+
"./utils/open": "./dist/utils/open.mjs",
|
|
43
48
|
"./utils/promise": "./dist/utils/promise.mjs",
|
|
49
|
+
"./utils/serve-static": "./dist/utils/serve-static.mjs",
|
|
44
50
|
"./utils/shared-state": "./dist/utils/shared-state.mjs",
|
|
45
|
-
"./utils/state": "./dist/utils/state.mjs",
|
|
46
51
|
"./utils/streaming-channel": "./dist/utils/streaming-channel.mjs",
|
|
52
|
+
"./utils/structured-clone": "./dist/utils/structured-clone.mjs",
|
|
47
53
|
"./utils/when": "./dist/utils/when.mjs",
|
|
48
54
|
"./package.json": "./package.json"
|
|
49
55
|
},
|
|
@@ -62,43 +68,50 @@
|
|
|
62
68
|
},
|
|
63
69
|
"dependencies": {
|
|
64
70
|
"@valibot/to-json-schema": "^1.7.0",
|
|
65
|
-
"ansis": "^4.2.0",
|
|
66
71
|
"birpc": "^4.0.0",
|
|
67
72
|
"cac": "^7.0.0",
|
|
68
73
|
"h3": "^1.15.11",
|
|
69
|
-
"immer": "^11.1.7",
|
|
70
|
-
"launch-editor": "^2.13.2",
|
|
71
74
|
"logs-sdk": "^0.0.6",
|
|
72
|
-
"
|
|
75
|
+
"mrmime": "^2.0.1",
|
|
73
76
|
"pathe": "^2.0.3",
|
|
74
|
-
"sirv": "^3.0.2",
|
|
75
|
-
"structured-clone-es": "^2.0.0",
|
|
76
77
|
"valibot": "^1.4.0",
|
|
77
78
|
"ws": "^8.20.0"
|
|
78
79
|
},
|
|
79
80
|
"devDependencies": {
|
|
80
81
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
82
|
+
"ansis": "^4.2.0",
|
|
83
|
+
"immer": "^11.1.8",
|
|
81
84
|
"launch-editor": "^2.13.2",
|
|
82
|
-
"
|
|
85
|
+
"ohash": "^2.0.11",
|
|
86
|
+
"open": "^11.0.0",
|
|
87
|
+
"structured-clone-es": "^2.0.0",
|
|
88
|
+
"tsdown": "^0.22.0",
|
|
83
89
|
"whenexpr": "^0.1.2"
|
|
84
90
|
},
|
|
85
91
|
"inlinedDependencies": {
|
|
92
|
+
"ansis": "4.2.0",
|
|
86
93
|
"bundle-name": "4.1.0",
|
|
87
94
|
"default-browser": "5.4.0",
|
|
88
95
|
"default-browser-id": "5.0.1",
|
|
89
96
|
"define-lazy-prop": "3.0.0",
|
|
90
97
|
"get-port-please": "3.2.0",
|
|
91
98
|
"human-id": "4.1.3",
|
|
99
|
+
"immer": "11.1.8",
|
|
92
100
|
"is-docker": "3.0.0",
|
|
93
101
|
"is-in-ssh": "1.0.0",
|
|
94
102
|
"is-inside-container": "1.0.0",
|
|
95
103
|
"is-wsl": "3.1.0",
|
|
104
|
+
"launch-editor": "2.13.2",
|
|
96
105
|
"obug": "2.1.1",
|
|
106
|
+
"ohash": "2.0.11",
|
|
97
107
|
"open": "11.0.0",
|
|
98
108
|
"p-limit": "7.3.0",
|
|
99
109
|
"perfect-debounce": "2.1.0",
|
|
110
|
+
"picocolors": "1.1.1",
|
|
100
111
|
"powershell-utils": "0.1.0",
|
|
101
112
|
"run-applescript": "7.1.0",
|
|
113
|
+
"shell-quote": "1.8.3",
|
|
114
|
+
"structured-clone-es": "2.0.0",
|
|
102
115
|
"ua-parser-modern": "0.1.1",
|
|
103
116
|
"whenexpr": "0.1.2",
|
|
104
117
|
"wsl-utils": "0.3.1",
|
package/skills/devframe/SKILL.md
CHANGED
|
@@ -3,21 +3,21 @@ name: devframe
|
|
|
3
3
|
description: >
|
|
4
4
|
Use when building one devtool integration with devframe — the
|
|
5
5
|
portable, framework-neutral container for a single tool. Covers
|
|
6
|
-
|
|
6
|
+
DevframeDefinition, picking the right deployment adapter
|
|
7
7
|
(cli / build / spa / vite / embedded / mcp), designing RPC
|
|
8
8
|
contracts, exposing an agent-native surface over MCP, and wiring
|
|
9
9
|
the author's SPA client. Hub-only concerns (docks, terminals,
|
|
10
10
|
commands, the unified messages dock) belong to
|
|
11
11
|
`@vitejs/devtools-kit` — see the `vite-devtools-kit` skill for
|
|
12
|
-
those. Triggers on `devframe` imports, `
|
|
13
|
-
`createCli`, `createMcpServer`, `
|
|
12
|
+
those. Triggers on `devframe` imports, `defineDevframe`,
|
|
13
|
+
`createCli`, `createMcpServer`, `connectDevframe`, and on
|
|
14
14
|
migrations of existing inspectors (eslint-config-inspector,
|
|
15
15
|
unocss-inspector, node-modules-inspector-style tools) to devframe.
|
|
16
16
|
---
|
|
17
17
|
|
|
18
18
|
# devframe skill
|
|
19
19
|
|
|
20
|
-
**Devframe is the container for one devtool integration, portable across viewers.** A devtool built on devframe is a single `
|
|
20
|
+
**Devframe is the container for one devtool integration, portable across viewers.** A devtool built on devframe is a single `DevframeDefinition` plus an author-provided SPA — the same definition deploys as a standalone CLI, a static report, an embedded SPA, an MCP server, or as a dock entry inside the Vite DevTools hub via `createPluginFromDevframe`.
|
|
21
21
|
|
|
22
22
|
Devframe deliberately stops at the boundary of one tool. Anything that only matters across multiple integrations — docks, terminals, command palette, cross-tool toasts — lives in `@vitejs/devtools-kit`, the hub layer. `devframe` must not depend on Vite, any `@vitejs/*` package, or hub-only concepts; it's the lowest-level layer in the monorepo.
|
|
23
23
|
|
|
@@ -25,7 +25,7 @@ Full reference: [devfra.me/](https://devfra.me/).
|
|
|
25
25
|
|
|
26
26
|
## When to use devframe
|
|
27
27
|
|
|
28
|
-
All adapter factories share the shape `createXxx(
|
|
28
|
+
All adapter factories share the shape `createXxx(devframeDef, options?)`.
|
|
29
29
|
|
|
30
30
|
| Author goal | Factory | Entry |
|
|
31
31
|
|-------------|---------|-------|
|
|
@@ -37,14 +37,14 @@ All adapter factories share the shape `createXxx(devtoolDef, options?)`.
|
|
|
37
37
|
| Register dynamically at runtime | `createEmbedded(def, { ctx })` | `devframe/adapters/embedded` |
|
|
38
38
|
| Expose to coding agents (MCP) | `createMcpServer(def, options?)` | `devframe/adapters/mcp` *(experimental)* |
|
|
39
39
|
|
|
40
|
-
The same `
|
|
40
|
+
The same `DevframeDefinition` runs under every adapter — pick based on deployment, not on what the tool does.
|
|
41
41
|
|
|
42
|
-
## Minimum viable
|
|
42
|
+
## Minimum viable devframe
|
|
43
43
|
|
|
44
44
|
```ts
|
|
45
|
-
import {
|
|
45
|
+
import { defineDevframe, defineRpcFunction } from 'devframe'
|
|
46
46
|
|
|
47
|
-
export default
|
|
47
|
+
export default defineDevframe({
|
|
48
48
|
id: 'my-inspector',
|
|
49
49
|
name: 'My Inspector',
|
|
50
50
|
icon: 'ph:magnifying-glass-duotone',
|
|
@@ -61,16 +61,16 @@ export default defineDevtool({
|
|
|
61
61
|
|
|
62
62
|
`setup(ctx)` registers RPC functions, shared state, diagnostics, and any other devframe-level wiring. It does **not** receive `docks` / `terminals` / `messages` / `commands` — those are hub features. When mounted into Vite DevTools via `createPluginFromDevframe(d)`, the kit auto-derives an iframe dock entry from `id` / `name` / `icon` / `basePath`; for richer hub-side behaviour (custom-render, terminals, palette commands) pass `options.setup` to `createPluginFromDevframe`.
|
|
63
63
|
|
|
64
|
-
See `templates/counter-
|
|
64
|
+
See `templates/counter-devframe.ts` for a runnable counter example, `templates/spa-devframe.ts` for an SPA-ready shape, and `templates/vite-client.ts` for the author's client entry.
|
|
65
65
|
|
|
66
66
|
## Namespacing
|
|
67
67
|
|
|
68
|
-
**Always prefix** RPC names, dock IDs, command IDs, shared-state keys, and agent tool IDs with the
|
|
68
|
+
**Always prefix** RPC names, dock IDs, command IDs, shared-state keys, and agent tool IDs with the devframe `id`:
|
|
69
69
|
|
|
70
70
|
```ts
|
|
71
71
|
'my-inspector:get-modules' // ✓
|
|
72
72
|
'my-inspector:state' // ✓
|
|
73
|
-
'get-modules' // ✗ — may collide with other
|
|
73
|
+
'get-modules' // ✗ — may collide with other devframes sharing the host
|
|
74
74
|
```
|
|
75
75
|
|
|
76
76
|
## DevToolsNodeContext at a glance
|
|
@@ -86,7 +86,7 @@ See `templates/counter-devtool.ts` for a runnable counter example, `templates/sp
|
|
|
86
86
|
| `ctx.host` | Runtime abstraction — `mountStatic`, `resolveOrigin`, `getStorageDir` |
|
|
87
87
|
| `ctx.mode` | `'dev'` or `'build'` — gate setup work per runtime |
|
|
88
88
|
|
|
89
|
-
> Hub-only hosts (`ctx.docks`, `ctx.terminals`, `ctx.messages`, `ctx.commands`) only exist when the
|
|
89
|
+
> Hub-only hosts (`ctx.docks`, `ctx.terminals`, `ctx.messages`, `ctx.commands`, `ctx.createJsonRenderer`) only exist when the devframe is mounted into Vite DevTools via `createPluginFromDevframe`. See the [`vite-devtools-kit` skill](../../skills/vite-devtools-kit) for those.
|
|
90
90
|
|
|
91
91
|
## RPC contracts
|
|
92
92
|
|
|
@@ -267,7 +267,7 @@ The kit auto-derives an iframe dock entry from `id` / `name` / `icon` / `basePat
|
|
|
267
267
|
|
|
268
268
|
## When clauses
|
|
269
269
|
|
|
270
|
-
Gate kit-side dock / command visibility with VS Code-style expressions
|
|
270
|
+
Gate kit-side dock / command visibility with VS Code-style expressions. The runtime + types ship bundled from `devframe/utils/when` — no separate install. The consumers (`when` field on docks and commands) live in the kit:
|
|
271
271
|
|
|
272
272
|
```ts
|
|
273
273
|
when: 'clientType == embedded'
|
|
@@ -275,7 +275,7 @@ when: 'dockOpen && !paletteOpen'
|
|
|
275
275
|
when: 'my-inspector.ready && count >= 10'
|
|
276
276
|
```
|
|
277
277
|
|
|
278
|
-
Built-in context: `clientType` (`'embedded' | 'standalone'`), `dockOpen`, `paletteOpen`, `dockSelectedId`. Plugins can add namespaced keys (`.` or `:` separators). Both the types (`WhenExpression<Ctx, S>`) and runtime (`evaluateWhen`, `resolveContextValue`)
|
|
278
|
+
Built-in context: `clientType` (`'embedded' | 'standalone'`), `dockOpen`, `paletteOpen`, `dockSelectedId`. Plugins can add namespaced keys (`.` or `:` separators). Both the types (`WhenExpression<Ctx, S>`) and runtime (`evaluateWhen`, `resolveContextValue`) come from `devframe/utils/when`.
|
|
279
279
|
|
|
280
280
|
## Agent-native surface (experimental)
|
|
281
281
|
|
|
@@ -319,25 +319,25 @@ Expose via MCP:
|
|
|
319
319
|
```ts
|
|
320
320
|
import { createMcpServer } from 'devframe/adapters/mcp'
|
|
321
321
|
|
|
322
|
-
await createMcpServer(
|
|
322
|
+
await createMcpServer(devframe, { transport: 'stdio' })
|
|
323
323
|
```
|
|
324
324
|
|
|
325
|
-
`@modelcontextprotocol/sdk` is a peer dependency. The CLI adapter also exposes `my-
|
|
325
|
+
`@modelcontextprotocol/sdk` is a peer dependency. The CLI adapter also exposes `my-devframe mcp` — route host logs to stderr (stdout is the MCP transport). Safety classifications (`'read' | 'action' | 'destructive'`) drive MCP hint annotations that agent clients use to prompt for confirmation.
|
|
326
326
|
|
|
327
327
|
## Author SPA
|
|
328
328
|
|
|
329
329
|
Authors bring their own SPA (any framework or plain HTML). Client entry:
|
|
330
330
|
|
|
331
331
|
```ts
|
|
332
|
-
import {
|
|
332
|
+
import { connectDevframe } from 'devframe/client'
|
|
333
333
|
|
|
334
|
-
const rpc = await
|
|
334
|
+
const rpc = await connectDevframe()
|
|
335
335
|
// await rpc.ensureTrusted() // WS mode only — blocks until server accepts
|
|
336
336
|
|
|
337
337
|
const data = await rpc.call('my-inspector:get-stats', { limit: 10 })
|
|
338
338
|
```
|
|
339
339
|
|
|
340
|
-
`
|
|
340
|
+
`connectDevframe` auto-detects the backend via `/.devtools/.connection.json`:
|
|
341
341
|
|
|
342
342
|
- **websocket** (dev mode) — full read/write, requires auth handshake. Listen for token updates on the `vite-devtools-auth` BroadcastChannel.
|
|
343
343
|
- **static** (build / spa output) — read-only, resolves calls from the baked RPC dump.
|
|
@@ -366,7 +366,7 @@ At runtime, static clients look up the argument hash in the dump; misses resolve
|
|
|
366
366
|
|
|
367
367
|
## CLI adapter subcommands
|
|
368
368
|
|
|
369
|
-
`createCli(
|
|
369
|
+
`createCli(devframe).parse()` gives the tool four subcommands out of the box:
|
|
370
370
|
|
|
371
371
|
| Subcommand | Action |
|
|
372
372
|
|------------|--------|
|
|
@@ -377,23 +377,45 @@ At runtime, static clients look up the argument hash in the dump; misses resolve
|
|
|
377
377
|
|
|
378
378
|
**Bring your own CLI framework?** `createCli` is just a cac wrapper around three peer factories — `createDevServer` (`devframe/adapters/dev`), `createBuild` (`devframe/adapters/build`), and `createMcpServer` (`devframe/adapters/mcp`). Use them directly with commander/yargs/oclif when `createCli`'s baked-in command structure doesn't fit. `createDevServer` returns a `StartedServer` handle (`origin`, `port`, `app`, `wss`, `close()`) so you can wire SIGINT / hot-reload teardown into the surrounding program. `parseCliFlags(schema, raw)` and `defineCliFlags(...)` (both from `devframe/adapters/cli`) validate an arbitrary flag bag against a `CliFlagsSchema` — typed flags aren't tied to cac.
|
|
379
379
|
|
|
380
|
+
## Bundled utilities
|
|
381
|
+
|
|
382
|
+
Devframe re-exports a curated set of helpers under `devframe/utils/*`. They are bundled — never add the underlying packages to a devtool's own `package.json`:
|
|
383
|
+
|
|
384
|
+
| Import | Wraps | Use for |
|
|
385
|
+
|--------|-------|---------|
|
|
386
|
+
| `colors` from `devframe/utils/colors` | `ansis` | Terminal ANSI colors (`c.red`, `c.green`, tagged templates) |
|
|
387
|
+
| `open` from `devframe/utils/open` | `open` | Open URLs / files in the OS default handler |
|
|
388
|
+
| `launchEditor` from `devframe/utils/launch-editor` | `launch-editor` | Open `file:line:column` in the user's editor (optional `editor` arg) |
|
|
389
|
+
| `hash` from `devframe/utils/hash` | `ohash` | Stable structural hash — cache keys, dedup |
|
|
390
|
+
| `structuredClone{Serialize,Deserialize,Stringify,Parse}` from `devframe/utils/structured-clone` | `structured-clone-es` | JSON-safe round-trip of `Map` / `Set` / `Date` / `BigInt` / cycles |
|
|
391
|
+
| `humanId` from `devframe/utils/human-id` | `human-id` | Human-readable IDs (`bright-orange-tiger`) |
|
|
392
|
+
| `nanoid` from `devframe/utils/nanoid` | (vendored) | URL-safe random IDs |
|
|
393
|
+
| `promiseWithResolver` from `devframe/utils/promise` | — | Externally-controlled `Promise` |
|
|
394
|
+
| `createEventEmitter` from `devframe/utils/events` | — | Typed event bus |
|
|
395
|
+
| `createSharedState` from `devframe/utils/shared-state` | (immer internal) | Immutable state container (see `ctx.rpc.sharedState`) |
|
|
396
|
+
| `createStreamSink` / `createStreamReader` from `devframe/utils/streaming-channel` | — | Low-level streaming primitives |
|
|
397
|
+
| `evaluateWhen` / `WhenExpression` from `devframe/utils/when` | `whenexpr` | When-clause expressions |
|
|
398
|
+
|
|
399
|
+
For "open file in editor" + "reveal in finder", prefer the prebuilt `openHelpers` RPC recipe — it wires the two utilities into named RPC functions ready to register.
|
|
400
|
+
|
|
380
401
|
## Testing
|
|
381
402
|
|
|
382
403
|
- Unit-test host classes with fake contexts.
|
|
383
|
-
- Run `templates/counter-
|
|
404
|
+
- Run `templates/counter-devframe.ts` under each adapter for integration coverage.
|
|
384
405
|
- Snapshot the build-static RPC dump (`<outDir>/.devtools/.rpc-dump/index.json`) to catch accidental drift in `static` function outputs.
|
|
385
406
|
|
|
386
407
|
## Further reading
|
|
387
408
|
|
|
388
409
|
Devframe-level pages (one-tool, portable surface):
|
|
389
410
|
|
|
390
|
-
- [
|
|
411
|
+
- [Devframe Definition](https://devfra.me/devframe-definition) — fields, runtime flags, multi-adapter wiring
|
|
391
412
|
- [Adapters](https://devfra.me/adapters) — full reference for all deployment adapters
|
|
392
413
|
- [RPC](https://devfra.me/rpc) — types, schema, broadcasts, dumps
|
|
393
414
|
- [Shared State](https://devfra.me/shared-state) — patches, events, client-side mutation
|
|
394
415
|
- [Streaming](https://devfra.me/streaming) — chunked feeds, uploads, replay, Web/Node Streams interop
|
|
395
416
|
- [When Clauses](https://devfra.me/when-clauses) — syntax, context, type-safe wrappers
|
|
396
417
|
- [Structured Diagnostics](https://devfra.me/diagnostics) — coded errors via `ctx.diagnostics`, register custom codes
|
|
418
|
+
- [Utilities](https://devfra.me/utilities) — bundled `devframe/utils/*` helpers (colors, hash, launchEditor, structured-clone, …)
|
|
397
419
|
- [Client](https://devfra.me/client) — auth handshake, modes, discovery
|
|
398
420
|
- [Agent-Native](https://devfra.me/agent-native) — agent field, tools/resources, MCP + Claude Desktop
|
|
399
421
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
// Smallest possible
|
|
1
|
+
// Smallest possible devframe. The dock entry is auto-derived from
|
|
2
2
|
// `id` / `name` / `icon` when this definition is mounted into Vite
|
|
3
|
-
// DevTools via `createPluginFromDevframe(
|
|
4
|
-
import {
|
|
3
|
+
// DevTools via `createPluginFromDevframe(devframe)`.
|
|
4
|
+
import { defineDevframe, defineRpcFunction } from 'devframe'
|
|
5
5
|
|
|
6
6
|
let counter = 0
|
|
7
7
|
|
|
8
|
-
export default
|
|
8
|
+
export default defineDevframe({
|
|
9
9
|
id: 'counter',
|
|
10
10
|
name: 'Counter',
|
|
11
11
|
icon: 'ph:counter-duotone',
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Devframe with setupBrowser + SPA query-loader — deployable as a static site.
|
|
2
2
|
// When mounted into Vite DevTools via `createPluginFromDevframe`, the kit
|
|
3
3
|
// auto-derives an iframe dock from `id` / `name` / `icon`.
|
|
4
|
-
import {
|
|
4
|
+
import { defineDevframe, defineRpcFunction } from 'devframe'
|
|
5
5
|
import * as v from 'valibot'
|
|
6
6
|
|
|
7
|
-
export default
|
|
7
|
+
export default defineDevframe({
|
|
8
8
|
id: 'my-inspector',
|
|
9
9
|
name: 'My Inspector',
|
|
10
10
|
icon: 'ph:magnifying-glass-duotone',
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Minimum SPA client that talks to a devframe-hosted RPC.
|
|
2
|
-
import {
|
|
2
|
+
import { connectDevframe } from 'devframe/client'
|
|
3
3
|
|
|
4
4
|
async function main() {
|
|
5
|
-
const rpc = await
|
|
5
|
+
const rpc = await connectDevframe()
|
|
6
6
|
// The method names below are just examples — replace with your own.
|
|
7
7
|
const data = await rpc.call('my-inspector:getStats' as any)
|
|
8
8
|
document.getElementById('root')!.textContent = JSON.stringify(data)
|
package/dist/internal/index.mjs
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { n as internalContextMap, t as getInternalContext } from "../context-internal-Dx_NoSv1.mjs";
|
|
2
|
-
import { n as resolveBasePath, t as normalizeBasePath } from "../_shared-iZy45oG3.mjs";
|
|
3
|
-
export { getInternalContext, internalContextMap, normalizeBasePath, resolveBasePath };
|
package/dist/utils/state.d.mts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { ct as EventEmitter } from "../devtool-CNvLs2_Y.mjs";
|
|
2
|
-
import { Objectish, Patch } from "immer";
|
|
3
|
-
|
|
4
|
-
//#region src/utils/state.d.ts
|
|
5
|
-
type ImmutablePrimitive = undefined | null | boolean | string | number | Function;
|
|
6
|
-
type Immutable<T> = T extends ImmutablePrimitive ? T : T extends Array<infer U> ? ImmutableArray<U> : T extends Map<infer K, infer V> ? ImmutableMap<K, V> : T extends Set<infer M> ? ImmutableSet<M> : ImmutableObject<T>;
|
|
7
|
-
type ImmutableArray<T> = ReadonlyArray<Immutable<T>>;
|
|
8
|
-
type ImmutableMap<K, V> = ReadonlyMap<Immutable<K>, Immutable<V>>;
|
|
9
|
-
type ImmutableSet<T> = ReadonlySet<Immutable<T>>;
|
|
10
|
-
type ImmutableObject<T> = { readonly [K in keyof T]: Immutable<T[K]> };
|
|
11
|
-
/**
|
|
12
|
-
* State host that is immutable by default with explicit mutate.
|
|
13
|
-
*/
|
|
14
|
-
interface SharedState<T> {
|
|
15
|
-
/**
|
|
16
|
-
* Get the current state. Immutable.
|
|
17
|
-
*/
|
|
18
|
-
get: () => Immutable<T>;
|
|
19
|
-
/**
|
|
20
|
-
* Subscribe to state changes.
|
|
21
|
-
*/
|
|
22
|
-
on: EventEmitter<SharedStateEvents<T>>['on'];
|
|
23
|
-
/**
|
|
24
|
-
* Mutate the state.
|
|
25
|
-
*/
|
|
26
|
-
mutate: (fn: (state: T) => void) => void;
|
|
27
|
-
/**
|
|
28
|
-
* Apply patches to the state.
|
|
29
|
-
*/
|
|
30
|
-
patch: (patches: Patch[]) => void;
|
|
31
|
-
}
|
|
32
|
-
interface SharedStateEvents<T> {
|
|
33
|
-
updated: (state: T) => void;
|
|
34
|
-
patches: (patches: Patch[]) => void;
|
|
35
|
-
}
|
|
36
|
-
interface SharedStateOptions<T> {
|
|
37
|
-
/**
|
|
38
|
-
* Initial state.
|
|
39
|
-
*/
|
|
40
|
-
initialState: T;
|
|
41
|
-
/**
|
|
42
|
-
* Enable patches.
|
|
43
|
-
*
|
|
44
|
-
* @default false
|
|
45
|
-
*/
|
|
46
|
-
enablePatches?: boolean;
|
|
47
|
-
}
|
|
48
|
-
declare function createSharedState<T extends Objectish>(options: SharedStateOptions<T>): SharedState<T>;
|
|
49
|
-
//#endregion
|
|
50
|
-
export { Immutable, ImmutableArray, ImmutableMap, ImmutableObject, ImmutableSet, SharedState, SharedStateEvents, SharedStateOptions, createSharedState };
|
package/dist/utils/state.mjs
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { createEventEmitter } from "./events.mjs";
|
|
2
|
-
import { applyPatches, produce, produceWithPatches } from "immer";
|
|
3
|
-
//#region src/utils/state.ts
|
|
4
|
-
function createSharedState(options) {
|
|
5
|
-
const { enablePatches = false } = options;
|
|
6
|
-
const events = createEventEmitter();
|
|
7
|
-
let state = options.initialState;
|
|
8
|
-
return {
|
|
9
|
-
on: events.on,
|
|
10
|
-
get: () => state,
|
|
11
|
-
patch: (patches) => {
|
|
12
|
-
state = applyPatches(state, patches);
|
|
13
|
-
events.emit("updated", state);
|
|
14
|
-
},
|
|
15
|
-
mutate: (fn) => {
|
|
16
|
-
if (enablePatches) {
|
|
17
|
-
const [newState, patches] = produceWithPatches(state, fn);
|
|
18
|
-
state = newState;
|
|
19
|
-
events.emit("patches", patches);
|
|
20
|
-
} else state = produce(state, fn);
|
|
21
|
-
events.emit("updated", state);
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
//#endregion
|
|
26
|
-
export { createSharedState };
|
|
File without changes
|