@zfdx123/dsh-session-cleaner 1.0.3 → 1.0.4

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.
Files changed (2) hide show
  1. package/client.js +60 -14
  2. package/package.json +1 -1
package/client.js CHANGED
@@ -405,13 +405,30 @@ window.__ModuleLoader__.load({
405
405
  const [pending, setPending] = React.useState(false)
406
406
  const [error, setError] = React.useState(null)
407
407
 
408
+ /**
409
+ * Leave the dialog and drop the attempt's own state. This component stays
410
+ * MOUNTED while it is closed — `title` is the open flag, and the Settings
411
+ * page never unmounts it — so state kept past a close is handed to the
412
+ * next session's dialog: a `pending` left true by a finished delete would
413
+ * greet the next row already reading 「正在删除…」 with both footer buttons
414
+ * disabled, and `confirm` returns early on `pending`, so that delete can
415
+ * neither start nor fail. One opening owns one attempt's state; leaving is
416
+ * what ends it.
417
+ * @param deleted - whether the session was actually deleted.
418
+ */
419
+ const close = (deleted) => {
420
+ setPending(false)
421
+ setError(null)
422
+ onClose(deleted)
423
+ }
424
+
408
425
  const confirm = async () => {
409
426
  if (pending) return
410
427
  setPending(true)
411
428
  setError(null)
412
429
  try {
413
430
  await run()
414
- onClose(true)
431
+ close(true)
415
432
  } catch (failure) {
416
433
  report('delete-failed', { message: String(failure?.message ?? failure) })
417
434
  setError(failureText(failure, labels))
@@ -423,7 +440,7 @@ window.__ModuleLoader__.load({
423
440
  Modal,
424
441
  {
425
442
  open: title !== null,
426
- onClose: () => onClose(false),
443
+ onClose: () => close(false),
427
444
  closeLabel: labels.close,
428
445
  title: labels.title,
429
446
  ...(title === null ? {} : { description: labels.description(title) }),
@@ -434,7 +451,7 @@ window.__ModuleLoader__.load({
434
451
  key: 'cancel',
435
452
  variant: 'outline',
436
453
  disabled: pending,
437
- onClick: () => onClose(false),
454
+ onClick: () => close(false),
438
455
  },
439
456
  labels.cancel,
440
457
  ),
@@ -863,12 +880,26 @@ window.__ModuleLoader__.load({
863
880
  * only: id resolution prefers React's props, so a failed fetch costs the
864
881
  * running flag, not the feature.
865
882
  *
866
- * `/api/session.list` is the single transport. The `remote` service is the
867
- * transport owner, not a namespace holder — a browser remote namespace is
868
- * its own `remote.<namespace>` service (DSH 0.1.6-alpha.2
869
- * api-gateway `client.js`), so `ctx.get('remote').session` never resolves,
870
- * and reading it reflectively would make the catalog depend on a service
871
- * this plugin does not inject.
883
+ * `/api/session/list` is the single transport, and every part of that call is
884
+ * load-bearing:
885
+ * - the endpoint must be exactly two slash-separated segments; the
886
+ * gateway's `claimsEndpoint` rejects anything else before it looks the
887
+ * name up, so a dotted `session.list` is never claimed and never
888
+ * answers an envelope;
889
+ * - the payload must hold nothing but a plain-object `args`
890
+ * (`remoteRequest`);
891
+ * - and `args` must carry exactly the descriptor's parameter names — the
892
+ * host validates them (`assertExactArguments`). `session/list` takes one
893
+ * parameter, `_request` (`SessionListRequest`, whose only field is an
894
+ * optional `cursor`), so an unfiltered call is `{ _request: {} }`.
895
+ * A call that misses any of the three is answered with the gateway's own
896
+ * refusal envelope, which {@link fetchCatalog} reports rather than swallows.
897
+ *
898
+ * The `remote` service is the transport owner, not a namespace holder — a
899
+ * browser remote namespace is its own `remote.<namespace>` service (DSH
900
+ * 0.1.6-alpha.2 api-gateway `client.js`), so `ctx.get('remote').session`
901
+ * never resolves, and reading it reflectively would make the catalog depend
902
+ * on a service this plugin does not inject.
872
903
  */
873
904
  async function fetchCatalog() {
874
905
  const build = (items) => {
@@ -887,21 +918,36 @@ window.__ModuleLoader__.load({
887
918
  return { byTitle, byId }
888
919
  }
889
920
  try {
890
- const response = await fetch('/api/session.list', {
921
+ const response = await fetch('/api/session/list', {
891
922
  method: 'POST',
892
923
  headers: { 'content-type': 'application/json' },
893
924
  credentials: 'same-origin',
894
925
  body: JSON.stringify({
895
926
  type: 'client-request',
896
927
  rpcId: 'session-cleaner-' + Math.random().toString(36).slice(2),
897
- method: 'session.list',
898
- payload: {},
928
+ method: 'session/list',
929
+ payload: { args: { _request: {} } },
899
930
  }),
900
931
  })
901
932
  const body = await response.json()
902
- if (body?.result === undefined) return null
933
+ // A refused call still comes back as the gateway's own envelope, so its
934
+ // reason is reported here: a wrong endpoint or a wrong args shape used to
935
+ // leave nothing behind but a null catalog.
936
+ if (body?.result?.ok === false) {
937
+ report('catalog-miss', {
938
+ status: response.status,
939
+ code: body.result.error?.code ?? null,
940
+ message: body.result.error?.message ?? null,
941
+ })
942
+ return null
943
+ }
944
+ if (body?.result === undefined) {
945
+ report('catalog-miss', { status: response.status, code: 'no-envelope', message: null })
946
+ return null
947
+ }
903
948
  return build(body.result?.value?.items)
904
- } catch {
949
+ } catch (error) {
950
+ report('catalog-miss', { status: null, code: 'transport', message: String(error?.message ?? error) })
905
951
  return null // no catalog; the caller reports it and the row keeps working
906
952
  }
907
953
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zfdx123/dsh-session-cleaner",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "会话清理:在运行中的 web 运行时里彻底删除 DSH 会话——实时 store 条目、工作区记录、磁盘产物与投影缓存行一并清掉,并在会话行菜单里加一个删除入口。",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/zfdx123/dsh-atelier/tree/main/packages/dsh-session-cleaner#readme",