@rustra/react 0.7.1 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +86 -0
- package/README.md +50 -5
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +21 -10
- package/dist/context.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/input-key.d.ts +4 -5
- package/dist/input-key.d.ts.map +1 -1
- package/dist/input-key.js +64 -6
- package/dist/input-key.js.map +1 -1
- package/dist/suspense-cache.d.ts +22 -0
- package/dist/suspense-cache.d.ts.map +1 -0
- package/dist/suspense-cache.js +117 -0
- package/dist/suspense-cache.js.map +1 -0
- package/dist/useEvent.js +2 -1
- package/dist/useEvent.js.map +1 -1
- package/dist/useMutation.d.ts.map +1 -1
- package/dist/useMutation.js +65 -41
- package/dist/useMutation.js.map +1 -1
- package/dist/useSuspenseCommand.d.ts +5 -44
- package/dist/useSuspenseCommand.d.ts.map +1 -1
- package/dist/useSuspenseCommand.js +6 -70
- package/dist/useSuspenseCommand.js.map +1 -1
- package/package.json +9 -5
package/README.ko.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
[English](./README.md) | 한국어
|
|
2
|
+
|
|
3
|
+
# @rustra/react
|
|
4
|
+
|
|
5
|
+
Rustra 명령 클라이언트를 위한 React 훅과 컨텍스트다. `RustraProvider`,
|
|
6
|
+
`useRustraEngine`, `useCommand`, `useMutation`, `useEvent`, `useSuspenseCommand`,
|
|
7
|
+
`invalidateCommands`, `configureSuspenseCache`를 제공한다. React는 peer dependency이며,
|
|
8
|
+
Provider를 렌더링하기 전에 플랫폼별 엔진을 설정한다.
|
|
9
|
+
|
|
10
|
+
```tsx
|
|
11
|
+
import { RustraProvider, useCommand } from '@rustra/react';
|
|
12
|
+
import { getItem } from './generated/commands.js';
|
|
13
|
+
|
|
14
|
+
function Item({ id }: { id: string }) {
|
|
15
|
+
const { data, loading, error } = useCommand(getItem, { id });
|
|
16
|
+
if (loading) return <span>Loading...</span>;
|
|
17
|
+
if (error) return <span>{error.message}</span>;
|
|
18
|
+
return <span>{data?.name}</span>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
<RustraProvider engine={engine}>
|
|
22
|
+
<Item id="item-1" />
|
|
23
|
+
</RustraProvider>;
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`useSuspenseCommand(commandFn, input?, options?)`는 대기 중 Promise를 던지고 완료 값을
|
|
27
|
+
직접 반환한다. 실패는 가장 가까운 오류 경계로 전달한다. 캐시는 Provider의
|
|
28
|
+
`EngineClient` 객체, 명령 이름, 구조화된 입력을 키로 삼는다. SSR 요청이나 계정마다
|
|
29
|
+
별도 Provider 엔진을 사용한다. 하나의 엔진을 공유하면 캐시도 의도적으로 공유한다.
|
|
30
|
+
Provider가 없으면 현재 전역 등록 범위를 공유하며, 등록 교체·해제 후 다음 렌더링은
|
|
31
|
+
새 범위를 사용한다. 이전 콜백은 교체된 엔진을 호출할 수 없다. 동시 SSR 사용자에게는
|
|
32
|
+
요청별 Provider가 필요하다.
|
|
33
|
+
|
|
34
|
+
엔진당 최대 **256개** 항목을 유지한다. 완료 후 **5분**이 지나면 만료하고, 용량에
|
|
35
|
+
도달하면 완료 항목 중 가장 오래 접근하지 않은 항목을 제거한다. 대기 Promise는
|
|
36
|
+
Suspense 재시도를 위해 유지한다. 모든 슬롯이 대기 중이면 새 키 요청은 용량 오류를
|
|
37
|
+
오류 경계로 전달한다. 대기 항목은 **30초** 후 reject되어 제거·만료할 수 있다.
|
|
38
|
+
대기 제한은 엔진 작업 자체를 취소하지 않는다. 호출 옵션은 항목을 생성할 때만 적용한다.
|
|
39
|
+
|
|
40
|
+
`configureSuspenseCache({ maxEntries, ttlMs, pendingTimeoutMs }, engine?)`는 한 엔진의
|
|
41
|
+
정책을 바꾸고 기존 항목을 비운다. 엔진을 생략하면 전역 기본 범위를 설정한다. 값은
|
|
42
|
+
양의 안전한 정수여야 하며, 시간 값은 2,147,483,647 ms 이하여야 한다. 대기 중 항목을
|
|
43
|
+
무효화해도 기존 호출자의 Promise는 유지되지만, 늦은 완료가 캐시를 다시 채우지 않는다.
|
|
44
|
+
|
|
45
|
+
- `invalidateCommands('getItem', engine)`: 해당 엔진의 정확한 명령 이름만 비운다.
|
|
46
|
+
- `invalidateCommands(undefined, engine)`: 해당 엔진의 전체 캐시를 비운다.
|
|
47
|
+
- `invalidateCommands('getItem')`: 살아 있는 모든 엔진에서 해당 명령을 비운다.
|
|
48
|
+
- `invalidateCommands()`: 살아 있는 모든 캐시를 비운다.
|
|
49
|
+
|
|
50
|
+
무효화와 만료는 다음 렌더링에 반영되며 스스로 렌더링을 발생시키지 않는다. 엔진은 약한
|
|
51
|
+
참조로 유지하고, 캐시 결과에도 유한 보관 기간을 적용한다.
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import { Suspense } from 'react';
|
|
55
|
+
import { invalidateCommands, useSuspenseCommand } from '@rustra/react';
|
|
56
|
+
import { getItem, saveItem } from './generated/commands.js';
|
|
57
|
+
|
|
58
|
+
function Item({ id }: { id: string }) {
|
|
59
|
+
const item = useSuspenseCommand(getItem, { id });
|
|
60
|
+
return <span>{item.name}</span>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function rename(id: string, name: string) {
|
|
64
|
+
await saveItem({ id, name });
|
|
65
|
+
invalidateCommands('getItem'); // 다음 렌더링에서 다시 조회
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
<Suspense fallback={<span>Loading...</span>}>
|
|
69
|
+
<Item id="item-1" />
|
|
70
|
+
</Suspense>;
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`useCommand`와 `useSuspenseCommand`는 일반 객체, 배열, bigint, Set, Map, Date,
|
|
74
|
+
ArrayBuffer, 타입 지정 바이너리 뷰를 포함한 구조화된 입력을 지원한다. 키는 값의 타입과
|
|
75
|
+
바이너리 내용을 구분한다. 일반 객체의 필드 순서는 무시하지만 Set/Map 반복 순서와
|
|
76
|
+
바이너리 뷰 타입은 보존한다. 함수·symbol·순환 참조·미지원 클래스 인스턴스는
|
|
77
|
+
TypeError로 거부한다. 엔진에는 원래 입력을 전달한다.
|
|
78
|
+
|
|
79
|
+
`useMutation`은 엔진 또는 결정된 명령이 바뀌면 표시 상태를 초기화한다. 진행 중 호출은
|
|
80
|
+
호출자에게 결과를 반환할 수 있지만 교체된 범위나 초기화·언마운트된 훅의 상태는
|
|
81
|
+
갱신하지 않는다. 성공·오류·완료 콜백은 호출 시작 시 캡처하고, 초기화나 범위 변경 후
|
|
82
|
+
완료하더라도 해당 호출에 귀속되어 실행한다. 중첩 호출은 현재 범위의 모든 호출이
|
|
83
|
+
끝날 때까지 `loading`을 유지하고, 마지막 호출만 data/error를 갱신한다.
|
|
84
|
+
|
|
85
|
+
`useEvent`는 동기·비동기 구독 해제 등록을 지원한다. 이벤트·구독자 교체 또는 언마운트 시
|
|
86
|
+
이전 구독의 전달을 즉시 차단하며, 늦게 도착한 정리 함수는 한 번 실행한다.
|
package/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
English | [한국어](./README.ko.md)
|
|
2
|
+
|
|
1
3
|
# @rustra/react
|
|
2
4
|
|
|
3
5
|
React hooks and context bindings for Rustra command clients.
|
|
@@ -19,16 +21,41 @@ function Item({ id }: { id: string }) {
|
|
|
19
21
|
```
|
|
20
22
|
|
|
21
23
|
The package provides `RustraProvider`, `useRustraEngine`, `useCommand`,
|
|
22
|
-
`useMutation`, `useEvent`,
|
|
24
|
+
`useMutation`, `useEvent`, `useSuspenseCommand`, `invalidateCommands`, and
|
|
25
|
+
`configureSuspenseCache`. React is a peer dependency;
|
|
23
26
|
configure the platform-specific Rustra engine before rendering the provider.
|
|
24
27
|
|
|
25
28
|
`useSuspenseCommand(commandFn, input?, options?)` is the Suspense-compatible read:
|
|
26
29
|
it suspends by throwing the in-flight promise until the command resolves, then
|
|
27
30
|
returns the value directly (a rejection is re-thrown to the nearest error
|
|
28
|
-
boundary). Results
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
boundary). Results are keyed by the provider's `EngineClient` identity, command
|
|
32
|
+
name, and structural input. Use a separate provider engine for every SSR request
|
|
33
|
+
or account; sharing one engine intentionally shares its cache. Without a provider,
|
|
34
|
+
all components share the current global registration scope. Replacing or disposing
|
|
35
|
+
the registration creates a fresh scope on the next render; stale retained callbacks
|
|
36
|
+
cannot invoke the replacement engine. Use a request-specific Provider for concurrent SSR users.
|
|
37
|
+
|
|
38
|
+
Each engine keeps at most **256 entries**. Completed entries expire **5 minutes**
|
|
39
|
+
after settlement; insertion at capacity evicts the least recently accessed settled
|
|
40
|
+
entry. Pending promises are protected from eviction so Suspense retries reuse the
|
|
41
|
+
same work. If all slots are pending, a new key throws a capacity error to the error
|
|
42
|
+
boundary. A pending entry rejects after **30 seconds** and can then be evicted or
|
|
43
|
+
expire. The cache deadline stops waiting; it does not cancel the underlying engine
|
|
44
|
+
operation. Invocation options apply only when creating the entry.
|
|
45
|
+
|
|
46
|
+
`configureSuspenseCache({ maxEntries, ttlMs, pendingTimeoutMs }, engine?)` changes
|
|
47
|
+
one engine's policy and clears its existing entries; omit the engine to configure
|
|
48
|
+
the global default scope. Values must be positive safe integers (time values at
|
|
49
|
+
most 2,147,483,647 ms). Explicitly invalidating pending work leaves its promise
|
|
50
|
+
intact for current callers, but late completion never repopulates the cache.
|
|
51
|
+
|
|
52
|
+
- `invalidateCommands('getItem', engine)` clears that exact command in one engine.
|
|
53
|
+
- `invalidateCommands(undefined, engine)` clears one engine's entire cache.
|
|
54
|
+
- `invalidateCommands('getItem')` clears that exact command across live engines.
|
|
55
|
+
- `invalidateCommands()` clears every live cache.
|
|
56
|
+
|
|
57
|
+
Invalidation and expiry take effect on the next render; neither triggers a render
|
|
58
|
+
by itself. Engines are weakly held, and cached results also have finite retention.
|
|
32
59
|
|
|
33
60
|
```tsx
|
|
34
61
|
import { Suspense } from 'react';
|
|
@@ -49,3 +76,21 @@ async function rename(id: string, name: string) {
|
|
|
49
76
|
<Item id="item-1" />
|
|
50
77
|
</Suspense>;
|
|
51
78
|
```
|
|
79
|
+
|
|
80
|
+
`useCommand` and `useSuspenseCommand` accept structural inputs containing plain
|
|
81
|
+
records, arrays, bigint, Set, Map, Date, ArrayBuffer, and typed binary views. Keys
|
|
82
|
+
include value types and binary contents; plain-record field order is ignored,
|
|
83
|
+
while Set/Map iteration order and binary view types are preserved. Functions,
|
|
84
|
+
symbols, cyclic structures, and unsupported class instances are rejected with a
|
|
85
|
+
TypeError instead of silently colliding. The engine receives the original input.
|
|
86
|
+
|
|
87
|
+
`useMutation` resets visible state when its engine or resolved command changes.
|
|
88
|
+
An in-flight call can still settle and return to its caller, but it cannot update
|
|
89
|
+
a replacement scope or a reset/unmounted hook. Success/error/settled callbacks
|
|
90
|
+
are captured at invocation time and still belong to that invocation, including
|
|
91
|
+
when it settles after a reset or scope change. Overlapping calls keep `loading`
|
|
92
|
+
true until all current-scope calls settle; only the latest call updates data/error.
|
|
93
|
+
|
|
94
|
+
`useEvent` accepts synchronous or asynchronous unsubscribe registration. Replacing
|
|
95
|
+
an event/subscriber or unmounting immediately disables delivery from the old
|
|
96
|
+
subscription. A cleanup function that arrives afterward is invoked once.
|
package/dist/context.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export interface RustraProviderProps {
|
|
|
9
9
|
* Provides a scoped Rustra `EngineClient` to component subtree.
|
|
10
10
|
*/
|
|
11
11
|
export declare function RustraProvider({ engine, children }: RustraProviderProps): React.ReactElement;
|
|
12
|
+
/** Shared by components and Suspense retries within one global registration. */
|
|
13
|
+
export declare function getDefaultEngine(): EngineClient;
|
|
12
14
|
/**
|
|
13
15
|
* Returns the currently active `EngineClient`, either from `<RustraProvider>` or
|
|
14
16
|
* a default engine invoking the global `invoke` singleton.
|
package/dist/context.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAA6B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,eAAe,CAAC;AAKjE,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,YAAY,CAAC;IACrB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,mBAAmB,GAAG,KAAK,CAAC,YAAY,CAE5F;AAKD,gFAAgF;AAChF,wBAAgB,gBAAgB,IAAI,YAAY,CAmB/C;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAE9C"}
|
package/dist/context.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React, { createContext, useContext
|
|
2
|
-
import { invoke } from '@rustra/types';
|
|
1
|
+
import React, { createContext, useContext } from 'react';
|
|
2
|
+
import { getEngineRegistrationToken, invoke, RustraCommandError } from '@rustra/types';
|
|
3
3
|
const RustraContext = createContext(null);
|
|
4
4
|
/**
|
|
5
5
|
* Provides a scoped Rustra `EngineClient` to component subtree.
|
|
@@ -7,18 +7,29 @@ const RustraContext = createContext(null);
|
|
|
7
7
|
export function RustraProvider({ engine, children }) {
|
|
8
8
|
return React.createElement(RustraContext.Provider, { value: engine }, children);
|
|
9
9
|
}
|
|
10
|
+
let defaultEngine;
|
|
11
|
+
let defaultRegistration;
|
|
12
|
+
/** Shared by components and Suspense retries within one global registration. */
|
|
13
|
+
export function getDefaultEngine() {
|
|
14
|
+
const registration = getEngineRegistrationToken();
|
|
15
|
+
if (!defaultEngine || registration !== defaultRegistration) {
|
|
16
|
+
defaultRegistration = registration;
|
|
17
|
+
defaultEngine = {
|
|
18
|
+
invoke: (command, args, options) => {
|
|
19
|
+
if (registration !== getEngineRegistrationToken()) {
|
|
20
|
+
return Promise.reject(new RustraCommandError('transport.unavailable', 'The global engine was replaced; render with the current engine before invoking'));
|
|
21
|
+
}
|
|
22
|
+
return invoke(command, args, options);
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return defaultEngine;
|
|
27
|
+
}
|
|
10
28
|
/**
|
|
11
29
|
* Returns the currently active `EngineClient`, either from `<RustraProvider>` or
|
|
12
30
|
* a default engine invoking the global `invoke` singleton.
|
|
13
31
|
*/
|
|
14
32
|
export function useRustraEngine() {
|
|
15
|
-
|
|
16
|
-
return useMemo(() => {
|
|
17
|
-
if (contextEngine)
|
|
18
|
-
return contextEngine;
|
|
19
|
-
return {
|
|
20
|
-
invoke: (command, args, options) => invoke(command, args, options),
|
|
21
|
-
};
|
|
22
|
-
}, [contextEngine]);
|
|
33
|
+
return useContext(RustraContext) ?? getDefaultEngine();
|
|
23
34
|
}
|
|
24
35
|
//# sourceMappingURL=context.js.map
|
package/dist/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,aAAa,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,aAAa,EAAE,UAAU,EAAkB,MAAM,OAAO,CAAC;AAEzE,OAAO,EAAE,0BAA0B,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEvF,MAAM,aAAa,GAAG,aAAa,CAAsB,IAAI,CAAC,CAAC;AAQ/D;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAuB;IACtE,OAAO,KAAK,CAAC,aAAa,CAAC,aAAa,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,QAAQ,CAAC,CAAC;AAClF,CAAC;AAED,IAAI,aAAuC,CAAC;AAC5C,IAAI,mBAAuC,CAAC;AAE5C,gFAAgF;AAChF,MAAM,UAAU,gBAAgB;IAC9B,MAAM,YAAY,GAAG,0BAA0B,EAAE,CAAC;IAClD,IAAI,CAAC,aAAa,IAAI,YAAY,KAAK,mBAAmB,EAAE,CAAC;QAC3D,mBAAmB,GAAG,YAAY,CAAC;QACnC,aAAa,GAAG;YACd,MAAM,EAAE,CAAI,OAAe,EAAE,IAAc,EAAE,OAAuB,EAAc,EAAE;gBAClF,IAAI,YAAY,KAAK,0BAA0B,EAAE,EAAE,CAAC;oBAClD,OAAO,OAAO,CAAC,MAAM,CACnB,IAAI,kBAAkB,CACpB,uBAAuB,EACvB,gFAAgF,CACjF,CACF,CAAC;gBACJ,CAAC;gBACD,OAAO,MAAM,CAAI,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;YAC3C,CAAC;SACF,CAAC;IACJ,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,UAAU,CAAC,aAAa,CAAC,IAAI,gBAAgB,EAAE,CAAC;AACzD,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -26,8 +26,8 @@ export { useCommand } from './useCommand.js';
|
|
|
26
26
|
export type { UseCommandOptions, UseCommandResult, CommandFn, VoidCommandFn, } from './useCommand.js';
|
|
27
27
|
export { useMutation } from './useMutation.js';
|
|
28
28
|
export type { UseMutationOptions, UseMutationResult } from './useMutation.js';
|
|
29
|
-
export { useSuspenseCommand, invalidateCommands } from './useSuspenseCommand.js';
|
|
30
|
-
export type { SuspenseEntry } from './useSuspenseCommand.js';
|
|
29
|
+
export { useSuspenseCommand, invalidateCommands, configureSuspenseCache, } from './useSuspenseCommand.js';
|
|
30
|
+
export type { SuspenseEntry, SuspenseCacheOptions } from './useSuspenseCommand.js';
|
|
31
31
|
export { useEvent } from './useEvent.js';
|
|
32
32
|
export type { EventCallback, UnsubscribeFn, SubscribeResult, SubscribeFn } from './useEvent.js';
|
|
33
33
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/D,YAAY,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,EACT,aAAa,GACd,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE9E,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/D,YAAY,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,EACT,aAAa,GACd,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE9E,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAEnF,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -23,6 +23,6 @@
|
|
|
23
23
|
export { RustraProvider, useRustraEngine } from './context.js';
|
|
24
24
|
export { useCommand } from './useCommand.js';
|
|
25
25
|
export { useMutation } from './useMutation.js';
|
|
26
|
-
export { useSuspenseCommand, invalidateCommands } from './useSuspenseCommand.js';
|
|
26
|
+
export { useSuspenseCommand, invalidateCommands, configureSuspenseCache, } from './useSuspenseCommand.js';
|
|
27
27
|
export { useEvent } from './useEvent.js';
|
|
28
28
|
//# 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;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAG/D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAQ7C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAG/D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAQ7C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/input-key.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* bigint with the same decimal string.
|
|
2
|
+
* Structural, type-tagged identity for supported command inputs. Tags are outside
|
|
3
|
+
* user objects, so a record cannot impersonate a bigint, Set, or binary value.
|
|
4
|
+
* Object keys are canonicalized; Map/Set iteration order and binary view type
|
|
5
|
+
* are preserved because the original input is passed unchanged to the engine.
|
|
7
6
|
*/
|
|
8
7
|
export declare function inputKey(value: unknown): string;
|
|
9
8
|
//# sourceMappingURL=input-key.d.ts.map
|
package/dist/input-key.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-key.d.ts","sourceRoot":"","sources":["../src/input-key.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"input-key.d.ts","sourceRoot":"","sources":["../src/input-key.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CA2D/C"}
|
package/dist/input-key.js
CHANGED
|
@@ -1,11 +1,69 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* bigint with the same decimal string.
|
|
2
|
+
* Structural, type-tagged identity for supported command inputs. Tags are outside
|
|
3
|
+
* user objects, so a record cannot impersonate a bigint, Set, or binary value.
|
|
4
|
+
* Object keys are canonicalized; Map/Set iteration order and binary view type
|
|
5
|
+
* are preserved because the original input is passed unchanged to the engine.
|
|
7
6
|
*/
|
|
8
7
|
export function inputKey(value) {
|
|
9
|
-
|
|
8
|
+
const ancestors = new Set();
|
|
9
|
+
function encode(item) {
|
|
10
|
+
if (item === null)
|
|
11
|
+
return ['null'];
|
|
12
|
+
switch (typeof item) {
|
|
13
|
+
case 'undefined':
|
|
14
|
+
return ['undefined'];
|
|
15
|
+
case 'string':
|
|
16
|
+
return ['string', item];
|
|
17
|
+
case 'boolean':
|
|
18
|
+
return ['boolean', item];
|
|
19
|
+
case 'bigint':
|
|
20
|
+
return ['bigint', item.toString()];
|
|
21
|
+
case 'number':
|
|
22
|
+
return ['number', Object.is(item, -0) ? '-0' : String(item)];
|
|
23
|
+
case 'function':
|
|
24
|
+
case 'symbol':
|
|
25
|
+
throw new TypeError('Rustra command inputs cannot contain functions or symbols');
|
|
26
|
+
}
|
|
27
|
+
if (ancestors.has(item))
|
|
28
|
+
throw new TypeError('Rustra command inputs cannot contain cycles');
|
|
29
|
+
ancestors.add(item);
|
|
30
|
+
try {
|
|
31
|
+
if (item instanceof ArrayBuffer || ArrayBuffer.isView(item)) {
|
|
32
|
+
const bytes = item instanceof ArrayBuffer
|
|
33
|
+
? new Uint8Array(item)
|
|
34
|
+
: new Uint8Array(item.buffer, item.byteOffset, item.byteLength);
|
|
35
|
+
return ['binary', Object.prototype.toString.call(item), Array.from(bytes)];
|
|
36
|
+
}
|
|
37
|
+
if (item instanceof Date)
|
|
38
|
+
return ['date', item.toISOString()];
|
|
39
|
+
if (item instanceof Set)
|
|
40
|
+
return ['set', Array.from(item, encode)];
|
|
41
|
+
if (item instanceof Map)
|
|
42
|
+
return ['map', Array.from(item, ([key, value]) => [encode(key), encode(value)])];
|
|
43
|
+
if (Array.isArray(item)) {
|
|
44
|
+
return [
|
|
45
|
+
'array',
|
|
46
|
+
Array.from({ length: item.length }, (_, index) => index in item ? encode(item[index]) : ['hole']),
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
const prototype = Object.getPrototypeOf(item);
|
|
50
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
51
|
+
throw new TypeError('Rustra command inputs must use supported values or plain records');
|
|
52
|
+
}
|
|
53
|
+
if (Object.getOwnPropertySymbols(item).length > 0) {
|
|
54
|
+
throw new TypeError('Rustra command inputs cannot contain symbol keys');
|
|
55
|
+
}
|
|
56
|
+
return [
|
|
57
|
+
'object',
|
|
58
|
+
Object.keys(item)
|
|
59
|
+
.sort()
|
|
60
|
+
.map((key) => [key, encode(item[key])]),
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
ancestors.delete(item);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return JSON.stringify(encode(value));
|
|
10
68
|
}
|
|
11
69
|
//# sourceMappingURL=input-key.js.map
|
package/dist/input-key.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-key.js","sourceRoot":"","sources":["../src/input-key.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"input-key.js","sourceRoot":"","sources":["../src/input-key.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { EngineClient } from '@rustra/types';
|
|
2
|
+
export interface SuspenseEntry<O = unknown> {
|
|
3
|
+
commandName: string;
|
|
4
|
+
promise: Promise<O>;
|
|
5
|
+
status: 'pending' | 'fulfilled' | 'rejected';
|
|
6
|
+
value?: O;
|
|
7
|
+
error?: unknown;
|
|
8
|
+
}
|
|
9
|
+
export interface SuspenseCacheOptions {
|
|
10
|
+
/** Maximum total entries per engine. Default: 256. */
|
|
11
|
+
maxEntries?: number;
|
|
12
|
+
/** Retention after settlement, in milliseconds. Default: 300000 (5 minutes). */
|
|
13
|
+
ttlMs?: number;
|
|
14
|
+
/** Maximum time a cached request can remain pending. Default: 30000. */
|
|
15
|
+
pendingTimeoutMs?: number;
|
|
16
|
+
}
|
|
17
|
+
/** Configure one engine's finite cache policy and discard its existing entries. */
|
|
18
|
+
export declare function configureSuspenseCache(options: SuspenseCacheOptions, engine?: EngineClient): void;
|
|
19
|
+
/** With an engine, invalidate only that scope; without one, all live scopes. */
|
|
20
|
+
export declare function invalidateCommands(commandName?: string, engine?: EngineClient): void;
|
|
21
|
+
export declare function resolveSuspenseEntry<O>(key: string, commandName: string, start: () => Promise<O>, engine?: EngineClient): SuspenseEntry<O>;
|
|
22
|
+
//# sourceMappingURL=suspense-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suspense-cache.d.ts","sourceRoot":"","sources":["../src/suspense-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGlD,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACpB,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;IAC7C,KAAK,CAAC,EAAE,CAAC,CAAC;IACV,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAsCD,mFAAmF;AACnF,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,oBAAoB,EAC7B,MAAM,eAAqB,GAC1B,IAAI,CAgBN;AAED,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI,CAWpF;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACvB,MAAM,GAAE,YAAiC,GACxC,aAAa,CAAC,CAAC,CAAC,CA0DlB"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { getDefaultEngine } from './context.js';
|
|
2
|
+
const defaults = { maxEntries: 256, ttlMs: 300_000, pendingTimeoutMs: 30_000 };
|
|
3
|
+
const caches = new WeakMap();
|
|
4
|
+
// Weak references preserve the legacy cross-engine invalidation API without
|
|
5
|
+
// retaining an engine (or its data) after its owner is gone.
|
|
6
|
+
const liveCaches = new Set();
|
|
7
|
+
function getCache(engine) {
|
|
8
|
+
let cache = caches.get(engine);
|
|
9
|
+
if (!cache) {
|
|
10
|
+
cache = { entries: new Map(), policy: { ...defaults } };
|
|
11
|
+
caches.set(engine, cache);
|
|
12
|
+
for (const reference of liveCaches)
|
|
13
|
+
if (!reference.deref())
|
|
14
|
+
liveCaches.delete(reference);
|
|
15
|
+
liveCaches.add(new WeakRef(cache));
|
|
16
|
+
}
|
|
17
|
+
return cache;
|
|
18
|
+
}
|
|
19
|
+
function remove(cache, key) {
|
|
20
|
+
const record = cache.entries.get(key);
|
|
21
|
+
if (record?.expiry)
|
|
22
|
+
clearTimeout(record.expiry);
|
|
23
|
+
cache.entries.delete(key);
|
|
24
|
+
}
|
|
25
|
+
function invalidate(cache, commandName) {
|
|
26
|
+
for (const [key, record] of cache.entries) {
|
|
27
|
+
if (commandName === undefined || record.entry.commandName === commandName)
|
|
28
|
+
remove(cache, key);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** Configure one engine's finite cache policy and discard its existing entries. */
|
|
32
|
+
export function configureSuspenseCache(options, engine = getDefaultEngine()) {
|
|
33
|
+
const policy = { ...defaults, ...options };
|
|
34
|
+
for (const [name, value] of Object.entries(policy)) {
|
|
35
|
+
if (!Number.isSafeInteger(value) ||
|
|
36
|
+
value < 1 ||
|
|
37
|
+
(name !== 'maxEntries' && value > 2_147_483_647)) {
|
|
38
|
+
throw new RangeError(`Rustra suspense cache ${name} must be a positive safe integer within timer limits`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const cache = getCache(engine);
|
|
42
|
+
invalidate(cache);
|
|
43
|
+
cache.policy = policy;
|
|
44
|
+
}
|
|
45
|
+
/** With an engine, invalidate only that scope; without one, all live scopes. */
|
|
46
|
+
export function invalidateCommands(commandName, engine) {
|
|
47
|
+
if (engine) {
|
|
48
|
+
const cache = caches.get(engine);
|
|
49
|
+
if (cache)
|
|
50
|
+
invalidate(cache, commandName);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
for (const reference of liveCaches) {
|
|
54
|
+
const cache = reference.deref();
|
|
55
|
+
if (cache)
|
|
56
|
+
invalidate(cache, commandName);
|
|
57
|
+
else
|
|
58
|
+
liveCaches.delete(reference);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export function resolveSuspenseEntry(key, commandName, start, engine = getDefaultEngine()) {
|
|
62
|
+
const cache = getCache(engine);
|
|
63
|
+
const now = Date.now();
|
|
64
|
+
for (const [candidate, record] of cache.entries) {
|
|
65
|
+
if (record.entry.status !== 'pending' && record.expiresAt <= now)
|
|
66
|
+
remove(cache, candidate);
|
|
67
|
+
}
|
|
68
|
+
const existing = cache.entries.get(key);
|
|
69
|
+
if (existing) {
|
|
70
|
+
cache.entries.delete(key);
|
|
71
|
+
cache.entries.set(key, existing);
|
|
72
|
+
return existing.entry;
|
|
73
|
+
}
|
|
74
|
+
if (cache.entries.size >= cache.policy.maxEntries) {
|
|
75
|
+
const evictable = [...cache.entries].find(([, record]) => record.entry.status !== 'pending');
|
|
76
|
+
if (evictable)
|
|
77
|
+
remove(cache, evictable[0]);
|
|
78
|
+
else
|
|
79
|
+
throw new Error('Rustra suspense cache capacity reached while all requests are pending');
|
|
80
|
+
}
|
|
81
|
+
let timeout;
|
|
82
|
+
const deadline = new Promise((_, reject) => {
|
|
83
|
+
timeout = setTimeout(() => reject(new Error('Rustra suspense command timed out')), cache.policy.pendingTimeoutMs);
|
|
84
|
+
});
|
|
85
|
+
let invocation;
|
|
86
|
+
try {
|
|
87
|
+
invocation = start();
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
invocation = Promise.reject(error);
|
|
91
|
+
}
|
|
92
|
+
const promise = Promise.race([invocation, deadline]);
|
|
93
|
+
const entry = { commandName, promise, status: 'pending' };
|
|
94
|
+
const record = { entry, expiresAt: Infinity };
|
|
95
|
+
cache.entries.set(key, record);
|
|
96
|
+
function settled() {
|
|
97
|
+
clearTimeout(timeout);
|
|
98
|
+
// Invalidated requests still settle for their callers but never reinsert.
|
|
99
|
+
if (cache.entries.get(key) !== record)
|
|
100
|
+
return;
|
|
101
|
+
record.expiresAt = Date.now() + cache.policy.ttlMs;
|
|
102
|
+
record.expiry = setTimeout(() => remove(cache, key), cache.policy.ttlMs);
|
|
103
|
+
// Node SSR must not remain alive solely for cache retention.
|
|
104
|
+
record.expiry.unref?.();
|
|
105
|
+
}
|
|
106
|
+
promise.then((value) => {
|
|
107
|
+
entry.status = 'fulfilled';
|
|
108
|
+
entry.value = value;
|
|
109
|
+
settled();
|
|
110
|
+
}, (error) => {
|
|
111
|
+
entry.status = 'rejected';
|
|
112
|
+
entry.error = error instanceof Error ? error : new Error(String(error));
|
|
113
|
+
settled();
|
|
114
|
+
});
|
|
115
|
+
return entry;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=suspense-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suspense-cache.js","sourceRoot":"","sources":["../src/suspense-cache.ts"],"names":[],"mappings":"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"}
|
package/dist/useEvent.js
CHANGED
package/dist/useEvent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useEvent.js","sourceRoot":"","sources":["../src/useEvent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAU1C;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CACtB,SAAiB,EACjB,QAA0B,EAC1B,SAA0B;IAE1B,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAErC,SAAS,CAAC,GAAG,EAAE;QACb,WAAW,CAAC,OAAO,GAAG,QAAQ,CAAC;IACjC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEf,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,SAAS;YAAE,OAAO;QACvB,IAAI,MAAM,GAAG,IAAI,CAAC;QAClB,IAAI,WAAsC,CAAC;QAC3C,IAAI,MAAuB,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,GAAG,SAAS,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE;gBACxC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"useEvent.js","sourceRoot":"","sources":["../src/useEvent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAU1C;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CACtB,SAAiB,EACjB,QAA0B,EAC1B,SAA0B;IAE1B,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAErC,SAAS,CAAC,GAAG,EAAE;QACb,WAAW,CAAC,OAAO,GAAG,QAAQ,CAAC;IACjC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEf,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,SAAS;YAAE,OAAO;QACvB,IAAI,MAAM,GAAG,IAAI,CAAC;QAClB,IAAI,WAAsC,CAAC;QAC3C,IAAI,MAAuB,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,GAAG,SAAS,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE;gBACxC,IAAI,MAAM;oBAAE,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAC3C,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,mCAAmC,SAAS,WAAW,EAAE,KAAK,CAAC,CAAC;YAC9E,OAAO,GAAG,EAAE;gBACV,MAAM,GAAG,KAAK,CAAC;YACjB,CAAC,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAC1B,CAAC,OAAO,EAAE,EAAE;YACV,IAAI,MAAM;gBAAE,WAAW,GAAG,OAAO,CAAC;;gBAC7B,OAAO,EAAE,CAAC;QACjB,CAAC,EACD,CAAC,KAAK,EAAE,EAAE;YACR,IAAI,MAAM,EAAE,CAAC;gBACX,OAAO,CAAC,KAAK,CAAC,mCAAmC,SAAS,WAAW,EAAE,KAAK,CAAC,CAAC;YAChF,CAAC;QACH,CAAC,CACF,CAAC;QACF,OAAO,GAAG,EAAE;YACV,MAAM,GAAG,KAAK,CAAC;YACf,WAAW,EAAE,EAAE,CAAC;QAClB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;AAC7B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMutation.d.ts","sourceRoot":"","sources":["../src/useMutation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhE,MAAM,WAAW,kBAAkB,CAAC,CAAC,EAAE,CAAC;IACtC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IACxC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC3C,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;CAC1E;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC,EAAE,CAAC;IACrC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC3B,WAAW,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/D,IAAI,EAAE,CAAC,GAAG,SAAS,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,wBAAgB,WAAW,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,OAAO,EAC/C,SAAS,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,EAC7C,OAAO,CAAC,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,GACjC,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"useMutation.d.ts","sourceRoot":"","sources":["../src/useMutation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhE,MAAM,WAAW,kBAAkB,CAAC,CAAC,EAAE,CAAC;IACtC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IACxC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC3C,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;CAC1E;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC,EAAE,CAAC;IACrC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC3B,WAAW,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/D,IAAI,EAAE,CAAC,GAAG,SAAS,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,wBAAgB,WAAW,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,OAAO,EAC/C,SAAS,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,EAC7C,OAAO,CAAC,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,GACjC,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,CAqGzB"}
|
package/dist/useMutation.js
CHANGED
|
@@ -1,71 +1,95 @@
|
|
|
1
|
-
import { useState, useCallback, useEffect,
|
|
1
|
+
import { useState, useCallback, useEffect, useInsertionEffect, useMemo } from 'react';
|
|
2
2
|
import { resolveCommandId } from '@rustra/types';
|
|
3
3
|
import { useRustraEngine } from './context.js';
|
|
4
4
|
export function useMutation(commandFn, options) {
|
|
5
5
|
const engine = useRustraEngine();
|
|
6
|
-
const [data, setData] = useState(undefined);
|
|
7
|
-
const [loading, setLoading] = useState(false);
|
|
8
|
-
const [error, setError] = useState(null);
|
|
9
|
-
// minify-안전 식별: 코드젠이 심은 commandId 를 우선한다 (Function.name 은
|
|
10
|
-
// 프로덕션 번들러 mangling 으로 바뀔 수 있다).
|
|
11
6
|
const commandName = resolveCommandId(commandFn);
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
7
|
+
// Each engine/command pair owns its counters and callback snapshot. Retained
|
|
8
|
+
// async functions cannot borrow a replacement scope's callbacks or state.
|
|
9
|
+
const scope = useMemo(() => ({
|
|
10
|
+
engine,
|
|
11
|
+
commandName,
|
|
12
|
+
active: true,
|
|
13
|
+
generation: 0,
|
|
14
|
+
latestCall: 0,
|
|
15
|
+
pendingCalls: 0,
|
|
16
|
+
options: undefined,
|
|
17
|
+
}), [engine, commandName]);
|
|
18
|
+
const emptyState = {
|
|
19
|
+
scope,
|
|
20
|
+
data: undefined,
|
|
21
|
+
loading: false,
|
|
22
|
+
error: null,
|
|
23
|
+
};
|
|
24
|
+
const [state, setState] = useState(emptyState);
|
|
25
|
+
if (state.scope !== scope)
|
|
26
|
+
setState(emptyState);
|
|
27
|
+
// Publish only committed options, before any descendant layout effect can
|
|
28
|
+
// invoke the stable mutation function. Render-time writes leak aborted renders.
|
|
29
|
+
useInsertionEffect(() => {
|
|
30
|
+
scope.options = options;
|
|
31
|
+
}, [scope, options]);
|
|
16
32
|
useEffect(() => {
|
|
17
|
-
|
|
18
|
-
|
|
33
|
+
scope.active = true;
|
|
34
|
+
return () => {
|
|
35
|
+
scope.active = false;
|
|
36
|
+
scope.generation += 1;
|
|
37
|
+
scope.pendingCalls = 0;
|
|
38
|
+
};
|
|
39
|
+
}, [scope]);
|
|
19
40
|
const mutateAsync = useCallback(async (input, invokeOptions) => {
|
|
20
|
-
const generation =
|
|
21
|
-
const callId = ++
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
41
|
+
const generation = scope.generation;
|
|
42
|
+
const callId = ++scope.latestCall;
|
|
43
|
+
const callbacks = scope.options;
|
|
44
|
+
const isCurrent = () => scope.active && scope.generation === generation;
|
|
45
|
+
const update = (changes) => {
|
|
46
|
+
if (!isCurrent())
|
|
47
|
+
return;
|
|
48
|
+
setState((current) => (current.scope === scope ? { ...current, ...changes } : current));
|
|
49
|
+
};
|
|
50
|
+
scope.pendingCalls += 1;
|
|
51
|
+
update({ loading: true, error: null });
|
|
25
52
|
let result;
|
|
26
53
|
try {
|
|
27
|
-
result = await engine.invoke(commandName, input, invokeOptions);
|
|
54
|
+
result = await scope.engine.invoke(scope.commandName, input, invokeOptions);
|
|
28
55
|
}
|
|
29
56
|
catch (err) {
|
|
30
57
|
const parsedError = err instanceof Error ? err : new Error(String(err));
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
optionsRef.current?.onSettled?.(undefined, parsedError, input);
|
|
58
|
+
if (scope.latestCall === callId)
|
|
59
|
+
update({ error: parsedError });
|
|
60
|
+
callbacks?.onError?.(parsedError, input);
|
|
61
|
+
callbacks?.onSettled?.(undefined, parsedError, input);
|
|
36
62
|
throw parsedError;
|
|
37
63
|
}
|
|
38
64
|
finally {
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
|
|
65
|
+
if (isCurrent()) {
|
|
66
|
+
scope.pendingCalls = Math.max(0, scope.pendingCalls - 1);
|
|
67
|
+
update({ loading: scope.pendingCalls > 0 });
|
|
42
68
|
}
|
|
43
69
|
}
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
optionsRef.current?.onSettled?.(result, null, input);
|
|
70
|
+
if (scope.latestCall === callId)
|
|
71
|
+
update({ data: result });
|
|
72
|
+
callbacks?.onSuccess?.(result, input);
|
|
73
|
+
callbacks?.onSettled?.(result, null, input);
|
|
49
74
|
return result;
|
|
50
|
-
}, [
|
|
75
|
+
}, [scope]);
|
|
51
76
|
const mutate = useCallback((input) => {
|
|
52
77
|
mutateAsync(input).catch(() => {
|
|
53
78
|
// Handled in mutateAsync state & onError callback
|
|
54
79
|
});
|
|
55
80
|
}, [mutateAsync]);
|
|
56
81
|
const reset = useCallback(() => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}, []);
|
|
82
|
+
scope.generation += 1;
|
|
83
|
+
scope.pendingCalls = 0;
|
|
84
|
+
setState((current) => current.scope === scope ? { scope, data: undefined, error: null, loading: false } : current);
|
|
85
|
+
}, [scope]);
|
|
86
|
+
const current = state.scope === scope ? state : emptyState;
|
|
63
87
|
return {
|
|
64
88
|
mutate,
|
|
65
89
|
mutateAsync,
|
|
66
|
-
data,
|
|
67
|
-
loading,
|
|
68
|
-
error,
|
|
90
|
+
data: current.data,
|
|
91
|
+
loading: current.loading,
|
|
92
|
+
error: current.error,
|
|
69
93
|
reset,
|
|
70
94
|
};
|
|
71
95
|
}
|
package/dist/useMutation.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMutation.js","sourceRoot":"","sources":["../src/useMutation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"useMutation.js","sourceRoot":"","sources":["../src/useMutation.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,50 +1,11 @@
|
|
|
1
1
|
import type { InvokeOptions } from '@rustra/types';
|
|
2
2
|
import type { CommandFn, VoidCommandFn } from './useCommand.js';
|
|
3
|
+
export { resolveSuspenseEntry, invalidateCommands, configureSuspenseCache, } from './suspense-cache.js';
|
|
4
|
+
export type { SuspenseEntry, SuspenseCacheOptions } from './suspense-cache.js';
|
|
3
5
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
export interface SuspenseEntry<O = unknown> {
|
|
8
|
-
/** Owning command — `invalidateCommands` matches this field, not the key prefix. */
|
|
9
|
-
commandName: string;
|
|
10
|
-
promise: Promise<O>;
|
|
11
|
-
status: 'pending' | 'fulfilled' | 'rejected';
|
|
12
|
-
value?: O;
|
|
13
|
-
error?: unknown;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Pure cache state machine: returns the existing entry for `key` when present,
|
|
17
|
-
* otherwise creates one by invoking `start()` and drives it to its terminal
|
|
18
|
-
* state. Settling updates the entry in place, so later accessors read the
|
|
19
|
-
* cached value/error without re-invoking. Rejections are normalized to `Error`
|
|
20
|
-
* (matching `useCommand`/`useMutation`); the stored object is re-thrown as-is.
|
|
21
|
-
*
|
|
22
|
-
* Exported for testing — the hook stays thin, and this is testable without
|
|
23
|
-
* React (a thrown promise is awkward to exercise under SSR renderToString).
|
|
24
|
-
*/
|
|
25
|
-
export declare function resolveSuspenseEntry<O>(key: string, commandName: string, start: () => Promise<O>): SuspenseEntry<O>;
|
|
26
|
-
/**
|
|
27
|
-
* Invalidate cached suspense entries.
|
|
28
|
-
*
|
|
29
|
-
* - `invalidateCommands('getItem')` — drop only that command's entries,
|
|
30
|
-
* matched by the entry's owning command (exact, so command names containing
|
|
31
|
-
* `::` cannot be over-matched by a shorter prefix).
|
|
32
|
-
* - `invalidateCommands()` — drop every cached entry.
|
|
33
|
-
*
|
|
34
|
-
* Works outside components (module-level cache), e.g. after a mutation.
|
|
35
|
-
*/
|
|
36
|
-
export declare function invalidateCommands(commandName?: string): void;
|
|
37
|
-
/**
|
|
38
|
-
* Suspense-compatible command hook. Must be called under a Suspense boundary.
|
|
39
|
-
*
|
|
40
|
-
* First call starts the invocation and throws the in-flight promise —
|
|
41
|
-
* thrown-thenable Suspense on React 18, `use` on React 19. Once settled,
|
|
42
|
-
* subsequent calls return the cached value. A rejected invocation re-throws
|
|
43
|
-
* the same stored error object on every access (error boundary contract) until
|
|
44
|
-
* `invalidateCommands` clears it.
|
|
45
|
-
*
|
|
46
|
-
* `options` are honored only on the first invocation per key; later calls
|
|
47
|
-
* reuse the cached promise.
|
|
6
|
+
* Suspends until an engine-scoped command result is ready. Inputs are structurally
|
|
7
|
+
* keyed; options apply only to the first invocation of a cached key. Rejected
|
|
8
|
+
* results reach the nearest error boundary until invalidation or expiry.
|
|
48
9
|
*/
|
|
49
10
|
export declare function useSuspenseCommand<I, O>(commandFn: CommandFn<I, O> | VoidCommandFn<O>, input?: I, options?: InvokeOptions): O;
|
|
50
11
|
//# sourceMappingURL=useSuspenseCommand.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSuspenseCommand.d.ts","sourceRoot":"","sources":["../src/useSuspenseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"useSuspenseCommand.d.ts","sourceRoot":"","sources":["../src/useSuspenseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAIhE,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE/E;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,CAAC,EACrC,SAAS,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,EAC7C,KAAK,CAAC,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,aAAa,GACtB,CAAC,CAYH"}
|
|
@@ -1,81 +1,17 @@
|
|
|
1
1
|
import { resolveCommandId } from '@rustra/types';
|
|
2
2
|
import { useRustraEngine } from './context.js';
|
|
3
3
|
import { inputKey } from './input-key.js';
|
|
4
|
+
import { resolveSuspenseEntry } from './suspense-cache.js';
|
|
5
|
+
export { resolveSuspenseEntry, invalidateCommands, configureSuspenseCache, } from './suspense-cache.js';
|
|
4
6
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* No eviction policy by design (YAGNI) — entries live for the session.
|
|
10
|
-
*/
|
|
11
|
-
const cache = new Map();
|
|
12
|
-
function cacheKey(commandName, input) {
|
|
13
|
-
return `${commandName}::${input === undefined ? '' : inputKey(input)}`;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Pure cache state machine: returns the existing entry for `key` when present,
|
|
17
|
-
* otherwise creates one by invoking `start()` and drives it to its terminal
|
|
18
|
-
* state. Settling updates the entry in place, so later accessors read the
|
|
19
|
-
* cached value/error without re-invoking. Rejections are normalized to `Error`
|
|
20
|
-
* (matching `useCommand`/`useMutation`); the stored object is re-thrown as-is.
|
|
21
|
-
*
|
|
22
|
-
* Exported for testing — the hook stays thin, and this is testable without
|
|
23
|
-
* React (a thrown promise is awkward to exercise under SSR renderToString).
|
|
24
|
-
*/
|
|
25
|
-
export function resolveSuspenseEntry(key, commandName, start) {
|
|
26
|
-
const existing = cache.get(key);
|
|
27
|
-
if (existing)
|
|
28
|
-
return existing;
|
|
29
|
-
const promise = start();
|
|
30
|
-
const entry = { commandName, promise, status: 'pending' };
|
|
31
|
-
cache.set(key, entry);
|
|
32
|
-
promise.then((value) => {
|
|
33
|
-
entry.status = 'fulfilled';
|
|
34
|
-
entry.value = value;
|
|
35
|
-
}, (err) => {
|
|
36
|
-
entry.status = 'rejected';
|
|
37
|
-
entry.error = err instanceof Error ? err : new Error(String(err));
|
|
38
|
-
});
|
|
39
|
-
return entry;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Invalidate cached suspense entries.
|
|
43
|
-
*
|
|
44
|
-
* - `invalidateCommands('getItem')` — drop only that command's entries,
|
|
45
|
-
* matched by the entry's owning command (exact, so command names containing
|
|
46
|
-
* `::` cannot be over-matched by a shorter prefix).
|
|
47
|
-
* - `invalidateCommands()` — drop every cached entry.
|
|
48
|
-
*
|
|
49
|
-
* Works outside components (module-level cache), e.g. after a mutation.
|
|
50
|
-
*/
|
|
51
|
-
export function invalidateCommands(commandName) {
|
|
52
|
-
if (commandName === undefined) {
|
|
53
|
-
cache.clear();
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
for (const [key, entry] of cache) {
|
|
57
|
-
if (entry.commandName === commandName)
|
|
58
|
-
cache.delete(key);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Suspense-compatible command hook. Must be called under a Suspense boundary.
|
|
63
|
-
*
|
|
64
|
-
* First call starts the invocation and throws the in-flight promise —
|
|
65
|
-
* thrown-thenable Suspense on React 18, `use` on React 19. Once settled,
|
|
66
|
-
* subsequent calls return the cached value. A rejected invocation re-throws
|
|
67
|
-
* the same stored error object on every access (error boundary contract) until
|
|
68
|
-
* `invalidateCommands` clears it.
|
|
69
|
-
*
|
|
70
|
-
* `options` are honored only on the first invocation per key; later calls
|
|
71
|
-
* reuse the cached promise.
|
|
7
|
+
* Suspends until an engine-scoped command result is ready. Inputs are structurally
|
|
8
|
+
* keyed; options apply only to the first invocation of a cached key. Rejected
|
|
9
|
+
* results reach the nearest error boundary until invalidation or expiry.
|
|
72
10
|
*/
|
|
73
11
|
export function useSuspenseCommand(commandFn, input, options) {
|
|
74
12
|
const engine = useRustraEngine();
|
|
75
|
-
// minify-안전 식별: 코드젠이 심은 commandId 를 우선한다 (Function.name 은
|
|
76
|
-
// 프로덕션 번들러 mangling 으로 바뀔 수 있다).
|
|
77
13
|
const commandName = resolveCommandId(commandFn);
|
|
78
|
-
const entry = resolveSuspenseEntry(
|
|
14
|
+
const entry = resolveSuspenseEntry(JSON.stringify([commandName, inputKey(input)]), commandName, () => engine.invoke(commandName, input, options), engine);
|
|
79
15
|
if (entry.status === 'pending')
|
|
80
16
|
throw entry.promise;
|
|
81
17
|
if (entry.status === 'rejected')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSuspenseCommand.js","sourceRoot":"","sources":["../src/useSuspenseCommand.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"useSuspenseCommand.js","sourceRoot":"","sources":["../src/useSuspenseCommand.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAG7B;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,SAA6C,EAC7C,KAAS,EACT,OAAuB;IAEvB,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,MAAM,WAAW,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,oBAAoB,CAChC,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAC9C,WAAW,EACX,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAI,WAAW,EAAE,KAAK,EAAE,OAAO,CAAC,EACnD,MAAM,CACP,CAAC;IACF,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;QAAE,MAAM,KAAK,CAAC,OAAO,CAAC;IACpD,IAAI,KAAK,CAAC,MAAM,KAAK,UAAU;QAAE,MAAM,KAAK,CAAC,KAAK,CAAC;IACnD,OAAO,KAAK,CAAC,KAAU,CAAC;AAC1B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rustra/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "React and React Native bindings and hooks for rustra-bridge",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -23,19 +23,23 @@
|
|
|
23
23
|
"scripts": {
|
|
24
24
|
"build": "tsc",
|
|
25
25
|
"clean": "rm -rf dist",
|
|
26
|
-
"test": "bun test src/index.test.ts",
|
|
26
|
+
"test": "bun test ./src/index.test.ts ./src/suspense-lifecycle.test.ts && bun test ./src/lifecycle.test.ts",
|
|
27
27
|
"test:compile": "tsc -p tsconfig.test.json"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"react": ">=18.0.0"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@rustra/types": "^0.
|
|
33
|
+
"@rustra/types": "^0.11.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/react": "^19.0.0",
|
|
37
|
-
"react": "
|
|
38
|
-
"typescript": "^5.9.0"
|
|
37
|
+
"react": "19.2.8",
|
|
38
|
+
"typescript": "^5.9.0",
|
|
39
|
+
"react-dom": "19.2.8",
|
|
40
|
+
"@types/react-dom": "^19.0.0",
|
|
41
|
+
"react-test-renderer": "19.2.8",
|
|
42
|
+
"@types/react-test-renderer": "^19.0.0"
|
|
39
43
|
},
|
|
40
44
|
"keywords": [
|
|
41
45
|
"rustra",
|