@aigne/doc-smith 0.8.0 → 0.8.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.
|
@@ -1,48 +1,1088 @@
|
|
|
1
|
+
- 使用 d2 展示架构关系、流程与组件交互
|
|
1
2
|
- 使用 d2 图表解释复杂的概念 (```d2``` format),让页面内容展示形式更丰富
|
|
2
|
-
-
|
|
3
|
-
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
3
|
+
- 使用的 d2 的版本是 0.7.x,d2 官方的文档请查看 https://d2lang.com/tour/intro/
|
|
4
|
+
- 图表应简洁明了,节点和连线命名准确,节点与连线文案保持简洁,不要太长
|
|
5
|
+
- bad
|
|
6
|
+
```d2
|
|
7
|
+
"TokenService": {
|
|
8
|
+
label: "TokenService (Handles token storage & refresh)"
|
|
9
|
+
shape: class
|
|
10
|
+
}
|
|
11
|
+
```
|
|
12
|
+
- good
|
|
13
|
+
```d2
|
|
14
|
+
"TokenService": {
|
|
15
|
+
label: "TokenService"
|
|
16
|
+
shape: class
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
- 连线上的文字描述,尽量简洁明了,一般来说只需要使用单个词或两个词即可
|
|
20
|
+
- bad:
|
|
21
|
+
```d2
|
|
22
|
+
"User Login" -> "Session Creation": "User submits login form with credentials"
|
|
23
|
+
```
|
|
24
|
+
- good:
|
|
25
|
+
```d2
|
|
26
|
+
"User Login" -> "Session Creation": "login"
|
|
27
|
+
```
|
|
28
|
+
- d2 代码块必须完整且可渲染,避免使用未闭合的语法与奇异字符,避免语法错误
|
|
29
|
+
- 确保每一个节点都有 label 属性,用来表达节点的名称
|
|
30
|
+
- 如果节点的 label 过长,则应该使用 `\n` 来进行换行
|
|
31
|
+
- bad
|
|
32
|
+
```d2
|
|
33
|
+
"AuthService": {
|
|
34
|
+
label: "AuthService (Handles user authentication, profile management, privacy settings, and related actions)"
|
|
35
|
+
shape: class
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
- good
|
|
39
|
+
```d2
|
|
40
|
+
"AuthService": {
|
|
41
|
+
label: "AuthService\n(Handles user authentication,\nprofile management, privacy settings,\nand related actions)"
|
|
42
|
+
shape: class
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
- **非常重要** 如果节点的名称包含了特殊字符(如 `@`、` `、`/`, 空格等),请将名称中的特殊字符转换为 `-`,然后使用 label 来表达原始的名称,确保节点的名称一定不要使用 `"` 包裹
|
|
46
|
+
- bad:
|
|
47
|
+
```d2
|
|
48
|
+
"@blocklet/js-sdk": {
|
|
49
|
+
shape: package
|
|
50
|
+
|
|
51
|
+
TokenService: {
|
|
52
|
+
shape: class
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
- good:
|
|
57
|
+
```d2
|
|
58
|
+
"blocklet-js-sdk": {
|
|
59
|
+
shape: package
|
|
60
|
+
label: "@blocklet/js-sdk
|
|
61
|
+
|
|
62
|
+
TokenService: {
|
|
63
|
+
shape: class
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
- 必须确保每个节点和子节点是有名称的
|
|
68
|
+
- bad:
|
|
69
|
+
```d2
|
|
70
|
+
"SDK Core Instance": {
|
|
71
|
+
shape: package
|
|
72
|
+
"TokenService": "Manages session and refresh tokens"
|
|
73
|
+
"Services": {
|
|
74
|
+
grid-columns: 2
|
|
75
|
+
"AuthService": ""
|
|
76
|
+
"BlockletService": ""
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
- good:
|
|
81
|
+
```d2
|
|
82
|
+
"SDK Core Instance": {
|
|
83
|
+
shape: package
|
|
84
|
+
"TokenService": "Manages session and refresh tokens"
|
|
85
|
+
"Services": {
|
|
86
|
+
grid-columns: 2
|
|
87
|
+
"AuthService": "AuthService"
|
|
88
|
+
"BlockletService": "BlockletService"
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
- 不要为节点添加 `tooltip`,保持简单即可
|
|
93
|
+
- bad
|
|
94
|
+
```d2
|
|
95
|
+
"AuthService": {
|
|
96
|
+
label: "AuthService"
|
|
97
|
+
tooltip: "Manages user profiles, privacy, and authentication actions"
|
|
98
|
+
shape: class
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
- good
|
|
102
|
+
```d2
|
|
103
|
+
"AuthService": {
|
|
104
|
+
label: "AuthService"
|
|
105
|
+
shape: class
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
- 不要随意给节点/连线填充颜色,除非节点/连线有明确的 yes/no 的状态,此时可以添加 `error`, `warning`, `success` 之类的颜色
|
|
109
|
+
- bad
|
|
110
|
+
```d2
|
|
111
|
+
"TokenService" {
|
|
112
|
+
shape: class
|
|
113
|
+
style.fill: "#fffbe6"
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
- good
|
|
117
|
+
```d2
|
|
118
|
+
"TokenService" {
|
|
119
|
+
shape: class
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
- 对于单个节点和连线,不要使用 `animate: true`,避免有些地方有,但有些地方没有的情况(看起来会很奇怪)
|
|
123
|
+
- 连线的箭头方向必须正确,确保箭头指向关系的下游端
|
|
124
|
+
- 连线的样式,尽量保持一致,不要有些实线,有些虚线的情况,除非有明确的区分意义
|
|
125
|
+
- 页面的整体布局使用 `direction: down`,这样能确保图表适合在网页中进行阅读;子图中可以根据情况来使用其他的方向布局,需要确保图表的整体效果看起来不会太宽
|
|
126
|
+
- bad:
|
|
127
|
+
```d2
|
|
128
|
+
direction: right
|
|
129
|
+
|
|
130
|
+
"online": {
|
|
131
|
+
shape: circle
|
|
132
|
+
style.fill: "#52c41a"
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
"offline": {
|
|
136
|
+
shape: circle
|
|
137
|
+
style.fill: "#faad14"
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
"expired": {
|
|
141
|
+
shape: circle
|
|
142
|
+
style.fill: "#ff4d4f"
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
"New Login" -> "online": "User authenticates"
|
|
146
|
+
"online" -> "offline": "User closes app/browser"
|
|
147
|
+
"online" -> "expired": "Token expires"
|
|
148
|
+
"offline" -> "online": "User returns"
|
|
149
|
+
"offline" -> "expired": "Extended inactivity"
|
|
150
|
+
```
|
|
151
|
+
- good:
|
|
152
|
+
```d2
|
|
153
|
+
direction: down
|
|
154
|
+
|
|
155
|
+
"online": {
|
|
156
|
+
shape: circle
|
|
157
|
+
style.fill: "#52c41a"
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
"offline": {
|
|
161
|
+
shape: circle
|
|
162
|
+
style.fill: "#faad14"
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
"expired": {
|
|
166
|
+
shape: circle
|
|
167
|
+
style.fill: "#ff4d4f"
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
"New Login" -> "online": "User authenticates"
|
|
171
|
+
"online" -> "offline": "User closes app/browser"
|
|
172
|
+
"online" -> "expired": "Token expires"
|
|
173
|
+
"offline" -> "online": "User returns"
|
|
174
|
+
"offline" -> "expired": "Extended inactivity"
|
|
175
|
+
```
|
|
176
|
+
- 如果一个节点中的字节点太多了(超过3个),请使用 `grid-columns` 限制一下单行的列数,`grid-columns` 的值优先使用2,最大不要超过 3,例如
|
|
177
|
+
- good:
|
|
178
|
+
```d2
|
|
179
|
+
"Instance": {
|
|
180
|
+
grid-columns: 3
|
|
181
|
+
"A": "A"
|
|
182
|
+
"B": "B"
|
|
183
|
+
"C": "C"
|
|
184
|
+
"D": "D"
|
|
185
|
+
"E": "E"
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
```d2
|
|
189
|
+
"Instance": {
|
|
190
|
+
grid-columns: 2
|
|
191
|
+
"A": "A"
|
|
192
|
+
"B": "B"
|
|
193
|
+
"C": "C"
|
|
194
|
+
"D": "D"
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
- 每一个容器节点中,最好设置 `grid-columns`
|
|
198
|
+
- bad:
|
|
199
|
+
```d2
|
|
200
|
+
direction: down
|
|
201
|
+
|
|
202
|
+
"SDK": "@blocklet/js-sdk" {
|
|
203
|
+
shape: package
|
|
204
|
+
|
|
205
|
+
"Core Instance": {
|
|
206
|
+
shape: rectangle
|
|
207
|
+
"BlockletSDK": "Main SDK Class"
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
"Services": {
|
|
211
|
+
grid-columns: 3
|
|
212
|
+
"AuthService": "User Authentication" {
|
|
213
|
+
shape: class
|
|
214
|
+
}
|
|
215
|
+
"TokenService": "Token Management" {
|
|
216
|
+
shape: class
|
|
217
|
+
}
|
|
218
|
+
"UserSessionService": "Session Management" {
|
|
219
|
+
shape: class
|
|
220
|
+
}
|
|
221
|
+
"BlockletService": "Blocklet Metadata" {
|
|
222
|
+
shape: class
|
|
223
|
+
}
|
|
224
|
+
"FederatedService": "Federated Login" {
|
|
225
|
+
shape: class
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
"HTTP Clients": {
|
|
230
|
+
grid-columns: 2
|
|
231
|
+
"createAxios": "Axios-based Client" {
|
|
232
|
+
shape: rectangle
|
|
233
|
+
}
|
|
234
|
+
"createFetch": "Fetch-based Client" {
|
|
235
|
+
shape: rectangle
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
"Your App": "Application Code" {
|
|
241
|
+
shape: rectangle
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
"Blocklet Services": "Remote APIs" {
|
|
245
|
+
shape: cylinder
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
"Your App" -> "SDK": "Import & Use"
|
|
249
|
+
"SDK" -> "Blocklet Services": "Authenticated Requests"
|
|
250
|
+
"Blocklet Services" -> "SDK": "Responses & Tokens"
|
|
251
|
+
```
|
|
252
|
+
- good:
|
|
253
|
+
```d2
|
|
254
|
+
direction: down
|
|
255
|
+
|
|
256
|
+
"SDK": "@blocklet/js-sdk" {
|
|
257
|
+
shape: package
|
|
258
|
+
grid-columns: 1
|
|
259
|
+
|
|
260
|
+
"Core Instance": {
|
|
261
|
+
shape: rectangle
|
|
262
|
+
"BlockletSDK": "Main SDK Class"
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
"Services": {
|
|
266
|
+
grid-columns: 3
|
|
267
|
+
"AuthService": "User Authentication" {
|
|
268
|
+
shape: class
|
|
269
|
+
}
|
|
270
|
+
"TokenService": "Token Management" {
|
|
271
|
+
shape: class
|
|
272
|
+
}
|
|
273
|
+
"UserSessionService": "Session Management" {
|
|
274
|
+
shape: class
|
|
275
|
+
}
|
|
276
|
+
"BlockletService": "Blocklet Metadata" {
|
|
277
|
+
shape: class
|
|
278
|
+
}
|
|
279
|
+
"FederatedService": "Federated Login" {
|
|
280
|
+
shape: class
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
"HTTP Clients": {
|
|
285
|
+
grid-columns: 2
|
|
286
|
+
"createAxios": "Axios-based Client" {
|
|
287
|
+
shape: rectangle
|
|
288
|
+
}
|
|
289
|
+
"createFetch": "Fetch-based Client" {
|
|
290
|
+
shape: rectangle
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
"Your App": "Application Code" {
|
|
296
|
+
shape: rectangle
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
"Blocklet Services": "Remote APIs" {
|
|
300
|
+
shape: cylinder
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
"Your App" -> "SDK": "Import & Use"
|
|
304
|
+
"SDK" -> "Blocklet Services": "Authenticated Requests"
|
|
305
|
+
"Blocklet Services" -> "SDK": "Responses & Tokens"
|
|
306
|
+
```
|
|
307
|
+
- 必须保证一个图中,所有的节点都是有关联的,不需要为图表设置 legend,如果有节点不存在关联性,则应该移除这些节点,或者拆分成多个独立的图表
|
|
308
|
+
- bad:
|
|
309
|
+
```d2
|
|
310
|
+
direction: down
|
|
311
|
+
|
|
312
|
+
"Your App": {
|
|
313
|
+
shape: rectangle
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
"SDK Request Helper": {
|
|
317
|
+
label: "@blocklet/js-sdk (createAxios / createFetch)"
|
|
318
|
+
shape: package
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
"Blocklet Service": {
|
|
322
|
+
shape: cylinder
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
"Token Refresh Endpoint": {
|
|
326
|
+
label: "/api/did/refreshSession"
|
|
327
|
+
shape: rectangle
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
"Your App" -> "SDK Request Helper": "1. Make API Call (e.g., /api/profile)"
|
|
331
|
+
|
|
332
|
+
"SDK Request Helper" -> "Blocklet Service": "2. Adds Auth Header & Sends Request" {
|
|
333
|
+
style {
|
|
334
|
+
stroke-dash: 2
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
"Success Path": {
|
|
339
|
+
style.stroke: "#52c41a"
|
|
340
|
+
|
|
341
|
+
"Blocklet Service" -> "SDK Request Helper": "3a. 200 OK (Token Valid)"
|
|
342
|
+
"SDK Request Helper" -> "Your App": "4a. Returns Data"
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
"Token Renewal Path": {
|
|
347
|
+
style.stroke: "#faad14"
|
|
348
|
+
|
|
349
|
+
"Blocklet Service" -> "SDK Request Helper": "3b. 401 Unauthorized (Token Expired)"
|
|
350
|
+
"SDK Request Helper" -> "Token Refresh Endpoint": "4b. Request New Token"
|
|
351
|
+
"Token Refresh Endpoint" -> "SDK Request Helper": "5b. New Tokens"
|
|
352
|
+
"SDK Request Helper" -> "Blocklet Service": "6b. Retry Original Request"
|
|
353
|
+
"Blocklet Service" -> "SDK Request Helper": "7b. 200 OK" {
|
|
354
|
+
style.stroke: "#52c41a"
|
|
355
|
+
}
|
|
356
|
+
"SDK Request Helper" -> "Your App": "8b. Returns Data Transparently" {
|
|
357
|
+
style.stroke: "#52c41a"
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
- good:
|
|
362
|
+
```d2
|
|
363
|
+
direction: down
|
|
364
|
+
|
|
365
|
+
"Your App": {
|
|
366
|
+
shape: rectangle
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
"SDK Request Helper": {
|
|
370
|
+
label: "@blocklet/js-sdk (createAxios / createFetch)"
|
|
371
|
+
shape: package
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
"Blocklet Service": {
|
|
375
|
+
shape: cylinder
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
"Token Refresh Endpoint": {
|
|
379
|
+
label: "/api/did/refreshSession"
|
|
380
|
+
shape: rectangle
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
"Your App" -> "SDK Request Helper": "1. Make API Call (e.g., /api/profile)"
|
|
384
|
+
|
|
385
|
+
"SDK Request Helper" -> "Blocklet Service": "2. Adds Auth Header & Sends Request" {
|
|
386
|
+
style {
|
|
387
|
+
stroke-dash: 2
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
```d2
|
|
392
|
+
"Success Path": {
|
|
393
|
+
style.stroke: "#52c41a"
|
|
394
|
+
|
|
395
|
+
"Blocklet Service" -> "SDK Request Helper": "3a. 200 OK (Token Valid)"
|
|
396
|
+
"SDK Request Helper" -> "Your App": "4a. Returns Data"
|
|
397
|
+
}
|
|
398
|
+
```
|
|
399
|
+
```d2
|
|
400
|
+
"Token Renewal Path": {
|
|
401
|
+
style.stroke: "#faad14"
|
|
402
|
+
|
|
403
|
+
"Blocklet Service" -> "SDK Request Helper": "3b. 401 Unauthorized (Token Expired)"
|
|
404
|
+
"SDK Request Helper" -> "Token Refresh Endpoint": "4b. Request New Token"
|
|
405
|
+
"Token Refresh Endpoint" -> "SDK Request Helper": "5b. New Tokens"
|
|
406
|
+
"SDK Request Helper" -> "Blocklet Service": "6b. Retry Original Request"
|
|
407
|
+
"Blocklet Service" -> "SDK Request Helper": "7b. 200 OK" {
|
|
408
|
+
style.stroke: "#52c41a"
|
|
409
|
+
}
|
|
410
|
+
"SDK Request Helper" -> "Your App": "8b. Returns Data Transparently" {
|
|
411
|
+
style.stroke: "#52c41a"
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
- 当有关联关系的节点,处于一个节点内部时,则它们的关联关系也应该写在节点内部
|
|
416
|
+
- bad
|
|
417
|
+
```d2
|
|
418
|
+
direction: down
|
|
419
|
+
|
|
420
|
+
"@blocklet/js-sdk": {
|
|
421
|
+
shape: package
|
|
422
|
+
|
|
423
|
+
"Main SDK Instance": {
|
|
424
|
+
shape: rectangle
|
|
425
|
+
"BlockletSDK Class": "Main entry point"
|
|
426
|
+
"getBlockletSDK()": "Singleton factory"
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
"HTTP Clients": {
|
|
430
|
+
shape: rectangle
|
|
431
|
+
grid-columns: 2
|
|
432
|
+
"createAxios()": "Axios-based client"
|
|
433
|
+
"createFetch()": "Fetch-based client"
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
"Core Services": {
|
|
437
|
+
shape: rectangle
|
|
438
|
+
grid-columns: 3
|
|
439
|
+
"AuthService": "User authentication"
|
|
440
|
+
"TokenService": "Token management"
|
|
441
|
+
"BlockletService": "Blocklet metadata"
|
|
442
|
+
"UserSessionService": "Session management"
|
|
443
|
+
"FederatedService": "Federated login"
|
|
444
|
+
"ComponentService": "Component utilities"
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
"Main SDK Instance" -> "HTTP Clients": "Uses for requests"
|
|
449
|
+
"Main SDK Instance" -> "Core Services": "Provides access to"
|
|
450
|
+
"HTTP Clients" -> "Core Services": "Configured with"
|
|
451
|
+
```
|
|
452
|
+
- good
|
|
453
|
+
```d2
|
|
454
|
+
direction: down
|
|
455
|
+
|
|
456
|
+
"@blocklet/js-sdk": {
|
|
457
|
+
shape: package
|
|
458
|
+
|
|
459
|
+
"Main SDK Instance": {
|
|
460
|
+
shape: rectangle
|
|
461
|
+
"BlockletSDK Class": "Main entry point"
|
|
462
|
+
"getBlockletSDK()": "Singleton factory"
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
"HTTP Clients": {
|
|
466
|
+
shape: rectangle
|
|
467
|
+
grid-columns: 2
|
|
468
|
+
"createAxios()": "Axios-based client"
|
|
469
|
+
"createFetch()": "Fetch-based client"
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
"Core Services": {
|
|
473
|
+
shape: rectangle
|
|
474
|
+
grid-columns: 3
|
|
475
|
+
"AuthService": "User authentication"
|
|
476
|
+
"TokenService": "Token management"
|
|
477
|
+
"BlockletService": "Blocklet metadata"
|
|
478
|
+
"UserSessionService": "Session management"
|
|
479
|
+
"FederatedService": "Federated login"
|
|
480
|
+
"ComponentService": "Component utilities"
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
"Main SDK Instance" -> "HTTP Clients": "Uses for requests"
|
|
484
|
+
"Main SDK Instance" -> "Core Services": "Provides access to"
|
|
485
|
+
"HTTP Clients" -> "Core Services": "Configured with"
|
|
486
|
+
}
|
|
487
|
+
```
|
|
488
|
+
- bad:
|
|
489
|
+
```d2
|
|
490
|
+
direction: down
|
|
491
|
+
|
|
492
|
+
"Your App": {
|
|
493
|
+
shape: rectangle
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
"SDK Request Helper": {
|
|
497
|
+
label: "@blocklet/js-sdk (createAxios / createFetch)"
|
|
498
|
+
shape: package
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
"Blocklet Service": {
|
|
502
|
+
shape: cylinder
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
"Your App" -> "SDK Request Helper": "1. Make API Call (e.g., /api/profile)"
|
|
507
|
+
|
|
508
|
+
"SDK Request Helper" -> "Blocklet Service": "2. Adds Auth Header & Sends Request" {
|
|
509
|
+
style {
|
|
510
|
+
stroke-dash: 2
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
"Token Renewal Path": {
|
|
515
|
+
style.stroke: "#faad14"
|
|
516
|
+
|
|
517
|
+
"Blocklet Service" -> "SDK Request Helper": "3. 401 Unauthorized (Token Expired)"
|
|
518
|
+
"SDK Request Helper" -> "Token Refresh Endpoint": "4. Request New Token"
|
|
519
|
+
"Token Refresh Endpoint" -> "SDK Request Helper": "5. New Tokens Received"
|
|
520
|
+
"SDK Request Helper" -> "Blocklet Service": "6. Retry Original Request with New Token"
|
|
521
|
+
"Blocklet Service" -> "SDK Request Helper": "7. 200 OK" {
|
|
522
|
+
style.stroke: "#52c41a"
|
|
523
|
+
}
|
|
524
|
+
"SDK Request Helper" -> "Your App": "8. Returns Data Transparently" {
|
|
525
|
+
style.stroke: "#52c41a"
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
```
|
|
529
|
+
- good:
|
|
530
|
+
```d2
|
|
531
|
+
direction: down
|
|
532
|
+
|
|
533
|
+
"Your App": {
|
|
534
|
+
shape: rectangle
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
"SDK Request Helper": {
|
|
538
|
+
label: "@blocklet/js-sdk (createAxios / createFetch)"
|
|
539
|
+
shape: package
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
"Blocklet Service": {
|
|
543
|
+
shape: cylinder
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
"Your App" -> "SDK Request Helper": "1. Make API Call (e.g., /api/profile)"
|
|
548
|
+
|
|
549
|
+
"SDK Request Helper" -> "Blocklet Service": "2. Adds Auth Header & Sends Request" {
|
|
550
|
+
style {
|
|
551
|
+
stroke-dash: 2
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
"Blocklet Service" -> "SDK Request Helper": "3. 401 Unauthorized (Token Expired)"
|
|
556
|
+
"SDK Request Helper" -> "Token Refresh Endpoint": "4. Request New Token"
|
|
557
|
+
"Token Refresh Endpoint" -> "SDK Request Helper": "5. New Tokens Received"
|
|
558
|
+
"SDK Request Helper" -> "Blocklet Service": "6. Retry Original Request with New Token"
|
|
559
|
+
"Blocklet Service" -> "SDK Request Helper": "7. 200 OK" {
|
|
560
|
+
style.stroke: "#52c41a"
|
|
561
|
+
}
|
|
562
|
+
"SDK Request Helper" -> "Your App": "8. Returns Data Transparently" {
|
|
563
|
+
style.stroke: "#52c41a"
|
|
564
|
+
}
|
|
565
|
+
```
|
|
566
|
+
- 如果整个图表只有一个容器节点,就不要增加这个容器节点,直接将内部的节点放在最外层
|
|
567
|
+
- bad:
|
|
568
|
+
```d2
|
|
569
|
+
direction: down
|
|
570
|
+
|
|
571
|
+
"User Sessions Flow": {
|
|
572
|
+
shape: package
|
|
573
|
+
grid-columns: 1
|
|
574
|
+
|
|
575
|
+
"User Login": {
|
|
576
|
+
shape: person
|
|
577
|
+
style.fill: "#e6f7ff"
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
"Session Creation": {
|
|
581
|
+
shape: rectangle
|
|
582
|
+
style.fill: "#f6ffed"
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
"Session Storage": {
|
|
586
|
+
shape: cylinder
|
|
587
|
+
style.fill: "#fff7e6"
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
"Multi-Device Access": {
|
|
591
|
+
shape: package
|
|
592
|
+
grid-columns: 3
|
|
593
|
+
"Web Browser": {
|
|
594
|
+
shape: rectangle
|
|
595
|
+
}
|
|
596
|
+
"Mobile App": {
|
|
597
|
+
shape: rectangle
|
|
598
|
+
}
|
|
599
|
+
"Desktop App": {
|
|
600
|
+
shape: rectangle
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
"User Login" -> "Session Creation": "Authenticate"
|
|
604
|
+
"Session Creation" -> "Session Storage": "Store session"
|
|
605
|
+
"Session Storage" -> "Multi-Device Access": "Access from devices"
|
|
606
|
+
}
|
|
607
|
+
```
|
|
608
|
+
- good:
|
|
609
|
+
```d2
|
|
610
|
+
direction: down
|
|
611
|
+
|
|
612
|
+
"User Login": {
|
|
613
|
+
shape: person
|
|
614
|
+
style.fill: "#e6f7ff"
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
"Session Creation": {
|
|
618
|
+
shape: rectangle
|
|
619
|
+
style.fill: "#f6ffed"
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
"Session Storage": {
|
|
623
|
+
shape: cylinder
|
|
624
|
+
style.fill: "#fff7e6"
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
"Multi-Device Access": {
|
|
628
|
+
shape: package
|
|
629
|
+
grid-columns: 3
|
|
630
|
+
"Web Browser": {
|
|
631
|
+
shape: rectangle
|
|
632
|
+
}
|
|
633
|
+
"Mobile App": {
|
|
634
|
+
shape: rectangle
|
|
635
|
+
}
|
|
636
|
+
"Desktop App": {
|
|
637
|
+
shape: rectangle
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
"User Login" -> "Session Creation": "Authenticate"
|
|
641
|
+
"Session Creation" -> "Session Storage": "Store session"
|
|
642
|
+
"Session Storage" -> "Multi-Device Access": "Access from devices"
|
|
643
|
+
```
|
|
644
|
+
- 某些情况下,单纯的设置 `direction: down` 还无法控制图表的整体方向,可以再结合 `grid-columns: 1` 来进行设置
|
|
645
|
+
- bad:
|
|
646
|
+
```d2
|
|
647
|
+
direction: down
|
|
648
|
+
|
|
649
|
+
"Your Application": {
|
|
650
|
+
shape: rectangle
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
"@blocklet/js-sdk": {
|
|
654
|
+
shape: package
|
|
655
|
+
grid-columns: 1
|
|
656
|
+
|
|
657
|
+
"AuthService": {
|
|
658
|
+
shape: class
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
"Blocklet API Endpoints": {
|
|
663
|
+
shape: cylinder
|
|
664
|
+
grid-columns: 2
|
|
665
|
+
"/api/user/profile": {}
|
|
666
|
+
"/api/user/privacy/config": {}
|
|
667
|
+
"/api/user/notification/config": {}
|
|
668
|
+
"/api/user/logout": {}
|
|
669
|
+
"/api/user/follow/{did}": {}
|
|
670
|
+
"/api/user": {}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
"Your Application" -> "@blocklet/js-sdk".AuthService: "e.g., sdk.auth.getProfile()"
|
|
674
|
+
"@blocklet/js-sdk".AuthService -> "Blocklet API Endpoints": "Makes authenticated API calls"
|
|
675
|
+
```
|
|
676
|
+
- good:
|
|
677
|
+
```d2
|
|
678
|
+
direction: down
|
|
679
|
+
grid-columns: 1
|
|
680
|
+
|
|
681
|
+
"Your Application": {
|
|
682
|
+
shape: rectangle
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
"@blocklet/js-sdk": {
|
|
686
|
+
shape: package
|
|
687
|
+
grid-columns: 1
|
|
688
|
+
|
|
689
|
+
"AuthService": {
|
|
690
|
+
shape: class
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
"Blocklet API Endpoints": {
|
|
695
|
+
shape: cylinder
|
|
696
|
+
grid-columns: 2
|
|
697
|
+
"/api/user/profile": {}
|
|
698
|
+
"/api/user/privacy/config": {}
|
|
699
|
+
"/api/user/notification/config": {}
|
|
700
|
+
"/api/user/logout": {}
|
|
701
|
+
"/api/user/follow/{did}": {}
|
|
702
|
+
"/api/user": {}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
"Your Application" -> "@blocklet/js-sdk".AuthService: "e.g., sdk.auth.getProfile()"
|
|
706
|
+
"@blocklet/js-sdk".AuthService -> "Blocklet API Endpoints": "Makes authenticated API calls"
|
|
707
|
+
```
|
|
708
|
+
- **非常重要** 当容器节点中子节点个数与 `grid-columns` 值相同时,则应该去掉容器节点中的 `grid-columns` 字段
|
|
709
|
+
- bad:
|
|
710
|
+
```d2
|
|
711
|
+
"@blocklet/js-sdk": {
|
|
712
|
+
shape: package
|
|
713
|
+
grid-columns: 1
|
|
714
|
+
|
|
715
|
+
"AuthService": {
|
|
716
|
+
shape: class
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
```
|
|
720
|
+
- good:
|
|
721
|
+
```d2
|
|
722
|
+
"@blocklet/js-sdk": {
|
|
723
|
+
shape: package
|
|
724
|
+
|
|
725
|
+
"AuthService": {
|
|
726
|
+
shape: class
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
```
|
|
730
|
+
- bad:
|
|
731
|
+
```d2
|
|
732
|
+
"Browser Storage": {
|
|
733
|
+
shape: package
|
|
734
|
+
grid-columns: 2
|
|
735
|
+
|
|
736
|
+
"Cookies": {
|
|
737
|
+
shape: document
|
|
738
|
+
"Session Token": {}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
"LocalStorage": {
|
|
742
|
+
shape: stored_data
|
|
743
|
+
"Refresh Token": {}
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
```
|
|
747
|
+
- good:
|
|
748
|
+
```d2
|
|
749
|
+
"Browser Storage": {
|
|
750
|
+
shape: package
|
|
751
|
+
|
|
752
|
+
"Cookies": {
|
|
753
|
+
shape: document
|
|
754
|
+
"Session Token": {}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
"LocalStorage": {
|
|
758
|
+
shape: stored_data
|
|
759
|
+
"Refresh Token": {}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
```
|
|
763
|
+
- 当一个容器节点外部有节点与当前容器节点内部节点相互关联时,应该将这些节点放在同一层级
|
|
764
|
+
- bad:
|
|
765
|
+
```d2
|
|
766
|
+
direction: down
|
|
767
|
+
|
|
768
|
+
"Federated Login Group": {
|
|
769
|
+
shape: package
|
|
770
|
+
|
|
771
|
+
"Master App": {
|
|
772
|
+
shape: rectangle
|
|
773
|
+
style.stroke: "#0052cc"
|
|
774
|
+
style.stroke-width: 2
|
|
775
|
+
"Provides central authentication"
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
"Member App 1 (Current App)": {
|
|
779
|
+
shape: rectangle
|
|
780
|
+
"User interacts here"
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
"Member App 2": {
|
|
784
|
+
shape: rectangle
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
"Master App" -> "Member App 1 (Current App)": "Shares user session"
|
|
788
|
+
"Master App" -> "Member App 2": "Shares user session"
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
User: {
|
|
792
|
+
shape: person
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
User -> "Member App 1 (Current App)": "Logs in via Master App"
|
|
796
|
+
```
|
|
797
|
+
- good:
|
|
798
|
+
```d2
|
|
799
|
+
direction: down
|
|
800
|
+
|
|
801
|
+
"Federated Login Group": {
|
|
802
|
+
shape: package
|
|
803
|
+
|
|
804
|
+
"Master App": {
|
|
805
|
+
shape: rectangle
|
|
806
|
+
style.stroke: "#0052cc"
|
|
807
|
+
style.stroke-width: 2
|
|
808
|
+
"Provides central authentication"
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
"Member App 1 (Current App)": {
|
|
812
|
+
shape: rectangle
|
|
813
|
+
"User interacts here"
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
"Member App 2": {
|
|
817
|
+
shape: rectangle
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
"Master App" -> "Member App 1 (Current App)": "Shares user session"
|
|
821
|
+
"Master App" -> "Member App 2": "Shares user session"
|
|
822
|
+
|
|
823
|
+
User: {
|
|
824
|
+
shape: person
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
User -> "Member App 1 (Current App)": "Logs in via Master App"
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
```
|
|
831
|
+
- **非常重要** 当存在多层容器节点嵌套时,外层的容器节点应该使用 `grid-columns: 1`
|
|
832
|
+
- bad:
|
|
833
|
+
```d2
|
|
834
|
+
direction: down
|
|
835
|
+
|
|
836
|
+
"User Account": {
|
|
837
|
+
shape: person
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
"Sessions": {
|
|
841
|
+
shape: package
|
|
842
|
+
grid-columns: 3
|
|
843
|
+
|
|
844
|
+
"Web Browser Session": {
|
|
845
|
+
shape: rectangle
|
|
846
|
+
"IP: 192.168.1.10"
|
|
847
|
+
"UA: Chrome on macOS"
|
|
848
|
+
"Status: online"
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
"iOS App Session": {
|
|
852
|
+
shape: rectangle
|
|
853
|
+
"IP: 10.0.0.5"
|
|
854
|
+
"UA: MyApp/1.2 iOS"
|
|
855
|
+
"Status: online"
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
"Old Laptop Session": {
|
|
859
|
+
shape: rectangle
|
|
860
|
+
"IP: 172.16.0.20"
|
|
861
|
+
"UA: Firefox on Windows"
|
|
862
|
+
"Status: expired"
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
"User Account" -> "Sessions": "Has multiple"
|
|
867
|
+
```
|
|
868
|
+
- good:
|
|
869
|
+
```d2
|
|
870
|
+
direction: down
|
|
871
|
+
|
|
872
|
+
"User Account": {
|
|
873
|
+
shape: person
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
"Sessions": {
|
|
877
|
+
shape: package
|
|
878
|
+
grid-columns: 1
|
|
879
|
+
|
|
880
|
+
"Web Browser Session": {
|
|
881
|
+
shape: rectangle
|
|
882
|
+
"IP: 192.168.1.10"
|
|
883
|
+
"UA: Chrome on macOS"
|
|
884
|
+
"Status: online"
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
"iOS App Session": {
|
|
888
|
+
shape: rectangle
|
|
889
|
+
"IP: 10.0.0.5"
|
|
890
|
+
"UA: MyApp/1.2 iOS"
|
|
891
|
+
"Status: online"
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
"Old Laptop Session": {
|
|
895
|
+
shape: rectangle
|
|
896
|
+
"IP: 172.16.0.20"
|
|
897
|
+
"UA: Firefox on Windows"
|
|
898
|
+
"Status: expired"
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
"User Account" -> "Sessions": "Has multiple"
|
|
903
|
+
```
|
|
904
|
+
- 当一个节点容器中包含了其他的节点容器,建议使用 `grid-gap` 来增加各个节点容器的距离,尽量大于 `100`
|
|
905
|
+
- bad:
|
|
906
|
+
```d2
|
|
907
|
+
direction: down
|
|
908
|
+
|
|
909
|
+
"Your Application": {
|
|
910
|
+
shape: rectangle
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
"SDK: @blocklet/js-sdk": {
|
|
914
|
+
shape: package
|
|
915
|
+
grid-columns: 1
|
|
916
|
+
|
|
917
|
+
"HTTP Clients": {
|
|
918
|
+
shape: rectangle
|
|
919
|
+
grid-columns: 2
|
|
920
|
+
"createAxios()": "Axios-based client"
|
|
921
|
+
"createFetch()": "Fetch-based client"
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
"Core Services": {
|
|
925
|
+
shape: rectangle
|
|
926
|
+
grid-columns: 3
|
|
927
|
+
"AuthService": "User & Auth"
|
|
928
|
+
"TokenService": "Token Management"
|
|
929
|
+
"UserSessionService": "Session Data"
|
|
930
|
+
"BlockletService": "Blocklet Metadata"
|
|
931
|
+
"FederatedService": "Federated Login"
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
"HTTP Clients" -> "Core Services".TokenService: "Uses for auth tokens"
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
"Blocklet Services": {
|
|
938
|
+
shape: cylinder
|
|
939
|
+
"Remote APIs"
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
"Your Application" -> "SDK: @blocklet/js-sdk": "Imports & Initializes"
|
|
943
|
+
"SDK: @blocklet/js-sdk" -> "Blocklet Services": "Makes authenticated requests"
|
|
944
|
+
```
|
|
945
|
+
- bad:
|
|
946
|
+
```d2
|
|
947
|
+
direction: down
|
|
948
|
+
|
|
949
|
+
"Your Application": {
|
|
950
|
+
shape: rectangle
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
"SDK: @blocklet/js-sdk": {
|
|
954
|
+
shape: package
|
|
955
|
+
grid-columns: 1
|
|
956
|
+
grid-gap: 100
|
|
957
|
+
|
|
958
|
+
"HTTP Clients": {
|
|
959
|
+
shape: rectangle
|
|
960
|
+
grid-columns: 2
|
|
961
|
+
"createAxios()": "Axios-based client"
|
|
962
|
+
"createFetch()": "Fetch-based client"
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
"Core Services": {
|
|
966
|
+
shape: rectangle
|
|
22
967
|
grid-columns: 3
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
968
|
+
"AuthService": "User & Auth"
|
|
969
|
+
"TokenService": "Token Management"
|
|
970
|
+
"UserSessionService": "Session Data"
|
|
971
|
+
"BlockletService": "Blocklet Metadata"
|
|
972
|
+
"FederatedService": "Federated Login"
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
"HTTP Clients" -> "Core Services".TokenService: "Uses for auth tokens"
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
"Blocklet Services": {
|
|
979
|
+
shape: cylinder
|
|
980
|
+
"Remote APIs"
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
"Your Application" -> "SDK: @blocklet/js-sdk": "Imports & Initializes"
|
|
984
|
+
"SDK: @blocklet/js-sdk" -> "Blocklet Services": "Makes authenticated requests"
|
|
985
|
+
```
|
|
986
|
+
- 如果节点的 `shape: person`,则不要加任何其他内部的文字
|
|
987
|
+
- bad:
|
|
988
|
+
```d2
|
|
989
|
+
"User Account": {
|
|
990
|
+
shape: person
|
|
991
|
+
"did:z... (John Doe)"
|
|
992
|
+
}
|
|
993
|
+
```
|
|
994
|
+
- good:
|
|
995
|
+
```d2
|
|
996
|
+
"User Account": {
|
|
997
|
+
shape: person
|
|
998
|
+
}
|
|
999
|
+
```
|
|
1000
|
+
- **非常重要** 在绘制连线的时候,一定要注意连接的节点的 ID 到底是什么,它可能有多个层级,但一定要弄清楚关系才能添加连线
|
|
1001
|
+
- bad:
|
|
1002
|
+
```d2
|
|
1003
|
+
direction: down
|
|
1004
|
+
|
|
1005
|
+
"User-Browser": {
|
|
1006
|
+
label: "User's Browser"
|
|
1007
|
+
shape: rectangle
|
|
1008
|
+
|
|
1009
|
+
"React-App": {
|
|
1010
|
+
label: "Your React App"
|
|
1011
|
+
shape: rectangle
|
|
1012
|
+
|
|
1013
|
+
"Uploader-Component": {
|
|
1014
|
+
label: "@blocklet/uploader"
|
|
36
1015
|
shape: package
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
"Blocklet-Server": {
|
|
1021
|
+
label: "Your Blocklet Server"
|
|
1022
|
+
shape: rectangle
|
|
1023
|
+
|
|
1024
|
+
"Express-App": {
|
|
1025
|
+
label: "Your Express App"
|
|
1026
|
+
shape: rectangle
|
|
1027
|
+
|
|
1028
|
+
"Uploader-Middleware": {
|
|
1029
|
+
label: "@blocklet/uploader-server"
|
|
1030
|
+
shape: package
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
"File-System": {
|
|
1036
|
+
label: "Storage\n(e.g., File System)"
|
|
1037
|
+
shape: cylinder
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
"Uploader-Component" -> "Uploader-Middleware": "HTTP POST Request\n(File Upload)"
|
|
1041
|
+
"Uploader-Middleware" -> "File-System": "Saves File"
|
|
1042
|
+
```
|
|
1043
|
+
- good:
|
|
1044
|
+
```d2
|
|
1045
|
+
direction: down
|
|
1046
|
+
|
|
1047
|
+
"User-Browser": {
|
|
1048
|
+
label: "User's Browser"
|
|
1049
|
+
shape: rectangle
|
|
1050
|
+
|
|
1051
|
+
"React-App": {
|
|
1052
|
+
label: "Your React App"
|
|
1053
|
+
shape: rectangle
|
|
1054
|
+
|
|
1055
|
+
"Uploader-Component": {
|
|
1056
|
+
label: "@blocklet/uploader"
|
|
1057
|
+
shape: package
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
"Blocklet-Server": {
|
|
1063
|
+
label: "Your Blocklet Server"
|
|
1064
|
+
shape: rectangle
|
|
1065
|
+
|
|
1066
|
+
"Express-App": {
|
|
1067
|
+
label: "Your Express App"
|
|
1068
|
+
shape: rectangle
|
|
1069
|
+
|
|
1070
|
+
"Uploader-Middleware": {
|
|
1071
|
+
label: "@blocklet/uploader-server"
|
|
1072
|
+
shape: package
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
"File-System": {
|
|
1078
|
+
label: "Storage\n(e.g., File System)"
|
|
1079
|
+
shape: cylinder
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
User-Browser.React-App.Uploader-Component -> Blocklet-Server.Express-App.Uploader-Middleware: "HTTP POST Request\n(File Upload)"
|
|
1083
|
+
Blocklet-Server.Express-App.Uploader-Middleware -> "File-System": "Saves File"
|
|
1084
|
+
```
|
|
1085
|
+
- 对于节点 shape 的选择,可以参考
|
|
1086
|
+
{% include "shape-rules.md" %}
|
|
1087
|
+
- 示例参考:
|
|
1088
|
+
{% include "diy-examples.md" %}
|