@linxin666/dsh-pet 0.1.14 → 0.1.15
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/lib/client.js +29 -16
- package/lib/client.js.map +1 -1
- package/lib/index.js +355 -251
- package/lib/invariant.js +1 -1
- package/lib/{state-P-wsVJ6O.js → state-CFyJv0sQ.js} +15 -1
- package/lib/types/affinity.d.ts +15 -0
- package/lib/types/affinity.d.ts.map +1 -1
- package/lib/types/affinity.js +14 -0
- package/lib/types/client/PluginSettingsCard.d.ts +26 -11
- package/lib/types/client/PluginSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PluginSettingsCard.js +27 -7
- package/lib/types/client/index.d.ts +1 -1
- package/lib/types/client/index.js +3 -3
- package/lib/types/client/settings-form.d.ts +14 -5
- package/lib/types/client/settings-form.d.ts.map +1 -1
- package/lib/types/client/settings-form.js +38 -10
- package/lib/types/dsh-home.d.ts +17 -0
- package/lib/types/dsh-home.d.ts.map +1 -0
- package/lib/types/dsh-home.js +34 -0
- package/lib/types/event-projection.d.ts +36 -0
- package/lib/types/event-projection.d.ts.map +1 -0
- package/lib/types/event-projection.js +98 -0
- package/lib/types/ledger.d.ts +77 -0
- package/lib/types/ledger.d.ts.map +1 -0
- package/lib/types/ledger.js +139 -0
- package/lib/types/persist.d.ts +5 -1
- package/lib/types/persist.d.ts.map +1 -1
- package/lib/types/persist.js +7 -3
- package/lib/types/service.d.ts +15 -46
- package/lib/types/service.d.ts.map +1 -1
- package/lib/types/service.js +47 -204
- package/package.json +1 -1
- package/src/affinity.ts +33 -0
- package/src/client/PluginSettingsCard.tsx +83 -17
- package/src/client/index.ts +3 -3
- package/src/client/settings-card.module.css +6 -0
- package/src/client/settings-form.ts +41 -9
- package/src/dsh-home.test.ts +35 -0
- package/src/dsh-home.ts +36 -0
- package/src/event-projection.ts +128 -0
- package/src/ledger.test.ts +67 -0
- package/src/ledger.ts +183 -0
- package/src/persist.ts +7 -3
- package/src/service.ts +60 -274
package/lib/client.js
CHANGED
|
@@ -686,7 +686,7 @@ window.__ModuleLoader__.load({
|
|
|
686
686
|
}
|
|
687
687
|
//#endregion
|
|
688
688
|
//#region \0dsh-css:packages/dsh-pet/src/client/settings-card.module.css.mjs
|
|
689
|
-
const css = ".kKk9aW_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.kKk9aW_card:hover{border-color:var(--dsw-alias-label-dimmed)}.kKk9aW_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.kKk9aW_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.kKk9aW_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.kKk9aW_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.kKk9aW_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.kKk9aW_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.kKk9aW_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.kKk9aW_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.kKk9aW_chevronOpen{transform:rotate(180deg)}.kKk9aW_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.kKk9aW_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.kKk9aW_notExposed{color:var(--dsw-alias-state-warn-primary);margin:12px 0 0;font-size:12px;line-height:1.5}.kKk9aW_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.kKk9aW_failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}.kKk9aW_discard,.kKk9aW_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.kKk9aW_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.kKk9aW_discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.kKk9aW_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.kKk9aW_discard:disabled,.kKk9aW_save:disabled{opacity:.4;cursor:default}.kKk9aW_discard:focus-visible,.kKk9aW_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.kKk9aW_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.kKk9aW_field+.kKk9aW_field{border-top:1px solid var(--dsw-alias-border-l2)}.kKk9aW_head{align-items:center;gap:8px;display:flex}.kKk9aW_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.kKk9aW_badges{align-items:center;gap:8px;display:inline-flex}.kKk9aW_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.kKk9aW_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.kKk9aW_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.kKk9aW_reset:disabled{cursor:default}.kKk9aW_reset:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.kKk9aW_input,.kKk9aW_select{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.kKk9aW_input:focus-visible,.kKk9aW_select:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.kKk9aW_input:disabled,.kKk9aW_select:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.kKk9aW_inputInvalid{border:1px solid var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.kKk9aW_inputInvalid:focus-visible{outline:2px solid var(--dsw-alias-label-error);outline-offset:1px;border-color:var(--dsw-alias-label-error)}.kKk9aW_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.kKk9aW_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}@media (prefers-reduced-motion:reduce){.kKk9aW_card,.kKk9aW_header,.kKk9aW_chevron,.kKk9aW_chevronOpen,.kKk9aW_discard,.kKk9aW_save{transition:none}}";
|
|
689
|
+
const css = ".kKk9aW_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.kKk9aW_card:hover{border-color:var(--dsw-alias-label-dimmed)}.kKk9aW_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.kKk9aW_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.kKk9aW_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.kKk9aW_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.kKk9aW_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.kKk9aW_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.kKk9aW_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.kKk9aW_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.kKk9aW_chevronOpen{transform:rotate(180deg)}.kKk9aW_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.kKk9aW_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.kKk9aW_notExposed{color:var(--dsw-alias-state-warn-primary);margin:12px 0 0;font-size:12px;line-height:1.5}.kKk9aW_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.kKk9aW_failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}.kKk9aW_discard,.kKk9aW_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.kKk9aW_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.kKk9aW_discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.kKk9aW_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.kKk9aW_discard:disabled,.kKk9aW_save:disabled{opacity:.4;cursor:default}.kKk9aW_discard:focus-visible,.kKk9aW_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.kKk9aW_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.kKk9aW_field+.kKk9aW_field{border-top:1px solid var(--dsw-alias-border-l2)}.kKk9aW_head{align-items:center;gap:8px;display:flex}.kKk9aW_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.kKk9aW_badges{align-items:center;gap:8px;display:inline-flex}.kKk9aW_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.kKk9aW_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.kKk9aW_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.kKk9aW_reset:disabled{cursor:default}.kKk9aW_reset:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.kKk9aW_input,.kKk9aW_select{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.kKk9aW_input:focus-visible,.kKk9aW_select:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.kKk9aW_input:disabled,.kKk9aW_select:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.kKk9aW_inputInvalid{border:1px solid var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.kKk9aW_inputInvalid:focus-visible{outline:2px solid var(--dsw-alias-label-error);outline-offset:1px;border-color:var(--dsw-alias-label-error)}.kKk9aW_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.kKk9aW_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}@media (prefers-reduced-motion:reduce){.kKk9aW_card,.kKk9aW_header,.kKk9aW_chevron,.kKk9aW_chevronOpen,.kKk9aW_discard,.kKk9aW_save{transition:none}}";
|
|
690
690
|
const tagId = "@linxin666/dsh-pet/settings-card.module.css";
|
|
691
691
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
692
692
|
const tag = document.createElement("style");
|
|
@@ -727,12 +727,12 @@ window.__ModuleLoader__.load({
|
|
|
727
727
|
//#endregion
|
|
728
728
|
//#region src/client/PluginSettingsCard.tsx
|
|
729
729
|
/**
|
|
730
|
-
*
|
|
731
|
-
* plugin and what its settings govern, the controls inside, and the save
|
|
732
|
-
* writes them. Renders nothing while the namespace is unavailable — a
|
|
730
|
+
* Family-shared chrome for plugin settings cards: a disclosure header naming
|
|
731
|
+
* the plugin and what its settings govern, the controls inside, and the save
|
|
732
|
+
* that writes them. Renders nothing while the namespace is unavailable — a
|
|
733
733
|
* deployment that does not compose the owning plugin should show no trace of
|
|
734
|
-
* it.
|
|
735
|
-
*
|
|
734
|
+
* it. Inlined into each consumer's client bundle; mirrors the official
|
|
735
|
+
* ui-plugin-config PluginCard in a self-contained slice.
|
|
736
736
|
*/
|
|
737
737
|
/**
|
|
738
738
|
* Render one plugin settings card.
|
|
@@ -744,6 +744,7 @@ window.__ModuleLoader__.load({
|
|
|
744
744
|
const { state } = props;
|
|
745
745
|
if (!state.available) return null;
|
|
746
746
|
const title = props.t(props.titleKey);
|
|
747
|
+
const description = props.t(props.descriptionKey);
|
|
747
748
|
const blocked = !state.dirty || state.invalid || state.saving;
|
|
748
749
|
const cardClass = open ? `${settings_card_module_css_default.cardOpen} ${settings_card_module_css_default.card}` : settings_card_module_css_default.card;
|
|
749
750
|
if (!state.exposed) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
@@ -760,10 +761,12 @@ window.__ModuleLoader__.load({
|
|
|
760
761
|
className: settings_card_module_css_default.headText,
|
|
761
762
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
762
763
|
className: settings_card_module_css_default.name,
|
|
764
|
+
title,
|
|
763
765
|
children: title
|
|
764
766
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
765
767
|
className: settings_card_module_css_default.description,
|
|
766
|
-
|
|
768
|
+
title: description,
|
|
769
|
+
children: description
|
|
767
770
|
})]
|
|
768
771
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
769
772
|
width: "14",
|
|
@@ -801,14 +804,17 @@ window.__ModuleLoader__.load({
|
|
|
801
804
|
className: settings_card_module_css_default.headText,
|
|
802
805
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
803
806
|
className: settings_card_module_css_default.name,
|
|
807
|
+
title,
|
|
804
808
|
children: title
|
|
805
809
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
806
810
|
className: settings_card_module_css_default.description,
|
|
807
|
-
|
|
811
|
+
title: description,
|
|
812
|
+
children: description
|
|
808
813
|
})]
|
|
809
814
|
}),
|
|
810
815
|
state.dirty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
811
816
|
className: settings_card_module_css_default.pending,
|
|
817
|
+
title: props.t("settings.unsaved"),
|
|
812
818
|
children: props.t("settings.unsaved")
|
|
813
819
|
}) : null,
|
|
814
820
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
@@ -963,8 +969,9 @@ window.__ModuleLoader__.load({
|
|
|
963
969
|
}
|
|
964
970
|
//#endregion
|
|
965
971
|
//#region src/client/settings-form.ts
|
|
966
|
-
/** A whole-number field. An empty draft clears the field; any other draft that is not a finite number blocks the save. */
|
|
967
|
-
function numberField(field) {
|
|
972
|
+
/** A whole- or decimal-number field. An empty draft clears the field; any other draft that is not a finite number within the constraints blocks the save. */
|
|
973
|
+
function numberField(field, constraints = {}) {
|
|
974
|
+
const { integer = false, min } = constraints;
|
|
968
975
|
return {
|
|
969
976
|
field,
|
|
970
977
|
format: (value) => typeof value === "number" ? String(value) : "",
|
|
@@ -972,10 +979,13 @@ window.__ModuleLoader__.load({
|
|
|
972
979
|
const trimmed = text.trim();
|
|
973
980
|
if (trimmed === "") return { kind: "clear" };
|
|
974
981
|
const parsed = Number(trimmed);
|
|
975
|
-
|
|
982
|
+
if (!Number.isFinite(parsed)) return void 0;
|
|
983
|
+
if (integer && !Number.isInteger(parsed)) return void 0;
|
|
984
|
+
if (min !== void 0 && parsed < min) return void 0;
|
|
985
|
+
return {
|
|
976
986
|
kind: "set",
|
|
977
987
|
value: parsed
|
|
978
|
-
}
|
|
988
|
+
};
|
|
979
989
|
}
|
|
980
990
|
};
|
|
981
991
|
}
|
|
@@ -999,11 +1009,13 @@ window.__ModuleLoader__.load({
|
|
|
999
1009
|
field,
|
|
1000
1010
|
format: (value) => typeof value === "boolean" ? String(value) : "",
|
|
1001
1011
|
parse: (text) => {
|
|
1002
|
-
|
|
1012
|
+
const trimmed = text.trim();
|
|
1013
|
+
if (trimmed === "") return { kind: "clear" };
|
|
1014
|
+
if (trimmed === "true") return {
|
|
1003
1015
|
kind: "set",
|
|
1004
1016
|
value: true
|
|
1005
1017
|
};
|
|
1006
|
-
if (
|
|
1018
|
+
if (trimmed === "false") return {
|
|
1007
1019
|
kind: "set",
|
|
1008
1020
|
value: false
|
|
1009
1021
|
};
|
|
@@ -1105,12 +1117,13 @@ window.__ModuleLoader__.load({
|
|
|
1105
1117
|
const plan = this.plan();
|
|
1106
1118
|
const writes = plan.flatMap((item) => item.run === void 0 ? [] : [item.run]);
|
|
1107
1119
|
if (plan.length === 0 || this.saving || writes.length !== plan.length) return;
|
|
1120
|
+
const fields = new Set(plan.map((item) => item.field));
|
|
1108
1121
|
this.saving = true;
|
|
1109
1122
|
this.failed = false;
|
|
1110
1123
|
this.publish();
|
|
1111
1124
|
let landed = true;
|
|
1112
1125
|
for (const write of writes) landed = await write() && landed;
|
|
1113
|
-
if (landed) this.staged.
|
|
1126
|
+
if (landed) for (const field of fields) this.staged.delete(field);
|
|
1114
1127
|
this.saving = false;
|
|
1115
1128
|
this.failed = !landed;
|
|
1116
1129
|
this.publish();
|
|
@@ -1472,7 +1485,7 @@ window.__ModuleLoader__.load({
|
|
|
1472
1485
|
setName: (name) => petFetch("/api/pet/set-name", { name })
|
|
1473
1486
|
};
|
|
1474
1487
|
/** Poll interval for the host snapshot. */
|
|
1475
|
-
const POLL_MS =
|
|
1488
|
+
const POLL_MS = 2e3;
|
|
1476
1489
|
/** Settings namespace the pet settings card edits (the Host plugin registers it). */
|
|
1477
1490
|
const PET_SETTINGS_NS = "pet";
|
|
1478
1491
|
/** Required services. */
|