@deepseek-ai/dsh-client-resources 0.1.5-alpha.1 → 0.1.5-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/README.i18n.yaml +2 -2
- package/README.md +3 -4
- package/README.zh.md +3 -4
- package/lib/client.js +9 -16
- package/lib/types/client/contract.d.ts +0 -7
- package/package.json +6 -6
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/client/resources/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 6b5afc82230be6930c41a01a584aeed39f596c37
|
|
6
|
+
README.zh.md: 6b928883bb54cd4663efa7a20a7bc768d4f8399e
|
package/README.md
CHANGED
|
@@ -33,12 +33,12 @@ Nothing needs configuration to mount: the plugin provides `ctx.resources` and co
|
|
|
33
33
|
<a id="read-a-resource"></a>
|
|
34
34
|
### Read a resource
|
|
35
35
|
|
|
36
|
-
Every slot component receives `useResource` in its props. `useResource<P>(address)` names the protocol as the type argument and returns `{ status, value, failure
|
|
36
|
+
Every slot component receives `useResource` in its props. `useResource<P>(address)` names the protocol as the type argument and returns `{ status, value, failure }`: `none` when no provider is registered for the address's protocol (or the address is not a `dsh-resource://` URL), `loading` while the provider has not yielded, `live` with the latest `ok` frame's value, and `failed` when the latest frame reported a failure, with that failure beside the last value. Subscribing through the hook is what holds the resource open; a component that mounts while another holder keeps the resource alive reads the latest value at once.
|
|
37
37
|
|
|
38
38
|
<a id="provide-a-protocol"></a>
|
|
39
39
|
### Provide a protocol
|
|
40
40
|
|
|
41
|
-
The protocol's owning client package declares its value type in `ResourceProtocolMap` and registers one provider as an owned effect. `open` yields `RemoteResult` frames: the current content first and one frame per later change, with a failure as an `ok: false` frame rather than a throw; it must stop when `signal` aborts
|
|
41
|
+
The protocol's owning client package declares its value type in `ResourceProtocolMap` and registers one provider as an owned effect. `open` yields `RemoteResult` frames: the current content first and one frame per later change, with a failure as an `ok: false` frame rather than a throw; it must stop when `signal` aborts:
|
|
42
42
|
|
|
43
43
|
```ts ignore-check
|
|
44
44
|
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
@@ -54,7 +54,6 @@ export function apply(ctx) {
|
|
|
54
54
|
yield await readNote(address, signal)
|
|
55
55
|
for await (const change of followNote(address, signal)) yield change
|
|
56
56
|
},
|
|
57
|
-
reload(address) { requestReread(address) },
|
|
58
57
|
}), 'my-notes: note resource provider')
|
|
59
58
|
}
|
|
60
59
|
```
|
|
@@ -72,7 +71,7 @@ A protocol has exactly one provider; a second registration throws. Registering a
|
|
|
72
71
|
<a id="lifecycle"></a>
|
|
73
72
|
### Lifecycle
|
|
74
73
|
|
|
75
|
-
One record per address holds a snapshot store, a holder count (hook subscribers plus pins), and the running stream's `AbortController`. The first holder opens the provider's stream; every later holder shares it; the last holder's release aborts the stream and resets the snapshot to idle (`loading` with a provider, `none` without). Records are kept for the page lifetime so `source()` stays reference-stable across React's render-then-subscribe window and a StrictMode remount.
|
|
74
|
+
One record per address holds a snapshot store, a holder count (hook subscribers plus pins), and the running stream's `AbortController`. The first holder opens the provider's stream; every later holder shares it; the last holder's release aborts the stream and resets the snapshot to idle (`loading` with a provider, `none` without). Records are kept for the page lifetime so `source()` stays reference-stable across React's render-then-subscribe window and a StrictMode remount.
|
|
76
75
|
|
|
77
76
|
<a id="failures"></a>
|
|
78
77
|
### Failures
|
package/README.zh.md
CHANGED
|
@@ -33,12 +33,12 @@ kind: "package-reference"
|
|
|
33
33
|
<a id="read-a-resource"></a>
|
|
34
34
|
### 读取资源
|
|
35
35
|
|
|
36
|
-
每个 slot 组件都在 props 上收到 `useResource`。`useResource<P>(address)` 以类型参数命名协议,返回 `{ status, value, failure
|
|
36
|
+
每个 slot 组件都在 props 上收到 `useResource`。`useResource<P>(address)` 以类型参数命名协议,返回 `{ status, value, failure }`:地址协议没有提供方(或地址不是 `dsh-resource://` URL)时为 `none`,提供方尚未产出值时为 `loading`,`live` 携带最新一个 `ok` 帧的值,`failed` 表示最新一帧报告了失败,失败放在最后一个值旁。通过 hook 订阅就是钉住资源的方式;另一个持有者让资源保持存活时,新挂载的组件立刻读到最新值。
|
|
37
37
|
|
|
38
38
|
<a id="provide-a-protocol"></a>
|
|
39
39
|
### 提供协议
|
|
40
40
|
|
|
41
|
-
协议所属的客户端包在 `ResourceProtocolMap` 声明其值类型,并以自有 effect 注册一个提供方。`open` 产出 `RemoteResult` 帧:先是当前内容,之后每次变化一帧,失败以 `ok: false` 帧而非抛错表达;必须在 `signal`
|
|
41
|
+
协议所属的客户端包在 `ResourceProtocolMap` 声明其值类型,并以自有 effect 注册一个提供方。`open` 产出 `RemoteResult` 帧:先是当前内容,之后每次变化一帧,失败以 `ok: false` 帧而非抛错表达;必须在 `signal` 中止时停止:
|
|
42
42
|
|
|
43
43
|
```ts ignore-check
|
|
44
44
|
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
@@ -54,7 +54,6 @@ export function apply(ctx) {
|
|
|
54
54
|
yield await readNote(address, signal)
|
|
55
55
|
for await (const change of followNote(address, signal)) yield change
|
|
56
56
|
},
|
|
57
|
-
reload(address) { requestReread(address) },
|
|
58
57
|
}), 'my-notes: note resource provider')
|
|
59
58
|
}
|
|
60
59
|
```
|
|
@@ -72,7 +71,7 @@ export function apply(ctx) {
|
|
|
72
71
|
<a id="lifecycle"></a>
|
|
73
72
|
### 生命周期
|
|
74
73
|
|
|
75
|
-
每个地址一条记录,持有一个快照 store、一个持有者计数(hook 订阅者加 pin)与运行中流的 `AbortController`。第一个持有者打开提供方的流;之后的持有者共享它;最后一个持有者释放时中止流并把快照重置为空闲(有提供方为 `loading`,没有为 `none`)。记录在页面存续期内保留,使 `source()` 在 React 渲染到订阅的窗口与 StrictMode
|
|
74
|
+
每个地址一条记录,持有一个快照 store、一个持有者计数(hook 订阅者加 pin)与运行中流的 `AbortController`。第一个持有者打开提供方的流;之后的持有者共享它;最后一个持有者释放时中止流并把快照重置为空闲(有提供方为 `loading`,没有为 `none`)。记录在页面存续期内保留,使 `source()` 在 React 渲染到订阅的窗口与 StrictMode 重挂载之间保持引用稳定。
|
|
76
75
|
|
|
77
76
|
<a id="failures"></a>
|
|
78
77
|
### 失败
|
package/lib/client.js
CHANGED
|
@@ -23,12 +23,11 @@ window.__ModuleLoader__.load({
|
|
|
23
23
|
if (parsed.protocol !== `dsh-resource:`) return void 0;
|
|
24
24
|
return parsed.hostname === "" ? void 0 : parsed.hostname.toLowerCase();
|
|
25
25
|
}
|
|
26
|
-
function idle(status
|
|
26
|
+
function idle(status) {
|
|
27
27
|
return {
|
|
28
28
|
status,
|
|
29
29
|
value: void 0,
|
|
30
|
-
failure: void 0
|
|
31
|
-
reload
|
|
30
|
+
failure: void 0
|
|
32
31
|
};
|
|
33
32
|
}
|
|
34
33
|
/** The `ctx.resources` implementation. */
|
|
@@ -77,15 +76,11 @@ window.__ModuleLoader__.load({
|
|
|
77
76
|
}
|
|
78
77
|
create(address) {
|
|
79
78
|
const protocol = protocolOf(address);
|
|
80
|
-
const
|
|
81
|
-
this.providerOf(protocol)?.reload?.(address);
|
|
82
|
-
};
|
|
83
|
-
const store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(idle(this.providerOf(protocol) === void 0 ? "none" : "loading", reload));
|
|
79
|
+
const store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(idle(this.providerOf(protocol) === void 0 ? "none" : "loading"));
|
|
84
80
|
const record = {
|
|
85
81
|
address,
|
|
86
82
|
protocol,
|
|
87
83
|
store,
|
|
88
|
-
reload,
|
|
89
84
|
holders: 0,
|
|
90
85
|
controller: void 0,
|
|
91
86
|
source: {
|
|
@@ -119,7 +114,7 @@ window.__ModuleLoader__.load({
|
|
|
119
114
|
record.holders -= 1;
|
|
120
115
|
if (record.holders > 0) return;
|
|
121
116
|
this.stop(record);
|
|
122
|
-
record.store.set(idle(this.providerOf(record.protocol) === void 0 ? "none" : "loading"
|
|
117
|
+
record.store.set(idle(this.providerOf(record.protocol) === void 0 ? "none" : "loading"));
|
|
123
118
|
}
|
|
124
119
|
/** The provider arrived: a held record opens its stream, an idle one turns `loading`. */
|
|
125
120
|
attach(record) {
|
|
@@ -127,19 +122,19 @@ window.__ModuleLoader__.load({
|
|
|
127
122
|
this.start(record);
|
|
128
123
|
return;
|
|
129
124
|
}
|
|
130
|
-
record.store.set(idle("loading"
|
|
125
|
+
record.store.set(idle("loading"));
|
|
131
126
|
}
|
|
132
127
|
/** The provider left: the stream ends and the record reports `none`. */
|
|
133
128
|
detach(record) {
|
|
134
129
|
this.stop(record);
|
|
135
|
-
record.store.set(idle("none"
|
|
130
|
+
record.store.set(idle("none"));
|
|
136
131
|
}
|
|
137
132
|
start(record) {
|
|
138
133
|
const provider = this.providerOf(record.protocol);
|
|
139
134
|
if (provider === void 0) return;
|
|
140
135
|
const controller = new AbortController();
|
|
141
136
|
record.controller = controller;
|
|
142
|
-
if (record.store.getSnapshot().status !== "loading") record.store.set(idle("loading"
|
|
137
|
+
if (record.store.getSnapshot().status !== "loading") record.store.set(idle("loading"));
|
|
143
138
|
this.consume(record, provider, controller.signal);
|
|
144
139
|
}
|
|
145
140
|
stop(record) {
|
|
@@ -154,13 +149,11 @@ window.__ModuleLoader__.load({
|
|
|
154
149
|
record.store.set(frame.ok ? {
|
|
155
150
|
status: "live",
|
|
156
151
|
value: frame.value,
|
|
157
|
-
failure: void 0
|
|
158
|
-
reload: record.reload
|
|
152
|
+
failure: void 0
|
|
159
153
|
} : {
|
|
160
154
|
status: "failed",
|
|
161
155
|
value: record.store.getSnapshot().value,
|
|
162
|
-
failure: frame.error
|
|
163
|
-
reload: record.reload
|
|
156
|
+
failure: frame.error
|
|
164
157
|
});
|
|
165
158
|
}
|
|
166
159
|
}
|
|
@@ -45,8 +45,6 @@ export interface ResourceSnapshot<Value> {
|
|
|
45
45
|
readonly value: Value | undefined;
|
|
46
46
|
/** The latest frame's failure; present only while `status` is `failed`. */
|
|
47
47
|
readonly failure: RemoteFailure | undefined;
|
|
48
|
-
/** Ask the provider for a fresh frame; a no-op when its protocol has no provider or no `reload`. */
|
|
49
|
-
readonly reload: () => void;
|
|
50
48
|
}
|
|
51
49
|
/**
|
|
52
50
|
* Global standard hook: the current state of one address, typed by the
|
|
@@ -74,11 +72,6 @@ export interface ResourceProvider<P extends ResourceProtocol> {
|
|
|
74
72
|
* @returns the frame stream; it must stop once `ctx.signal` aborts.
|
|
75
73
|
*/
|
|
76
74
|
open(address: string, ctx: ResourceOpenContext): AsyncIterable<RemoteResult<ResourceProtocolMap[P]>>;
|
|
77
|
-
/**
|
|
78
|
-
* Produce a fresh frame on the open stream. Absent when the protocol has no refresh.
|
|
79
|
-
* @param address - the full address, a `dsh-resource://<type>/…` URL.
|
|
80
|
-
*/
|
|
81
|
-
reload?(address: string): void;
|
|
82
75
|
}
|
|
83
76
|
/**
|
|
84
77
|
* The `ctx.resources` service. One resource is one address; it stays open
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-client-resources",
|
|
3
3
|
"description": "Unified client resource model: protocol-registered providers turn URL addresses into live values, consumed through the useResource global standard hook",
|
|
4
|
-
"version": "0.1.5-alpha.
|
|
4
|
+
"version": "0.1.5-alpha.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -39,11 +39,11 @@
|
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
42
|
-
"@deepseek-ai/dsh-client-store": "^0.1.5-alpha.
|
|
43
|
-
"@deepseek-ai/dsh-client-
|
|
44
|
-
"@deepseek-ai/dsh-client-ui-slots": "^0.1.5-alpha.
|
|
45
|
-
"@deepseek-ai/dsh-typert-protocol": "^0.1.5-alpha.
|
|
46
|
-
"@deepseek-ai/dsh-client-
|
|
42
|
+
"@deepseek-ai/dsh-client-store": "^0.1.5-alpha.2",
|
|
43
|
+
"@deepseek-ai/dsh-client-ui-renderer": "^0.1.5-alpha.2",
|
|
44
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.5-alpha.2",
|
|
45
|
+
"@deepseek-ai/dsh-typert-protocol": "^0.1.5-alpha.2",
|
|
46
|
+
"@deepseek-ai/dsh-client-test-runtime": "^0.1.5-alpha.2"
|
|
47
47
|
},
|
|
48
48
|
"files": [
|
|
49
49
|
"lib/index.js",
|