You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
pnpm test# pnpm build && vitest (api snapshot guards against stale dist)
25
-
pnpm typecheck # tsc --noEmit
25
+
pnpm typecheck #turbo run typecheck (per-package tsc --noEmit)
26
26
pnpm lint --fix # ESLint via @antfu/eslint-config
27
27
pnpm start # tsx src/index.ts
28
28
```
29
29
30
30
The `pnpm test` script intentionally runs `build` first so `tsnapi` snapshots compare against fresh `dist/`. `tsdown-stale-guard` enforces this in `test/api-snapshot.test.ts`.
31
31
32
+
`pnpm typecheck` fans out through Turbo: every workspace package owns a `"typecheck": "tsc --noEmit"` script and its own `tsconfig.json` (extending `tsconfig.base.json` with an explicit `include`). Cross-package imports resolve to source through the `paths` aliases in `tsconfig.base.json`, so no prior build is needed. Any package added under `packages/*` or `plugins/*` is typechecked automatically once it ships that `typecheck` script — add one to every new package so it can't silently skip type errors.
33
+
32
34
## Conventions
33
35
34
36
- RPC functions must use `defineRpcFunction`; always namespace IDs (`my-plugin:fn-name`).
> Scoped RPC registration for namespace "`{namespace}`" received an already-namespaced function name "`{name}`".
10
+
11
+
## Cause
12
+
13
+
A [scoped context](../guide/scoped-context) auto-namespaces the ids you pass it. `ctx.scope('my-plugin').rpc.register(...)` therefore expects a **bare** function name and stores it as `my-plugin:<name>`. Passing a name that already contains a `:` separator would produce a double-prefixed id, so registration throws instead.
- Pass a bare name (no `:` separator) to the scoped `register`.
30
+
- To register a fully-qualified name on purpose, use the unscoped host: `ctx.base.rpc.register(...)` (server) or `client.scope(...).base.client.register(...)` (browser).
31
+
32
+
## Source
33
+
34
+
-[`packages/devframe/src/node/scope.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/scope.ts) — `register()` / `update()` throw this when the supplied definition name is already namespaced.
> Dock entry "`{id}`" cannot set groupId to its own id
10
+
11
+
## Cause
12
+
13
+
A dock entry registered with `groupId` pointing at its own `id`. `groupId` is a pointer to a *different* group entry the entry belongs to, so a self-reference would describe an entry that collapses under itself.
14
+
15
+
## Fix
16
+
17
+
- Point `groupId` at the `id` of a `type: 'group'` entry, such as `groupId: 'nuxt'`.
18
+
- Omit `groupId` entirely to keep the entry as a normal top-level dock entry.
19
+
20
+
## Source
21
+
22
+
-[`packages/hub/src/node/host-docks.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-docks.ts) — `DevframeDocksHost.register()` and `update()` throw this when `view.groupId === view.id`.
> Dock group "`{id}`" cannot itself belong to a group (nested groups are unsupported)
10
+
11
+
## Cause
12
+
13
+
A `type: 'group'` entry was registered with `groupId` set. Dock grouping is one level deep: a group collects member entries, but a group cannot itself be a member of another group.
14
+
15
+
## Fix
16
+
17
+
- Remove `groupId` from the group entry so it stays a top-level dock-bar button.
18
+
- Keep members one level under their group; place each member's `groupId` on the leaf entry, not on another group.
19
+
20
+
## Source
21
+
22
+
-[`packages/hub/src/node/host-docks.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/host-docks.ts) — `DevframeDocksHost.register()` and `update()` throw this when `view.type === 'group'` and `view.groupId` is set.
> Devframe "`{name}`" (id "`{id}`") is already mounted on this hub
10
+
11
+
## Cause
12
+
13
+
`mountDevframe(ctx, def)` was called with a devframe whose `id` already belongs to another devframe mounted on the same hub. Devframes are deduplicated by `id`, and the definition's `duplicationStrategy` is `'warn'` (the default) or `'throw'`.
14
+
15
+
## Fix
16
+
17
+
Set `duplicationStrategy` on the definition to choose how duplicates are handled:
18
+
19
+
-`'warn'` (default) — keep the first registration, drop the later one, and emit this warning.
20
+
-`'silent'` — drop the later one without warning.
21
+
-`'throw'` — surface duplicates as a thrown error.
22
+
-`'duplicate'` — let every instance coexist under a disambiguated dock id (`my-tool`, `my-tool-2`, …).
23
+
24
+
Otherwise, remove the redundant `mountDevframe` call so each devframe is mounted once.
25
+
26
+
## Source
27
+
28
+
-[`packages/hub/src/node/mount-devframe.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/mount-devframe.ts) — `mountDevframe()` emits this when a devframe sharing an already-mounted `id` is mounted and the strategy is not `'duplicate'`.
TypeScript types flow through from the server's `defineRpcFunction` definitions, so argument and return shapes are known at the call site.
111
+
The unscoped `rpc.call('my-devframe:get-modules', ...)` works too. Either way, TypeScript types flow through from the server's `defineRpcFunction` definitions, so argument and return shapes are known at the call site.
110
112
111
113
## Registering client functions
112
114
113
-
The client can register functions that the server calls via `ctx.rpc.broadcast`:
115
+
The client can register functions that the server calls via `rpc.broadcast`:
Client-side mutations round-trip through the server before reappearing locally. See [Shared State](./shared-state) for the full API.
148
150
151
+
## Settings
152
+
153
+
A scoped client also exposes a top-level persisted `settings` store, synced from the server. Read and write per-user (`global`) or per-workspace (`project`) values:
0 commit comments