@rustra/react 0.5.0 → 0.7.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/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/useSuspenseCommand.d.ts +50 -0
- package/dist/useSuspenseCommand.d.ts.map +1 -0
- package/dist/useSuspenseCommand.js +85 -0
- package/dist/useSuspenseCommand.js.map +1 -0
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -26,6 +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
31
|
export { useEvent } from './useEvent.js';
|
|
30
32
|
export type { EventCallback, UnsubscribeFn, SubscribeResult, SubscribeFn } from './useEvent.js';
|
|
31
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,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
|
|
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,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AACjF,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,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,5 +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
27
|
export { useEvent } from './useEvent.js';
|
|
27
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,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
|
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,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAGjF,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { InvokeOptions } from '@rustra/types';
|
|
2
|
+
import type { CommandFn, VoidCommandFn } from './useCommand.js';
|
|
3
|
+
/**
|
|
4
|
+
* Cache entry state machine — `pending` until the in-flight promise settles,
|
|
5
|
+
* then `fulfilled` (value stored) or `rejected` (error stored).
|
|
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.
|
|
48
|
+
*/
|
|
49
|
+
export declare function useSuspenseCommand<I, O>(commandFn: CommandFn<I, O> | VoidCommandFn<O>, input?: I, options?: InvokeOptions): O;
|
|
50
|
+
//# sourceMappingURL=useSuspenseCommand.d.ts.map
|
|
@@ -0,0 +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;AAGhE;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO;IACxC,oFAAoF;IACpF,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;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACtB,aAAa,CAAC,CAAC,CAAC,CAmBlB;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAQ7D;AAED;;;;;;;;;;;GAWG;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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { resolveCommandId } from '@rustra/types';
|
|
2
|
+
import { useRustraEngine } from './context.js';
|
|
3
|
+
import { inputKey } from './input-key.js';
|
|
4
|
+
/**
|
|
5
|
+
* Module-level suspense cache. Key is the resolved command name followed by
|
|
6
|
+
* `::` and the serialized input — an absent input collapses to the bare
|
|
7
|
+
* `commandName + '::'` suffix, otherwise `inputKey(input)` (bigint-safe).
|
|
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.
|
|
72
|
+
*/
|
|
73
|
+
export function useSuspenseCommand(commandFn, input, options) {
|
|
74
|
+
const engine = useRustraEngine();
|
|
75
|
+
// minify-안전 식별: 코드젠이 심은 commandId 를 우선한다 (Function.name 은
|
|
76
|
+
// 프로덕션 번들러 mangling 으로 바뀔 수 있다).
|
|
77
|
+
const commandName = resolveCommandId(commandFn);
|
|
78
|
+
const entry = resolveSuspenseEntry(cacheKey(commandName, input), commandName, () => engine.invoke(commandName, input, options));
|
|
79
|
+
if (entry.status === 'pending')
|
|
80
|
+
throw entry.promise;
|
|
81
|
+
if (entry.status === 'rejected')
|
|
82
|
+
throw entry.error;
|
|
83
|
+
return entry.value;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=useSuspenseCommand.js.map
|
|
@@ -0,0 +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;AAe1C;;;;;;GAMG;AACH,MAAM,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAC;AAE/C,SAAS,QAAQ,CAAC,WAAmB,EAAE,KAAc;IACnD,OAAO,GAAG,WAAW,KAAK,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;AACzE,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAClC,GAAW,EACX,WAAmB,EACnB,KAAuB;IAEvB,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,QAAQ;QAAE,OAAO,QAA4B,CAAC;IAElD,MAAM,OAAO,GAAG,KAAK,EAAE,CAAC;IACxB,MAAM,KAAK,GAAqB,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAC5E,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAEtB,OAAO,CAAC,IAAI,CACV,CAAC,KAAK,EAAE,EAAE;QACR,KAAK,CAAC,MAAM,GAAG,WAAW,CAAC;QAC3B,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;IACtB,CAAC,EACD,CAAC,GAAY,EAAE,EAAE;QACf,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC;QAC1B,KAAK,CAAC,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACpE,CAAC,CACF,CAAC;IACF,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAoB;IACrD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,OAAO;IACT,CAAC;IACD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC;QACjC,IAAI,KAAK,CAAC,WAAW,KAAK,WAAW;YAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAChC,SAA6C,EAC7C,KAAS,EACT,OAAuB;IAEvB,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,0DAA0D;IAC1D,iCAAiC;IACjC,MAAM,WAAW,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,oBAAoB,CAAI,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,CACpF,MAAM,CAAC,MAAM,CAAI,WAAW,EAAE,KAAK,EAAE,OAAO,CAAC,CAC9C,CAAC;IAEF,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.7.0",
|
|
4
4
|
"description": "React and React Native bindings and hooks for rustra-bridge",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"react": ">=18.0.0"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@rustra/types": "^0.
|
|
33
|
+
"@rustra/types": "^0.8.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/react": "^19.0.0",
|