@praxisjs/store 1.0.12 → 1.2.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @praxisjs/store
2
2
 
3
+ ## 1.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 4ec660f: Rename decorators for consistency: `@Store()` → `@Storable()` (class decorator), `@UseStore(Class)` → `@Store(Class)` (field decorator), `useStore()` → `store()` (imperative function).
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [cfb0de2]
12
+ - @praxisjs/decorators@1.0.2
13
+
14
+ ## 1.1.0
15
+
16
+ ### Minor Changes
17
+
18
+ - 22da23e: Add `useStore()` — functional alternative to `@UseStore` for use outside component context.
19
+
20
+ ```ts
21
+ import { useStore } from "@praxisjs/store";
22
+
23
+ const cart = useStore(CartStore);
24
+ ```
25
+
26
+ Resolves from the same global registry as `@UseStore` — always returns the same singleton instance. Useful in route guards, plain functions, and any place where a class field decorator is unavailable.
27
+
3
28
  ## 1.0.12
4
29
 
5
30
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  import { describe, it, expect } from "vitest";
2
- import { Store, UseStore, ReactiveStore } from "../decorators";
3
- describe("Store decorator", () => {
2
+ import { Storable, Store, store, ReactiveStore } from "../decorators";
3
+ describe("@Storable decorator", () => {
4
4
  it("registers the class without throwing", () => {
5
5
  class CounterStore extends ReactiveStore {
6
6
  constructor() {
@@ -8,7 +8,7 @@ describe("Store decorator", () => {
8
8
  this.value = 0;
9
9
  }
10
10
  }
11
- expect(() => { Store()(CounterStore, {}); }).not.toThrow();
11
+ expect(() => { Storable()(CounterStore, {}); }).not.toThrow();
12
12
  });
13
13
  it("returns void and the original class remains directly instantiable", () => {
14
14
  class MyStore extends ReactiveStore {
@@ -18,7 +18,7 @@ describe("Store decorator", () => {
18
18
  }
19
19
  }
20
20
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
21
- const result = Store()(MyStore, {});
21
+ const result = Storable()(MyStore, {});
22
22
  expect(result).toBeUndefined();
23
23
  expect(() => new MyStore()).not.toThrow();
24
24
  expect(new MyStore().value).toBe(42);
@@ -35,7 +35,7 @@ function makeFieldCtx(name) {
35
35
  run(instance) { initializers.forEach((fn) => { fn.call(instance); }); },
36
36
  };
37
37
  }
38
- describe("UseStore decorator", () => {
38
+ describe("@Store field decorator", () => {
39
39
  it("injects a singleton store instance via getter", () => {
40
40
  class AppStore extends ReactiveStore {
41
41
  constructor() {
@@ -43,9 +43,9 @@ describe("UseStore decorator", () => {
43
43
  this.name = "app";
44
44
  }
45
45
  }
46
- Store()(AppStore, {});
46
+ Storable()(AppStore, {});
47
47
  const { ctx, run } = makeFieldCtx("store");
48
- UseStore(AppStore)(undefined, ctx);
48
+ Store(AppStore)(undefined, ctx);
49
49
  const instance = {};
50
50
  run(instance);
51
51
  expect(instance.store).toBeInstanceOf(AppStore);
@@ -54,30 +54,28 @@ describe("UseStore decorator", () => {
54
54
  it("returns the same instance on repeated access (singleton)", () => {
55
55
  class SharedStore extends ReactiveStore {
56
56
  }
57
- Store()(SharedStore, {});
57
+ Storable()(SharedStore, {});
58
58
  const { ctx, run } = makeFieldCtx("sharedStore");
59
- UseStore(SharedStore)(undefined, ctx);
59
+ Store(SharedStore)(undefined, ctx);
60
60
  const a = {};
61
61
  const b = {};
62
62
  run(a);
63
63
  run(b);
64
64
  expect(a.sharedStore).toBe(b.sharedStore);
65
65
  });
66
- it("@UseStore(ClassWithoutStoreDecorator) — creates a new instance (no crash, no pre-registration needed)", () => {
66
+ it("@Store(ClassWithoutStorable) — creates a new instance (no crash, no pre-registration needed)", () => {
67
67
  class NotRegistered {
68
68
  constructor() {
69
69
  this.value = 99;
70
70
  }
71
71
  }
72
- // UseStore lazily creates an instance even without @Store, but should not throw
73
72
  const { ctx, run } = makeFieldCtx("svc");
74
- UseStore(NotRegistered)(undefined, ctx);
73
+ Store(NotRegistered)(undefined, ctx);
75
74
  const instance = {};
76
75
  run(instance);
77
- // The implementation instantiates it on first access regardless
78
76
  expect(instance.svc).toBeInstanceOf(NotRegistered);
79
77
  });
80
- it("@UseStore on two fields of same class — each field gets the correct store type independently", () => {
78
+ it("two @Store fields on the same class each get the correct store type", () => {
81
79
  class StoreAlpha extends ReactiveStore {
82
80
  constructor() {
83
81
  super(...arguments);
@@ -90,12 +88,12 @@ describe("UseStore decorator", () => {
90
88
  this.kind = "beta";
91
89
  }
92
90
  }
93
- Store()(StoreAlpha, {});
94
- Store()(StoreBeta, {});
91
+ Storable()(StoreAlpha, {});
92
+ Storable()(StoreBeta, {});
95
93
  const { ctx: ctxA, run: runA } = makeFieldCtx("alpha");
96
94
  const { ctx: ctxB, run: runB } = makeFieldCtx("beta");
97
- UseStore(StoreAlpha)(undefined, ctxA);
98
- UseStore(StoreBeta)(undefined, ctxB);
95
+ Store(StoreAlpha)(undefined, ctxA);
96
+ Store(StoreBeta)(undefined, ctxB);
99
97
  const instance = {};
100
98
  runA(instance);
101
99
  runB(instance);
@@ -104,21 +102,93 @@ describe("UseStore decorator", () => {
104
102
  expect(instance.alpha.kind).toBe("alpha");
105
103
  expect(instance.beta.kind).toBe("beta");
106
104
  });
107
- it("store singleton is shared across multiple class instances", () => {
105
+ it("singleton is shared across multiple component instances", () => {
108
106
  class CounterStore extends ReactiveStore {
109
107
  constructor() {
110
108
  super(...arguments);
111
109
  this.count = 0;
112
110
  }
113
111
  }
114
- Store()(CounterStore, {});
112
+ Storable()(CounterStore, {});
115
113
  const { ctx, run } = makeFieldCtx("counter");
116
- UseStore(CounterStore)(undefined, ctx);
114
+ Store(CounterStore)(undefined, ctx);
117
115
  const obj1 = {};
118
116
  const obj2 = {};
119
117
  run(obj1);
120
118
  run(obj2);
121
119
  expect(obj1.counter).toBe(obj2.counter);
122
120
  });
121
+ it("shares the same instance as store() (same registry)", () => {
122
+ class FlagsStore extends ReactiveStore {
123
+ constructor() {
124
+ super(...arguments);
125
+ this.enabled = true;
126
+ }
127
+ }
128
+ Storable()(FlagsStore, {});
129
+ const { ctx, run } = makeFieldCtx("flags");
130
+ Store(FlagsStore)(undefined, ctx);
131
+ const obj = {};
132
+ run(obj);
133
+ expect(obj.flags).toBe(store(FlagsStore));
134
+ });
135
+ });
136
+ // ── store() ────────────────────────────────────────────────────────────────
137
+ describe("store()", () => {
138
+ it("returns a store instance without requiring a class field", () => {
139
+ class ProfileStore extends ReactiveStore {
140
+ constructor() {
141
+ super(...arguments);
142
+ this.name = "alice";
143
+ }
144
+ }
145
+ Storable()(ProfileStore, {});
146
+ const instance = store(ProfileStore);
147
+ expect(instance).toBeInstanceOf(ProfileStore);
148
+ expect(instance.name).toBe("alice");
149
+ });
150
+ it("returns the same singleton instance on repeated calls", () => {
151
+ class TimerStore extends ReactiveStore {
152
+ constructor() {
153
+ super(...arguments);
154
+ this.ticks = 0;
155
+ }
156
+ }
157
+ Storable()(TimerStore, {});
158
+ expect(store(TimerStore)).toBe(store(TimerStore));
159
+ });
160
+ it("lazily creates the instance on first call", () => {
161
+ class LazyStore extends ReactiveStore {
162
+ constructor() {
163
+ super(...arguments);
164
+ this.ready = false;
165
+ }
166
+ }
167
+ Storable()(LazyStore, {});
168
+ const instance = store(LazyStore);
169
+ expect(instance).toBeInstanceOf(LazyStore);
170
+ });
171
+ it("works without @Storable — creates a plain instance", () => {
172
+ class BareStore extends ReactiveStore {
173
+ constructor() {
174
+ super(...arguments);
175
+ this.value = 7;
176
+ }
177
+ }
178
+ const instance = store(BareStore);
179
+ expect(instance).toBeInstanceOf(BareStore);
180
+ expect(instance.value).toBe(7);
181
+ });
182
+ it("mutations on the returned instance are reflected on subsequent calls", () => {
183
+ class ThemeStore extends ReactiveStore {
184
+ constructor() {
185
+ super(...arguments);
186
+ this.dark = false;
187
+ }
188
+ }
189
+ Storable()(ThemeStore, {});
190
+ store(ThemeStore).dark = true;
191
+ expect(store(ThemeStore).dark).toBe(true);
192
+ });
123
193
  });
124
194
  //# sourceMappingURL=decorators.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"decorators.test.js","sourceRoot":"","sources":["../../src/__tests__/decorators.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"decorators.test.js","sourceRoot":"","sources":["../../src/__tests__/decorators.test.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import { type ReactiveHost } from "@praxisjs/decorators";
3
3
  export declare class ReactiveStore implements ReactiveHost {
4
4
  _stateDirty: boolean;
5
5
  }
6
- export declare function Store(): (constructor: new (...args: unknown[]) => ReactiveStore, _context: ClassDecoratorContext) => void;
7
- export declare function UseStore(StoreConstructor: new () => unknown): (_value: undefined, context: ClassFieldDecoratorContext<any>) => void;
6
+ export declare function Storable(): (constructor: new (...args: unknown[]) => ReactiveStore, _context: ClassDecoratorContext) => void;
7
+ export declare function store<T extends ReactiveStore>(StoreClass: new () => T): T;
8
+ export declare function Store(StoreConstructor: new () => unknown): (_value: undefined, context: ClassFieldDecoratorContext<any>) => void;
8
9
  //# sourceMappingURL=decorators.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,sBAAsB,CAAC;AAI9B,qGAAqG;AACrG,qBAAa,aAAc,YAAW,YAAY;IAChD,WAAW,UAAS;CACrB;AAED,wBAAgB,KAAK,KAEjB,aAAa,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,aAAa,EACtD,UAAU,qBAAqB,KAC9B,IAAI,CAGR;AAED,wBAAgB,QAAQ,CAAC,gBAAgB,EAAE,UAAU,OAAO,GAuBzC,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,0BAA0B,CAAC,GAAG,CAAC,KAAK,IAAI,CACvF"}
1
+ {"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,sBAAsB,CAAC;AAI9B,qGAAqG;AACrG,qBAAa,aAAc,YAAW,YAAY;IAChD,WAAW,UAAS;CACrB;AAED,wBAAgB,QAAQ,KAEpB,aAAa,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,aAAa,EACtD,UAAU,qBAAqB,KAC9B,IAAI,CAGR;AAED,wBAAgB,KAAK,CAAC,CAAC,SAAS,aAAa,EAAE,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,CAKzE;AAED,wBAAgB,KAAK,CAAC,gBAAgB,EAAE,UAAU,OAAO,GAYtC,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,0BAA0B,CAAC,GAAG,CAAC,KAAK,IAAI,CACvF"}
@@ -6,26 +6,24 @@ export class ReactiveStore {
6
6
  this._stateDirty = false;
7
7
  }
8
8
  }
9
- export function Store() {
9
+ export function Storable() {
10
10
  return function (constructor, _context) {
11
11
  storeRegistry.set(constructor, null);
12
12
  };
13
13
  }
14
- export function UseStore(StoreConstructor) {
15
- const cache = new WeakMap();
14
+ export function store(StoreClass) {
15
+ if (!storeRegistry.has(StoreClass) || storeRegistry.get(StoreClass) === null) {
16
+ storeRegistry.set(StoreClass, new StoreClass());
17
+ }
18
+ return storeRegistry.get(StoreClass);
19
+ }
20
+ export function Store(StoreConstructor) {
16
21
  return createFieldDecorator({
17
22
  bind(_instance, _name, _initialValue) {
18
23
  return {
19
24
  descriptor: {
20
25
  get() {
21
- if (!cache.has(this)) {
22
- if (!storeRegistry.has(StoreConstructor) ||
23
- storeRegistry.get(StoreConstructor) === null) {
24
- storeRegistry.set(StoreConstructor, new StoreConstructor());
25
- }
26
- cache.set(this, storeRegistry.get(StoreConstructor));
27
- }
28
- return cache.get(this);
26
+ return store(StoreConstructor);
29
27
  },
30
28
  },
31
29
  };
@@ -1 +1 @@
1
- {"version":3,"file":"decorators.js","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,GAGrB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,aAAa,GAAG,IAAI,GAAG,EAAgD,CAAC;AAE9E,qGAAqG;AACrG,MAAM,OAAO,aAAa;IAA1B;QACE,gBAAW,GAAG,KAAK,CAAC;IACtB,CAAC;CAAA;AAED,MAAM,UAAU,KAAK;IACnB,OAAO,UACL,WAAsD,EACtD,QAA+B;QAE/B,aAAa,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IACvC,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,gBAAmC;IAC1D,MAAM,KAAK,GAAG,IAAI,OAAO,EAAmB,CAAC;IAE7C,OAAO,oBAAoB,CAAC;QAC1B,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,aAAa;YAClC,OAAO;gBACL,UAAU,EAAE;oBACV,GAAG;wBACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;4BACrB,IACE,CAAC,aAAa,CAAC,GAAG,CAAC,gBAAgB,CAAC;gCACpC,aAAa,CAAC,GAAG,CAAC,gBAAgB,CAAC,KAAK,IAAI,EAC5C,CAAC;gCACD,aAAa,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,gBAAgB,EAAE,CAAC,CAAC;4BAC9D,CAAC;4BACD,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC;wBACvD,CAAC;wBACD,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBACzB,CAAC;iBACF;aACF,CAAC;QACJ,CAAC;QACH,8DAA8D;KAC7D,CAAqF,CAAC;AACzF,CAAC"}
1
+ {"version":3,"file":"decorators.js","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,GAGrB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,aAAa,GAAG,IAAI,GAAG,EAAgD,CAAC;AAE9E,qGAAqG;AACrG,MAAM,OAAO,aAAa;IAA1B;QACE,gBAAW,GAAG,KAAK,CAAC;IACtB,CAAC;CAAA;AAED,MAAM,UAAU,QAAQ;IACtB,OAAO,UACL,WAAsD,EACtD,QAA+B;QAE/B,aAAa,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IACvC,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,KAAK,CAA0B,UAAuB;IACpE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,IAAI,EAAE,CAAC;QAC7E,aAAa,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,UAAU,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,aAAa,CAAC,GAAG,CAAC,UAAU,CAAM,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,gBAAmC;IACvD,OAAO,oBAAoB,CAAC;QAC1B,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,aAAa;YAClC,OAAO;gBACL,UAAU,EAAE;oBACV,GAAG;wBACD,OAAO,KAAK,CAAC,gBAA2C,CAAC,CAAC;oBAC5D,CAAC;iBACF;aACF,CAAC;QACJ,CAAC;QACH,8DAA8D;KAC7D,CAAqF,CAAC;AACzF,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { Store, UseStore, ReactiveStore } from "./decorators";
1
+ export { Storable, Store, store, ReactiveStore } from "./decorators";
2
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { Store, UseStore, ReactiveStore } from "./decorators";
1
+ export { Storable, Store, store, ReactiveStore } from "./decorators";
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praxisjs/store",
3
- "version": "1.0.12",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "@praxisjs/core": "1.6.0",
18
- "@praxisjs/decorators": "1.0.1"
18
+ "@praxisjs/decorators": "1.0.2"
19
19
  },
20
20
  "scripts": {
21
21
  "build": "tsc",
@@ -1,14 +1,14 @@
1
1
  import { describe, it, expect } from "vitest";
2
2
 
3
- import { Store, UseStore, ReactiveStore } from "../decorators";
3
+ import { Storable, Store, store, ReactiveStore } from "../decorators";
4
4
 
5
- describe("Store decorator", () => {
5
+ describe("@Storable decorator", () => {
6
6
  it("registers the class without throwing", () => {
7
7
  class CounterStore extends ReactiveStore {
8
8
  value = 0;
9
9
  }
10
10
  expect(() =>
11
- { Store()(CounterStore, {} as ClassDecoratorContext); },
11
+ { Storable()(CounterStore, {} as ClassDecoratorContext); },
12
12
  ).not.toThrow();
13
13
  });
14
14
 
@@ -17,7 +17,7 @@ describe("Store decorator", () => {
17
17
  value = 42;
18
18
  }
19
19
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
- const result = Store()(MyStore as any, {} as ClassDecoratorContext);
20
+ const result = Storable()(MyStore as any, {} as ClassDecoratorContext);
21
21
  expect(result).toBeUndefined();
22
22
  expect(() => new MyStore()).not.toThrow();
23
23
  expect(new MyStore().value).toBe(42);
@@ -36,15 +36,15 @@ function makeFieldCtx(name: string) {
36
36
  };
37
37
  }
38
38
 
39
- describe("UseStore decorator", () => {
39
+ describe("@Store field decorator", () => {
40
40
  it("injects a singleton store instance via getter", () => {
41
41
  class AppStore extends ReactiveStore {
42
42
  name = "app";
43
43
  }
44
- Store()(AppStore, {} as ClassDecoratorContext);
44
+ Storable()(AppStore, {} as ClassDecoratorContext);
45
45
 
46
46
  const { ctx, run } = makeFieldCtx("store");
47
- UseStore(AppStore)(undefined, ctx);
47
+ Store(AppStore)(undefined, ctx);
48
48
 
49
49
  const instance: Record<string, unknown> = {};
50
50
  run(instance);
@@ -55,10 +55,10 @@ describe("UseStore decorator", () => {
55
55
 
56
56
  it("returns the same instance on repeated access (singleton)", () => {
57
57
  class SharedStore extends ReactiveStore {}
58
- Store()(SharedStore, {} as ClassDecoratorContext);
58
+ Storable()(SharedStore, {} as ClassDecoratorContext);
59
59
 
60
60
  const { ctx, run } = makeFieldCtx("sharedStore");
61
- UseStore(SharedStore)(undefined, ctx);
61
+ Store(SharedStore)(undefined, ctx);
62
62
 
63
63
  const a: Record<string, unknown> = {};
64
64
  const b: Record<string, unknown> = {};
@@ -68,33 +68,31 @@ describe("UseStore decorator", () => {
68
68
  expect(a.sharedStore).toBe(b.sharedStore);
69
69
  });
70
70
 
71
- it("@UseStore(ClassWithoutStoreDecorator) — creates a new instance (no crash, no pre-registration needed)", () => {
71
+ it("@Store(ClassWithoutStorable) — creates a new instance (no crash, no pre-registration needed)", () => {
72
72
  class NotRegistered {
73
73
  value = 99;
74
74
  }
75
- // UseStore lazily creates an instance even without @Store, but should not throw
76
75
  const { ctx, run } = makeFieldCtx("svc");
77
- UseStore(NotRegistered)(undefined, ctx);
76
+ Store(NotRegistered)(undefined, ctx);
78
77
  const instance: Record<string, unknown> = {};
79
78
  run(instance);
80
- // The implementation instantiates it on first access regardless
81
79
  expect(instance.svc).toBeInstanceOf(NotRegistered);
82
80
  });
83
81
 
84
- it("@UseStore on two fields of same class — each field gets the correct store type independently", () => {
82
+ it("two @Store fields on the same class each get the correct store type", () => {
85
83
  class StoreAlpha extends ReactiveStore {
86
84
  kind = "alpha";
87
85
  }
88
86
  class StoreBeta extends ReactiveStore {
89
87
  kind = "beta";
90
88
  }
91
- Store()(StoreAlpha, {} as ClassDecoratorContext);
92
- Store()(StoreBeta, {} as ClassDecoratorContext);
89
+ Storable()(StoreAlpha, {} as ClassDecoratorContext);
90
+ Storable()(StoreBeta, {} as ClassDecoratorContext);
93
91
 
94
92
  const { ctx: ctxA, run: runA } = makeFieldCtx("alpha");
95
93
  const { ctx: ctxB, run: runB } = makeFieldCtx("beta");
96
- UseStore(StoreAlpha)(undefined, ctxA);
97
- UseStore(StoreBeta)(undefined, ctxB);
94
+ Store(StoreAlpha)(undefined, ctxA);
95
+ Store(StoreBeta)(undefined, ctxB);
98
96
 
99
97
  const instance: Record<string, unknown> = {};
100
98
  runA(instance);
@@ -106,14 +104,14 @@ describe("UseStore decorator", () => {
106
104
  expect((instance.beta as StoreBeta).kind).toBe("beta");
107
105
  });
108
106
 
109
- it("store singleton is shared across multiple class instances", () => {
107
+ it("singleton is shared across multiple component instances", () => {
110
108
  class CounterStore extends ReactiveStore {
111
109
  count = 0;
112
110
  }
113
- Store()(CounterStore, {} as ClassDecoratorContext);
111
+ Storable()(CounterStore, {} as ClassDecoratorContext);
114
112
 
115
113
  const { ctx, run } = makeFieldCtx("counter");
116
- UseStore(CounterStore)(undefined, ctx);
114
+ Store(CounterStore)(undefined, ctx);
117
115
 
118
116
  const obj1: Record<string, unknown> = {};
119
117
  const obj2: Record<string, unknown> = {};
@@ -122,4 +120,71 @@ describe("UseStore decorator", () => {
122
120
 
123
121
  expect(obj1.counter).toBe(obj2.counter);
124
122
  });
123
+
124
+ it("shares the same instance as store() (same registry)", () => {
125
+ class FlagsStore extends ReactiveStore {
126
+ enabled = true;
127
+ }
128
+ Storable()(FlagsStore, {} as ClassDecoratorContext);
129
+
130
+ const { ctx, run } = makeFieldCtx("flags");
131
+ Store(FlagsStore)(undefined, ctx);
132
+ const obj: Record<string, unknown> = {};
133
+ run(obj);
134
+
135
+ expect(obj.flags).toBe(store(FlagsStore));
136
+ });
137
+ });
138
+
139
+ // ── store() ────────────────────────────────────────────────────────────────
140
+
141
+ describe("store()", () => {
142
+ it("returns a store instance without requiring a class field", () => {
143
+ class ProfileStore extends ReactiveStore {
144
+ name = "alice";
145
+ }
146
+ Storable()(ProfileStore, {} as ClassDecoratorContext);
147
+
148
+ const instance = store(ProfileStore);
149
+ expect(instance).toBeInstanceOf(ProfileStore);
150
+ expect(instance.name).toBe("alice");
151
+ });
152
+
153
+ it("returns the same singleton instance on repeated calls", () => {
154
+ class TimerStore extends ReactiveStore {
155
+ ticks = 0;
156
+ }
157
+ Storable()(TimerStore, {} as ClassDecoratorContext);
158
+
159
+ expect(store(TimerStore)).toBe(store(TimerStore));
160
+ });
161
+
162
+ it("lazily creates the instance on first call", () => {
163
+ class LazyStore extends ReactiveStore {
164
+ ready = false;
165
+ }
166
+ Storable()(LazyStore, {} as ClassDecoratorContext);
167
+
168
+ const instance = store(LazyStore);
169
+ expect(instance).toBeInstanceOf(LazyStore);
170
+ });
171
+
172
+ it("works without @Storable — creates a plain instance", () => {
173
+ class BareStore extends ReactiveStore {
174
+ value = 7;
175
+ }
176
+ const instance = store(BareStore);
177
+ expect(instance).toBeInstanceOf(BareStore);
178
+ expect(instance.value).toBe(7);
179
+ });
180
+
181
+ it("mutations on the returned instance are reflected on subsequent calls", () => {
182
+ class ThemeStore extends ReactiveStore {
183
+ dark = false;
184
+ }
185
+ Storable()(ThemeStore, {} as ClassDecoratorContext);
186
+
187
+ store(ThemeStore).dark = true;
188
+ expect(store(ThemeStore).dark).toBe(true);
189
+ });
125
190
  });
package/src/decorators.ts CHANGED
@@ -11,7 +11,7 @@ export class ReactiveStore implements ReactiveHost {
11
11
  _stateDirty = false;
12
12
  }
13
13
 
14
- export function Store() {
14
+ export function Storable() {
15
15
  return function (
16
16
  constructor: new (...args: unknown[]) => ReactiveStore,
17
17
  _context: ClassDecoratorContext,
@@ -20,24 +20,20 @@ export function Store() {
20
20
  };
21
21
  }
22
22
 
23
- export function UseStore(StoreConstructor: new () => unknown) {
24
- const cache = new WeakMap<object, unknown>();
23
+ export function store<T extends ReactiveStore>(StoreClass: new () => T): T {
24
+ if (!storeRegistry.has(StoreClass) || storeRegistry.get(StoreClass) === null) {
25
+ storeRegistry.set(StoreClass, new StoreClass());
26
+ }
27
+ return storeRegistry.get(StoreClass) as T;
28
+ }
25
29
 
30
+ export function Store(StoreConstructor: new () => unknown) {
26
31
  return createFieldDecorator({
27
32
  bind(_instance, _name, _initialValue): FieldBinding {
28
33
  return {
29
34
  descriptor: {
30
35
  get(this: object): unknown {
31
- if (!cache.has(this)) {
32
- if (
33
- !storeRegistry.has(StoreConstructor) ||
34
- storeRegistry.get(StoreConstructor) === null
35
- ) {
36
- storeRegistry.set(StoreConstructor, new StoreConstructor());
37
- }
38
- cache.set(this, storeRegistry.get(StoreConstructor));
39
- }
40
- return cache.get(this);
36
+ return store(StoreConstructor as new () => ReactiveStore);
41
37
  },
42
38
  },
43
39
  };
package/src/index.ts CHANGED
@@ -1 +1 @@
1
- export { Store, UseStore, ReactiveStore } from "./decorators";
1
+ export { Storable, Store, store, ReactiveStore } from "./decorators";