@perrylink/dsh-github 0.6.5 → 0.7.1

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 CHANGED
@@ -1,22 +1,3 @@
1
- /**
2
- * dsh-github browser half — one card in the "Plugins" settings section.
3
- *
4
- * The card edits the `dsh-github` settings namespace and lets the user fill
5
- * the GitHub token directly from the settings page. The token literal never
6
- * rides the settings document: it is written through the credentials domain,
7
- * addressed by the reference the namespace names (`tokenRef`, default
8
- * `GITHUB_TOKEN`), which is exactly where the host half resolves it — per
9
- * operation, no restart needed.
10
- *
11
- * The card is collapsible and mirrors the host's `PluginCard` chrome one for
12
- * one (same design tokens, same layout), the way the market card does: the
13
- * plugins tab only lays out a flex column and dispatches
14
- * `settings.plugin.item`, so the container is ours to draw, but drawing it
15
- * with the same tokens is what keeps it from looking like it wandered in from
16
- * another product. Buttons and the chevron come from the shared primitives.
17
- *
18
- * This file is a self-contained bundle executed by the browser module loader.
19
- */
20
1
  window.__ModuleLoader__.load({
21
2
  id: "@perrylink/dsh-github",
22
3
  factory: (require) => {
@@ -25,52 +6,56 @@ window.__ModuleLoader__.load({
25
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
26
7
  let react = require("react");
27
8
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
28
- let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
29
-
30
- // ── styles (mirrors the host PluginCard / market card tokens) ────────────
31
-
32
- const css = [
33
- "/* @perrylink/dsh-github: token configuration card */",
34
- ".ghc-card{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-bg-layer-3,#fff);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}",
35
- ".ghc-card:hover{border-color:var(--dsw-alias-label-dimmed,#c8ccd4)}",
36
- ".ghc-cardOpen{background:var(--dsw-alias-bg-layer-2,#f7f8fa);border-color:var(--dsw-alias-label-dimmed,#c8ccd4)}",
37
- ".ghc-header{-webkit-appearance:none;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}",
38
- ".ghc-header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#4f6ef7);outline-offset:-2px}",
39
- ".ghc-headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}",
40
- ".ghc-name{color:var(--dsw-alias-label-primary,#1f2328);font-size:15px;font-weight:600;line-height:1.4}",
41
- ".ghc-description{color:var(--dsw-alias-label-tertiary,#8b93a1);font-size:13px;line-height:1.5}",
42
- ".ghc-chevron{color:var(--dsw-alias-label-tertiary,#8b93a1);flex:none;transition:transform .16s;display:inline-flex}",
43
- ".ghc-chevronOpen{transform:rotate(180deg)}",
44
- ".ghc-pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform,#eef0f4);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}",
45
- ".ghc-body{border-top:1px solid var(--dsw-alias-border-l2,#e5e7eb);margin:0 16px;padding-bottom:8px}",
46
- ".ghc-readOnly{color:var(--dsw-alias-label-tertiary,#8b93a1);margin:12px 0 0;font-size:12px;line-height:1.5}",
47
- ".ghc-field{flex-direction:column;gap:6px;padding:12px 0;display:flex}",
48
- ".ghc-head{align-items:center;gap:8px;display:flex}",
49
- ".ghc-label{min-width:0;color:var(--dsw-alias-label-primary,#1f2328);flex:1;font-size:13px;font-weight:500;line-height:1.5}",
50
- ".ghc-badges{align-items:center;gap:8px;display:inline-flex}",
51
- ".ghc-badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform,#eef0f4);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}",
52
- ".ghc-badgeMuted{white-space:nowrap;color:var(--dsw-alias-label-tertiary,#8b93a1);border-radius:999px;padding:1px 8px;font-size:11px;line-height:17px}",
53
- ".ghc-input{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-bg-layer-3,#fff);height:34px;font:inherit;color:var(--dsw-alias-label-primary,#1f2328);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}",
54
- ".ghc-input:focus-visible{border-color:var(--dsw-alias-brand-primary,#4f6ef7);outline:none}",
55
- ".ghc-input:disabled{color:var(--dsw-alias-label-tertiary,#8b93a1);cursor:default}",
56
- ".ghc-hint{color:var(--dsw-alias-label-tertiary,#8b93a1);margin:0;font-size:12px;line-height:1.5}",
57
- ".ghc-actions{border-top:1px solid var(--dsw-alias-border-l2,#e5e7eb);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}",
58
- ".ghc-failed{min-width:0;color:var(--dsw-alias-label-error,#dc2626);flex:1;margin:0;font-size:12px;line-height:1.5}",
59
- ".ghc-spin{display:inline-flex;animation:ghc-spin .8s linear infinite}",
60
- "@keyframes ghc-spin{to{transform:rotate(360deg)}}",
61
- ].join("");
62
- const tagId = "@perrylink/dsh-github/github-card.css";
63
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
64
- const tag = document.createElement("style");
65
- tag.dataset.plugin = "@perrylink/dsh-github";
66
- tag.dataset.pluginCss = tagId;
67
- tag.textContent = css;
68
- document.head.appendChild(tag);
9
+ //#region D:/deepseek-harness/Project/Plugins/dsh-github/src/client.ts
10
+ /**
11
+ * dsh-github browser half — one card in the "Plugins" settings section.
12
+ *
13
+ * The card edits the `dsh-github` settings namespace and lets the user fill
14
+ * the GitHub token directly from the settings page. The token literal never
15
+ * rides the settings document: it is written through the credentials domain,
16
+ * addressed by the reference the namespace names (`tokenRef`, default
17
+ * `GITHUB_TOKEN`), which is exactly where the host half resolves it — per
18
+ * operation, no restart needed.
19
+ *
20
+ * The card is collapsible and mirrors the host's `PluginCard` chrome one for
21
+ * one (same design tokens, same layout), the way the market card does: the
22
+ * plugins tab only lays out a flex column and dispatches
23
+ * `settings.plugin.item`, so the container is ours to draw, but drawing it
24
+ * with the same tokens is what keeps it from looking like it wandered in from
25
+ * another product. Buttons and the chevron come from the shared primitives.
26
+ *
27
+ * The shipped `lib/client.js` is the __ModuleLoader__ bundle built from this
28
+ * module (plain ESM here; the bundle wraps it in the loader factory). The
29
+ * browser module loader executes that bundle, not this file.
30
+ * @module @perrylink/dsh-github/client
31
+ */
32
+ /**
33
+ * Create the minimal card store.
34
+ * @param init - initial state.
35
+ * @returns the store.
36
+ */
37
+ function createSnapshotStore(init) {
38
+ let state = init;
39
+ const listeners = /* @__PURE__ */ new Set();
40
+ return {
41
+ getSnapshot: () => state,
42
+ subscribe: (listener) => {
43
+ listeners.add(listener);
44
+ return () => {
45
+ listeners.delete(listener);
46
+ };
47
+ },
48
+ set: (next) => {
49
+ state = next;
50
+ for (const listener of [...listeners]) listener();
51
+ }
52
+ };
69
53
  }
70
-
71
- // ── locale ───────────────────────────────────────────────────────────────
72
-
73
- /** English copy for the card. */
54
+ /** Namespace of the GitHub capability. Spelled here rather than imported: a client package must not depend on a Host package. */
55
+ const GITHUB_NS = "dsh-github";
56
+ /** Credential reference the provider resolves when the section names none. */
57
+ const DEFAULT_TOKEN_REF = "GITHUB_TOKEN";
58
+ /** English copy. */
74
59
  const en = {
75
60
  githubTitle: "GitHub",
76
61
  githubDescription: "GitHub pull requests, issues, and CI through the agent.",
@@ -83,7 +68,7 @@ window.__ModuleLoader__.load({
83
68
  save: "Save",
84
69
  saving: "Saving…",
85
70
  discard: "Discard",
86
- saveFailed: "The deployment did not accept this value; it was left for you to correct.",
71
+ saveFailed: "The deployment did not accept this value; it was left for you to correct."
87
72
  };
88
73
  /** Simplified Chinese copy. */
89
74
  const zh = {
@@ -98,37 +83,30 @@ window.__ModuleLoader__.load({
98
83
  save: "保存",
99
84
  saving: "保存中…",
100
85
  discard: "放弃修改",
101
- saveFailed: "本部署没有接受该值,已保留供你修改。",
86
+ saveFailed: "本部署没有接受该值,已保留供你修改。"
102
87
  };
103
-
104
- // ── controller ───────────────────────────────────────────────────────────
105
-
106
88
  /**
107
- * Namespace of the GitHub capability. Spelled here rather than imported:
108
- * a client package must not depend on a Host package.
109
- */
110
- const GITHUB_NS = "dsh-github";
111
- /** Credential reference the provider resolves when the section names none. */
112
- const DEFAULT_TOKEN_REF = "GITHUB_TOKEN";
113
-
114
- /**
115
- * Bridges the `dsh-github` scope and the credentials domain onto the
116
- * card. The token is the one control that does not live in the section:
117
- * its literal never rides a response, so the card learns only whether
118
- * one is configured and writes it through the credentials domain,
119
- * addressed by the reference the section names.
120
- */
89
+ * Bridges the `dsh-github` scope and the credentials domain onto the card.
90
+ * The token is the one control that does not live in the section: its literal
91
+ * never rides a response, so the card learns only whether one is configured
92
+ * and writes it through the credentials domain, addressed by the reference the
93
+ * section names.
94
+ */
121
95
  var GithubCardController = class {
122
96
  scope;
123
97
  api;
124
98
  store;
125
99
  saving = false;
126
100
  failed = false;
127
- credential = { ref: "", configured: false, writable: true };
101
+ credential = {
102
+ ref: "",
103
+ configured: false,
104
+ writable: true
105
+ };
128
106
  constructor(scope, api) {
129
107
  this.scope = scope;
130
108
  this.api = api;
131
- this.store = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)(this.projection());
109
+ this.store = createSnapshotStore(this.projection());
132
110
  scope.subscribe(() => {
133
111
  this.readCredential();
134
112
  this.publish();
@@ -145,56 +123,62 @@ window.__ModuleLoader__.load({
145
123
  credentialWritable: this.credential.writable,
146
124
  saving: this.saving,
147
125
  failed: this.failed,
148
- ref: this.credential.ref,
126
+ ref: this.credential.ref
149
127
  };
150
128
  }
151
129
  /** The credential reference the section names, or the provider default. */
152
130
  refOf() {
153
- const snapshot = this.scope.getSnapshot();
154
- const declared = snapshot.value?.tokenRef;
131
+ const declared = this.scope.getSnapshot().value?.tokenRef;
155
132
  return declared !== void 0 && declared.length > 0 ? declared : DEFAULT_TOKEN_REF;
156
133
  }
157
134
  /**
158
- * Ask the credentials domain about the reference the section names.
159
- * A response is published only while it still answers for the
160
- * reference in force, so two reads settling out of order cannot
161
- * clobber each other.
162
- */
135
+ * Ask the credentials domain about the reference the section names. A
136
+ * response is published only while it still answers for the reference in
137
+ * force, so two reads settling out of order cannot clobber each other.
138
+ */
163
139
  async readCredential() {
164
140
  const ref = this.refOf();
165
141
  if (ref !== this.credential.ref) {
166
- this.credential = { ref, configured: false, writable: true };
142
+ this.credential = {
143
+ ref,
144
+ configured: false,
145
+ writable: true
146
+ };
167
147
  this.publish();
168
148
  }
169
149
  let response;
170
150
  try {
171
- response = await this.api.credentials.describe({ refs: [ref] });
172
- } catch (_credentialReadFailure) {
151
+ response = await this.api.describe({ refs: [ref] });
152
+ } catch {
173
153
  return;
174
154
  }
175
155
  if (!response.result.ok || ref !== this.refOf()) return;
176
156
  const view = response.result.value.credentials[ref];
177
- const next = { ref, configured: view?.configured ?? false, writable: view?.writable ?? true };
157
+ const next = {
158
+ ref,
159
+ configured: view?.configured ?? false,
160
+ writable: view?.writable ?? true
161
+ };
178
162
  if (next.configured === this.credential.configured && next.writable === this.credential.writable) return;
179
163
  this.credential = next;
180
164
  this.publish();
181
165
  }
182
166
  /**
183
- * Re-read after the Host reports a change to the reference this card
184
- * watches — a token can be written from elsewhere, and the section
185
- * does not change when it is.
186
- * @param ref - the reference the Host reports as changed.
187
- */
167
+ * Re-read after the Host reports a change to the reference this card
168
+ * watches — a token can be written from elsewhere, and the section does not
169
+ * change when it is.
170
+ * @param ref - the reference the Host reports as changed.
171
+ */
188
172
  refreshCredential(ref) {
189
173
  if (ref !== this.credential.ref) return;
190
174
  this.readCredential();
191
175
  }
192
176
  /**
193
- * Write the staged token, then re-read whether the Host now holds
194
- * one. A blank value writes nothing, which keeps the stored key.
195
- * @param value - the staged credential literal.
196
- * @returns whether the Host reports a configured credential afterwards.
197
- */
177
+ * Write the staged token, then re-read whether the Host now holds one. A
178
+ * blank value writes nothing, which keeps the stored key.
179
+ * @param value - the staged credential literal.
180
+ * @returns whether the Host reports a configured credential afterwards.
181
+ */
198
182
  async save(value) {
199
183
  const text = (value ?? "").trim();
200
184
  if (text === "" || this.saving) return false;
@@ -202,9 +186,11 @@ window.__ModuleLoader__.load({
202
186
  this.failed = false;
203
187
  this.publish();
204
188
  try {
205
- await this.api.credentials.set({ ref: this.refOf(), value: text });
206
- } catch (_credentialWriteFailure) {
207
- }
189
+ await this.api.set({
190
+ ref: this.refOf(),
191
+ value: text
192
+ });
193
+ } catch {}
208
194
  await this.readCredential();
209
195
  const landed = this.credential.configured;
210
196
  this.saving = false;
@@ -216,127 +202,107 @@ window.__ModuleLoader__.load({
216
202
  inject() {
217
203
  return {
218
204
  hooks: { githubCard: this.store },
219
- submit: (value) => this.save(value),
205
+ submit: (value) => this.save(value)
220
206
  };
221
207
  }
222
208
  publish() {
223
209
  this.store.set(this.projection());
224
210
  }
225
211
  };
226
-
227
- // ── card component ───────────────────────────────────────────────────────
228
-
212
+ /** One class name builder (static strings only — no bundler CSS modules here). */
213
+ const cx = (...parts) => parts.filter(Boolean).join(" ");
229
214
  /**
230
- * Render the GitHub card: a collapsible header naming the plugin, and —
231
- * once expanded — the token control and the save/discard row.
232
- * Renders nothing while the namespace is unavailable.
233
- */
215
+ * Render the GitHub card: a collapsible header naming the plugin, and — once
216
+ * expanded — the token control and the save/discard row. Renders nothing
217
+ * while the namespace is unavailable.
218
+ */
234
219
  function GithubCard(props) {
235
220
  const { t } = props;
236
221
  const state = props.useGithubCard((snapshot) => snapshot);
237
- const [open, setOpen] = react.useState(false);
238
- const [draft, setDraft] = react.useState("");
222
+ const [open, setOpen] = (0, react.useState)(false);
223
+ const [draft, setDraft] = (0, react.useState)("");
239
224
  if (!state.available) return null;
240
225
  const title = t("githubTitle");
241
226
  const dirty = draft.trim() !== "";
242
227
  const saveLabel = state.saving ? t("saving") : t("save");
243
- return react.createElement("li", {
244
- className: "ghc-card" + (open ? " ghc-cardOpen" : ""),
245
- },
246
- react.createElement("button", {
247
- type: "button",
248
- className: "ghc-header",
249
- "aria-expanded": open,
250
- "aria-label": (open ? "Collapse" : "Expand") + ": " + title,
251
- onClick: () => setOpen(!open),
252
- },
253
- react.createElement("span", { className: "ghc-headText" },
254
- react.createElement("span", { className: "ghc-name" }, title),
255
- react.createElement("span", { className: "ghc-description" }, t("githubDescription")),
256
- ),
257
- dirty ? react.createElement("span", { className: "ghc-pending" }, t("unsaved")) : null,
258
- react.createElement("span", { className: "ghc-chevron" + (open ? " ghc-chevronOpen" : "") },
259
- react.createElement(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 }),
260
- ),
261
- ),
262
- open ? react.createElement("div", { className: "ghc-body" },
263
- !state.writable ? react.createElement("p", { className: "ghc-readOnly", role: "status" }, t("readOnly")) : null,
264
- react.createElement("div", { className: "ghc-field" },
265
- react.createElement("div", { className: "ghc-head" },
266
- react.createElement("label", { className: "ghc-label", htmlFor: "plugin-config-github-token" }, t("tokenLabel")),
267
- react.createElement("span", { className: "ghc-badges" },
268
- react.createElement("span", { className: state.configured ? "ghc-badge" : "ghc-badgeMuted" },
269
- state.configured ? t("tokenSet") : t("tokenUnset"),
270
- ),
271
- ),
272
- ),
273
- react.createElement("input", {
274
- id: "plugin-config-github-token",
275
- className: "ghc-input",
276
- type: "password",
277
- autoComplete: "off",
278
- value: draft,
279
- disabled: !state.credentialWritable,
280
- onChange: (event) => setDraft(event.target.value),
281
- }),
282
- react.createElement("p", { className: "ghc-hint" }, t("tokenHint")),
283
- ),
284
- react.createElement("div", { className: "ghc-actions" },
285
- state.failed ? react.createElement("p", { className: "ghc-failed", role: "status" }, t("saveFailed")) : null,
286
- react.createElement(_deepseek_ai_dsh_client_ui_primitives.Button, {
287
- variant: "ghost",
288
- size: "sm",
289
- disabled: !dirty || state.saving,
290
- onClick: () => setDraft(""),
291
- }, t("discard")),
292
- react.createElement(_deepseek_ai_dsh_client_ui_primitives.Button, {
293
- variant: "primary",
294
- size: "sm",
295
- disabled: !state.writable || !dirty || state.saving,
296
- icon: state.saving ? react.createElement("span", { className: "ghc-spin" },
297
- react.createElement(_deepseek_ai_dsh_client_ui_primitives.IconLoadingOutline16, { size: 16 }),
298
- ) : void 0,
299
- onClick: async () => {
300
- const landed = await props.submit(draft);
301
- if (landed) setDraft("");
302
- },
303
- }, saveLabel),
304
- ),
305
- ) : null,
306
- );
228
+ return (0, react.createElement)("li", { className: cx("ghc-card", open && "ghc-cardOpen") }, (0, react.createElement)("button", {
229
+ type: "button",
230
+ className: "ghc-header",
231
+ "aria-expanded": open,
232
+ "aria-label": `${open ? "Collapse" : "Expand"}: ${title}`,
233
+ onClick: () => setOpen(!open)
234
+ }, (0, react.createElement)("span", { className: "ghc-headText" }, (0, react.createElement)("span", { className: "ghc-name" }, title), (0, react.createElement)("span", { className: "ghc-description" }, t("githubDescription"))), dirty ? (0, react.createElement)("span", { className: "ghc-pending" }, t("unsaved")) : null, (0, react.createElement)("span", { className: cx("ghc-chevron", open && "ghc-chevronOpen") }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 }))), open ? (0, react.createElement)("div", { className: "ghc-body" }, !state.writable ? (0, react.createElement)("p", {
235
+ className: "ghc-readOnly",
236
+ role: "status"
237
+ }, t("readOnly")) : null, (0, react.createElement)("div", { className: "ghc-field" }, (0, react.createElement)("div", { className: "ghc-head" }, (0, react.createElement)("label", {
238
+ className: "ghc-label",
239
+ htmlFor: "plugin-config-github-token"
240
+ }, t("tokenLabel")), (0, react.createElement)("span", { className: "ghc-badges" }, (0, react.createElement)("span", { className: state.configured ? "ghc-badge" : "ghc-badgeMuted" }, state.configured ? t("tokenSet") : t("tokenUnset")))), (0, react.createElement)("input", {
241
+ id: "plugin-config-github-token",
242
+ className: "ghc-input",
243
+ type: "password",
244
+ autoComplete: "off",
245
+ value: draft,
246
+ disabled: !state.credentialWritable,
247
+ onChange: (event) => setDraft(event.target.value)
248
+ }), (0, react.createElement)("p", { className: "ghc-hint" }, t("tokenHint"))), (0, react.createElement)("div", { className: "ghc-actions" }, state.failed ? (0, react.createElement)("p", {
249
+ className: "ghc-failed",
250
+ role: "status"
251
+ }, t("saveFailed")) : null, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
252
+ variant: "ghost",
253
+ size: "sm",
254
+ disabled: !dirty || state.saving,
255
+ onClick: () => setDraft("")
256
+ }, t("discard")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
257
+ variant: "primary",
258
+ size: "sm",
259
+ disabled: !state.writable || !dirty || state.saving,
260
+ icon: state.saving ? (0, react.createElement)("span", { className: "ghc-spin" }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconLoadingOutline16, { size: 16 })) : void 0,
261
+ onClick: async () => {
262
+ if (await props.submit(draft)) setDraft("");
263
+ }
264
+ }, saveLabel))) : null);
307
265
  }
308
-
309
- // ── entry ────────────────────────────────────────────────────────────────
310
-
311
266
  /** Dictionary namespace owned by this plugin. */
312
267
  const NS = "dsh-github";
313
268
  /** Required services (cordis fiber inject). */
314
- const inject = ["slots", "locale", "connection", "remote", "settingsScope"];
315
-
316
- /**
317
- * Mount the GitHub configuration card into the plugins settings section.
318
- * @param ctx - the browser plugin context.
319
- */
269
+ const inject = [
270
+ "slots",
271
+ "locale",
272
+ "connection",
273
+ "remote",
274
+ "settingsScope"
275
+ ];
276
+ /** Mount the GitHub configuration card into the plugins settings section. */
320
277
  function apply(ctx) {
321
- const { api } = ctx.get("connection");
322
- const t = ctx.locale.bind(NS);
323
- ctx.effect(() => ctx.locale.register(NS, { zh, en }), "dsh-github: card dictionaries");
324
- const github = new GithubCardController(ctx.settingsScope.bind({ namespace: NS }), api);
325
- ctx.effect(() => ctx.remote.$on("credentials/reference-updated", (ref) => {
326
- github.refreshCredential(ref);
327
- }), "dsh-github: credential invalidations");
278
+ const connection = ctx.get("connection");
279
+ ctx.locale.bind(NS);
280
+ ctx.effect(() => ctx.locale.register(NS, {
281
+ zh,
282
+ en
283
+ }), "dsh-github: card dictionaries");
284
+ const github = new GithubCardController(ctx.settingsScope.bind({ namespace: NS }), connection.api);
285
+ ctx.effect(() => ctx.remote.$on("credentials/reference-updated", (ref) => github.refreshCredential(ref)), "dsh-github: credential invalidations");
328
286
  ctx.slots.inject("settings.plugin.item", function* () {
329
287
  yield ctx.slots.register({
330
288
  name: "settings.plugin.item",
331
289
  key: NS,
332
290
  locale: NS,
333
- inject: () => github.inject(),
291
+ inject: () => github.inject()
334
292
  }, GithubCard);
335
293
  });
336
294
  }
337
-
295
+ //#endregion
296
+ exports.DEFAULT_TOKEN_REF = DEFAULT_TOKEN_REF;
297
+ exports.GITHUB_NS = GITHUB_NS;
298
+ exports.GithubCard = GithubCard;
299
+ exports.GithubCardController = GithubCardController;
300
+ exports.NS = NS;
338
301
  exports.apply = apply;
302
+ exports.createSnapshotStore = createSnapshotStore;
303
+ exports.en = en;
339
304
  exports.inject = inject;
305
+ exports.zh = zh;
340
306
  return module.exports;
341
307
  }
342
308
  });
package/lib/github.d.ts CHANGED
@@ -43,17 +43,26 @@ interface ClientOptions {
43
43
  fetchImpl: typeof fetch;
44
44
  }
45
45
  /**
46
- * Authenticated GitHub REST client with rate-limit retry.
47
- *
48
- * Retries 429 (primary limit) and 403-with-Retry-After (secondary limit /
49
- * abuse detection) honoring Retry-After / x-ratelimit-reset and the caller's
50
- * signal; other non-2xx responses surface as {@link GithubError} carrying the
51
- * status and current rate-limit facts. Errors never contain the token.
46
+ * Shared authenticated transport over the GitHub API. It owns the
47
+ * Authorization header, the per-request timeout, and the 429/403 rate-limit
48
+ * retry loop; the REST and GraphQL clients both delegate here, so they share
49
+ * one token, one timeout, and one backoff policy. Errors never contain the
50
+ * token.
52
51
  */
53
- export declare class GithubClient {
52
+ export declare class GithubTransport {
54
53
  private readonly token;
55
54
  private readonly options;
56
55
  constructor(token: string, options: ClientOptions);
56
+ /** Fetch with Authorization, timeout, and retry (429/403 rate limits always; reads also on network errors and 5xx). */
57
+ request(method: string, path: string, options: GithubRequestOptions): Promise<Response>;
58
+ }
59
+ /**
60
+ * Authenticated GitHub REST client: JSON/text requests with the shared
61
+ * transport's 429/403 backoff-retry and rate-limit surfacing.
62
+ */
63
+ export declare class GithubClient {
64
+ private readonly transport;
65
+ constructor(token: string, options: ClientOptions);
57
66
  /** One JSON request with retry; `GithubError` on any non-2xx status. */
58
67
  requestJson<T>(method: string, path: string, options?: GithubRequestOptions): Promise<GithubJsonResponse<T>>;
59
68
  /** One text request (the diff media type) with retry. */
@@ -61,8 +70,41 @@ export declare class GithubClient {
61
70
  text: string;
62
71
  rateLimit: RateLimitInfo;
63
72
  }>;
64
- /** Fetch with Authorization, timeout, and retry (429/403 rate limits always; reads also on network errors and 5xx). */
65
- private request;
73
+ }
74
+ /** Successful GraphQL response with its rate-limit facts. */
75
+ export interface GithubGraphqlResponse<T> {
76
+ data: T;
77
+ rateLimit: RateLimitInfo;
78
+ }
79
+ /**
80
+ * Authenticated GitHub GraphQL client over the shared transport. One POST to
81
+ * `/graphql` carries a document; `query` sends a single document and `batch`
82
+ * merges several aliased sub-queries into one request, sharing the transport's
83
+ * token, timeout, and 429 backoff with the REST client.
84
+ */
85
+ export declare class GithubGraphqlClient {
86
+ private readonly transport;
87
+ constructor(token: string, options: ClientOptions);
88
+ /**
89
+ * Run one GraphQL document. A non-2xx response or a GraphQL `errors` payload
90
+ * fails loud as a {@link GithubError}; the token never appears in messages.
91
+ * @param document - the GraphQL query/mutation document.
92
+ * @param variables - optional variables.
93
+ * @param signal - optional abort signal.
94
+ * @returns the `data` plus rate-limit facts.
95
+ */
96
+ query<T>(document: string, variables?: Record<string, unknown>, signal?: AbortSignal): Promise<GithubGraphqlResponse<T>>;
97
+ /**
98
+ * Batch several sub-queries into ONE GraphQL request using aliases. Each
99
+ * value is a single top-level field selection (e.g.
100
+ * `repository(owner:"o", name:"r") { id }`); the document sent is
101
+ * `query { <alias>: <field> … }` and the result maps each alias to its data.
102
+ * @param aliases - `alias → top-level field selection`.
103
+ * @param variables - optional shared variables.
104
+ * @param signal - optional abort signal.
105
+ * @returns `{ <alias>: data, … }` plus rate-limit facts.
106
+ */
107
+ batch<T>(aliases: Record<string, string>, variables?: Record<string, unknown>, signal?: AbortSignal): Promise<GithubGraphqlResponse<Record<string, T>>>;
66
108
  }
67
109
  /** Build a client from config; resolves the base URL once. */
68
110
  export declare function clientOptionsFromConfig(config: Config, fetchImpl?: typeof fetch): ClientOptions;
@@ -1 +1 @@
1
- {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB;AAED,4EAA4E;AAC5E,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAA;gBAErB,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa;CAMtE;AAED,0DAA0D;AAC1D,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,CAAC,CAAA;IACP,SAAS,EAAE,aAAa,CAAA;CACzB;AAED,MAAM,WAAW,oBAAoB;IACnC,4BAA4B;IAC5B,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,UAAU,aAAa;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;IACtB,iEAAiE;IACjE,gBAAgB,EAAE,MAAM,CAAA;IACxB,SAAS,EAAE,OAAO,KAAK,CAAA;CACxB;AAwDD;;;;;;;GAOG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;gBAE3B,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa;IAKjD,wEAAwE;IAClE,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;IAkBtH,yDAAyD;IACnD,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,aAAa,CAAA;KAAE,CAAC;IAgBxI,uHAAuH;YACzG,OAAO;CA0CtB;AAED,8DAA8D;AAC9D,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,KAAK,GAAG,aAAa,CAS/F"}
1
+ {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"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"}