devframe 0.5.4 → 0.6.0-beta.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.
- package/dist/{_shared-CUFqO4kJ.mjs → _shared-bWRzeSa0.mjs} +2 -3
- package/dist/adapters/build.d.mts +1 -1
- package/dist/adapters/build.mjs +7 -7
- package/dist/adapters/cli.d.mts +1 -1
- package/dist/adapters/cli.mjs +2 -2
- package/dist/adapters/dev.d.mts +8 -2
- package/dist/adapters/dev.mjs +1 -1
- package/dist/adapters/embedded.d.mts +1 -1
- package/dist/adapters/mcp.d.mts +1 -1
- package/dist/adapters/mcp.mjs +4 -4
- package/dist/client/index.d.mts +148 -6
- package/dist/client/index.mjs +257 -44
- package/dist/constants.d.mts +17 -1
- package/dist/constants.mjs +17 -1
- package/dist/context-3x_bgBgZ.mjs +48 -0
- package/dist/{context-DTRcO_UH.d.mts → context-BEVByy_Z.d.mts} +1 -1
- package/dist/{dev-Cv43GfqM.mjs → dev-BaX8fLH2.mjs} +39 -13
- package/dist/{devframe-BuR6n9ZD.d.mts → devframe-D-gr9sBx.d.mts} +365 -15
- package/dist/{diagnostics-GitRGKbr.mjs → diagnostics-BXwBQmoN.mjs} +1 -1
- package/dist/{dump-9lKIJTLh.mjs → dump-DoXkj4ku.mjs} +1 -1
- package/dist/helpers/vite.d.mts +1 -1
- package/dist/helpers/vite.mjs +11 -11
- package/dist/{host-h3-Dgpgr1Ul.mjs → host-h3-C5SZlk03.mjs} +134 -6
- package/dist/{index-C7M1hnvL.d.mts → index-CxaPKDXX.d.mts} +2 -2
- package/dist/{index-DH2sBIwd.d.mts → index-DXHWuwJk.d.mts} +1 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +1 -1
- package/dist/{launch-editor-BbNhtg7b.mjs → launch-editor-DPfltGA4.mjs} +88 -13
- package/dist/node/auth.d.mts +43 -23
- package/dist/node/auth.mjs +84 -37
- package/dist/node/hub-internals.d.mts +2 -2
- package/dist/node/hub-internals.mjs +2 -2
- package/dist/node/index.d.mts +22 -6
- package/dist/node/index.mjs +4 -4
- package/dist/recipes/open-helpers.d.mts +1 -1
- package/dist/recipes/open-helpers.mjs +3 -3
- package/dist/revoke-ENfxWkFK.mjs +79 -0
- package/dist/rpc/dump.d.mts +1 -1
- package/dist/rpc/dump.mjs +1 -1
- 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 -2
- package/dist/rpc/transports/ws-server.d.mts +2 -2
- package/dist/rpc/transports/ws-server.mjs +154 -61
- package/dist/{serialization-BD_qXGjd.mjs → serialization-DpLXCy13.mjs} +1 -1
- package/dist/{server-BBaBJaUL.mjs → server-Dl6TU5LE.mjs} +19 -14
- package/dist/server-rX781kz-.d.mts +90 -0
- package/dist/{shared-state-u0y123fi.mjs → shared-state-D4PPieA0.mjs} +4 -4
- package/dist/{shared-state-BlBNYziY.mjs → storage-l2ezeend.mjs} +128 -6
- package/dist/types/index.d.mts +4 -4
- package/dist/{types-BkkQ0Txg.d.mts → types-DZEx4ffs.d.mts} +9 -1
- package/dist/utils/crypto-token.d.mts +24 -0
- package/dist/utils/crypto-token.mjs +45 -0
- package/dist/utils/events.d.mts +1 -1
- package/dist/utils/hash.mjs +1 -1
- package/dist/utils/launch-editor.mjs +1 -1
- package/dist/utils/open.mjs +1 -1
- package/dist/utils/scope.d.mts +11 -0
- package/dist/utils/scope.mjs +15 -0
- package/dist/utils/shared-state.d.mts +1 -1
- package/dist/utils/shared-state.mjs +1 -1
- package/dist/utils/streaming-channel.d.mts +1 -1
- package/dist/utils/structured-clone.mjs +1 -1
- package/dist/{ws-client-CVYX9niP.d.mts → ws-client-D0z0pOhn.d.mts} +1 -1
- package/dist/ws-server-Bc2wBHl-.d.mts +119 -0
- package/package.json +12 -7
- package/skills/devframe/SKILL.md +123 -23
- package/skills/devframe/templates/counter-devframe.ts +14 -4
- package/skills/devframe/templates/spa-devframe.ts +13 -3
- package/skills/devframe/templates/vite-client.ts +3 -2
- package/dist/context-DaKmhhHY.mjs +0 -164
- package/dist/revoke-CL0LSAN9.mjs +0 -803
- package/dist/server-wHlpcdZ9.d.mts +0 -55
- package/dist/utils/human-id.d.mts +0 -8
- package/dist/utils/human-id.mjs +0 -769
- package/dist/ws-server-C1LjmRnp.d.mts +0 -61
- /package/dist/{define-CW9gLnyG.mjs → define-BLWPsH6y.mjs} +0 -0
- /package/dist/{diagnostics-reporter-CBBZwoMv.mjs → diagnostics-reporter-CsIG85Q5.mjs} +0 -0
- /package/dist/{hash-bwOD8RgU.mjs → hash-DFc5WwhO.mjs} +0 -0
- /package/dist/{open-DiQn6zCH.mjs → open-Dusa2Zzd.mjs} +0 -0
- /package/dist/{structured-clone-PdCZwt7F.mjs → structured-clone-CeZOHvkd.mjs} +0 -0
- /package/dist/{structured-clone-jegjz0hM.mjs → structured-clone-XpHLZ8nr.mjs} +0 -0
- /package/dist/{transports-DTFoMUbE.mjs → transports-BmDVn4SF.mjs} +0 -0
|
@@ -836,10 +836,10 @@ function enablePatches() {
|
|
|
836
836
|
const parentType = getArchtype(base);
|
|
837
837
|
let p = path[i];
|
|
838
838
|
if (typeof p !== "string" && typeof p !== "number") p = "" + p;
|
|
839
|
-
if ((parentType === 0 || parentType === 1) && (p === "__proto__" || p === CONSTRUCTOR)) die(
|
|
840
|
-
if (isFunction(base) && p === PROTOTYPE) die(
|
|
839
|
+
if ((parentType === 0 || parentType === 1) && (p === "__proto__" || p === CONSTRUCTOR)) die(19);
|
|
840
|
+
if (isFunction(base) && p === PROTOTYPE) die(19);
|
|
841
841
|
base = get(base, p);
|
|
842
|
-
if (!isObjectish(base)) die(
|
|
842
|
+
if (!isObjectish(base)) die(18, path.join("/"));
|
|
843
843
|
}
|
|
844
844
|
const type = getArchtype(base);
|
|
845
845
|
const value = deepClonePatchValue(patch.value);
|
|
@@ -862,7 +862,7 @@ function enablePatches() {
|
|
|
862
862
|
case 3: return base.delete(patch.value);
|
|
863
863
|
default: return delete base[key];
|
|
864
864
|
}
|
|
865
|
-
default: die(
|
|
865
|
+
default: die(17, op);
|
|
866
866
|
}
|
|
867
867
|
});
|
|
868
868
|
return draft;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { t as devframeReporter } from "./diagnostics-reporter-
|
|
1
|
+
import { t as devframeReporter } from "./diagnostics-reporter-CsIG85Q5.mjs";
|
|
2
2
|
import { defineDiagnostics } from "nostics";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import { dirname } from "pathe";
|
|
5
|
+
import { destr } from "destr";
|
|
3
6
|
//#region src/node/diagnostics.ts
|
|
4
7
|
const diagnostics = defineDiagnostics({
|
|
5
8
|
docsBase: "https://devfra.me/errors",
|
|
@@ -39,6 +42,10 @@ const diagnostics = defineDiagnostics({
|
|
|
39
42
|
DF0033: {
|
|
40
43
|
why: (p) => `Failed to start dev RPC bridge for "${p.id}": ${p.reason}`,
|
|
41
44
|
fix: "Verify the bridge port is free and the devframe setup function does not throw. Pin a port via `cli.port` / `cli.portRange` on the definition, or via `devMiddleware.port` on `viteDevBridge`."
|
|
45
|
+
},
|
|
46
|
+
DF0034: {
|
|
47
|
+
why: (p) => `Scoped RPC registration for namespace "${p.namespace}" received an already-namespaced function name "${p.name}".`,
|
|
48
|
+
fix: "A scoped context auto-namespaces ids. Pass a bare name without a \":\" separator (e.g. `register({ name: \"get-cwd\" })`), or use the unscoped `ctx.base.rpc.register` for a fully-qualified name."
|
|
42
49
|
}
|
|
43
50
|
}
|
|
44
51
|
});
|
|
@@ -918,10 +925,10 @@ function enablePatches() {
|
|
|
918
925
|
const parentType = getArchtype(base);
|
|
919
926
|
let p = path[i];
|
|
920
927
|
if (typeof p !== "string" && typeof p !== "number") p = "" + p;
|
|
921
|
-
if ((parentType === 0 || parentType === 1) && (p === "__proto__" || p === CONSTRUCTOR)) die(
|
|
922
|
-
if (isFunction(base) && p === PROTOTYPE) die(
|
|
928
|
+
if ((parentType === 0 || parentType === 1) && (p === "__proto__" || p === CONSTRUCTOR)) die(19);
|
|
929
|
+
if (isFunction(base) && p === PROTOTYPE) die(19);
|
|
923
930
|
base = get(base, p);
|
|
924
|
-
if (!isObjectish(base)) die(
|
|
931
|
+
if (!isObjectish(base)) die(18, path.join("/"));
|
|
925
932
|
}
|
|
926
933
|
const type = getArchtype(base);
|
|
927
934
|
const value = deepClonePatchValue(patch.value);
|
|
@@ -944,7 +951,7 @@ function enablePatches() {
|
|
|
944
951
|
case 3: return base.delete(patch.value);
|
|
945
952
|
default: return delete base[key];
|
|
946
953
|
}
|
|
947
|
-
default: die(
|
|
954
|
+
default: die(17, op);
|
|
948
955
|
}
|
|
949
956
|
});
|
|
950
957
|
return draft;
|
|
@@ -1016,4 +1023,119 @@ function createSharedState(options) {
|
|
|
1016
1023
|
};
|
|
1017
1024
|
}
|
|
1018
1025
|
//#endregion
|
|
1019
|
-
|
|
1026
|
+
//#region ../../node_modules/.pnpm/perfect-debounce@2.1.0/node_modules/perfect-debounce/dist/index.mjs
|
|
1027
|
+
const DEBOUNCE_DEFAULTS = { trailing: true };
|
|
1028
|
+
/**
|
|
1029
|
+
Debounce functions
|
|
1030
|
+
@param fn - Promise-returning/async function to debounce.
|
|
1031
|
+
@param wait - Milliseconds to wait before calling `fn`. Default value is 25ms
|
|
1032
|
+
@returns A function that delays calling `fn` until after `wait` milliseconds have elapsed since the last time it was called.
|
|
1033
|
+
@example
|
|
1034
|
+
```
|
|
1035
|
+
import { debounce } from 'perfect-debounce';
|
|
1036
|
+
const expensiveCall = async input => input;
|
|
1037
|
+
const debouncedFn = debounce(expensiveCall, 200);
|
|
1038
|
+
for (const number of [1, 2, 3]) {
|
|
1039
|
+
console.log(await debouncedFn(number));
|
|
1040
|
+
}
|
|
1041
|
+
//=> 1
|
|
1042
|
+
//=> 2
|
|
1043
|
+
//=> 3
|
|
1044
|
+
```
|
|
1045
|
+
*/
|
|
1046
|
+
function debounce(fn, wait = 25, options = {}) {
|
|
1047
|
+
options = {
|
|
1048
|
+
...DEBOUNCE_DEFAULTS,
|
|
1049
|
+
...options
|
|
1050
|
+
};
|
|
1051
|
+
if (!Number.isFinite(wait)) throw new TypeError("Expected `wait` to be a finite number");
|
|
1052
|
+
let leadingValue;
|
|
1053
|
+
let timeout;
|
|
1054
|
+
let resolveList = [];
|
|
1055
|
+
let currentPromise;
|
|
1056
|
+
let trailingArgs;
|
|
1057
|
+
const applyFn = (_this, args) => {
|
|
1058
|
+
currentPromise = _applyPromised(fn, _this, args);
|
|
1059
|
+
currentPromise.finally(() => {
|
|
1060
|
+
currentPromise = null;
|
|
1061
|
+
if (options.trailing && trailingArgs && !timeout) {
|
|
1062
|
+
const promise = applyFn(_this, trailingArgs);
|
|
1063
|
+
trailingArgs = null;
|
|
1064
|
+
return promise;
|
|
1065
|
+
}
|
|
1066
|
+
});
|
|
1067
|
+
return currentPromise;
|
|
1068
|
+
};
|
|
1069
|
+
const debounced = function(...args) {
|
|
1070
|
+
if (options.trailing) trailingArgs = args;
|
|
1071
|
+
if (currentPromise) return currentPromise;
|
|
1072
|
+
return new Promise((resolve) => {
|
|
1073
|
+
const shouldCallNow = !timeout && options.leading;
|
|
1074
|
+
clearTimeout(timeout);
|
|
1075
|
+
timeout = setTimeout(() => {
|
|
1076
|
+
timeout = null;
|
|
1077
|
+
const promise = options.leading ? leadingValue : applyFn(this, args);
|
|
1078
|
+
trailingArgs = null;
|
|
1079
|
+
for (const _resolve of resolveList) _resolve(promise);
|
|
1080
|
+
resolveList = [];
|
|
1081
|
+
}, wait);
|
|
1082
|
+
if (shouldCallNow) {
|
|
1083
|
+
leadingValue = applyFn(this, args);
|
|
1084
|
+
resolve(leadingValue);
|
|
1085
|
+
} else resolveList.push(resolve);
|
|
1086
|
+
});
|
|
1087
|
+
};
|
|
1088
|
+
const _clearTimeout = (timer) => {
|
|
1089
|
+
if (timer) {
|
|
1090
|
+
clearTimeout(timer);
|
|
1091
|
+
timeout = null;
|
|
1092
|
+
}
|
|
1093
|
+
};
|
|
1094
|
+
debounced.isPending = () => !!timeout;
|
|
1095
|
+
debounced.cancel = () => {
|
|
1096
|
+
_clearTimeout(timeout);
|
|
1097
|
+
resolveList = [];
|
|
1098
|
+
trailingArgs = null;
|
|
1099
|
+
};
|
|
1100
|
+
debounced.flush = () => {
|
|
1101
|
+
_clearTimeout(timeout);
|
|
1102
|
+
if (!trailingArgs || currentPromise) return;
|
|
1103
|
+
const args = trailingArgs;
|
|
1104
|
+
trailingArgs = null;
|
|
1105
|
+
return applyFn(this, args);
|
|
1106
|
+
};
|
|
1107
|
+
return debounced;
|
|
1108
|
+
}
|
|
1109
|
+
async function _applyPromised(fn, _this, args) {
|
|
1110
|
+
return await fn.apply(_this, args);
|
|
1111
|
+
}
|
|
1112
|
+
//#endregion
|
|
1113
|
+
//#region src/node/storage.ts
|
|
1114
|
+
function createStorage(options) {
|
|
1115
|
+
const { mergeInitialValue = (initialValue, savedValue) => ({
|
|
1116
|
+
...initialValue,
|
|
1117
|
+
...savedValue
|
|
1118
|
+
}), debounce: debounceTime = 100 } = options;
|
|
1119
|
+
let initialValue = options.initialValue;
|
|
1120
|
+
if (fs.existsSync(options.filepath)) try {
|
|
1121
|
+
const savedValue = destr(fs.readFileSync(options.filepath, "utf-8"), { strict: true });
|
|
1122
|
+
initialValue = mergeInitialValue ? mergeInitialValue(options.initialValue, savedValue) : savedValue;
|
|
1123
|
+
} catch (error) {
|
|
1124
|
+
diagnostics.DF0012({
|
|
1125
|
+
filepath: options.filepath,
|
|
1126
|
+
cause: error
|
|
1127
|
+
}, { method: "warn" });
|
|
1128
|
+
initialValue = options.initialValue;
|
|
1129
|
+
}
|
|
1130
|
+
const state = createSharedState({
|
|
1131
|
+
initialValue,
|
|
1132
|
+
enablePatches: false
|
|
1133
|
+
});
|
|
1134
|
+
state.on("updated", debounce((newState) => {
|
|
1135
|
+
fs.mkdirSync(dirname(options.filepath), { recursive: true });
|
|
1136
|
+
fs.writeFileSync(options.filepath, `${JSON.stringify(newState, null, 2)}\n`);
|
|
1137
|
+
}, debounceTime));
|
|
1138
|
+
return state;
|
|
1139
|
+
}
|
|
1140
|
+
//#endregion
|
|
1141
|
+
export { diagnostics as a, createEventEmitter as i, createSharedState as n, nanoid as r, createStorage as t };
|
package/dist/types/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import {
|
|
3
|
-
import { t as DevframeNodeRpcSessionMeta } from "../ws-server-
|
|
4
|
-
export { AgentHandle, AgentManifest, AgentResource, AgentResourceContent, AgentResourceInput, AgentTool, AgentToolInput, ConnectionMeta, DevframeAgentHost, DevframeAgentHostEvents, DevframeBrowserContext, DevframeCapabilities, DevframeCliOptions, DevframeDefineDiagnosticsOptions, DevframeDefinition, DevframeDeploymentKind, DevframeDiagnosticsDefinition, DevframeDiagnosticsHost, DevframeDiagnosticsLogger, DevframeHost, DevframeNodeContext, DevframeNodeRpcSession, DevframeNodeRpcSessionMeta, DevframeRpcClientFunctions, DevframeRpcServerFunctions, DevframeRpcSharedStates, DevframeRuntime, DevframeSetupInfo, DevframeSpaOptions, DevframeViewHost, EntriesToObject, EventEmitter, EventUnsubscribe, EventsMap, PartialWithoutId, RpcBroadcastOptions, RpcFunctionAgentOptions, RpcFunctionsHost, RpcSharedStateGetOptions, RpcSharedStateHost, RpcStreamingChannel, RpcStreamingChannelOptions, RpcStreamingHost, Thenable, defineDevframe };
|
|
1
|
+
import { $ as ScopedServerFunctions, G as DevframeScopedNodeContext, H as EntriesToObject, J as DevframeSettings, K as DevframeScopedNodeRpc, Q as ScopedClientFunctions, S as RpcStreamingHost, St as EventsMap, U as PartialWithoutId, W as Thenable, X as DevframeSettingsStore, Y as DevframeSettingsRegistry, Z as ScopedBroadcastOptions, _ as RpcFunctionsHost, _t as AgentToolInput, a as DevframeDuplicationStrategy, at as DevframeRpcSharedStates, b as RpcStreamingChannel, bt as EventEmitter, c as DevframeSpaOptions, ct as DevframeDiagnosticsDefinition, d as ConnectionMeta, dt as AgentHandle, et as ScopedSharedStates, f as ConnectionMetaWebsocket, ft as AgentManifest, g as RpcBroadcastOptions, gt as AgentTool, h as DevframeNodeRpcSession, ht as AgentResourceInput, i as DevframeDeploymentKind, it as DevframeRpcServerFunctions, l as DevframeWsOptions, lt as DevframeDiagnosticsHost, m as DevframeNodeContext, mt as AgentResourceContent, n as DevframeCliOptions, nt as DevframeViewHost, o as DevframeRuntime, ot as DevframeHost, p as DevframeCapabilities, pt as AgentResource, q as DevframeScopedStreamingHost, r as DevframeDefinition, rt as DevframeRpcClientFunctions, s as DevframeSetupInfo, st as DevframeDefineDiagnosticsOptions, t as DevframeBrowserContext, tt as SettingsForNamespace, u as defineDevframe, ut as DevframeDiagnosticsLogger, v as RpcSharedStateGetOptions, vt as DevframeAgentHost, x as RpcStreamingChannelOptions, xt as EventUnsubscribe, y as RpcSharedStateHost, yt as DevframeAgentHostEvents } from "../devframe-D-gr9sBx.mjs";
|
|
2
|
+
import { g as RpcFunctionAgentOptions } from "../types-DZEx4ffs.mjs";
|
|
3
|
+
import { t as DevframeNodeRpcSessionMeta } from "../ws-server-Bc2wBHl-.mjs";
|
|
4
|
+
export { AgentHandle, AgentManifest, AgentResource, AgentResourceContent, AgentResourceInput, AgentTool, AgentToolInput, ConnectionMeta, ConnectionMetaWebsocket, DevframeAgentHost, DevframeAgentHostEvents, DevframeBrowserContext, DevframeCapabilities, DevframeCliOptions, DevframeDefineDiagnosticsOptions, DevframeDefinition, DevframeDeploymentKind, DevframeDiagnosticsDefinition, DevframeDiagnosticsHost, DevframeDiagnosticsLogger, DevframeDuplicationStrategy, DevframeHost, DevframeNodeContext, DevframeNodeRpcSession, DevframeNodeRpcSessionMeta, DevframeRpcClientFunctions, DevframeRpcServerFunctions, DevframeRpcSharedStates, DevframeRuntime, DevframeScopedNodeContext, DevframeScopedNodeRpc, DevframeScopedStreamingHost, DevframeSettings, DevframeSettingsRegistry, DevframeSettingsStore, DevframeSetupInfo, DevframeSpaOptions, DevframeViewHost, DevframeWsOptions, EntriesToObject, EventEmitter, EventUnsubscribe, EventsMap, PartialWithoutId, RpcBroadcastOptions, RpcFunctionAgentOptions, RpcFunctionsHost, RpcSharedStateGetOptions, RpcSharedStateHost, RpcStreamingChannel, RpcStreamingChannelOptions, RpcStreamingHost, ScopedBroadcastOptions, ScopedClientFunctions, ScopedServerFunctions, ScopedSharedStates, SettingsForNamespace, Thenable, defineDevframe };
|
|
@@ -282,8 +282,16 @@ type RpcFunctionDefinitionToFunction<T extends RpcFunctionDefinitionAny> = T ext
|
|
|
282
282
|
type RpcFunctionDefinitionAny = RpcFunctionDefinition<string, any, any, any, any, any, any>;
|
|
283
283
|
type RpcFunctionDefinitionAnyWithContext<CONTEXT = undefined> = RpcFunctionDefinition<string, any, any, any, any, any, CONTEXT>;
|
|
284
284
|
type RpcDefinitionsToFunctions<T extends readonly RpcFunctionDefinitionAny[]> = EntriesToObject<{ [K in keyof T]: [T[K]['name'], RpcFunctionDefinitionToFunction<T[K]>] }>;
|
|
285
|
+
/**
|
|
286
|
+
* Like {@link RpcDefinitionsToFunctions}, but prefixes every (bare)
|
|
287
|
+
* definition name with `<NS>:`. Use this when functions are defined with
|
|
288
|
+
* bare names and registered through a scoped context
|
|
289
|
+
* (`ctx.scope(NS).rpc.register(...)`), so the augmented registry keys
|
|
290
|
+
* match the namespaced ids stored at runtime.
|
|
291
|
+
*/
|
|
292
|
+
type RpcDefinitionsToFunctionsWithNamespace<NS extends string, T extends readonly RpcFunctionDefinitionAny[]> = EntriesToObject<{ [K in keyof T]: [`${NS}:${T[K]['name'] & string}`, RpcFunctionDefinitionToFunction<T[K]>] }>;
|
|
285
293
|
type RpcDefinitionsFilter<T extends readonly RpcFunctionDefinitionAny[], Type extends RpcFunctionType> = { [K in keyof T]: T[K] extends {
|
|
286
294
|
type: Type;
|
|
287
295
|
} ? T[K] : never };
|
|
288
296
|
//#endregion
|
|
289
|
-
export {
|
|
297
|
+
export { RpcFunctionType as C, Thenable as E, RpcFunctionSetupResult as S, RpcReturnSchema as T, RpcFunctionDefinition as _, RpcDefinitionsFilter as a, RpcFunctionDefinitionBase as b, RpcDump as c, RpcDumpDefinition as d, RpcDumpGetter as f, RpcFunctionAgentOptions as g, RpcDumpStore as h, RpcArgsSchema as i, RpcDumpClientOptions as l, RpcDumpRecordError as m, BirpcReturn$1 as n, RpcDefinitionsToFunctions as o, RpcDumpRecord as p, EntriesToObject as r, RpcDefinitionsToFunctionsWithNamespace as s, BirpcFn as t, RpcDumpCollectionOptions as u, RpcFunctionDefinitionAny as v, RpcFunctionsCollector as w, RpcFunctionDefinitionToFunction as x, RpcFunctionDefinitionAnyWithContext as y };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/utils/crypto-token.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Generate a high-entropy, URL-safe (hex) random token suitable for use as a
|
|
4
|
+
* bearer credential — e.g. the persistent client auth token or an ephemeral
|
|
5
|
+
* remote-dock token. Defaults to 16 bytes (128 bits) of entropy.
|
|
6
|
+
*/
|
|
7
|
+
declare function randomToken(byteLength?: number): string;
|
|
8
|
+
/**
|
|
9
|
+
* Generate a uniformly-distributed string of decimal digits using rejection
|
|
10
|
+
* sampling to avoid modulo bias. Intended for short, human-typed one-time
|
|
11
|
+
* codes (e.g. a 6-digit authentication code). Leading zeros are preserved.
|
|
12
|
+
*/
|
|
13
|
+
declare function randomDigits(length: number): string;
|
|
14
|
+
/**
|
|
15
|
+
* Constant-time string equality. Compares every character so the comparison
|
|
16
|
+
* time does not depend on the position of the first mismatch, mitigating
|
|
17
|
+
* timing side-channels when verifying secrets.
|
|
18
|
+
*
|
|
19
|
+
* Length is treated as public (it short-circuits on differing lengths), which
|
|
20
|
+
* is appropriate for fixed-length codes and tokens.
|
|
21
|
+
*/
|
|
22
|
+
declare function timingSafeEqual(a: string, b: string): boolean;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { randomDigits, randomToken, timingSafeEqual };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region src/utils/crypto-token.ts
|
|
2
|
+
const HEX = "0123456789abcdef";
|
|
3
|
+
/**
|
|
4
|
+
* Generate a high-entropy, URL-safe (hex) random token suitable for use as a
|
|
5
|
+
* bearer credential — e.g. the persistent client auth token or an ephemeral
|
|
6
|
+
* remote-dock token. Defaults to 16 bytes (128 bits) of entropy.
|
|
7
|
+
*/
|
|
8
|
+
function randomToken(byteLength = 16) {
|
|
9
|
+
const bytes = new Uint8Array(byteLength);
|
|
10
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
11
|
+
let out = "";
|
|
12
|
+
for (let i = 0; i < bytes.length; i++) out += HEX[bytes[i] >> 4] + HEX[bytes[i] & 15];
|
|
13
|
+
return out;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Generate a uniformly-distributed string of decimal digits using rejection
|
|
17
|
+
* sampling to avoid modulo bias. Intended for short, human-typed one-time
|
|
18
|
+
* codes (e.g. a 6-digit authentication code). Leading zeros are preserved.
|
|
19
|
+
*/
|
|
20
|
+
function randomDigits(length) {
|
|
21
|
+
const limit = 250;
|
|
22
|
+
const buf = new Uint8Array(1);
|
|
23
|
+
let out = "";
|
|
24
|
+
while (out.length < length) {
|
|
25
|
+
globalThis.crypto.getRandomValues(buf);
|
|
26
|
+
if (buf[0] < limit) out += String(buf[0] % 10);
|
|
27
|
+
}
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Constant-time string equality. Compares every character so the comparison
|
|
32
|
+
* time does not depend on the position of the first mismatch, mitigating
|
|
33
|
+
* timing side-channels when verifying secrets.
|
|
34
|
+
*
|
|
35
|
+
* Length is treated as public (it short-circuits on differing lengths), which
|
|
36
|
+
* is appropriate for fixed-length codes and tokens.
|
|
37
|
+
*/
|
|
38
|
+
function timingSafeEqual(a, b) {
|
|
39
|
+
if (a.length !== b.length) return false;
|
|
40
|
+
let mismatch = 0;
|
|
41
|
+
for (let i = 0; i < a.length; i++) mismatch |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
42
|
+
return mismatch === 0;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { randomDigits, randomToken, timingSafeEqual };
|
package/dist/utils/events.d.mts
CHANGED
package/dist/utils/hash.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as hash } from "../hash-
|
|
1
|
+
import { t as hash } from "../hash-DFc5WwhO.mjs";
|
|
2
2
|
export { hash };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as launchEditor } from "../launch-editor-
|
|
1
|
+
import { t as launchEditor } from "../launch-editor-DPfltGA4.mjs";
|
|
2
2
|
export { launchEditor };
|
package/dist/utils/open.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as open } from "../open-
|
|
1
|
+
import { t as open } from "../open-Dusa2Zzd.mjs";
|
|
2
2
|
export { open };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/utils/scope.d.ts
|
|
2
|
+
/** Whether a name is already namespaced (contains a `:` separator). */
|
|
3
|
+
declare function isQualifiedName(name: string): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Prefix a bare name with `<namespace>:`. Names that already contain a
|
|
6
|
+
* `:` are returned unchanged, so callers can reference another scope's
|
|
7
|
+
* ids explicitly (e.g. `ctx.rpc.call('other-plugin:fn')`).
|
|
8
|
+
*/
|
|
9
|
+
declare function qualifyName(namespace: string, name: string): string;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { isQualifiedName, qualifyName };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/utils/scope.ts
|
|
2
|
+
/** Whether a name is already namespaced (contains a `:` separator). */
|
|
3
|
+
function isQualifiedName(name) {
|
|
4
|
+
return name.includes(":");
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Prefix a bare name with `<namespace>:`. Names that already contain a
|
|
8
|
+
* `:` are returned unchanged, so callers can reference another scope's
|
|
9
|
+
* ids explicitly (e.g. `ctx.rpc.call('other-plugin:fn')`).
|
|
10
|
+
*/
|
|
11
|
+
function qualifyName(namespace, name) {
|
|
12
|
+
return isQualifiedName(name) ? name : `${namespace}:${name}`;
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { isQualifiedName, qualifyName };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { B as SharedStatePatch, F as ImmutableObject, I as ImmutableSet, L as SharedState, M as Immutable, N as ImmutableArray, P as ImmutableMap, R as SharedStateEvents, V as createSharedState, z as SharedStateOptions } from "../devframe-D-gr9sBx.mjs";
|
|
2
2
|
export { Immutable, ImmutableArray, ImmutableMap, ImmutableObject, ImmutableSet, SharedState, SharedStateEvents, SharedStateOptions, SharedStatePatch, createSharedState };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as createSharedState } from "../shared-state-
|
|
1
|
+
import { t as createSharedState } from "../shared-state-D4PPieA0.mjs";
|
|
2
2
|
export { createSharedState };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { A as createStreamReader, C as BufferedChunk, D as StreamReader, E as StreamErrorPayload, O as StreamSink, T as CreateStreamSinkOptions, j as createStreamSink, k as StreamSinkEvents, w as CreateStreamReaderOptions } from "../devframe-D-gr9sBx.mjs";
|
|
2
2
|
export { BufferedChunk, CreateStreamReaderOptions, CreateStreamSinkOptions, StreamErrorPayload, StreamReader, StreamSink, StreamSinkEvents, createStreamReader, createStreamSink };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as structuredCloneStringify, n as structuredCloneParse, r as structuredCloneSerialize, t as structuredCloneDeserialize } from "../structured-clone-
|
|
1
|
+
import { i as structuredCloneStringify, n as structuredCloneParse, r as structuredCloneSerialize, t as structuredCloneDeserialize } from "../structured-clone-CeZOHvkd.mjs";
|
|
2
2
|
export { structuredCloneDeserialize, structuredCloneParse, structuredCloneSerialize, structuredCloneStringify };
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { v as RpcFunctionDefinitionAny } from "./types-DZEx4ffs.mjs";
|
|
2
|
+
import { BirpcGroup, ChannelOptions } from "birpc";
|
|
3
|
+
import { Peer } from "crossws";
|
|
4
|
+
import { NodeAdapter } from "crossws/adapters/node";
|
|
5
|
+
import { Server } from "node:http";
|
|
6
|
+
import { Server as Server$1, ServerOptions } from "node:https";
|
|
7
|
+
|
|
8
|
+
//#region src/rpc/transports/ws-server.d.ts
|
|
9
|
+
interface DevframeNodeRpcSessionMeta {
|
|
10
|
+
id: number;
|
|
11
|
+
/** The crossws peer backing this session's socket. */
|
|
12
|
+
peer?: Peer;
|
|
13
|
+
clientAuthToken?: string;
|
|
14
|
+
isTrusted?: boolean;
|
|
15
|
+
subscribedStates: Set<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Streams this session has subscribed to via
|
|
18
|
+
* `rpc.streaming.subscribe(channel, id)`. Tracked here for O(1) cleanup
|
|
19
|
+
* on disconnect; the wire format is `${channel}\x1F${id}`.
|
|
20
|
+
*/
|
|
21
|
+
subscribedStreams?: Set<string>;
|
|
22
|
+
/**
|
|
23
|
+
* Inbound streams this session is currently uploading to (via
|
|
24
|
+
* `rpc.streaming.upload(channel, id)`). Tracked for cleanup on
|
|
25
|
+
* disconnect; same wire format as `subscribedStreams`.
|
|
26
|
+
*/
|
|
27
|
+
uploadingStreams?: Set<string>;
|
|
28
|
+
}
|
|
29
|
+
interface WsRpcTransportOptions {
|
|
30
|
+
/**
|
|
31
|
+
* Attach to an existing HTTP(S) server, sharing its port. Combine with
|
|
32
|
+
* `path` to bind the WS endpoint to a single route so it coexists with
|
|
33
|
+
* other upgrade handlers on the same server (e.g. a Vite dev server's HMR
|
|
34
|
+
* socket). The shared server's lifecycle is owned by the caller — closing
|
|
35
|
+
* this transport detaches the upgrade listener without closing the server.
|
|
36
|
+
*/
|
|
37
|
+
server?: Server | Server$1;
|
|
38
|
+
/** Port for a newly-created standalone WS server. */
|
|
39
|
+
port?: number;
|
|
40
|
+
/** Host for a newly-created standalone WS server. Defaults to `localhost`. */
|
|
41
|
+
host?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Restrict the WS endpoint to a single upgrade route (e.g. `/__devframe_ws`). When
|
|
44
|
+
* sharing a `server`, non-matching upgrade requests are left untouched for
|
|
45
|
+
* other listeners to handle, so devframe's socket can sit alongside
|
|
46
|
+
* framework sockets (Vite HMR, etc.).
|
|
47
|
+
*/
|
|
48
|
+
path?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Destroy upgrade requests that don't match `path` instead of leaving them
|
|
51
|
+
* for other listeners. Enable this when devframe owns the shared server
|
|
52
|
+
* outright (nothing else handles its upgrades), so an off-route client is
|
|
53
|
+
* rejected promptly rather than left hanging. Default: `false`
|
|
54
|
+
* (coexist-friendly); servers this transport creates itself always
|
|
55
|
+
* destroy unmatched upgrades.
|
|
56
|
+
*/
|
|
57
|
+
destroyUnmatched?: boolean;
|
|
58
|
+
/** When set, a new https.Server is created and the WS endpoint is attached to it. */
|
|
59
|
+
https?: ServerOptions;
|
|
60
|
+
/**
|
|
61
|
+
* Extra origins to accept on the WS upgrade beyond the loopback default.
|
|
62
|
+
* Add your LAN/tunnel origin here when reaching the tool from another host.
|
|
63
|
+
* Pass `false` to disable origin checking entirely (not recommended).
|
|
64
|
+
* Default: loopback-only.
|
|
65
|
+
*/
|
|
66
|
+
allowedOrigins?: readonly string[] | false;
|
|
67
|
+
/**
|
|
68
|
+
* RPC function definitions, used by the per-call wire serializer to
|
|
69
|
+
* dispatch between strict-JSON and structured-clone encoding based
|
|
70
|
+
* on each function's `jsonSerializable` flag.
|
|
71
|
+
*
|
|
72
|
+
* When omitted, all messages fall back to structured-clone — safe but
|
|
73
|
+
* loses dev-time validation for `jsonSerializable: true` declarations.
|
|
74
|
+
*/
|
|
75
|
+
definitions?: ReadonlyMap<string, Pick<RpcFunctionDefinitionAny, 'jsonSerializable'>>;
|
|
76
|
+
onConnected?: (peer: Peer, meta: DevframeNodeRpcSessionMeta) => void;
|
|
77
|
+
onDisconnected?: (peer: Peer, meta: DevframeNodeRpcSessionMeta) => void;
|
|
78
|
+
/** Override the default per-call serializer. Most callers should leave this unset. */
|
|
79
|
+
serialize?: ChannelOptions['serialize'];
|
|
80
|
+
/** Override the default per-call deserializer. Most callers should leave this unset. */
|
|
81
|
+
deserialize?: ChannelOptions['deserialize'];
|
|
82
|
+
}
|
|
83
|
+
interface WsRpcTransport {
|
|
84
|
+
/**
|
|
85
|
+
* The crossws node adapter driving the socket — exposes the connected
|
|
86
|
+
* `peers` and pub/sub. See https://crossws.h3.dev.
|
|
87
|
+
*/
|
|
88
|
+
ws: NodeAdapter;
|
|
89
|
+
/** Remove the upgrade listener from a shared `server` (a no-op otherwise). */
|
|
90
|
+
detach: () => void;
|
|
91
|
+
/**
|
|
92
|
+
* Tear the transport down deterministically: detach from a shared server,
|
|
93
|
+
* force-terminate every connected peer, and close any server this
|
|
94
|
+
* transport created itself (`port` / `https` modes).
|
|
95
|
+
*/
|
|
96
|
+
close: () => Promise<void>;
|
|
97
|
+
}
|
|
98
|
+
declare function isLoopbackHostname(hostname: string): boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Default origin policy for a localhost dev tool: allow requests with no
|
|
101
|
+
* `Origin` header (native, non-browser clients), allow any loopback origin
|
|
102
|
+
* (so cross-port localhost dev setups keep working), and allow explicitly
|
|
103
|
+
* configured origins. Everything else — a real remote page in the dev's
|
|
104
|
+
* browser — is rejected.
|
|
105
|
+
*/
|
|
106
|
+
declare function isAllowedOrigin(origin: string | undefined, allowedOrigins: readonly string[]): boolean;
|
|
107
|
+
/**
|
|
108
|
+
* Attach a WebSocket transport to an existing RPC group, powered by
|
|
109
|
+
* [crossws](https://crossws.h3.dev). Either attach to an existing HTTP(S)
|
|
110
|
+
* `server` (sharing its port, optionally scoped to a `path`), or let this
|
|
111
|
+
* helper create a standalone server from `port` / `host` / `https`.
|
|
112
|
+
*
|
|
113
|
+
* Returns the crossws node adapter plus `detach` (remove the upgrade
|
|
114
|
+
* listener from a shared `server`) and `close` (full deterministic
|
|
115
|
+
* teardown).
|
|
116
|
+
*/
|
|
117
|
+
declare function attachWsRpcTransport<ClientFunctions extends object, ServerFunctions extends object>(rpcGroup: BirpcGroup<ClientFunctions, ServerFunctions, false>, options?: WsRpcTransportOptions): WsRpcTransport;
|
|
118
|
+
//#endregion
|
|
119
|
+
export { isAllowedOrigin as a, attachWsRpcTransport as i, WsRpcTransport as n, isLoopbackHostname as o, WsRpcTransportOptions as r, DevframeNodeRpcSessionMeta as t };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devframe",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.6.0-beta.2",
|
|
5
5
|
"description": "Framework for building generic devframes",
|
|
6
6
|
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -40,13 +40,14 @@
|
|
|
40
40
|
"./rpc/transports/ws-server": "./dist/rpc/transports/ws-server.mjs",
|
|
41
41
|
"./types": "./dist/types/index.mjs",
|
|
42
42
|
"./utils/colors": "./dist/utils/colors.mjs",
|
|
43
|
+
"./utils/crypto-token": "./dist/utils/crypto-token.mjs",
|
|
43
44
|
"./utils/events": "./dist/utils/events.mjs",
|
|
44
45
|
"./utils/hash": "./dist/utils/hash.mjs",
|
|
45
|
-
"./utils/human-id": "./dist/utils/human-id.mjs",
|
|
46
46
|
"./utils/launch-editor": "./dist/utils/launch-editor.mjs",
|
|
47
47
|
"./utils/nanoid": "./dist/utils/nanoid.mjs",
|
|
48
48
|
"./utils/open": "./dist/utils/open.mjs",
|
|
49
49
|
"./utils/promise": "./dist/utils/promise.mjs",
|
|
50
|
+
"./utils/scope": "./dist/utils/scope.mjs",
|
|
50
51
|
"./utils/serve-static": "./dist/utils/serve-static.mjs",
|
|
51
52
|
"./utils/shared-state": "./dist/utils/shared-state.mjs",
|
|
52
53
|
"./utils/streaming-channel": "./dist/utils/streaming-channel.mjs",
|
|
@@ -71,12 +72,14 @@
|
|
|
71
72
|
"@valibot/to-json-schema": "^1.7.0",
|
|
72
73
|
"birpc": "^4.0.0",
|
|
73
74
|
"cac": "^7.0.0",
|
|
75
|
+
"crossws": "^0.4.8",
|
|
76
|
+
"destr": "^2.0.5",
|
|
74
77
|
"h3": "2.0.1-rc.22",
|
|
75
78
|
"mrmime": "^2.0.1",
|
|
76
|
-
"nostics": "^
|
|
79
|
+
"nostics": "^1.1.4",
|
|
77
80
|
"pathe": "^2.0.3",
|
|
78
|
-
"
|
|
79
|
-
"
|
|
81
|
+
"ufo": "^1.6.4",
|
|
82
|
+
"valibot": "^1.4.1"
|
|
80
83
|
},
|
|
81
84
|
"devDependencies": {
|
|
82
85
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
@@ -93,7 +96,8 @@
|
|
|
93
96
|
"tinyglobby": "^0.2.16",
|
|
94
97
|
"tsdown": "^0.22.0",
|
|
95
98
|
"ua-parser-modern": "^0.1.1",
|
|
96
|
-
"whenexpr": "^0.1.2"
|
|
99
|
+
"whenexpr": "^0.1.2",
|
|
100
|
+
"ws": "^8.21.0"
|
|
97
101
|
},
|
|
98
102
|
"inlinedDependencies": {
|
|
99
103
|
"bundle-name": "4.1.0",
|
|
@@ -124,6 +128,7 @@
|
|
|
124
128
|
},
|
|
125
129
|
"scripts": {
|
|
126
130
|
"build": "tsdown",
|
|
127
|
-
"watch": "tsdown --watch"
|
|
131
|
+
"watch": "tsdown --watch",
|
|
132
|
+
"typecheck": "tsc --noEmit"
|
|
128
133
|
}
|
|
129
134
|
}
|