@deepseek-ai/dsh-client-store 0.1.2-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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DeepSeek
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
2
+ # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
+ # after editing either side, bring the other along and re-record with:
4
+ # pnpm run verify-translation-pairing --write packages/client/store/README.md
5
+ README.md: 49990551a47e81cdeeeeee0daa56b6fadb956fe6
6
+ README.zh.md: 97c29b9f776c06c5b8eddd382d1d3dc58e29a8d5
package/README.md ADDED
@@ -0,0 +1,45 @@
1
+ ---
2
+ description: "Observable browser state stores with explicit snapshots, subscriptions, and lifecycle ownership."
3
+ kind: "package-library"
4
+ ---
5
+ # @deepseek-ai/dsh-client-store
6
+
7
+ English | [中文](README.zh.md)
8
+
9
+ ## Summary
10
+
11
+ React-free observable and snapshot-store primitives shared by Client controllers and renderer adapters. The package owns synchronous and animation-frame publication, Immer-backed updates, shallow equality, and optional browser persistence; React hook construction remains in `@deepseek-ai/dsh-client-ui-renderer`. Use it when Client state must publish stable snapshots without depending on React.
12
+
13
+ ## Table of Contents
14
+
15
+ - [Model Experience](#model-experience)
16
+ - [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
17
+ - [Dev Note](#dev-note)
18
+
19
+ -----
20
+
21
+ <a id="model-experience"></a>
22
+ ## Model Experience
23
+
24
+ None, as this package provides browser-side state primitives and registers nothing model-facing.
25
+
26
+ #### KV Cache effect
27
+
28
+ None; the stores neither assemble nor send model requests.
29
+
30
+ ## Known Limitations and Deferred Work
31
+
32
+ <a id="known-limitations-and-deferred-work"></a>
33
+
34
+ - **Persistence is browser-local** — persisted stores use JSON in `localStorage`; non-browser runtimes disable persistence, and the package provides no cross-device synchronization.
35
+
36
+
37
+ <a id="dev-note"></a>
38
+ ### Dev Note
39
+
40
+ <details>
41
+ <summary>Working context for maintainers — click to expand</summary>
42
+
43
+ None.
44
+
45
+ </details>
package/README.zh.md ADDED
@@ -0,0 +1,45 @@
1
+ ---
2
+ description: "具有显式快照、订阅与生命周期所有权的浏览器可观察状态 store。"
3
+ kind: "package-library"
4
+ ---
5
+ # @deepseek-ai/dsh-client-store
6
+
7
+ [English](README.md) | 中文
8
+
9
+ ## 概述
10
+
11
+ 供 Client controller 与 renderer adapter 共用的不依赖 React 的 observable 和 snapshot-store 基础设施。本包负责同步与 animation-frame 发布、基于 Immer 的更新、浅比较和可选的浏览器持久化;React hook 的构造仍属于 `@deepseek-ai/dsh-client-ui-renderer`。当 Client 状态必须在不依赖 React 的情况下发布稳定 snapshot 时,请使用它。
12
+
13
+ ## 目录
14
+
15
+ - [模型体验](#model-experience)
16
+ - [已知限制与暂缓事项](#known-limitations-and-deferred-work)
17
+ - [开发备注](#dev-note)
18
+
19
+ -----
20
+
21
+ <a id="model-experience"></a>
22
+ ## 模型体验
23
+
24
+ 无,因为本包提供浏览器侧状态基础设施,不注册任何面向模型的内容。
25
+
26
+ #### KV Cache 影响
27
+
28
+ 无;这些 store 既不组装也不发送模型请求。
29
+
30
+ ## 已知限制与暂缓事项
31
+
32
+ <a id="known-limitations-and-deferred-work"></a>
33
+
34
+ - **持久化仅限浏览器本地**——持久化 store 使用 `localStorage` 中的 JSON;非浏览器运行时会禁用持久化,本包也不提供跨设备同步。
35
+
36
+
37
+ <a id="dev-note"></a>
38
+ ### 开发备注
39
+
40
+ <details>
41
+ <summary>维护者工作上下文——点击展开</summary>
42
+
43
+ 无。
44
+
45
+ </details>
package/lib/index.js ADDED
@@ -0,0 +1,180 @@
1
+ import { createStore } from "zustand/vanilla";
2
+ import { subscribeWithSelector } from "zustand/middleware";
3
+ import { shallow } from "zustand/shallow";
4
+ import { freeze, produce } from "immer";
5
+ //#region lib/types/index.js
6
+ /**
7
+ * React-free snapshot store engine (zustand vanilla + immer + subscribeWithSelector +
8
+ * rafFlush middleware + opt-in persist + dev freeze) plus the declarative
9
+ * shell over it: {@link defineStore} bakes an init/persist/actions literal
10
+ * into a {@link StoreHandle}, the registration-side store seat of slot
11
+ * terminals. Engine products are bare observables — subscribe/getSnapshot/
12
+ * update/set, NO selector hook. Hook synthesis is ui-renderer's (the one
13
+ * uSES bridge, cached per source at the binding site).
14
+ */
15
+ /**
16
+ * Notify an observer set without allowing one callback to starve the rest.
17
+ * @param listeners - current observer callbacks; copied before dispatch.
18
+ * @param label - diagnostic owner prefix.
19
+ * @param args - callback arguments.
20
+ */
21
+ function notifySubscribers(listeners, label, ...args) {
22
+ for (const listener of [...listeners]) try {
23
+ listener(...args);
24
+ } catch (error) {
25
+ console.error(`${label} subscriber failed:`, error);
26
+ }
27
+ }
28
+ /**
29
+ * Shallow equality for selector slices (zustand/shallow semantics; travels
30
+ * with the engine so hook consumers need no zustand dependency).
31
+ * @param a - left value.
32
+ * @param b - right value.
33
+ * @returns whether the values are shallowly equal.
34
+ */
35
+ function shallowEqual(a, b) {
36
+ return shallow(a, b);
37
+ }
38
+ /** Batches subscriber notification into one flush per animation frame. */
39
+ function rafBatch(notify) {
40
+ const schedule = typeof requestAnimationFrame === "function" ? (fn) => {
41
+ requestAnimationFrame(() => {
42
+ fn();
43
+ });
44
+ } : (fn) => {
45
+ queueMicrotask(fn);
46
+ };
47
+ let scheduled = false;
48
+ return () => {
49
+ if (scheduled) return;
50
+ scheduled = true;
51
+ schedule(() => {
52
+ scheduled = false;
53
+ notify();
54
+ });
55
+ };
56
+ }
57
+ /**
58
+ * Create a snapshot store.
59
+ *
60
+ * Flush default is 'sync' (controlled inputs need same-tick echo); frame-driven
61
+ * stores opt into 'raf', where a frame's worth of updates coalesces into one
62
+ * notification. Known raf-mode tradeoff: a component mounting mid-frame reads
63
+ * fresh state while existing subscribers hear it next flush — transient
64
+ * frame-level skew, same nature as the object layer's microtask batching.
65
+ *
66
+ * @param init - initial state.
67
+ * @param opts - flush mode and opt-in persistence (localStorage, keyed by name).
68
+ * @returns the store.
69
+ */
70
+ function createSnapshotStore(init, opts) {
71
+ const withSelector = subscribeWithSelector(() => init);
72
+ const api = createStore()(withSelector);
73
+ if (opts?.persist) attachPersistence(api, opts.persist.name);
74
+ let subscribe = (fn) => api.subscribe(() => {
75
+ notifySubscribers([fn], "[client-store]");
76
+ });
77
+ if (opts?.flush === "raf") {
78
+ const listeners = /* @__PURE__ */ new Set();
79
+ const flush = rafBatch(() => {
80
+ notifySubscribers(listeners, "[client-store]");
81
+ });
82
+ api.subscribe(flush);
83
+ subscribe = (fn) => {
84
+ listeners.add(fn);
85
+ return () => {
86
+ listeners.delete(fn);
87
+ };
88
+ };
89
+ }
90
+ return {
91
+ getSnapshot: () => api.getState(),
92
+ subscribe: (fn) => subscribe(fn),
93
+ update: (mutator) => {
94
+ api.setState(produce(api.getState(), (draft) => {
95
+ mutator(draft);
96
+ }), true);
97
+ },
98
+ set: (next) => {
99
+ api.setState(devFreeze(next), true);
100
+ }
101
+ };
102
+ }
103
+ /**
104
+ * Whole-value JSON persistence to localStorage. Hand-rolled instead of the
105
+ * zustand persist middleware: its write path spreads state into an object
106
+ * (`partialize({ ...get() })`), exploding primitive state (a persisted string
107
+ * draft becomes {0:'h',1:'e',...}) — not fixable via merge/deserialize options
108
+ * because the corruption happens before serialization. Storage failures
109
+ * (quota, private mode) only disable persistence, never break the store.
110
+ */
111
+ function attachPersistence(api, name) {
112
+ if (typeof localStorage === "undefined") return;
113
+ try {
114
+ const raw = localStorage.getItem(name);
115
+ if (raw !== null) api.setState(devFreeze(JSON.parse(raw)), true);
116
+ } catch (error) {
117
+ console.error(`snapshot store '${name}' rehydration failed:`, error);
118
+ }
119
+ api.subscribe((state) => {
120
+ try {
121
+ localStorage.setItem(name, JSON.stringify(state));
122
+ } catch (error) {
123
+ console.error(`snapshot store '${name}' persistence failed:`, error);
124
+ }
125
+ });
126
+ }
127
+ /** Deep-freeze draftable wholesale-set state outside production: set() bypasses immer's freeze. */
128
+ function devFreeze(value) {
129
+ return freeze(value, true);
130
+ }
131
+ /**
132
+ * Declare a store: initial state, optional persistence, and the full write
133
+ * set as pure draft mutators. The returned handle is the registration
134
+ * currency of the store seat — its identity keys instance sharing. Satisfies
135
+ * ui-slots' DefineStore contract (the handle/instance are the engine-extended
136
+ * subtypes).
137
+ *
138
+ * The `A & ActionsDecl<T>` actions position is load-bearing: T resolves from
139
+ * `init` in the first inference round, and the intersection then contextually
140
+ * types each mutator's draft parameter (context-sensitive functions defer),
141
+ * so call sites write `(d, x: X) => { ... }` with no draft annotation. If a
142
+ * future TS version breaks this single-literal inference, the design's
143
+ * documented fallback is currying (`defineStore(init).actions({...})`).
144
+ * @param decl - init lambda (fresh state per instance), optional persist key, actions table.
145
+ * @returns the store handle.
146
+ */
147
+ function defineStore(decl) {
148
+ return {
149
+ spec: decl,
150
+ create(scopeKey) {
151
+ const persistKey = decl.persist === void 0 ? void 0 : scopeKey === void 0 ? decl.persist : `${decl.persist}.${scopeKey}`;
152
+ const store = createSnapshotStore(decl.init(), persistKey !== void 0 ? { persist: { name: persistKey } } : void 0);
153
+ const actions = {};
154
+ for (const key of Object.keys(decl.actions)) {
155
+ const mutate = decl.actions[key];
156
+ actions[key] = (...params) => {
157
+ store.update((draft) => {
158
+ mutate(draft, ...params);
159
+ });
160
+ };
161
+ }
162
+ return {
163
+ actions,
164
+ getSnapshot: () => store.getSnapshot(),
165
+ subscribe: (fn) => store.subscribe(fn),
166
+ store,
167
+ clearPersisted: () => {
168
+ if (persistKey === void 0 || typeof localStorage === "undefined") return;
169
+ try {
170
+ localStorage.removeItem(persistKey);
171
+ } catch {}
172
+ }
173
+ };
174
+ }
175
+ };
176
+ }
177
+ //#endregion
178
+ export { createSnapshotStore, defineStore, notifySubscribers, shallowEqual };
179
+
180
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,25 @@
1
+ //#region lib/types/invariant.js
2
+ /**
3
+ * Package-owned invariant companion for `@deepseek-ai/dsh-client-store`.
4
+ * @module @deepseek-ai/dsh-client-store/invariant
5
+ */
6
+ const PACKAGE_NAME = "@deepseek-ai/dsh-client-store";
7
+ /** Cordis companion plugin name. */
8
+ const name = "client-store-invariant";
9
+ /** Service required before the companion can reserve package ownership. */
10
+ const inject = ["invariants"];
11
+ /**
12
+ * No runtime invariant: the package exports a library engine and creates no
13
+ * process-global state; each store instance is covered by its owning tests.
14
+ */
15
+ const install = () => {};
16
+ /**
17
+ * Register this package's invariant companion.
18
+ * @param ctx - Cordis context carrying the invariant service.
19
+ * @returns the installed registration's disposer after setup succeeds.
20
+ */
21
+ const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
22
+ //#endregion
23
+ export { apply, inject, name };
24
+
25
+ //# sourceMappingURL=invariant.js.map
@@ -0,0 +1,122 @@
1
+ /** Framework-neutral snapshot and store contracts. */
2
+ /** Minimal observable snapshot source shared by controllers, stores, and render adapters. */
3
+ export interface ObservableSnapshot<T> {
4
+ /** Read the cached snapshot reference. */
5
+ getSnapshot(): T;
6
+ /**
7
+ * Subscribe to snapshot invalidation.
8
+ * @param fn - invalidation callback.
9
+ * @returns unsubscribe function.
10
+ */
11
+ subscribe(fn: () => void): () => void;
12
+ }
13
+ /**
14
+ * Typed selector hook over a snapshot source. Canonical shape for the whole
15
+ * slot system (ui-renderer's engine hook is structurally identical; the
16
+ * framework is the only party that ever constructs one).
17
+ */
18
+ export type SnapshotSelectorHook<T> = <S>(sel: (s: T) => S, eq?: (a: S, b: S) => boolean) => S;
19
+ /**
20
+ * Selector hook over a source that follows the current session. The hook is
21
+ * always present, while its selected value is absent whenever no session is
22
+ * current. This keeps hook call sites stable across no-session/session
23
+ * transitions without pretending that a session snapshot exists.
24
+ */
25
+ export type MaybeSnapshotSelectorHook<T> = <S>(sel: (s: T) => S, eq?: (a: S, b: S) => boolean) => S | undefined;
26
+ /**
27
+ * Action declaration table: pure immer-draft transforms over the store state,
28
+ * declared as the store's complete write set (the audit face — components can
29
+ * only write through these).
30
+ */
31
+ export type ActionsDecl<T> = Record<string, (draft: T, ...params: any[]) => void>;
32
+ /**
33
+ * Draft-stripped callback form of an actions table: what components
34
+ * (`props.actions`) and inject factories receive — the framework bakes the
35
+ * draft parameter away by binding each action to the resolved instance.
36
+ */
37
+ export type BakedActions<T, A extends ActionsDecl<T>> = {
38
+ [K in keyof A]: A[K] extends (draft: T, ...params: infer P) => void ? (...params: P) => void : never;
39
+ };
40
+ /**
41
+ * Store declaration spec: initial-state factory (a lambda so every instance
42
+ * gets a fresh state), optional persistence key (mechanical, framework-run),
43
+ * and the actions write set.
44
+ */
45
+ export interface StoreSpec<T, A extends ActionsDecl<T>> {
46
+ init: () => T;
47
+ persist?: string;
48
+ actions: A;
49
+ }
50
+ /**
51
+ * Live engine instance: the create() product consumed by the render machinery
52
+ * and by tests. A bare snapshot source plus the baked write set — no React
53
+ * hook rides the engine product (the engine lives in this React-free package);
54
+ * the render machinery binds the `useStore` hook from this source on its own
55
+ * side, cached per instance. Production components and render paths never
56
+ * call create() themselves — instance lifecycle is the framework's.
57
+ */
58
+ export interface StoreInstance<T, A extends ActionsDecl<T>> {
59
+ readonly actions: BakedActions<T, A>;
60
+ getSnapshot(): T;
61
+ /**
62
+ * Subscribe to state changes (uSES subscribe side).
63
+ * @param fn - change callback.
64
+ * @returns unsubscribe.
65
+ */
66
+ subscribe(fn: () => void): () => void;
67
+ /**
68
+ * Drop this instance's persisted value (no-op for non-persist specs). The
69
+ * framework calls it when the owning scope dies for good — a pruned session
70
+ * must not leave orphaned storage keys behind.
71
+ */
72
+ clearPersisted(): void;
73
+ }
74
+ /**
75
+ * Store handle: spec + state/actions types + shared identity + instance
76
+ * factory in one value. Handles are constructed in apply world (shared across
77
+ * registrations of one plugin) or by the framework from a registrant's
78
+ * factory (exclusive). Never export a handle at module level — module-cache
79
+ * identity is a disguised singleton across plugin reloads.
80
+ */
81
+ export interface StoreHandle<T, A extends ActionsDecl<T>> {
82
+ readonly spec: StoreSpec<T, A>;
83
+ /**
84
+ * Create a live engine instance (framework machinery and tests only).
85
+ * @param scopeKey - session id for session-scope instances; suffixes the
86
+ * persist key so per-session instances persist independently (root-scope
87
+ * instances omit it).
88
+ * @returns a fresh instance seeded from `spec.init()`.
89
+ */
90
+ create(scopeKey?: string): StoreInstance<T, A>;
91
+ }
92
+ /**
93
+ * Exclusive-store registration form: the registrant passes the factory itself
94
+ * and the framework calls it per entry x scope (no shared identity exists).
95
+ */
96
+ export type StoreFactory = () => StoreHandle<any, any>;
97
+ /** The register `store` option position: a shared handle or an exclusive factory. */
98
+ export type StoreDecl = StoreHandle<any, any> | StoreFactory;
99
+ /** Normalize a store declaration to its handle type (factories yield their return). */
100
+ export type HandleOf<H> = H extends () => infer R ? R : H;
101
+ /**
102
+ * Handle-keyed baked actions: the `actions` parameter of an inject factory
103
+ * whose registration declared a store — the same baked callback set the
104
+ * component receives via {@link PropsStore}.
105
+ */
106
+ export type BoundActions<H> = H extends StoreHandle<infer T, infer A> ? BakedActions<T, A> : never;
107
+ /**
108
+ * The store props share, derived from the declared handle: a typed selector
109
+ * hook plus the baked write set. Components never see the instance itself
110
+ * (no update/set — reads via useStore, writes via the declared actions only).
111
+ */
112
+ export type PropsStore<H> = H extends StoreHandle<infer T, infer A> ? {
113
+ useStore: SnapshotSelectorHook<T>;
114
+ actions: BakedActions<T, A>;
115
+ } : object;
116
+ /**
117
+ * The defineStore contract (implementation lives beside this declaration,
118
+ * bound to the snapshot-store engine): spec in, handle out, with T inferred
119
+ * from `init` and the actions table constrained by T.
120
+ */
121
+ export type DefineStore = <T, A extends ActionsDecl<T>>(spec: StoreSpec<T, A>) => StoreHandle<T, A>;
122
+ //# sourceMappingURL=contract.d.ts.map
@@ -0,0 +1,92 @@
1
+ import type { ActionsDecl, ObservableSnapshot, StoreHandle, StoreInstance, StoreSpec } from './contract.ts';
2
+ export type { ActionsDecl, BakedActions, BoundActions, DefineStore, HandleOf, MaybeSnapshotSelectorHook, ObservableSnapshot, PropsStore, SnapshotSelectorHook, StoreDecl, StoreFactory, StoreHandle, StoreInstance, StoreSpec, } from './contract.ts';
3
+ /** Writable snapshot store (bare data face; React selector hooks are synthesized in ui-renderer). */
4
+ export interface SnapshotStore<T> extends ObservableSnapshot<T> {
5
+ /**
6
+ * Mutate the state through an immer draft.
7
+ * @param mutator - draft mutator.
8
+ */
9
+ update(mutator: (draft: T) => void): void;
10
+ /**
11
+ * Replace the state wholesale.
12
+ * @param next - next state.
13
+ */
14
+ set(next: T): void;
15
+ }
16
+ /**
17
+ * Notify an observer set without allowing one callback to starve the rest.
18
+ * @param listeners - current observer callbacks; copied before dispatch.
19
+ * @param label - diagnostic owner prefix.
20
+ * @param args - callback arguments.
21
+ */
22
+ export declare function notifySubscribers<Args extends readonly unknown[]>(listeners: Iterable<(...args: Args) => void>, label: string, ...args: Args): void;
23
+ /**
24
+ * Shallow equality for selector slices (zustand/shallow semantics; travels
25
+ * with the engine so hook consumers need no zustand dependency).
26
+ * @param a - left value.
27
+ * @param b - right value.
28
+ * @returns whether the values are shallowly equal.
29
+ */
30
+ export declare function shallowEqual(a: unknown, b: unknown): boolean;
31
+ /**
32
+ * Create a snapshot store.
33
+ *
34
+ * Flush default is 'sync' (controlled inputs need same-tick echo); frame-driven
35
+ * stores opt into 'raf', where a frame's worth of updates coalesces into one
36
+ * notification. Known raf-mode tradeoff: a component mounting mid-frame reads
37
+ * fresh state while existing subscribers hear it next flush — transient
38
+ * frame-level skew, same nature as the object layer's microtask batching.
39
+ *
40
+ * @param init - initial state.
41
+ * @param opts - flush mode and opt-in persistence (localStorage, keyed by name).
42
+ * @returns the store.
43
+ */
44
+ export declare function createSnapshotStore<T>(init: T, opts?: {
45
+ flush?: 'raf' | 'sync';
46
+ persist?: {
47
+ name: string;
48
+ };
49
+ }): SnapshotStore<T>;
50
+ /** A live engine instance: the contract instance plus the raw engine store. */
51
+ export interface EngineStoreInstance<T, A extends ActionsDecl<T>> extends StoreInstance<T, A> {
52
+ /** The underlying engine store (framework/test API; components never see it). */
53
+ readonly store: SnapshotStore<T>;
54
+ }
55
+ /** The engine-backed handle: create() narrowed to the engine instance. */
56
+ export interface EngineStoreHandle<T, A extends ActionsDecl<T>> extends StoreHandle<T, A> {
57
+ /**
58
+ * Construct a live engine instance (see the contract JSDoc on
59
+ * {@link StoreHandle.create} for scopeKey/persist semantics).
60
+ *
61
+ * Known boundary: the persist key is the storage identity, so multiple live
62
+ * instances created under the same resolved key share (and cross-pollute)
63
+ * one localStorage entry. Instance uniqueness per key is the caller's
64
+ * responsibility — production is safe because the framework caches one
65
+ * instance per handle x scope key; tests wanting isolation use distinct
66
+ * scope keys or persist-free declarations (multi-create freedom is a
67
+ * feature there, so create() deliberately does not dedupe or throw).
68
+ * @param scopeKey - session id for session-scope instances; omitted for root scope.
69
+ * @returns the engine instance.
70
+ */
71
+ create(scopeKey?: string): EngineStoreInstance<T, A>;
72
+ }
73
+ /**
74
+ * Declare a store: initial state, optional persistence, and the full write
75
+ * set as pure draft mutators. The returned handle is the registration
76
+ * currency of the store seat — its identity keys instance sharing. Satisfies
77
+ * ui-slots' DefineStore contract (the handle/instance are the engine-extended
78
+ * subtypes).
79
+ *
80
+ * The `A & ActionsDecl<T>` actions position is load-bearing: T resolves from
81
+ * `init` in the first inference round, and the intersection then contextually
82
+ * types each mutator's draft parameter (context-sensitive functions defer),
83
+ * so call sites write `(d, x: X) => { ... }` with no draft annotation. If a
84
+ * future TS version breaks this single-literal inference, the design's
85
+ * documented fallback is currying (`defineStore(init).actions({...})`).
86
+ * @param decl - init lambda (fresh state per instance), optional persist key, actions table.
87
+ * @returns the store handle.
88
+ */
89
+ export declare function defineStore<T, A extends ActionsDecl<T>>(decl: StoreSpec<T, A> & {
90
+ actions: A & ActionsDecl<T>;
91
+ }): EngineStoreHandle<T, A>;
92
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Package-owned invariant companion for `@deepseek-ai/dsh-client-store`.
3
+ * @module @deepseek-ai/dsh-client-store/invariant
4
+ */
5
+ import type { Context } from '@deepseek-ai/cordis';
6
+ /** Cordis companion plugin name. */
7
+ export declare const name = "client-store-invariant";
8
+ /** Service required before the companion can reserve package ownership. */
9
+ export declare const inject: string[];
10
+ /**
11
+ * Register this package's invariant companion.
12
+ * @param ctx - Cordis context carrying the invariant service.
13
+ * @returns the installed registration's disposer after setup succeeds.
14
+ */
15
+ export declare const apply: (ctx: Context) => Promise<() => void>;
16
+ //# sourceMappingURL=invariant.d.ts.map
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@deepseek-ai/dsh-client-store",
3
+ "description": "React-free observable and snapshot-store contracts with the shared Zustand/Immer engine",
4
+ "version": "0.1.2-alpha.2",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
11
+ "directory": "packages/client/store"
12
+ },
13
+ "type": "module",
14
+ "main": "lib/index.js",
15
+ "types": "lib/types/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./lib/types/index.d.ts",
19
+ "default": "./lib/index.js"
20
+ },
21
+ "./invariant": {
22
+ "types": "./lib/types/invariant.d.ts",
23
+ "default": "./lib/invariant.js"
24
+ },
25
+ "./src/*": "./src/*",
26
+ "./package.json": "./package.json"
27
+ },
28
+ "license": "MIT",
29
+ "dependencies": {
30
+ "immer": "^10.1.1",
31
+ "zustand": "~4.4.7"
32
+ },
33
+ "peerDependencies": {
34
+ "@deepseek-ai/cordis": "^4.0.2"
35
+ },
36
+ "devDependencies": {
37
+ "@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2",
38
+ "@deepseek-ai/cordis": "^4.0.2"
39
+ },
40
+ "files": [
41
+ "lib/index.js",
42
+ "lib/invariant.js",
43
+ "lib/types/**/*.d.ts"
44
+ ]
45
+ }