@comecaramelos/dsh-custom-provider 0.0.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/LICENSE.md +21 -0
- package/README.md +52 -0
- package/cordis.patch.yml +9 -0
- package/lib/client.js +766 -0
- package/lib/client.js.map +7 -0
- package/lib/host/apply.d.ts +10 -0
- package/lib/host/apply.d.ts.map +1 -0
- package/lib/host/apply.js +10 -0
- package/lib/host/apply.js.map +1 -0
- package/lib/host/plugin-meta.d.ts +14 -0
- package/lib/host/plugin-meta.d.ts.map +1 -0
- package/lib/host/plugin-meta.js +14 -0
- package/lib/host/plugin-meta.js.map +1 -0
- package/lib/host/types.d.ts +11 -0
- package/lib/host/types.d.ts.map +1 -0
- package/lib/host/types.js +8 -0
- package/lib/host/types.js.map +1 -0
- package/lib/index.d.ts +20 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +19 -0
- package/lib/index.js.map +1 -0
- package/package.json +65 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ComeCaramelos
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# @comecaramelos/dsh-custom-provider
|
|
2
|
+
|
|
3
|
+
DSH plugin that adds a **"No API key required"** toggle to saved hand-declared
|
|
4
|
+
provider cards in **Settings → Models**, and lights a **green status dot** on
|
|
5
|
+
hand-declared rows whose profile authenticates through a non-empty
|
|
6
|
+
`Authorization` header (the toggle's placeholder or one you wrote yourself).
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
dsh plugin add @comecaramelos/dsh-custom-provider
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
For development, link this checkout into your `web` profile (after
|
|
15
|
+
building the bundle once). The checkout is mounted from the source tree, never
|
|
16
|
+
from a published npm copy — if the same package is installed system-wide, keep
|
|
17
|
+
the link in the `web` profile and make sure it wins (see the guidance
|
|
18
|
+
in `~/.dsh/profiles/web/README.md`):
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install
|
|
22
|
+
npm run build
|
|
23
|
+
dsh plugin --profile web add link:/path/to/dsh-custom-provider
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
1. Open **Settings → Models** and save your custom provider (the create form
|
|
29
|
+
itself has no toggle).
|
|
30
|
+
2. Open the saved provider's card so its editor expands — the toggle lives
|
|
31
|
+
inside that editor (it is invisible while the card is closed).
|
|
32
|
+
3. Tick **No API key required** for endpoints that ignore authentication.
|
|
33
|
+
4. The row lights a green dot whenever its profile authenticates through a
|
|
34
|
+
non-empty `Authorization` header — via the toggle, by inheritance, or one
|
|
35
|
+
you typed yourself. The dot never touches the profile and never shows on
|
|
36
|
+
top of the page's own credential dot (never two indicators).
|
|
37
|
+
|
|
38
|
+
## Development
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install # typescript + esbuild devDependencies
|
|
42
|
+
npm run build # src/**/*.ts → lib/ (host: tsc; browser: tsc typecheck + esbuild bundle)
|
|
43
|
+
npm test # builds, then node --test (pure logic through stubbed loader + React)
|
|
44
|
+
npm run dev # tsc --watch
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The tests drive the **emitted** `lib/client.js` through a stubbed module
|
|
48
|
+
loader, so the shipped artifact is what is verified.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
[`CONTRIBUTING`](CONTRIBUTING.md) | [`LICENSE`](LICENSE.md)
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @comecaramelos/dsh-custom-provider — bundle patch.
|
|
2
|
+
# Registers the `custom-provider` row so the browser bundle (lib/client.js)
|
|
3
|
+
# loads. The whole feature is web-plane: the row carries no host configuration
|
|
4
|
+
# because the toggle reads and writes the pi-ai adapter's own `llm-pi-ai`
|
|
5
|
+
# settings namespace — there is no plugin-owned settings section.
|
|
6
|
+
- insert:
|
|
7
|
+
- id: custom-provider
|
|
8
|
+
name: '@comecaramelos/dsh-custom-provider'
|
|
9
|
+
config: {}
|
package/lib/client.js
ADDED
|
@@ -0,0 +1,766 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "@comecaramelos/dsh-custom-provider",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
"use strict";
|
|
8
|
+
var __defProp = Object.defineProperty;
|
|
9
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
10
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
11
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
16
|
+
var __copyProps = (to, from, except, desc) => {
|
|
17
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
18
|
+
for (let key of __getOwnPropNames(from))
|
|
19
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
20
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
21
|
+
}
|
|
22
|
+
return to;
|
|
23
|
+
};
|
|
24
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
25
|
+
|
|
26
|
+
// src/client/index.ts
|
|
27
|
+
var index_exports = {};
|
|
28
|
+
__export(index_exports, {
|
|
29
|
+
NO_KEY_HEADER: () => NO_KEY_HEADER,
|
|
30
|
+
NO_KEY_VALUE: () => NO_KEY_VALUE,
|
|
31
|
+
NoApiKeyToggleCard: () => NoApiKeyToggleCard,
|
|
32
|
+
PRIMARY_BUTTON_CLASS_END: () => PRIMARY_BUTTON_CLASS_END,
|
|
33
|
+
SECONDARY_BUTTON_CLASS_END: () => SECONDARY_BUTTON_CLASS_END,
|
|
34
|
+
SETTINGS_NS: () => SETTINGS_NS,
|
|
35
|
+
ToggleView: () => ToggleView,
|
|
36
|
+
apply: () => apply,
|
|
37
|
+
clearOps: () => clearOps,
|
|
38
|
+
configureOps: () => configureOps,
|
|
39
|
+
findActionsWithin: () => findActionsWithin,
|
|
40
|
+
findButtonWithin: () => findButtonWithin,
|
|
41
|
+
findCancelWithin: () => findCancelWithin,
|
|
42
|
+
findCommitWithin: () => findCommitWithin,
|
|
43
|
+
findEditorWithin: () => findEditorWithin,
|
|
44
|
+
findKeyFieldWithin: () => findKeyFieldWithin,
|
|
45
|
+
findRowIdentityWithin: () => findRowIdentityWithin,
|
|
46
|
+
hasClassEnding: () => hasClassEnding,
|
|
47
|
+
hasCredentialDotWithin: () => hasCredentialDotWithin,
|
|
48
|
+
hasForeignAuthorization: () => hasForeignAuthorization,
|
|
49
|
+
headerConfigured: () => headerConfigured,
|
|
50
|
+
inject: () => inject,
|
|
51
|
+
isNoKeyActive: () => isNoKeyActive,
|
|
52
|
+
noKeyPath: () => noKeyPath,
|
|
53
|
+
positionDot: () => positionDot,
|
|
54
|
+
positionHost: () => positionHost,
|
|
55
|
+
profileHeaders: () => profileHeaders,
|
|
56
|
+
resolvedProfile: () => resolvedProfile,
|
|
57
|
+
showDot: () => showDot,
|
|
58
|
+
showToggle: () => showToggle,
|
|
59
|
+
stageOf: () => stageOf,
|
|
60
|
+
stagedDirection: () => stagedDirection,
|
|
61
|
+
stagedOps: () => stagedOps
|
|
62
|
+
});
|
|
63
|
+
module.exports = __toCommonJS(index_exports);
|
|
64
|
+
|
|
65
|
+
// src/client/card/toggle-card.ts
|
|
66
|
+
var import_react6 = require("react");
|
|
67
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
68
|
+
|
|
69
|
+
// src/client/copy.ts
|
|
70
|
+
var COPY = {
|
|
71
|
+
label: "No API key required",
|
|
72
|
+
configured: "No-API-key request header configured",
|
|
73
|
+
hint: "Disables API key input and sets up the profile so keyless endpoints pass key check.",
|
|
74
|
+
staged: "Staged with this card \u2014 stored when the card itself is saved.",
|
|
75
|
+
conflict: "A custom Authorization header is already set on this provider. Clear it in the profile settings to use this toggle.",
|
|
76
|
+
readOnly: "Settings are read-only in this deployment.",
|
|
77
|
+
failed: "The settings write was rejected; the profile was left unchanged.",
|
|
78
|
+
dotAuthorizationConfigured: "Authorization header configured"
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// src/client/plugin-meta.ts
|
|
82
|
+
var SETTINGS_NS = "llm-pi-ai";
|
|
83
|
+
var NO_KEY_HEADER = "Authorization";
|
|
84
|
+
var NO_KEY_VALUE = "Bearer none";
|
|
85
|
+
var inject = ["settingsScope", "slots"];
|
|
86
|
+
|
|
87
|
+
// src/client/profile.ts
|
|
88
|
+
function profileHeaders(snapshot, route) {
|
|
89
|
+
var user = snapshot && snapshot.user;
|
|
90
|
+
var profile = user && user.providers && user.providers[route];
|
|
91
|
+
var headers = profile && profile.headers;
|
|
92
|
+
if (!headers || typeof headers !== "object" || Array.isArray(headers)) return void 0;
|
|
93
|
+
return headers;
|
|
94
|
+
}
|
|
95
|
+
function isNoKeyActive(snapshot, route) {
|
|
96
|
+
var headers = profileHeaders(snapshot, route);
|
|
97
|
+
return !!headers && headers[NO_KEY_HEADER] === NO_KEY_VALUE;
|
|
98
|
+
}
|
|
99
|
+
function hasForeignAuthorization(snapshot, route) {
|
|
100
|
+
var headers = profileHeaders(snapshot, route);
|
|
101
|
+
return !!headers && Object.prototype.hasOwnProperty.call(headers, NO_KEY_HEADER) && headers[NO_KEY_HEADER] !== NO_KEY_VALUE;
|
|
102
|
+
}
|
|
103
|
+
function resolvedProfile(snapshot, route) {
|
|
104
|
+
var value = snapshot && snapshot.value;
|
|
105
|
+
if (!value || typeof value !== "object") return void 0;
|
|
106
|
+
var providers = value.providers;
|
|
107
|
+
if (!providers || typeof providers !== "object") return void 0;
|
|
108
|
+
var profile = providers[route];
|
|
109
|
+
return profile && typeof profile === "object" ? profile : void 0;
|
|
110
|
+
}
|
|
111
|
+
function headerConfigured(profile) {
|
|
112
|
+
var headers = profile && profile.headers;
|
|
113
|
+
if (!headers || typeof headers !== "object" || Array.isArray(headers)) return false;
|
|
114
|
+
var names = Object.keys(headers);
|
|
115
|
+
for (var i = 0; i < names.length; i++) {
|
|
116
|
+
if (names[i].toLowerCase() === "authorization") {
|
|
117
|
+
var value = headers[names[i]];
|
|
118
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
function showDot(owner, snapshot) {
|
|
124
|
+
var provider = owner && owner.provider;
|
|
125
|
+
if (!(provider && provider.declared === true && typeof provider.provider === "string" && provider.provider.length > 0)) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
if (!(snapshot && snapshot.status === "ready")) return false;
|
|
129
|
+
return headerConfigured(resolvedProfile(snapshot, provider.provider));
|
|
130
|
+
}
|
|
131
|
+
function noKeyPath(route) {
|
|
132
|
+
return ["providers", route, "headers", NO_KEY_HEADER];
|
|
133
|
+
}
|
|
134
|
+
function configureOps(route) {
|
|
135
|
+
return [{ op: "set", path: noKeyPath(route), value: NO_KEY_VALUE }];
|
|
136
|
+
}
|
|
137
|
+
function clearOps(route) {
|
|
138
|
+
return [{ op: "unset", path: noKeyPath(route) }];
|
|
139
|
+
}
|
|
140
|
+
function stagedDirection(ops) {
|
|
141
|
+
return !!ops && ops[0] !== void 0 && ops[0].op === "set";
|
|
142
|
+
}
|
|
143
|
+
function stagedOps(checked, storedActive, route) {
|
|
144
|
+
if (checked === storedActive) return null;
|
|
145
|
+
return checked ? configureOps(route) : clearOps(route);
|
|
146
|
+
}
|
|
147
|
+
function stageOf(ops, storedActive) {
|
|
148
|
+
if (ops === null) return { draftActive: storedActive, dirty: false };
|
|
149
|
+
var on = stagedDirection(ops);
|
|
150
|
+
var dirty = on !== storedActive;
|
|
151
|
+
return { draftActive: dirty ? on : storedActive, dirty };
|
|
152
|
+
}
|
|
153
|
+
function showToggle(owner) {
|
|
154
|
+
var provider = owner && owner.provider;
|
|
155
|
+
return !!(provider && provider.declared === true && owner.configured === true && owner.keyConfigured === false);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// src/client/toggle-view.ts
|
|
159
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
160
|
+
var SwitchResolved = null;
|
|
161
|
+
var switchResolved = false;
|
|
162
|
+
function resolveSwitch() {
|
|
163
|
+
if (!switchResolved) {
|
|
164
|
+
switchResolved = true;
|
|
165
|
+
try {
|
|
166
|
+
var primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
167
|
+
SwitchResolved = primitives && primitives.Switch || null;
|
|
168
|
+
} catch (error) {
|
|
169
|
+
SwitchResolved = null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return SwitchResolved;
|
|
173
|
+
}
|
|
174
|
+
function ToggleView(props) {
|
|
175
|
+
var Switch = resolveSwitch();
|
|
176
|
+
var active = props.active === true;
|
|
177
|
+
var conflict = props.conflict === true;
|
|
178
|
+
var disabled = props.writable !== true || conflict;
|
|
179
|
+
var control = Switch ? (0, import_jsx_runtime.jsx)(Switch, {
|
|
180
|
+
checked: active,
|
|
181
|
+
disabled,
|
|
182
|
+
label: COPY.label,
|
|
183
|
+
onChange: function(checked) {
|
|
184
|
+
props.onToggle(checked === true);
|
|
185
|
+
}
|
|
186
|
+
}) : (0, import_jsx_runtime.jsxs)("label", {
|
|
187
|
+
children: [
|
|
188
|
+
(0, import_jsx_runtime.jsx)("input", {
|
|
189
|
+
type: "checkbox",
|
|
190
|
+
checked: active,
|
|
191
|
+
disabled,
|
|
192
|
+
"aria-label": COPY.label,
|
|
193
|
+
onChange: function(event) {
|
|
194
|
+
props.onToggle(!!(event && event.target && event.target.checked));
|
|
195
|
+
}
|
|
196
|
+
}),
|
|
197
|
+
(0, import_jsx_runtime.jsx)("span", { children: COPY.label })
|
|
198
|
+
]
|
|
199
|
+
});
|
|
200
|
+
var failure = props.failure || null;
|
|
201
|
+
return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, {
|
|
202
|
+
children: [
|
|
203
|
+
(0, import_jsx_runtime.jsxs)("div", {
|
|
204
|
+
className: "ccp_line",
|
|
205
|
+
children: [
|
|
206
|
+
control,
|
|
207
|
+
active ? (0, import_jsx_runtime.jsx)("input", {
|
|
208
|
+
className: "ccp_value",
|
|
209
|
+
value: NO_KEY_HEADER + ": " + NO_KEY_VALUE,
|
|
210
|
+
disabled: true,
|
|
211
|
+
readOnly: true,
|
|
212
|
+
tabIndex: -1,
|
|
213
|
+
"aria-label": COPY.configured
|
|
214
|
+
}) : null
|
|
215
|
+
]
|
|
216
|
+
}),
|
|
217
|
+
props.writable ? null : (0, import_jsx_runtime.jsx)("p", { className: "ccp_warning", children: COPY.readOnly }),
|
|
218
|
+
failure ? (0, import_jsx_runtime.jsx)("p", { className: "ccp_warning", children: failure }) : conflict ? (0, import_jsx_runtime.jsx)("p", { className: "ccp_warning", children: COPY.conflict }) : props.staged === true ? (0, import_jsx_runtime.jsx)("p", { className: "ccp_hint", children: COPY.staged }) : (0, import_jsx_runtime.jsx)("p", { className: "ccp_hint", children: COPY.hint })
|
|
219
|
+
]
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/client/card/click-signals.ts
|
|
224
|
+
var import_react = require("react");
|
|
225
|
+
|
|
226
|
+
// src/client/dom.ts
|
|
227
|
+
var PRIMARY_BUTTON_CLASS_END = "primaryButton";
|
|
228
|
+
var SECONDARY_BUTTON_CLASS_END = "secondaryButton";
|
|
229
|
+
var EDITOR_CLASS_END = "_editor";
|
|
230
|
+
var EDITOR_ACTIONS_CLASS_END = "_editorActions";
|
|
231
|
+
var EDITOR_FIELD_CLASS_END = "_field";
|
|
232
|
+
var ROW_IDENTITY_CLASS_END = "rowIdentity";
|
|
233
|
+
var CREDENTIAL_DOT_CLASS_END = "credentialDot";
|
|
234
|
+
function hasClassEnding(element, suffix) {
|
|
235
|
+
var cls = element && element.className || "";
|
|
236
|
+
if (typeof cls !== "string" || cls.indexOf(suffix) < 0) return false;
|
|
237
|
+
var tokens = cls.split(/\s+/);
|
|
238
|
+
for (var i = 0; i < tokens.length; i++) {
|
|
239
|
+
if (tokens[i].length > suffix.length && tokens[i].slice(-suffix.length) === suffix) return true;
|
|
240
|
+
}
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
function findEditorWithin(root) {
|
|
244
|
+
if (!root || typeof root.querySelectorAll !== "function") return null;
|
|
245
|
+
var nodes = root.querySelectorAll("[class]");
|
|
246
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
247
|
+
if (hasClassEnding(nodes[i], EDITOR_CLASS_END)) return nodes[i];
|
|
248
|
+
}
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
function findActionsWithin(editor) {
|
|
252
|
+
if (!editor || typeof editor.querySelectorAll !== "function") return null;
|
|
253
|
+
var nodes = editor.querySelectorAll("[class]");
|
|
254
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
255
|
+
if (hasClassEnding(nodes[i], EDITOR_ACTIONS_CLASS_END)) return nodes[i];
|
|
256
|
+
}
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
function findButtonWithin(editor, buttonClassEnd) {
|
|
260
|
+
if (!editor || typeof editor.querySelectorAll !== "function") return null;
|
|
261
|
+
var scope = findActionsWithin(editor);
|
|
262
|
+
var nodes = (scope || editor).querySelectorAll("[class]");
|
|
263
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
264
|
+
if (hasClassEnding(nodes[i], buttonClassEnd)) return nodes[i];
|
|
265
|
+
}
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
function findCommitWithin(editor) {
|
|
269
|
+
return findButtonWithin(editor, PRIMARY_BUTTON_CLASS_END);
|
|
270
|
+
}
|
|
271
|
+
function findCancelWithin(editor) {
|
|
272
|
+
return findButtonWithin(editor, SECONDARY_BUTTON_CLASS_END);
|
|
273
|
+
}
|
|
274
|
+
function findKeyFieldWithin(editor) {
|
|
275
|
+
if (!editor || typeof editor.querySelectorAll !== "function") return null;
|
|
276
|
+
var fields = editor.querySelectorAll("[class]");
|
|
277
|
+
for (var i = 0; i < fields.length; i++) {
|
|
278
|
+
if (!hasClassEnding(fields[i], EDITOR_FIELD_CLASS_END)) continue;
|
|
279
|
+
if (fields[i].querySelectorAll('input[type="password"]').length > 0) return fields[i];
|
|
280
|
+
}
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
function retireHost(host, anchor) {
|
|
284
|
+
if (anchor && host.parentElement !== anchor) anchor.appendChild(host);
|
|
285
|
+
return anchor;
|
|
286
|
+
}
|
|
287
|
+
function disablePasswordInput(editor, active) {
|
|
288
|
+
if (!editor || typeof editor.querySelectorAll !== "function") return;
|
|
289
|
+
var inputs = editor.querySelectorAll('input[type="password"]');
|
|
290
|
+
for (var i = 0; i < inputs.length; i++) {
|
|
291
|
+
inputs[i].disabled = active === true;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function positionHost(host, card, anchor, park, active) {
|
|
295
|
+
if (!park) return retireHost(host, anchor);
|
|
296
|
+
var editor = findEditorWithin(card);
|
|
297
|
+
if (!editor) return retireHost(host, anchor);
|
|
298
|
+
var keyField = findKeyFieldWithin(editor);
|
|
299
|
+
if (keyField && keyField.parentElement) {
|
|
300
|
+
var parent = keyField.parentElement;
|
|
301
|
+
if (host.parentElement !== parent || keyField.nextSibling !== host) {
|
|
302
|
+
parent.insertBefore(host, keyField.nextSibling || null);
|
|
303
|
+
}
|
|
304
|
+
disablePasswordInput(editor, active);
|
|
305
|
+
return parent;
|
|
306
|
+
}
|
|
307
|
+
var actions = findActionsWithin(editor);
|
|
308
|
+
if (actions) {
|
|
309
|
+
if (host.parentElement !== editor || host.nextSibling !== actions) editor.insertBefore(host, actions);
|
|
310
|
+
} else if (host.parentElement !== editor) {
|
|
311
|
+
editor.appendChild(host);
|
|
312
|
+
}
|
|
313
|
+
disablePasswordInput(editor, active);
|
|
314
|
+
return editor;
|
|
315
|
+
}
|
|
316
|
+
function findRowIdentityWithin(root) {
|
|
317
|
+
if (!root || typeof root.querySelectorAll !== "function") return null;
|
|
318
|
+
var nodes = root.querySelectorAll("[class]");
|
|
319
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
320
|
+
if (hasClassEnding(nodes[i], ROW_IDENTITY_CLASS_END)) return nodes[i];
|
|
321
|
+
}
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
function hasCredentialDotWithin(identity) {
|
|
325
|
+
if (!identity || typeof identity.querySelectorAll !== "function") return false;
|
|
326
|
+
var nodes = identity.querySelectorAll("[class]");
|
|
327
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
328
|
+
if (hasClassEnding(nodes[i], CREDENTIAL_DOT_CLASS_END)) return true;
|
|
329
|
+
}
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
function positionDot(host, card, anchor, show) {
|
|
333
|
+
if (!show) return retireHost(host, anchor);
|
|
334
|
+
var identity = findRowIdentityWithin(card);
|
|
335
|
+
if (!identity || hasCredentialDotWithin(identity)) return retireHost(host, anchor);
|
|
336
|
+
if (host.parentElement !== identity) identity.appendChild(host);
|
|
337
|
+
return identity;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// src/client/card/click-signals.ts
|
|
341
|
+
function useClickSignals(state) {
|
|
342
|
+
(0, import_react.useEffect)(
|
|
343
|
+
function() {
|
|
344
|
+
if (typeof window === "undefined" || typeof window.addEventListener !== "function") return function() {
|
|
345
|
+
};
|
|
346
|
+
function chainHits(node, ancestor) {
|
|
347
|
+
while (node) {
|
|
348
|
+
if (node === ancestor) return true;
|
|
349
|
+
node = node.parentElement;
|
|
350
|
+
}
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
function buttonInChain(node, stopAt) {
|
|
354
|
+
var sawSecondary = false;
|
|
355
|
+
while (node && node !== stopAt) {
|
|
356
|
+
if (hasClassEnding(node, SECONDARY_BUTTON_CLASS_END)) sawSecondary = true;
|
|
357
|
+
else if (hasClassEnding(node, PRIMARY_BUTTON_CLASS_END)) {
|
|
358
|
+
return sawSecondary ? "cancel" : "commit";
|
|
359
|
+
}
|
|
360
|
+
node = node.parentElement;
|
|
361
|
+
}
|
|
362
|
+
return sawSecondary ? "cancel" : null;
|
|
363
|
+
}
|
|
364
|
+
function onWindowCapture(event) {
|
|
365
|
+
var target = event && event.target;
|
|
366
|
+
if (!target || typeof target.closest !== "function") return;
|
|
367
|
+
var anchor = state.anchorRef.current;
|
|
368
|
+
if (!anchor || !anchor.isConnected || typeof anchor.closest !== "function") return;
|
|
369
|
+
var row = anchor.closest("li");
|
|
370
|
+
if (!row || target.closest("li") !== row) return;
|
|
371
|
+
var button = buttonInChain(target, row);
|
|
372
|
+
if (button === "cancel") {
|
|
373
|
+
state.cancelSeenRef.current = true;
|
|
374
|
+
state.commitSeenRef.current = false;
|
|
375
|
+
} else if (button === "commit") {
|
|
376
|
+
state.commitSeenRef.current = true;
|
|
377
|
+
state.cancelSeenRef.current = false;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
function onWindowClick(event) {
|
|
381
|
+
var target = event && event.target;
|
|
382
|
+
var anchor = state.anchorRef.current;
|
|
383
|
+
if (!target || !anchor || !anchor.isConnected) return;
|
|
384
|
+
var card = typeof anchor.closest === "function" ? anchor.closest("li") : null;
|
|
385
|
+
var live = state.liveRef.current;
|
|
386
|
+
var editor = findEditorWithin(card);
|
|
387
|
+
var last = state.lastEditorRef.current;
|
|
388
|
+
if (!editor) editor = last;
|
|
389
|
+
if (!editor || !chainHits(target, editor)) return;
|
|
390
|
+
var commit = findCommitWithin(editor);
|
|
391
|
+
var cancel = findCancelWithin(editor);
|
|
392
|
+
var commitHit = false;
|
|
393
|
+
var cancelHit = false;
|
|
394
|
+
var node = target;
|
|
395
|
+
while (node && node !== editor) {
|
|
396
|
+
if (commit && node === commit) {
|
|
397
|
+
commitHit = true;
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
400
|
+
if (cancel && node === cancel) {
|
|
401
|
+
cancelHit = true;
|
|
402
|
+
break;
|
|
403
|
+
}
|
|
404
|
+
node = node.parentElement;
|
|
405
|
+
}
|
|
406
|
+
if (!commitHit && !cancelHit) {
|
|
407
|
+
var button = buttonInChain(target, editor);
|
|
408
|
+
commitHit = button === "commit";
|
|
409
|
+
cancelHit = button === "cancel";
|
|
410
|
+
}
|
|
411
|
+
if (!commitHit && !cancelHit) return;
|
|
412
|
+
if (cancelHit) {
|
|
413
|
+
state.cancelSeenRef.current = true;
|
|
414
|
+
if (live.staged !== null) state.setStaged(null);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
if (live.staged === null) return;
|
|
418
|
+
state.beginFlush(live);
|
|
419
|
+
}
|
|
420
|
+
window.addEventListener("click", onWindowCapture, true);
|
|
421
|
+
window.addEventListener("click", onWindowClick);
|
|
422
|
+
return function() {
|
|
423
|
+
window.removeEventListener("click", onWindowCapture, true);
|
|
424
|
+
window.removeEventListener("click", onWindowClick);
|
|
425
|
+
};
|
|
426
|
+
},
|
|
427
|
+
[]
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// src/client/card/placement.ts
|
|
432
|
+
var import_react2 = require("react");
|
|
433
|
+
function noop() {
|
|
434
|
+
}
|
|
435
|
+
function usePlacement(state, visible, active, dot) {
|
|
436
|
+
(0, import_react2.useEffect)(
|
|
437
|
+
function() {
|
|
438
|
+
var anchor = state.anchorRef.current;
|
|
439
|
+
if (!anchor || typeof MutationObserver !== "function" || typeof document === "undefined") return noop;
|
|
440
|
+
var hostEl = state.hostRef.current;
|
|
441
|
+
var dotEl = state.dotRef.current;
|
|
442
|
+
function cardOf() {
|
|
443
|
+
return anchor.isConnected && typeof anchor.closest === "function" ? anchor.closest("li") : null;
|
|
444
|
+
}
|
|
445
|
+
function position() {
|
|
446
|
+
var card2 = cardOf();
|
|
447
|
+
var live = state.liveRef.current;
|
|
448
|
+
var editorNode = findEditorWithin(card2);
|
|
449
|
+
if (editorNode) state.lastEditorRef.current = editorNode;
|
|
450
|
+
if (hostEl) positionHost(hostEl, card2, anchor, live.visible, live.active);
|
|
451
|
+
if (dotEl) positionDot(dotEl, card2, anchor, live.dot);
|
|
452
|
+
if (live.staged !== null && editorNode === null) {
|
|
453
|
+
if (state.cancelSeenRef.current) {
|
|
454
|
+
state.cancelSeenRef.current = false;
|
|
455
|
+
state.commitSeenRef.current = false;
|
|
456
|
+
state.setStaged(null);
|
|
457
|
+
} else if (state.commitSeenRef.current) {
|
|
458
|
+
if (!state.flushingRef.current) state.beginFlush(live);
|
|
459
|
+
} else {
|
|
460
|
+
state.deferredCloseRef.current = true;
|
|
461
|
+
Promise.resolve().then(state.deferredDecision);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
position();
|
|
466
|
+
var observer = new MutationObserver(function() {
|
|
467
|
+
position();
|
|
468
|
+
});
|
|
469
|
+
var card = cardOf();
|
|
470
|
+
if (card) observer.observe(card, { childList: true, subtree: true });
|
|
471
|
+
return function() {
|
|
472
|
+
observer.disconnect();
|
|
473
|
+
if (hostEl) hostEl.remove();
|
|
474
|
+
if (dotEl) dotEl.remove();
|
|
475
|
+
};
|
|
476
|
+
},
|
|
477
|
+
[visible, active, dot]
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// src/client/card/revision.ts
|
|
482
|
+
var import_react3 = require("react");
|
|
483
|
+
function noop2() {
|
|
484
|
+
}
|
|
485
|
+
function useRevisionWatch(state, scope) {
|
|
486
|
+
(0, import_react3.useEffect)(
|
|
487
|
+
function() {
|
|
488
|
+
if (!scope || typeof scope.subscribe !== "function") return noop2;
|
|
489
|
+
var seed = scope.getSnapshot();
|
|
490
|
+
state.lastRevisionRef.current = seed ? seed.revision : void 0;
|
|
491
|
+
function onScopeChange() {
|
|
492
|
+
var live = state.liveRef.current;
|
|
493
|
+
var snap = live.scope ? live.scope.getSnapshot() : void 0;
|
|
494
|
+
var revision = snap ? snap.revision : void 0;
|
|
495
|
+
var last = state.lastRevisionRef.current;
|
|
496
|
+
state.lastRevisionRef.current = revision;
|
|
497
|
+
if (last === void 0 || revision === void 0 || revision === last) return;
|
|
498
|
+
if (live.staged !== null && !state.flushingRef.current) state.beginFlush(live);
|
|
499
|
+
}
|
|
500
|
+
try {
|
|
501
|
+
return scope.subscribe(onScopeChange);
|
|
502
|
+
} catch {
|
|
503
|
+
return noop2;
|
|
504
|
+
}
|
|
505
|
+
},
|
|
506
|
+
[scope]
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// src/client/card/state.ts
|
|
511
|
+
var import_react4 = require("react");
|
|
512
|
+
|
|
513
|
+
// src/client/card/flush.ts
|
|
514
|
+
function landStaged(ops, flushScope, flushRoute) {
|
|
515
|
+
var target = stagedDirection(ops);
|
|
516
|
+
function attempt(retry) {
|
|
517
|
+
var snapshotNow = flushScope.getSnapshot();
|
|
518
|
+
if (!!snapshotNow && snapshotNow.status === "ready" && isNoKeyActive(snapshotNow, flushRoute) === target) {
|
|
519
|
+
return Promise.resolve();
|
|
520
|
+
}
|
|
521
|
+
return flushScope.mutate(ops).then(function() {
|
|
522
|
+
var after = flushScope.getSnapshot();
|
|
523
|
+
var landed = !!after && after.status === "ready" && isNoKeyActive(after, flushRoute) === target;
|
|
524
|
+
if (landed) return;
|
|
525
|
+
if (!retry) return attempt(true);
|
|
526
|
+
return Promise.reject(new Error("rejected"));
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
return Promise.resolve().then(function() {
|
|
530
|
+
return attempt(false);
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// src/client/card/state.ts
|
|
535
|
+
function useCardState(scope) {
|
|
536
|
+
var failurePair = (0, import_react4.useState)(null);
|
|
537
|
+
var failure = failurePair[0];
|
|
538
|
+
var setFailure = failurePair[1];
|
|
539
|
+
var stagedPair = (0, import_react4.useState)(null);
|
|
540
|
+
var staged = stagedPair[0];
|
|
541
|
+
var setStagedState = stagedPair[1];
|
|
542
|
+
var stagedRef = (0, import_react4.useRef)(null);
|
|
543
|
+
var liveRef = (0, import_react4.useRef)({ visible: false, dot: false, active: false, route: "", scope, staged: null });
|
|
544
|
+
var anchorRef = (0, import_react4.useRef)(null);
|
|
545
|
+
var hostRef = (0, import_react4.useRef)(null);
|
|
546
|
+
var dotRef = (0, import_react4.useRef)(null);
|
|
547
|
+
var flushingRef = (0, import_react4.useRef)(false);
|
|
548
|
+
var cancelSeenRef = (0, import_react4.useRef)(false);
|
|
549
|
+
var commitSeenRef = (0, import_react4.useRef)(false);
|
|
550
|
+
var deferredCloseRef = (0, import_react4.useRef)(false);
|
|
551
|
+
var lastRevisionRef = (0, import_react4.useRef)(void 0);
|
|
552
|
+
var lastEditorRef = (0, import_react4.useRef)(null);
|
|
553
|
+
function setStaged(ops) {
|
|
554
|
+
stagedRef.current = ops;
|
|
555
|
+
var st = stageOf(ops, liveRef.current.active);
|
|
556
|
+
liveRef.current.staged = st.dirty ? ops : null;
|
|
557
|
+
setStagedState(ops);
|
|
558
|
+
}
|
|
559
|
+
function beginFlush(live) {
|
|
560
|
+
if (flushingRef.current || live.staged === null) return;
|
|
561
|
+
var ops = live.staged;
|
|
562
|
+
var flushScope = live.scope;
|
|
563
|
+
var flushRoute = live.route;
|
|
564
|
+
cancelSeenRef.current = false;
|
|
565
|
+
commitSeenRef.current = false;
|
|
566
|
+
flushingRef.current = true;
|
|
567
|
+
landStaged(ops, flushScope, flushRoute).then(
|
|
568
|
+
function() {
|
|
569
|
+
flushingRef.current = false;
|
|
570
|
+
setFailure(null);
|
|
571
|
+
},
|
|
572
|
+
function() {
|
|
573
|
+
flushingRef.current = false;
|
|
574
|
+
setFailure(COPY.failed);
|
|
575
|
+
}
|
|
576
|
+
);
|
|
577
|
+
setStaged(null);
|
|
578
|
+
}
|
|
579
|
+
function deferredDecision() {
|
|
580
|
+
if (!deferredCloseRef.current) return;
|
|
581
|
+
deferredCloseRef.current = false;
|
|
582
|
+
var live = liveRef.current;
|
|
583
|
+
if (live.staged === null) return;
|
|
584
|
+
if (cancelSeenRef.current) {
|
|
585
|
+
cancelSeenRef.current = false;
|
|
586
|
+
commitSeenRef.current = false;
|
|
587
|
+
setStaged(null);
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
if (commitSeenRef.current) {
|
|
591
|
+
if (!flushingRef.current) beginFlush(live);
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
commitSeenRef.current = false;
|
|
595
|
+
setStaged(null);
|
|
596
|
+
}
|
|
597
|
+
return {
|
|
598
|
+
failure,
|
|
599
|
+
staged,
|
|
600
|
+
stagedRef,
|
|
601
|
+
liveRef,
|
|
602
|
+
anchorRef,
|
|
603
|
+
hostRef,
|
|
604
|
+
dotRef,
|
|
605
|
+
flushingRef,
|
|
606
|
+
cancelSeenRef,
|
|
607
|
+
commitSeenRef,
|
|
608
|
+
deferredCloseRef,
|
|
609
|
+
lastRevisionRef,
|
|
610
|
+
lastEditorRef,
|
|
611
|
+
setStaged,
|
|
612
|
+
beginFlush,
|
|
613
|
+
deferredDecision
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// src/client/card/snapshot.ts
|
|
618
|
+
var import_react5 = require("react");
|
|
619
|
+
function useScopeSnapshot(scope) {
|
|
620
|
+
var subscribe = (0, import_react5.useMemo)(
|
|
621
|
+
function() {
|
|
622
|
+
return function(listener) {
|
|
623
|
+
return scope.subscribe(listener);
|
|
624
|
+
};
|
|
625
|
+
},
|
|
626
|
+
[scope]
|
|
627
|
+
);
|
|
628
|
+
return (0, import_react5.useSyncExternalStore)(
|
|
629
|
+
subscribe,
|
|
630
|
+
function() {
|
|
631
|
+
return scope.getSnapshot();
|
|
632
|
+
},
|
|
633
|
+
function() {
|
|
634
|
+
return scope.getSnapshot();
|
|
635
|
+
}
|
|
636
|
+
);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// src/client/card/view.ts
|
|
640
|
+
function resolveCardView(props, snapshot, staged, stagedNow) {
|
|
641
|
+
var visible = showToggle(props);
|
|
642
|
+
var dot = showDot(props, snapshot);
|
|
643
|
+
var route = visible ? props.provider.provider || "" : "";
|
|
644
|
+
var ready = !!snapshot && snapshot.status === "ready";
|
|
645
|
+
var active = visible && ready && isNoKeyActive(snapshot, route);
|
|
646
|
+
var writable = ready && snapshot.writable === true;
|
|
647
|
+
return {
|
|
648
|
+
visible,
|
|
649
|
+
dot,
|
|
650
|
+
route,
|
|
651
|
+
ready,
|
|
652
|
+
active,
|
|
653
|
+
writable,
|
|
654
|
+
conflict: visible && ready && hasForeignAuthorization(snapshot, route),
|
|
655
|
+
stage: stageOf(staged, active),
|
|
656
|
+
liveStage: stageOf(stagedNow, active)
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// src/client/card/toggle-card.ts
|
|
661
|
+
function NoApiKeyToggleCard(props) {
|
|
662
|
+
var scope = props.scope;
|
|
663
|
+
var state = useCardState(scope);
|
|
664
|
+
var snapshot = useScopeSnapshot(scope);
|
|
665
|
+
var view = resolveCardView(props, snapshot, state.staged, state.stagedRef.current);
|
|
666
|
+
state.liveRef.current = {
|
|
667
|
+
visible: view.visible,
|
|
668
|
+
dot: view.dot,
|
|
669
|
+
active: view.active,
|
|
670
|
+
route: view.route,
|
|
671
|
+
scope,
|
|
672
|
+
staged: view.liveStage.dirty ? state.stagedRef.current : null
|
|
673
|
+
};
|
|
674
|
+
usePlacement(state, view.visible, view.active, view.dot);
|
|
675
|
+
useClickSignals(state);
|
|
676
|
+
useRevisionWatch(state, scope);
|
|
677
|
+
function onToggle(checked) {
|
|
678
|
+
if (view.conflict) return;
|
|
679
|
+
if (checked === view.stage.draftActive) return;
|
|
680
|
+
state.cancelSeenRef.current = false;
|
|
681
|
+
state.commitSeenRef.current = false;
|
|
682
|
+
state.setStaged(stagedOps(checked, view.active, view.route));
|
|
683
|
+
}
|
|
684
|
+
(0, import_react6.useEffect)(
|
|
685
|
+
function() {
|
|
686
|
+
if (state.staged !== null && !view.stage.dirty) state.setStaged(null);
|
|
687
|
+
},
|
|
688
|
+
[state.staged, view.stage.dirty]
|
|
689
|
+
);
|
|
690
|
+
return (0, import_jsx_runtime2.jsx)("div", {
|
|
691
|
+
ref: state.anchorRef,
|
|
692
|
+
className: "ccp_anchor",
|
|
693
|
+
"aria-hidden": "true",
|
|
694
|
+
children: [
|
|
695
|
+
// Both hosts render HERE, inside the anchor, always: showing one
|
|
696
|
+
// is the DOM move of the same node (park) — hiding one moves it
|
|
697
|
+
// back (retire) — never a React unmount, or React would delete a
|
|
698
|
+
// node it is not standing on.
|
|
699
|
+
(0, import_jsx_runtime2.jsx)("div", {
|
|
700
|
+
ref: state.hostRef,
|
|
701
|
+
className: "ccp_editorHost",
|
|
702
|
+
children: view.visible ? (0, import_jsx_runtime2.jsx)(ToggleView, { active: view.stage.draftActive, staged: view.stage.dirty, writable: view.writable, conflict: view.conflict, failure: state.failure, onToggle }) : null
|
|
703
|
+
}),
|
|
704
|
+
(0, import_jsx_runtime2.jsx)("span", {
|
|
705
|
+
ref: state.dotRef,
|
|
706
|
+
className: "ccp_dot",
|
|
707
|
+
role: "img",
|
|
708
|
+
"aria-label": COPY.dotAuthorizationConfigured,
|
|
709
|
+
title: COPY.dotAuthorizationConfigured
|
|
710
|
+
})
|
|
711
|
+
]
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// src/client/styles.ts
|
|
716
|
+
var CSS = ".ccp_editorHost{display:flex;flex-direction:column;gap:2px}.ccp_dot{display:inline-block;flex:none;width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-state-success-primary)}.ccp_anchor{display:none}.ccp_line{align-items:center;gap:8px;display:flex}.ccp_value{color:var(--dsw-alias-label-secondary);border:0;background:0 0;padding:0;font-size:12px}.ccp_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.ccp_warning{color:var(--dsw-alias-label-error);margin:0;font-size:12px}";
|
|
717
|
+
var CSS_TAG = "@comecaramelos/dsh-custom-provider/NoApiKeyToggle.module.css";
|
|
718
|
+
var cssInstalled = false;
|
|
719
|
+
function ensureCss(doc) {
|
|
720
|
+
if (cssInstalled) return;
|
|
721
|
+
if (doc.querySelector('style[data-plugin-css="' + CSS_TAG + '"]') !== null) {
|
|
722
|
+
cssInstalled = true;
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
var tag = doc.createElement("style");
|
|
726
|
+
tag.dataset.plugin = "@comecaramelos/dsh-custom-provider";
|
|
727
|
+
tag.dataset.pluginCss = CSS_TAG;
|
|
728
|
+
tag.textContent = CSS;
|
|
729
|
+
doc.head.appendChild(tag);
|
|
730
|
+
cssInstalled = true;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// src/client/apply.ts
|
|
734
|
+
function noop3() {
|
|
735
|
+
}
|
|
736
|
+
function apply(ctx) {
|
|
737
|
+
if (!ctx.settingsScope || !ctx.slots || typeof ctx.slots.inject !== "function") return noop3;
|
|
738
|
+
if (typeof document !== "undefined") ensureCss(document);
|
|
739
|
+
return ctx.effect(function() {
|
|
740
|
+
var scope;
|
|
741
|
+
try {
|
|
742
|
+
scope = ctx.settingsScope.bind({ namespace: SETTINGS_NS });
|
|
743
|
+
} catch (error) {
|
|
744
|
+
return noop3;
|
|
745
|
+
}
|
|
746
|
+
return ctx.slots.inject("settings.models.provider-card", function() {
|
|
747
|
+
return ctx.slots.register(
|
|
748
|
+
{
|
|
749
|
+
name: "settings.models.provider-card",
|
|
750
|
+
// Every card of this adapter family dispatches with
|
|
751
|
+
// entryKey = settingsNs; hand-declared routes live
|
|
752
|
+
// in this namespace, which is the family claimed.
|
|
753
|
+
key: SETTINGS_NS,
|
|
754
|
+
inject: function() {
|
|
755
|
+
return { scope };
|
|
756
|
+
}
|
|
757
|
+
},
|
|
758
|
+
NoApiKeyToggleCard
|
|
759
|
+
);
|
|
760
|
+
});
|
|
761
|
+
}, "custom-provider: models card");
|
|
762
|
+
}
|
|
763
|
+
return module.exports;
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/client/index.ts", "../src/client/card/toggle-card.ts", "../src/client/copy.ts", "../src/client/plugin-meta.ts", "../src/client/profile.ts", "../src/client/toggle-view.ts", "../src/client/card/click-signals.ts", "../src/client/dom.ts", "../src/client/card/placement.ts", "../src/client/card/revision.ts", "../src/client/card/state.ts", "../src/client/card/flush.ts", "../src/client/card/snapshot.ts", "../src/client/card/view.ts", "../src/client/styles.ts", "../src/client/apply.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * @comecaramelos/dsh-custom-provider \u2014 browser half, public surface.\n *\n * The one module the bundler walks, so the emitted `client.js` exports exactly\n * what the loader and the tests consume: `apply` (the mount), the component\n * halves (`NoApiKeyToggleCard`, `ToggleView`), the pure read/write surface\n * they share (`profileHeaders` \u2026 `showToggle`), the DOM placement helpers, and\n * the identifiers this half registers under (`inject`, `SETTINGS_NS`,\n * `NO_KEY_HEADER`, `NO_KEY_VALUE`).\n *\n * Re-export only: nothing here decides anything. The pure surface is on this\n * face only so the tests can drive it; the loader ignores it.\n */\nexport { apply } from \"./apply.js\";\nexport { NoApiKeyToggleCard } from \"./card/index.js\";\nexport { ToggleView } from \"./toggle-view.js\";\nexport {\n clearOps,\n configureOps,\n hasForeignAuthorization,\n headerConfigured,\n isNoKeyActive,\n noKeyPath,\n profileHeaders,\n resolvedProfile,\n showDot,\n showToggle,\n stageOf,\n stagedDirection,\n stagedOps\n} from \"./profile.js\";\nexport {\n findActionsWithin,\n findButtonWithin,\n findCancelWithin,\n findCommitWithin,\n findEditorWithin,\n findKeyFieldWithin,\n findRowIdentityWithin,\n hasClassEnding,\n hasCredentialDotWithin,\n positionDot,\n positionHost,\n PRIMARY_BUTTON_CLASS_END,\n SECONDARY_BUTTON_CLASS_END\n} from \"./dom.js\";\nexport { inject, NO_KEY_HEADER, NO_KEY_VALUE, SETTINGS_NS } from \"./plugin-meta.js\";\n", "/**\n * Browser half \u2014 `card/`: the seat component, composed.\n *\n * One `settings.models.provider-card` seat occurrence per saved card. It\n * renders inside a hidden anchor \u2014 which marks \"which card this is\" \u2014 and TWO\n * hosts rendered INSIDE that anchor, always rendered, never conditionally:\n * the toggle view (`div.ccp_editorHost`), DOM-moved (parked) into the open\n * `*_editor` right after the API-key field while the gate stands, and the\n * row status dot (`span.ccp_dot`, DOM-moved into the row-head identity\n * block, the very spot where the page parks its own credential dot \u2014 ours\n * only when that page dot is absent).\n *\n * Why always rendered: React deletes DOM nodes when a tree flips them off.\n * For a node that React itself tracks inside the anchor but the observer has\n * DOM-moved OUT to the editor/identity, that deletion calls\n * `hostParent.removeChild(moved)` against the fiber's parent \u2014 the anchor \u2014\n * and throws `NotFoundError: The node is not a child of this node`. The\n * error lands on the slot's error boundary, the card dies (an un-clickable\n * toggle, gone on reopen) \u2014 hence: nothing this component renders is ever\n * unmounted mid-mount; showing/hiding a host is a DOM move in or out of the\n * anchor (park/retire), never a React unmount. The anchor itself only goes\n * away with the component, and the placement hook below first detaches both\n * hosts, so React never deletes a moved node.\n *\n * Everything the original monolith did lives behind this composition, one\n * concern per module \u2014 the scope store (`snapshot.ts`), the view's gates and\n * facts (`view.ts`), the shared staging/flush state (`state.ts`, with its\n * one landing attempt in `flush.ts`), and the three DOM-facing signal hooks\n * (`placement.ts`, `click-signals.ts`, `revision.ts`). The toggle NEVER\n * writes on a click: the choice stages locally, the way the page's own\n * editor fields stage their draft, and lands through the scope's fenced\n * mutation queue when the page's own Save/Apply runs. The dot never writes,\n * in any rhythm.\n */\nimport { useEffect } from \"react\";\nimport { jsx } from \"react/jsx-runtime\";\nimport { COPY } from \"../copy.js\";\nimport { stagedOps } from \"../profile.js\";\nimport { ToggleView } from \"../toggle-view.js\";\nimport type { NoApiKeyToggleCardProps } from \"../types.js\";\nimport { useClickSignals } from \"./click-signals.js\";\nimport { usePlacement } from \"./placement.js\";\nimport { useRevisionWatch } from \"./revision.js\";\nimport { useCardState } from \"./state.js\";\nimport { useScopeSnapshot } from \"./snapshot.js\";\nimport { resolveCardView } from \"./view.js\";\n\nexport function NoApiKeyToggleCard(props: NoApiKeyToggleCardProps): any {\n var scope = props.scope;\n var state = useCardState(scope);\n var snapshot = useScopeSnapshot(scope);\n\n var view = resolveCardView(props, snapshot, state.staged, state.stagedRef.current);\n\n // Refresh the live view the DOM-dispatched signals read: they run off the\n // page, not off this render, and must never act on what an earlier render\n // left standing. A spent stage is not staged: the live view holds the\n // stage only while it still says something.\n state.liveRef.current = {\n visible: view.visible,\n dot: view.dot,\n active: view.active,\n route: view.route,\n scope: scope,\n staged: view.liveStage.dirty ? state.stagedRef.current : null\n };\n\n // Park/retire both hosts across churn (+ the close-with-stage verdict)\u2026\n usePlacement(state, view.visible, view.active, view.dot);\n // \u2026the commit/cancel click verdicts\u2026\n useClickSignals(state);\n // \u2026and the revision bump that means the page's own save just ran.\n useRevisionWatch(state, scope);\n\n function onToggle(checked: boolean): void {\n if (view.conflict) return;\n if (checked === view.stage.draftActive) return;\n // Staged, never written: the editor persists every other field the\n // same way, only when its Save/Apply runs. A new draft starts with\n // no pending click verdicts.\n state.cancelSeenRef.current = false;\n state.commitSeenRef.current = false;\n state.setStaged(stagedOps(checked, view.active, view.route));\n }\n\n // Once the STORED value matches the staged direction, the stage is spent:\n // clear the state, so an old stage can never re-land a stale choice.\n useEffect(\n function (): void {\n if (state.staged !== null && !view.stage.dirty) state.setStaged(null);\n },\n [state.staged, view.stage.dirty]\n );\n\n return jsx(\"div\", {\n ref: state.anchorRef,\n className: \"ccp_anchor\",\n \"aria-hidden\": \"true\",\n children: [\n // Both hosts render HERE, inside the anchor, always: showing one\n // is the DOM move of the same node (park) \u2014 hiding one moves it\n // back (retire) \u2014 never a React unmount, or React would delete a\n // node it is not standing on.\n jsx(\"div\", {\n ref: state.hostRef,\n className: \"ccp_editorHost\",\n children: view.visible\n ? jsx(ToggleView, { active: view.stage.draftActive, staged: view.stage.dirty, writable: view.writable, conflict: view.conflict, failure: state.failure, onToggle: onToggle })\n : null\n }),\n jsx(\"span\", {\n ref: state.dotRef,\n className: \"ccp_dot\",\n role: \"img\",\n \"aria-label\": COPY.dotAuthorizationConfigured,\n title: COPY.dotAuthorizationConfigured\n })\n ]\n });\n}\n", "/**\n * Browser half \u2014 the view's copy.\n *\n * The strings the toggle renders. English is the source of truth (this half\n * registers no locale service); the warning texts carry the two facts the\n * user must not mistake for the other: the reason a foreign header disables\n * the control, and what a rejected write means for the profile.\n */\nexport const COPY: Record<string, string> = {\n label: \"No API key required\",\n configured: \"No-API-key request header configured\",\n hint: 'Disables API key input and sets up the profile so keyless endpoints pass key check.',\n staged: \"Staged with this card \u2014 stored when the card itself is saved.\",\n conflict: 'A custom Authorization header is already set on this provider. Clear it in the profile settings to use this toggle.',\n readOnly: \"Settings are read-only in this deployment.\",\n failed: \"The settings write was rejected; the profile was left unchanged.\",\n dotAuthorizationConfigured: \"Authorization header configured\"\n};\n", "/**\n * Browser half \u2014 the identifiers this bundle registers under.\n *\n * These are the contract shared with the page and with the Host: the\n * namespace this card claims is the namespace the hand-declared routes live\n * in, and the two constants it writes are exactly what the `pi-ai`\n * openai-completions key check accepts in place of a key. Declared once here\n * and imported by every other module of this half.\n */\n\n/** The `pi-ai` adapter's settings namespace \u2014 the family this card claims. */\nexport const SETTINGS_NS = \"llm-pi-ai\";\n\n/** Header pi-ai accepts in place of a key. */\nexport const NO_KEY_HEADER = \"Authorization\";\n\n/** The placeholder value written when the toggle stands on. */\nexport const NO_KEY_VALUE = \"Bearer none\";\n\n/** Browser services consumed by this half (`slots` is wrapped in by the web runner). */\nexport const inject: string[] = [\"settingsScope\", \"slots\"];\n", "/**\n * Browser half \u2014 the pure read/write surface.\n *\n * Every fact the card claims about a route's profile resolves here, against\n * the namespace scope snapshot, and every mutation this plugin issues is\n * described here as an op. Nothing in this module touches the DOM, React or\n * the shell services; it is the module the tests drive directly.\n *\n * Two layers, deliberately read apart:\n *\n * - the **user** layer backs the toggle (`profileHeaders`): presence there is\n * what marks the field configured *by this card*, and it is what this card\n * writes back;\n * - the resolved **value** layer backs the row status dot (`resolvedProfile`):\n * what matters for the dot is what actually rides the wire, so a header\n * folded in from the base layer counts.\n *\n * The writes address the single header key rather than the whole `headers`\n * map \u2014 both directions \u2014 so a profile whose owner maintains other headers\n * by hand keeps them.\n */\nimport { NO_KEY_HEADER, NO_KEY_VALUE } from \"./plugin-meta.js\";\nimport type {\n ProfileHeaderMap,\n ProviderOwner,\n ResolvedProfile,\n ScopeSnapshot,\n SettingsPathOp\n} from \"./types.js\";\n\n/**\n * The hand-written request headers of one route's user-layer profile.\n * Presence in the user layer is what marks the header configured; the\n * resolved `value` would ride the adapter's base profiles and could\n * show a header the user never stored.\n * @param snapshot - the namespace scope snapshot.\n * @param route - the provider route id.\n * @returns the header map, or undefined when the route names none.\n */\nexport function profileHeaders(snapshot: ScopeSnapshot | undefined, route: string): ProfileHeaderMap | undefined {\n var user = snapshot && snapshot.user;\n var profile = user && user.providers && user.providers[route];\n var headers = profile && profile.headers;\n if (!headers || typeof headers !== \"object\" || Array.isArray(headers)) return undefined;\n return headers as ProfileHeaderMap;\n}\n\n/**\n * Whether the no-key placeholder header stands on this route. Only the\n * exact value counts; an `Authorization` the user typed themselves is\n * not this toggle's state.\n */\nexport function isNoKeyActive(snapshot: ScopeSnapshot | undefined, route: string): boolean {\n var headers = profileHeaders(snapshot, route);\n return !!headers && headers[NO_KEY_HEADER] === NO_KEY_VALUE;\n}\n\n/**\n * Whether the route carries an `Authorization` header with some other\n * value. That header already wins the `authorization` check and is the\n * user's own configuration \u2014 this toggle neither claims nor overwrites\n * it, so the view must stay off and disabled with the reason shown.\n * The value itself is never read out (it can be a real key).\n */\nexport function hasForeignAuthorization(snapshot: ScopeSnapshot | undefined, route: string): boolean {\n var headers = profileHeaders(snapshot, route);\n return !!headers && Object.prototype.hasOwnProperty.call(headers, NO_KEY_HEADER) && headers[NO_KEY_HEADER] !== NO_KEY_VALUE;\n}\n\n/**\n * The profile of one route in the RESOLVED (`value`) layer: the\n * document that actually rides the wire \u2014 user writes folded in,\n * composed over the base layer. The toggle reads the `user` layer for\n * its own state; the row dot reads this layer, because what matters\n * is what the adapter SENDS (a header inherited from `base` counts).\n * @param snapshot - the namespace scope snapshot.\n * @param route - the provider route id.\n * @returns the profile, or `undefined` when the route names none.\n */\nexport function resolvedProfile(snapshot: ScopeSnapshot | undefined, route: string): ResolvedProfile | undefined {\n var value = snapshot && snapshot.value;\n if (!value || typeof value !== \"object\") return undefined;\n var providers = (value as { providers?: unknown }).providers;\n if (!providers || typeof providers !== \"object\") return undefined;\n var profile = (providers as Record<string, unknown>)[route];\n return profile && typeof profile === \"object\" ? (profile as ResolvedProfile) : undefined;\n}\n\n/**\n * Whether a resolved profile carries a NON-EMPTY `Authorization`\n * header, spelled in any casing. This is exactly what pi-ai's key\n * check accepts on the wire (`getClientApiKey` in\n * `openai-completions.js`), so it is the single fact the row dot\n * reports. The value itself is never read out \u2014 it can be a real\n * credential.\n */\nexport function headerConfigured(profile: ResolvedProfile | undefined): boolean {\n var headers = profile && profile.headers;\n if (!headers || typeof headers !== \"object\" || Array.isArray(headers)) return false;\n var names = Object.keys(headers as Record<string, unknown>);\n for (var i = 0; i < names.length; i++) {\n if (names[i].toLowerCase() === \"authorization\") {\n var value = (headers as Record<string, unknown>)[names[i]];\n return typeof value === \"string\" && value.trim().length > 0;\n }\n }\n return false;\n}\n\n/**\n * Whether the row earns the plugin's own dot. The gate is narrower\n * than the toggle's and shallower than it looks: a hand-declared\n * route (never decorate shipped adapters) whose RESOLVED profile\n * authenticates by header. `keyConfigured` decides nothing \u2014 the\n * referenced-key fact and the own-header fact are distinct, and a\n * key-configured row still lights it only when the page shows no dot\n * of its own (the DOM check in `positionDot` never parks two). Pure\n * observation: nothing here writes.\n */\nexport function showDot(owner: ProviderOwner | undefined, snapshot: ScopeSnapshot | undefined): boolean {\n var provider = owner && owner.provider;\n if (!(provider && provider.declared === true && typeof provider.provider === \"string\" && provider.provider.length > 0)) {\n return false;\n }\n if (!(snapshot && snapshot.status === \"ready\")) return false;\n return headerConfigured(resolvedProfile(snapshot, provider.provider));\n}\n\n/** One whole-map `unset` would erase headers the user keeps by hand, so writes address the single key. */\nexport function noKeyPath(route: string): string[] {\n return [\"providers\", route, \"headers\", NO_KEY_HEADER];\n}\n\n/** Ops that turn the route keyless: a per-key set creates the headers map as needed. */\nexport function configureOps(route: string): SettingsPathOp[] {\n return [{ op: \"set\", path: noKeyPath(route), value: NO_KEY_VALUE }];\n}\n\n/** Ops that restore the stock flow: clears this header only, keeping any other. */\nexport function clearOps(route: string): SettingsPathOp[] {\n return [{ op: \"unset\", path: noKeyPath(route) }];\n}\n\n/** Which way a staged op leans: `set` stands ON, `unset` stands OFF. */\nexport function stagedDirection(ops: SettingsPathOp[] | null): boolean {\n return !!ops && ops[0] !== undefined && ops[0].op === \"set\";\n}\n\n/**\n * What a click STAGES (the card never writes on a click): the editor keeps\n * every other field as a draft and persists it only through its Save/Apply,\n * so the toggle's choice waits for the same moment. A click that agrees\n * with the stored value stages nothing.\n */\nexport function stagedOps(checked: boolean, storedActive: boolean, route: string): SettingsPathOp[] | null {\n if (checked === storedActive) return null;\n return checked ? configureOps(route) : clearOps(route);\n}\n\n/**\n * What a staged choice SHOWS while nothing has landed: a dirty stage takes\n * the value over, a spent one falls back to the stored value. The stored\n * value alone never lies.\n */\nexport function stageOf(ops: SettingsPathOp[] | null, storedActive: boolean): { draftActive: boolean; dirty: boolean } {\n if (ops === null) return { draftActive: storedActive, dirty: false };\n var on = stagedDirection(ops);\n var dirty = on !== storedActive;\n return { draftActive: dirty ? on : storedActive, dirty };\n}\n\n/**\n * Whether the seat's owner props call for the toggle: a hand-declared\n * route (the shipped adapters own their credential flow), with a\n * profile that resolves, and no confirmed credential \u2014 a row that can\n * already authenticate should keep that path, not be forced through\n * headers.\n */\nexport function showToggle(owner: ProviderOwner | undefined): boolean {\n var provider = owner && owner.provider;\n return !!(provider && provider.declared === true && owner!.configured === true && owner!.keyConfigured === false);\n}\n", "/**\n * Browser half \u2014 the toggle view.\n *\n * The DOM body of the editor block: the control and, while configured, a\n * read-only view of the header it writes. Stateless on purpose \u2014 the card\n * component owns the snapshot, the failure draft and the write calls, this\n * half only renders.\n *\n * The control is the shell's `Switch` primitive when the surface resolves\n * one; a plain checkbox stands in when it does not. The primitive is not a\n * module this bundle declares \u2014 the runner may or may not have seeded it \u2014\n * so its id is required through a guard: a surface without it is a normal\n * page state, never an error.\n */\nimport { Fragment, jsx, jsxs } from \"react/jsx-runtime\";\nimport { COPY } from \"./copy.js\";\nimport { NO_KEY_HEADER, NO_KEY_VALUE } from \"./plugin-meta.js\";\nimport type { ToggleViewProps } from \"./types.js\";\n\n/** Shell toggle primitive when the surface resolves it; `null` when it does not. */\nvar SwitchResolved: any = null;\nvar switchResolved = false;\n\n/**\n * Resolve the shell primitive once. Guarded so a surface without the\n * primitives module simply yields no Switch (the checkbox fallback), never a\n * factory-time failure.\n */\nfunction resolveSwitch(): any {\n if (!switchResolved) {\n switchResolved = true;\n try {\n var primitives = require(\"@deepseek-ai/dsh-client-ui-primitives\");\n SwitchResolved = (primitives && primitives.Switch) || null;\n } catch (error) {\n SwitchResolved = null;\n }\n }\n return SwitchResolved;\n}\n\n/**\n * The toggle's DOM (the body half), rendered inside the editor host parked\n * by the card component.\n */\nexport function ToggleView(props: ToggleViewProps): any {\n var Switch = resolveSwitch();\n var active = props.active === true;\n var conflict = props.conflict === true;\n var disabled = props.writable !== true || conflict;\n var control = Switch ? (\n jsx(Switch, {\n checked: active,\n disabled: disabled,\n label: COPY.label,\n onChange: function (checked: boolean) {\n props.onToggle(checked === true);\n }\n })\n ) : (\n jsxs(\"label\", {\n children: [\n jsx(\"input\", {\n type: \"checkbox\",\n checked: active,\n disabled: disabled,\n \"aria-label\": COPY.label,\n onChange: function (event: any) {\n props.onToggle(!!(event && event.target && event.target.checked));\n }\n }),\n jsx(\"span\", { children: COPY.label })\n ]\n })\n );\n var failure = props.failure || null;\n return jsxs(Fragment, {\n children: [\n jsxs(\"div\", {\n className: \"ccp_line\",\n children: [\n control,\n active ? (\n jsx(\"input\", {\n className: \"ccp_value\",\n value: NO_KEY_HEADER + \": \" + NO_KEY_VALUE,\n disabled: true,\n readOnly: true,\n tabIndex: -1,\n \"aria-label\": COPY.configured\n })\n ) : null\n ]\n }),\n props.writable ? null : jsx(\"p\", { className: \"ccp_warning\", children: COPY.readOnly }),\n failure\n ? jsx(\"p\", { className: \"ccp_warning\", children: failure })\n : conflict\n ? jsx(\"p\", { className: \"ccp_warning\", children: COPY.conflict })\n : props.staged === true\n ? jsx(\"p\", { className: \"ccp_hint\", children: COPY.staged })\n : jsx(\"p\", { className: \"ccp_hint\", children: COPY.hint })\n ]\n });\n}\n", "/**\n * Browser half \u2014 `card/`: the window click listeners that judge each click.\n *\n * The editor persists every field through its own Save/Apply \u2014 this card's\n * click only STAGED the choice \u2014 so the page's commit control is what lands\n * it. Two listeners, two phases, because a real MOUSE click is a DISCRETE\n * event: React 19 drains its whole effect (the async `apply()`'s microtasks\n * included \u2014 and with no page-field edits it awaits nothing that matters)\n * synchronously inside the root container's handler, and the editor is\n * already unmounted by the time the event bubbles to `window`. A bubble-only\n * listener that demands a live editor therefore never sees the page's commit\n * control in the very case that matters.\n *\n * - CAPTURE (window, before React's root handler \u2014 the DOM is still live):\n * marks Cancel clicks on THIS card's row so the close it triggers is read\n * as a DROP, never as a save.\n * - BUBBLE (window, after React's queued `writeSettings`, so a staged write\n * lands behind theirs and their still-stale `expectedRevision` fence never\n * conflicts): lands the stage on the commit control \u2014 recognizing it either\n * in a live editor or in the detached tree this card's host just stood in\n * (`lastEditorRef`).\n */\nimport { useEffect } from \"react\";\nimport { findCancelWithin, findCommitWithin, findEditorWithin, hasClassEnding, PRIMARY_BUTTON_CLASS_END, SECONDARY_BUTTON_CLASS_END } from \"../dom.js\";\nimport type { CardState } from \"./state.js\";\n\n/** Attach the capture verdict marker and the bubble commit lander to `window`. */\nexport function useClickSignals(state: CardState): void {\n useEffect(\n function (): () => void {\n if (typeof window === \"undefined\" || typeof window.addEventListener !== \"function\") return function (): void {};\n\n function chainHits(node: any, ancestor: any): boolean {\n while (node) {\n if (node === ancestor) return true;\n node = node.parentElement;\n }\n return false;\n }\n function buttonInChain(node: any, stopAt?: any): string | null {\n var sawSecondary = false;\n while (node && node !== stopAt) {\n if (hasClassEnding(node, SECONDARY_BUTTON_CLASS_END)) sawSecondary = true;\n else if (hasClassEnding(node, PRIMARY_BUTTON_CLASS_END)) {\n return sawSecondary ? \"cancel\" : \"commit\";\n }\n node = node.parentElement;\n }\n return sawSecondary ? \"cancel\" : null;\n }\n\n function onWindowCapture(event: any): void {\n var target = event && event.target;\n if (!target || typeof target.closest !== \"function\") return;\n var anchor = state.anchorRef.current;\n if (!anchor || !anchor.isConnected || typeof anchor.closest !== \"function\") return;\n var row = anchor.closest(\"li\");\n if (!row || target.closest(\"li\") !== row) return;\n var button = buttonInChain(target, row);\n if (button === \"cancel\") {\n state.cancelSeenRef.current = true;\n state.commitSeenRef.current = false;\n } else if (button === \"commit\") {\n state.commitSeenRef.current = true;\n state.cancelSeenRef.current = false;\n }\n }\n\n function onWindowClick(event: any): void {\n var target = event && event.target;\n var anchor = state.anchorRef.current;\n if (!target || !anchor || !anchor.isConnected) return;\n var card = typeof anchor.closest === \"function\" ? anchor.closest(\"li\") : null;\n var live = state.liveRef.current;\n var editor = findEditorWithin(card);\n var last = state.lastEditorRef.current;\n if (!editor) editor = last;\n // The click must stand inside THIS card's editor (live, or the\n // tree React just detached in this same dispatch) \u2014 never in\n // any other card's footer.\n if (!editor || !chainHits(target, editor)) return;\n var commit = findCommitWithin(editor);\n var cancel = findCancelWithin(editor);\n var commitHit = false;\n var cancelHit = false;\n var node = target;\n while (node && node !== editor) {\n if (commit && node === commit) { commitHit = true; break; }\n if (cancel && node === cancel) { cancelHit = true; break; }\n node = node.parentElement;\n }\n if (!commitHit && !cancelHit) {\n var button = buttonInChain(target, editor);\n commitHit = button === \"commit\";\n cancelHit = button === \"cancel\";\n }\n if (!commitHit && !cancelHit) return;\n if (cancelHit) {\n state.cancelSeenRef.current = true;\n if (live.staged !== null) state.setStaged(null);\n return;\n }\n if (live.staged === null) return;\n state.beginFlush(live);\n }\n window.addEventListener(\"click\", onWindowCapture, true);\n window.addEventListener(\"click\", onWindowClick);\n return function () {\n window.removeEventListener(\"click\", onWindowCapture, true);\n window.removeEventListener(\"click\", onWindowClick);\n };\n },\n []\n );\n}\n", "/**\n * DOM-moves, never deletions. Both hosts this component renders (the toggle\n * view and the row status dot) live inside DOM the page owns and freely\n * re-mounts; each of the two functions below moves one host either to its\n * page position (park) or back inside the component's anchor (retire) \u2014\n * never a detach, because the host must keep standing somewhere React\n * tracks it. (A detached host could still be DELETED by React while React\n * believes it lives in the anchor, and removing a DOM-moved node throws\n * NotFoundError \u2014 the crash that used to kill the card.) Page-local CSS is\n * only ever matched by the stable un-hashed SUFFIX of each class\n * (`*_editor`, `*_field`, `*_editorActions`, `rowIdentity`, `credentialDot`);\n * the hashed prefix churns every rebuild and is never referenced.\n *\n * Every move here is idempotent against the page's own re-mounts, so the\n * seat component's churn observer can replay them freely.\n */\n\n/** The page's commit control: the action row's primary (Save/Apply) button. */\nexport const PRIMARY_BUTTON_CLASS_END = \"primaryButton\";\n/** The page's cancel control: the action row's secondary button. A click on\n * it closes the card WITHOUT saving \u2014 the staged toggle must die with it. */\nexport const SECONDARY_BUTTON_CLASS_END = \"secondaryButton\";\n\n/** Page-local editor classes, matched by their un-hashed suffix. */\nexport const EDITOR_CLASS_END = \"_editor\";\nexport const EDITOR_ACTIONS_CLASS_END = \"_editorActions\";\n/** The key-input field: a `*_field` block that wraps the password box. */\nexport const EDITOR_FIELD_CLASS_END = \"_field\";\n/** Page-local row classes, matched by their un-hashed suffix. */\nexport const ROW_IDENTITY_CLASS_END = \"rowIdentity\";\n/**\n * The page's own credential indicator (its `credentialDotConfigured`\n * / `credentialDotMissing` states ride on this base class, which only\n * the dots themselves carry).\n */\nexport const CREDENTIAL_DOT_CLASS_END = \"credentialDot\";\n\n/**\n * Whether `element`'s class list carries a hashed page-local class\n * whose name ENDS with `suffix` \u2014 so matching `_editor` never matches\n * the `*_editorActions` children. Only the suffix\n * is stable across rebuilds; the hash prefix is ignored.\n */\nexport function hasClassEnding(element: any, suffix: string): boolean {\n var cls = (element && element.className) || \"\";\n if (typeof cls !== \"string\" || cls.indexOf(suffix) < 0) return false;\n var tokens = cls.split(/\\s+/);\n for (var i = 0; i < tokens.length; i++) {\n if (tokens[i].length > suffix.length && tokens[i].slice(-suffix.length) === suffix) return true;\n }\n return false;\n}\n\n/**\n * The mounted editor container inside `root`, located by class suffix\n * rather than by hashed name; `null` while no editor stands open.\n */\nexport function findEditorWithin(root: any): any {\n if (!root || typeof root.querySelectorAll !== \"function\") return null;\n var nodes = root.querySelectorAll(\"[class]\");\n for (var i = 0; i < nodes.length; i++) {\n if (hasClassEnding(nodes[i], EDITOR_CLASS_END)) return nodes[i];\n }\n return null;\n}\n\n/** The editor's own action row (`*_editorActions`) when mounted inside `editor`. */\nexport function findActionsWithin(editor: any): any {\n if (!editor || typeof editor.querySelectorAll !== \"function\") return null;\n var nodes = editor.querySelectorAll(\"[class]\");\n for (var i = 0; i < nodes.length; i++) {\n if (hasClassEnding(nodes[i], EDITOR_ACTIONS_CLASS_END)) return nodes[i];\n }\n return null;\n}\n\n/**\n * The first node inside `editor` whose class ENDS with `buttonClassEnd` \u2014\n * the footer's primary/cancel buttons live in the action row, but the whole\n * editor is searched so a footer restructure never hides the control. `null`\n * while the control is not mounted.\n */\nexport function findButtonWithin(editor: any, buttonClassEnd: string): any {\n if (!editor || typeof editor.querySelectorAll !== \"function\") return null;\n var scope = findActionsWithin(editor);\n var nodes = (scope || editor).querySelectorAll(\"[class]\");\n for (var i = 0; i < nodes.length; i++) {\n if (hasClassEnding(nodes[i], buttonClassEnd)) return nodes[i];\n }\n return null;\n}\n\n/**\n * The editor's commit (Save/Apply) button \u2014 the page's own control that\n * lands EVERY staged field of the card. A staged toggle write rides this\n * same moment, so it must never fire on any other click. `null` while no\n * editor stands.\n */\nexport function findCommitWithin(editor: any): any {\n return findButtonWithin(editor, PRIMARY_BUTTON_CLASS_END);\n}\n\n/**\n * The editor's CANCEL button (the action row's secondary button). Clicking\n * it closes the card WITHOUT saving \u2014 the page drops its own draft edits,\n * and the staged toggle is dropped the same way. `null` while no editor\n * stands (the footer always renders both buttons; this stays null-safe).\n */\nexport function findCancelWithin(editor: any): any {\n return findButtonWithin(editor, SECONDARY_BUTTON_CLASS_END);\n}\n\n/**\n * The editor's API-key field: a `*_field` block that wraps a password\n * input (the page's key input renders as `type: \"password\"`; route or\n * URL fields never do). `null` while the key block is not mounted.\n */\nexport function findKeyFieldWithin(editor: any): any {\n if (!editor || typeof editor.querySelectorAll !== \"function\") return null;\n var fields = editor.querySelectorAll(\"[class]\");\n for (var i = 0; i < fields.length; i++) {\n if (!hasClassEnding(fields[i], EDITOR_FIELD_CLASS_END)) continue;\n if (fields[i].querySelectorAll(\"input[type=\\\"password\\\"]\").length > 0) return fields[i];\n }\n return null;\n}\n\n/**\n * Retire `host` back INTO `anchor` \u2014 its own React parent. This is the\n * hiding half of every DOM move: the node keeps standing in the DOM and\n * in the place the fiber tree expects it, so a later React op (an\n * unmount cascade, a re-render) reaches it exactly where it stands.\n * Never `remove()` \u2014 a detached node is still React's child on paper,\n * and deleting one that was moved out throws NotFoundError.\n */\nfunction retireHost(host: any, anchor: any): any {\n if (anchor && host.parentElement !== anchor) anchor.appendChild(host);\n return anchor;\n}\n\n/**\n * Find the page's password input inside the editor and mark it\n * disabled \u2014 so the user cannot type while the no-key header is set.\n * Called from the MutationObserver so it survives React re-renders.\n * @param editor - the editor container.\n * @param active - whether the toggle is on (true = disable, false = re-enable).\n */\nexport function disablePasswordInput(editor: any, active: boolean | undefined): void {\n if (!editor || typeof editor.querySelectorAll !== \"function\") return;\n var inputs = editor.querySelectorAll(\"input[type=\\\"password\\\"]\");\n for (var i = 0; i < inputs.length; i++) {\n inputs[i].disabled = active === true;\n }\n}\n\n/**\n * Park `host` directly AFTER the editor's API-key field \u2014 the toggle\n * then reads as a continuation of the credential block. With the key\n * field absent (still mounting) it falls back to the action row, or to\n * the editor's end. When `park` is falsy, or no editor stands open, the\n * host is retired back into `anchor`. Idempotent against the page's\n * re-renders, so the churn observer can replay it.\n * @param host - this card's toggle host element.\n * @param card - the row's `li` subtree.\n * @param anchor - the component's anchor (the host's React parent).\n * @param park - whether the host stands in the editor (its gate is open).\n * @param active - whether the no-key header is set (disables the password input).\n * @returns the element the host stands in.\n */\nexport function positionHost(host: any, card: any, anchor: any, park?: boolean, active?: boolean): any {\n if (!park) return retireHost(host, anchor);\n var editor = findEditorWithin(card);\n if (!editor) return retireHost(host, anchor);\n var keyField = findKeyFieldWithin(editor);\n if (keyField && keyField.parentElement) {\n var parent = keyField.parentElement;\n // Already parked directly behind the key block? Then stand\n // still \u2014 comparing against the key field's OWN next sibling\n // would re-target the host onto itself.\n if (host.parentElement !== parent || keyField.nextSibling !== host) {\n parent.insertBefore(host, keyField.nextSibling || null);\n }\n disablePasswordInput(editor, active);\n return parent;\n }\n var actions = findActionsWithin(editor);\n if (actions) {\n if (host.parentElement !== editor || host.nextSibling !== actions) editor.insertBefore(host, actions);\n } else if (host.parentElement !== editor) {\n editor.appendChild(host);\n }\n disablePasswordInput(editor, active);\n return editor;\n}\n\n/**\n * The row-identity block (`*_rowIdentity`) inside `root` (the row's\n * `li`): the page's own head span that holds `rowName`, the `custom`\n * `rowTag` and, for referenced credentials, the credential dot.\n * `null` when the row head is not mounted.\n */\nexport function findRowIdentityWithin(root: any): any {\n if (!root || typeof root.querySelectorAll !== \"function\") return null;\n var nodes = root.querySelectorAll(\"[class]\");\n for (var i = 0; i < nodes.length; i++) {\n if (hasClassEnding(nodes[i], ROW_IDENTITY_CLASS_END)) return nodes[i];\n }\n return null;\n}\n\n/**\n * Whether the row head already draws the page's own credential dot.\n * The dot spans carry the base `credentialDot` class and a state\n * token (`\u2026Configured` green, `\u2026Missing` amber); matching the base\n * catches either. A row that already speaks through a referenced\n * credential has its own indicator \u2014 parking ours beside it would\n * double the signal, so any dot (green OR amber) suppresses ours.\n */\nexport function hasCredentialDotWithin(identity: any): boolean {\n if (!identity || typeof identity.querySelectorAll !== \"function\") return false;\n var nodes = identity.querySelectorAll(\"[class]\");\n for (var i = 0; i < nodes.length; i++) {\n if (hasClassEnding(nodes[i], CREDENTIAL_DOT_CLASS_END)) return true;\n }\n return false;\n}\n\n/**\n * Move `host` to the row-identity block as its last child \u2014 the very spot\n * where the page draws its own credential dot, right after the name and the\n * `custom` tag. When `show` is falsy, no identity stands mounted, or the\n * page's own dot stands, the host is retired back into `anchor` (also\n * caught here, so a churn replay retires ours the moment the page starts\n * showing its indicator). Idempotent against the page's re-maps.\n * @param host - this card's dot host element.\n * @param card - the row's `li` subtree.\n * @param anchor - the component's anchor (the host's React parent).\n * @param show - whether the wire fact stands.\n * @returns the element the host stands in.\n */\nexport function positionDot(host: any, card: any, anchor: any, show?: boolean): any {\n if (!show) return retireHost(host, anchor);\n var identity = findRowIdentityWithin(card);\n if (!identity || hasCredentialDotWithin(identity)) return retireHost(host, anchor);\n if (host.parentElement !== identity) identity.appendChild(host);\n return identity;\n}\n", "/**\n * Browser half \u2014 `card/`: parking both hosts across the page's own re-mounts.\n *\n * The anchor marks \"which card this is\"; both hosts stand inside it until\n * their gate parks them where the page shows them: the toggle host inside the\n * open `*_editor` right after the API-key field, the status dot inside the\n * row-head identity block. Every move is a DOM MOVE \u2014 never a React unmount\n * (deleting a node the fiber tracks inside the anchor throws NotFoundError\n * inside the commit and kills the card). The churn observer re-parks on every\n * subtree change, so the page re-mapping its row or editor is harmless: the\n * same moves are idempotent (`../dom.js`).\n *\n * The observer also watches for the editor closing WHILE a stage stands, and\n * the close's verdict is a cross-signal call: in a real (mouse) click the\n * close lands INSIDE the click's own discrete processing \u2014 before this\n * observer, before any bubble listener \u2014 so whatever the capture-phase\n * listeners left in `cancelSeenRef`/`commitSeenRef` decides:\n *\n * - Cancel clicked \u2192 DROPS the stage, exactly like the page drops its\n * own draft edits;\n * - Apply clicked \u2192 LANDS it: the page's own write is already queued\n * ahead (its apply awaits `writeSettings` before closing), so ours fences\n * cleanly behind it;\n * - no verdict seen \u2192 wait one step (the bubble of the very same click\n * may still be the verdict; a walk-away close DROPS the stage).\n */\nimport { useEffect } from \"react\";\nimport { findEditorWithin, positionDot, positionHost } from \"../dom.js\";\nimport type { CardState } from \"./state.js\";\n\nfunction noop(): void {}\n\n/**\n * Keep both hosts parked where their gate stands, re-parked on every churn,\n * and retire both out of the page DOM BEFORE React's teardown cascade can\n * reach them when the component unmounts.\n * @param state - the card's shared state (refs in, refs out \u2014 the moves read\n * the live view the component refreshes every render).\n * @param visible - the toggle's gate (re-park when it flips).\n * @param active - the stored no-key state (drives the password disable).\n * @param dot - the dot's gate (re-park when it flips).\n */\nexport function usePlacement(state: CardState, visible: boolean, active: boolean, dot: boolean): void {\n useEffect(\n function (): () => void {\n var anchor = state.anchorRef.current;\n if (!anchor || typeof MutationObserver !== \"function\" || typeof document === \"undefined\") return noop;\n var hostEl = state.hostRef.current;\n var dotEl = state.dotRef.current;\n function cardOf(): any {\n return anchor!.isConnected && typeof anchor!.closest === \"function\" ? anchor!.closest(\"li\") : null;\n }\n function position(): void {\n var card = cardOf();\n var live = state.liveRef.current;\n var editorNode = findEditorWithin(card);\n if (editorNode) state.lastEditorRef.current = editorNode;\n if (hostEl) positionHost(hostEl, card, anchor, live.visible, live.active);\n if (dotEl) positionDot(dotEl, card, anchor, live.dot);\n // The editor is gone while a stage still stands: whatever\n // the close was, the stage cannot sit and wait for a\n // Save/Apply that is already unmounted. The capture-phase\n // verdicts decide \u2014 Cancel drops, Apply lands, none waits\n // one step for the bubble (see the module note above).\n if (live.staged !== null && editorNode === null) {\n if (state.cancelSeenRef.current) {\n state.cancelSeenRef.current = false;\n state.commitSeenRef.current = false;\n state.setStaged(null);\n } else if (state.commitSeenRef.current) {\n if (!state.flushingRef.current) state.beginFlush(live);\n } else {\n state.deferredCloseRef.current = true;\n Promise.resolve().then(state.deferredDecision);\n }\n }\n }\n position();\n var observer = new MutationObserver(function () {\n position();\n });\n var card = cardOf();\n if (card) observer.observe(card, { childList: true, subtree: true });\n return function () {\n observer.disconnect();\n // Unmounting the component: pull the hosts OUT of the page\n // before the cascade can reach them (each host is DOM-moved\n // \u2014 the cascade would delete it from the anchor, its fiber\n // parent, not from where it stands).\n if (hostEl) hostEl.remove();\n if (dotEl) dotEl.remove();\n };\n },\n [visible, active, dot]\n );\n}\n", "/**\n * Browser half \u2014 `card/`: the namespace-revision watcher.\n *\n * While a stage stands, the moment the namespace revision moves is the moment\n * the page wrote its own draft through its Save/Apply \u2014 its write is already\n * queued ahead of any we land, so this card's staged op fences cleanly behind\n * it. A bump with no stage tells us nothing worth acting on; a bump the page\n * never got to announce (the first one after the stage stands) still lands.\n */\nimport { useEffect } from \"react\";\nimport type { CardState } from \"./state.js\";\nimport type { SettingsScope } from \"../types.js\";\n\nfunction noop(): void {}\n\n/**\n * Watch `scope` for the revision bump that means the page just saved, and\n * hand any standing stage to the flush.\n * @param state - the card's shared state.\n * @param scope - the namespace scope bound to this component.\n */\nexport function useRevisionWatch(state: CardState, scope: SettingsScope): void {\n useEffect(\n function (): () => void {\n if (!scope || typeof scope.subscribe !== \"function\") return noop;\n // Seed the last seen revision NOW: a bump is the page's write \u2014\n // the very first bump after the stage stands must already count\n // (a baseline-seed-less `last === undefined` would swallow it).\n var seed = scope.getSnapshot();\n state.lastRevisionRef.current = seed ? seed.revision : undefined;\n function onScopeChange(): void {\n var live = state.liveRef.current;\n var snap = live.scope ? live.scope.getSnapshot() : undefined;\n var revision = snap ? snap.revision : undefined;\n var last = state.lastRevisionRef.current;\n state.lastRevisionRef.current = revision;\n if (last === undefined || revision === undefined || revision === last) return;\n if (live.staged !== null && !state.flushingRef.current) state.beginFlush(live);\n }\n try {\n return scope.subscribe(onScopeChange);\n } catch {\n return noop;\n }\n },\n [scope]\n );\n}\n", "/**\n * Browser half \u2014 `card/`: the mutable state every effect shares.\n *\n * One component, several concurrent signals (churn observer, window listeners,\n * the scope subscription), and each may stage or land a choice. Every fact\n * they must NOT race on lives here as refs, created once by the component and\n * handed to each effect hook \u2014 an effect must never depend on one render's\n * closure of a value another signal already moved.\n *\n * The live view (`liveRef`) is what the DOM-dispatched signals read: React\n * events cannot reach the closure of an effect attached once, so whatever the\n * listeners need stands here, refreshed every render by the component. The\n * staged ops keep BOTH shapes on purpose: the state (`staged`) is what the\n * render draws its hint from, the reference (`stagedRef`) what every DOM\n * signal reads synchronously \u2014 React batches renders, and a churn or click\n * can run several times before the state settles (a Cancel's drop read one\n * render late would let a later churn re-land what Cancel killed).\n */\nimport { useRef, useState } from \"react\";\nimport { COPY } from \"../copy.js\";\nimport { stageOf } from \"../profile.js\";\nimport { landStaged } from \"./flush.js\";\nimport type { SettingsPathOp, SettingsScope } from \"../types.js\";\n\n/** The live view the DOM-dispatched signals read. Refreshed every render. */\nexport interface CardLiveView {\n visible: boolean;\n dot: boolean;\n active: boolean;\n route: string;\n scope: SettingsScope;\n staged: SettingsPathOp[] | null;\n}\n\n/** Everything the component's effect hooks need out of each other's hands. */\nexport interface CardState {\n /** The last write rejection's message (null while nothing failed). */\n failure: string | null;\n /** The staged draft as render state; `null` stands for nothing staged. */\n staged: SettingsPathOp[] | null;\n /** The staged ops as a synchronous reference \u2014 what DOM signals read. */\n stagedRef: { current: SettingsPathOp[] | null };\n liveRef: { current: CardLiveView };\n /** The hidden anchor div: \"which card this is\", the hosts' React parent. */\n anchorRef: { current: any };\n /** The toggle-view host (DOM-moved into the open editor, else parked here). */\n hostRef: { current: any };\n /** The row status-dot host (DOM-moved into the row identity, else parked here). */\n dotRef: { current: any };\n /** A flush in flight: the three landing signals never land the same op twice. */\n flushingRef: { current: boolean };\n /** A Cancel click was seen in this editor's session: closing now DROPS the stage. */\n cancelSeenRef: { current: boolean };\n /** A COMMIT click was seen in this editor's session: its close LANDS the stage. */\n commitSeenRef: { current: boolean };\n /** A close with no click verdict yet: the decision waits one step (the bubble phase). */\n deferredCloseRef: { current: boolean };\n /** The last namespace revision seen: a bump with a stage stands means the page saved. */\n lastRevisionRef: { current: number | undefined };\n /** The last live editor this card DOM-moved into: a discrete click's close detaches it. */\n lastEditorRef: { current: any };\n /** Change the stage NOW (ref + live view) and schedule the state render. */\n setStaged: (ops: SettingsPathOp[] | null) => void;\n /** Begin the ONE write the landing signals agreed on. */\n beginFlush: (live: CardLiveView) => void;\n /** One step after a no-verdict close: whatever the bubble read decides. */\n deferredDecision: () => void;\n}\n\n/**\n * Create the card's shared state: every ref, both draft states, and the two\n * cross-signal verbs (staging, flushing) the effects call through it.\n * @param scope - the namespace scope bound to this component.\n */\nexport function useCardState(scope: SettingsScope): CardState {\n var failurePair: [string | null, (value: string | null) => void] = useState<string | null>(null);\n var failure = failurePair[0];\n var setFailure = failurePair[1];\n // The toggle's DRAFT: a click stages the write locally, exactly like the\n // page's own field edits (which the editor keeps in its `draft` and\n // persists only through its Save/Apply). `null` stands for nothing\n // staged.\n var stagedPair: [SettingsPathOp[] | null, (value: SettingsPathOp[] | null) => void] = useState<SettingsPathOp[] | null>(null);\n var staged = stagedPair[0];\n var setStagedState = stagedPair[1];\n\n var stagedRef = useRef<SettingsPathOp[] | null>(null);\n var liveRef = useRef<CardLiveView>({ visible: false, dot: false, active: false, route: \"\", scope: scope, staged: null });\n /** The hidden anchor div: \"which card this is\", the hosts' React parent. */\n var anchorRef = useRef(null);\n /** The toggle-view host: DOM-moved into the open editor, else parked in the anchor. */\n var hostRef = useRef(null);\n /** The row status-dot host: DOM-moved into the row identity, else parked in the anchor. */\n var dotRef = useRef(null);\n /** A flush in flight: the three landing signals must never land the same staged op twice. */\n var flushingRef = useRef(false);\n /** A Cancel click was seen in this editor's session: closing now DROPS the stage (the\n * page drops its own draft edits the same way) \u2014 the opposite of closing by Apply\n * without a click seen (a restructured footer), which lands the stage. */\n var cancelSeenRef = useRef(false);\n /** A COMMIT (Save/Apply) click was seen in this editor's session, marked in the capture\n * phase. Its close LANDS the stage \u2014 any other close (Cancel, or simply walking away)\n * DROPS it exactly like the page drops its own draft edits. */\n var commitSeenRef = useRef(false);\n /** A close with no click verdict yet: the decision waits one step (the bubble phase of\n * the very same click may be the verdict; a close with no click at all \u2014 the user\n * walked away \u2014 must DROP the stage). */\n var deferredCloseRef = useRef(false);\n /** Last namespace revision seen \u2014 a bump while a stage stands means the page just wrote\n * ITS own draft through its Save/Apply. */\n var lastRevisionRef = useRef<number | undefined>(undefined);\n /** The last live editor this card's DOM moved into. A real (mouse) click is a DISCRETE\n * event: React 19 processes its whole effect \u2014 including the async `apply()`'s\n * microtasks and the unmount it causes \u2014 before the event ever bubbles to `window`, so\n * a click listener that insists on a live editor never sees the page's commit control.\n * This reference lets the bubble listener still recognize the buttons' chain (and the\n * buttons themselves) in the DOM tree it just detached \u2014 and lets the capture listener\n * catch Cancel BEFORE the close it triggers. */\n var lastEditorRef = useRef(null);\n\n // Change the stage NOW (ref + live view), schedule the state update the\n // render draws its hint from. Every stage change must ride this path \u2014\n // the state alone would let DOM signals act on one render's stale view.\n function setStaged(ops: SettingsPathOp[] | null): void {\n stagedRef.current = ops;\n var st = stageOf(ops, liveRef.current.active);\n liveRef.current.staged = st.dirty ? ops : null;\n setStagedState(ops);\n }\n\n // Begin the ONE write any of the three landing signals agreed on. The\n // stage is taken out of local draft state FIRST: the write is no longer\n // the user's local intent, and until it settles no signal may land the\n // same op a second time (the flush-in-flight ref holds the other two\n // signals off). If the attempt ultimately fails, the draft falls back to\n // the stored value and the failure message stands \u2014 the choice has to be\n // re-staged deliberately, exactly like any failed write.\n function beginFlush(live: CardLiveView): void {\n if (flushingRef.current || live.staged === null) return;\n var ops = live.staged;\n var flushScope = live.scope;\n var flushRoute = live.route;\n cancelSeenRef.current = false;\n commitSeenRef.current = false;\n flushingRef.current = true;\n landStaged(ops, flushScope, flushRoute).then(\n function (): void {\n flushingRef.current = false;\n setFailure(null);\n },\n function (): void {\n flushingRef.current = false;\n setFailure(COPY.failed);\n }\n );\n // Take the stage out synchronously: a later signal must not re-land\n // it (React batches this with the flush's own state settles).\n setStaged(null);\n }\n\n // One step after a no-verdict close: whatever the bubble read decides.\n function deferredDecision(): void {\n if (!deferredCloseRef.current) return;\n deferredCloseRef.current = false;\n var live = liveRef.current;\n if (live.staged === null) return;\n if (cancelSeenRef.current) {\n cancelSeenRef.current = false;\n commitSeenRef.current = false;\n setStaged(null);\n return;\n }\n if (commitSeenRef.current) {\n if (!flushingRef.current) beginFlush(live);\n return;\n }\n commitSeenRef.current = false;\n setStaged(null);\n }\n\n return {\n failure: failure,\n staged: staged,\n stagedRef: stagedRef,\n liveRef: liveRef,\n anchorRef: anchorRef,\n hostRef: hostRef,\n dotRef: dotRef,\n flushingRef: flushingRef,\n cancelSeenRef: cancelSeenRef,\n commitSeenRef: commitSeenRef,\n deferredCloseRef: deferredCloseRef,\n lastRevisionRef: lastRevisionRef,\n lastEditorRef: lastEditorRef,\n setStaged: setStaged,\n beginFlush: beginFlush,\n deferredDecision: deferredDecision\n };\n}\n", "/**\n * Browser half \u2014 `card/`: the staged write's ONE landing attempt.\n *\n * The pure machinery the flush gate (`state.beginFlush`) hands its staged ops\n * to. The write only stands when the STORED state ends up matching the staged\n * direction: a rejection (the page's own save bumped the revision under a\n * stale fence \u2014 a stale-fence rejection has already re-read the scope) gets\n * exactly ONE replay, and the chain rejects only when the replay still\n * disagrees.\n *\n * The route is CAPTURED for the flush: the editor may unmount mid-flight\n * (the card closing), which zeroes the live view's route, and reading it\n * there would mistake an unset profile for the OFF target and drop an\n * unsaved OFF.\n */\nimport { isNoKeyActive, stagedDirection } from \"../profile.js\";\nimport type { SettingsPathOp, SettingsScope } from \"../types.js\";\n\n/**\n * Land `ops` against `flushScope`, one attempt plus one replay. Resolves when\n * the stored state matches the staged direction; rejects otherwise (the\n * caller then falls the draft back to the stored value).\n * @param ops - the staged path ops (`set` ON, `unset` OFF, never the whole map).\n * @param flushScope - the scope captured when the flush began.\n * @param flushRoute - the route captured when the flush began.\n */\nexport function landStaged(ops: SettingsPathOp[], flushScope: SettingsScope, flushRoute: string): Promise<unknown> {\n var target = stagedDirection(ops);\n function attempt(retry: boolean): Promise<unknown> {\n var snapshotNow = flushScope.getSnapshot();\n if (!!snapshotNow && snapshotNow.status === \"ready\" && isNoKeyActive(snapshotNow, flushRoute) === target) {\n return Promise.resolve();\n }\n return flushScope.mutate(ops).then(function () {\n var after = flushScope.getSnapshot();\n var landed = !!after && after.status === \"ready\" && isNoKeyActive(after, flushRoute) === target;\n if (landed) return;\n if (!retry) return attempt(true);\n return Promise.reject(new Error(\"rejected\"));\n });\n }\n // The first attempt waits one microtask: whatever signal tripped this\n // flush (a commit click, a revision bump, a close verdict) has more work\n // queued in the same tick \u2014 the write must land BEHIND the page's own.\n return Promise.resolve().then(function () {\n return attempt(false);\n });\n}\n", "/**\n * Browser half \u2014 `card/`: the namespace scope snapshot as render state.\n *\n * Every pushed `settings/document-updated` lands as a NEW snapshot object and\n * re-renders the card: that is the card's whole connection to stored state\n * (the toggle reads the `user` layer, the dot the resolved `value` layer \u2014\n * `../profile.js` reads them out here). The `getSnapshot` reference is stable\n * per scope, and `subscribe` is re-bound on scope identity only: the scope is\n * bound once at mount, so a churn of props never re-seats the store.\n */\nimport { useMemo, useSyncExternalStore } from \"react\";\nimport type { ScopeSnapshot, SettingsScope } from \"../types.js\";\n\n/**\n * Subscribe the component to `scope`: the returned snapshot re-renders on\n * every document update.\n * @param scope - the namespace scope bound to this component.\n * @returns the current snapshot, or `undefined` while the scope resolves.\n */\nexport function useScopeSnapshot(scope: SettingsScope): ScopeSnapshot | undefined {\n var subscribe = useMemo(\n function (): (listener: () => void) => () => void {\n return function (listener) {\n return scope.subscribe(listener);\n };\n },\n [scope]\n );\n return useSyncExternalStore(\n subscribe,\n function (): ScopeSnapshot | undefined {\n return scope.getSnapshot();\n },\n function (): ScopeSnapshot | undefined {\n return scope.getSnapshot();\n }\n );\n}\n", "/**\n * Browser half \u2014 `card/`: what one render claims about the card.\n *\n * The pure view of the seat: from the owner props and the snapshot it resolves\n * the gates (which host may stand where) and the stored facts every part of\n * the component re-reads. Nothing here touches the DOM or the mutable state \u2014\n * the staging facts arrive as parameters (render state and the synchronous\n * reference) because the DOM signals read the synchronous one while the hint\n * draws from the state, and the view states both sides of that pair.\n */\nimport { hasForeignAuthorization, isNoKeyActive, showDot, showToggle, stageOf } from \"../profile.js\";\nimport type { NoApiKeyToggleCardProps, ScopeSnapshot, SettingsPathOp } from \"../types.js\";\n\n/** Every gate and fact one render draws. */\nexport interface CardView {\n /** The toggle stands on this card (`showToggle`'s gate). */\n visible: boolean;\n /** The row dot stands on this card (`showDot`'s gate \u2014 not the toggle's). */\n dot: boolean;\n /** The route id the facts are read under (empty when the toggle is off). */\n route: string;\n /** The scope resolves \u2014 without it no fact stands. */\n ready: boolean;\n /** The no-key header stands in the STORED (user-layer) profile. */\n active: boolean;\n /** Writes may land at all. */\n writable: boolean;\n /** A foreign `Authorization` stands: the toggle renders off and disabled. */\n conflict: boolean;\n /** What the STAGED state shows (render-side; `stageOf` over the state). */\n stage: { draftActive: boolean; dirty: boolean };\n /** What the SYNCHRONOUS stage shows (what DOM signals just consumed). */\n liveStage: { draftActive: boolean; dirty: boolean };\n}\n\n/**\n * Resolve the view's gates and facts.\n * @param props - the seat's owner props plus the bound scope.\n * @param snapshot - the current scope snapshot.\n * @param staged - the staged ops as render state (`null` for none).\n * @param stagedNow - the staged ops as the synchronous reference.\n */\nexport function resolveCardView(\n props: NoApiKeyToggleCardProps,\n snapshot: ScopeSnapshot | undefined,\n staged: SettingsPathOp[] | null,\n stagedNow: SettingsPathOp[] | null\n): CardView {\n var visible = showToggle(props);\n var dot = showDot(props, snapshot);\n var route = visible ? props.provider!.provider || \"\" : \"\";\n var ready = !!snapshot && snapshot.status === \"ready\";\n var active = visible && ready && isNoKeyActive(snapshot, route);\n var writable = ready && snapshot!.writable === true;\n // A staged direction differs from the STORED value only while it is\n // worth saying; once the stored value matches it, the stage is spent.\n return {\n visible: visible,\n dot: dot,\n route: route,\n ready: ready,\n active: active,\n writable: writable,\n conflict: visible && ready && hasForeignAuthorization(snapshot, route),\n stage: stageOf(staged, active),\n liveStage: stageOf(stagedNow, active)\n };\n}\n", "/**\n * Browser half \u2014 the component's stylesheet.\n *\n * The plugin never references the Models page's hashed CSS-module class names\n * (they churn every rebuild); its own rules ride in under stable `ccp_*`\n * class names through a single `style[data-plugin-css=\u2026]` tag, installed once\n * per document. The colors come from the design-system alias variables the\n * page already defines \u2014 nothing here invents a shade.\n */\n\n/** The whole rule sheet \u2014 one plugin-owned tag, never page class names. */\nvar CSS =\n \".ccp_editorHost{display:flex;flex-direction:column;gap:2px}\" +\n \".ccp_dot{display:inline-block;flex:none;width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-state-success-primary)}\" +\n \".ccp_anchor{display:none}\" +\n \".ccp_line{align-items:center;gap:8px;display:flex}\" +\n \".ccp_value{color:var(--dsw-alias-label-secondary);border:0;background:0 0;padding:0;font-size:12px}\" +\n \".ccp_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}\" +\n \".ccp_warning{color:var(--dsw-alias-label-error);margin:0;font-size:12px}\";\n\n/** The `data-plugin-css` tag identity \u2014 the one installed sheet for this half. */\nvar CSS_TAG = \"@comecaramelos/dsh-custom-provider/NoApiKeyToggle.module.css\";\n\nvar cssInstalled = false;\n\n/** Install the stylesheet once per document (the tag may pre-exist from an earlier mount). */\nexport function ensureCss(doc: Document): void {\n if (cssInstalled) return;\n if (doc.querySelector('style[data-plugin-css=\"' + CSS_TAG + '\"]') !== null) {\n cssInstalled = true;\n return;\n }\n var tag = doc.createElement(\"style\");\n tag.dataset.plugin = \"@comecaramelos/dsh-custom-provider\";\n tag.dataset.pluginCss = CSS_TAG;\n tag.textContent = CSS;\n doc.head.appendChild(tag);\n cssInstalled = true;\n}\n", "/**\n * Browser half \u2014 the plugin body.\n *\n * The entry the loader calls: install the stylesheet, bind one scope over the\n * adapter's namespace (binding never touches the wire) and claim the\n * provider-card seat through the slot-injection ledger so the ledger order is\n * the Host's problem, not ours.\n */\nimport { NoApiKeyToggleCard } from \"./card/index.js\";\nimport { SETTINGS_NS } from \"./plugin-meta.js\";\nimport { ensureCss } from \"./styles.js\";\nimport type { SettingsScope } from \"./types.js\";\n\nfunction noop(): void {}\n\nexport function apply(ctx: any): () => void {\n if (!ctx.settingsScope || !ctx.slots || typeof ctx.slots.inject !== \"function\") return noop;\n if (typeof document !== \"undefined\") ensureCss(document);\n return ctx.effect(function (): any {\n var scope: SettingsScope | undefined;\n try {\n scope = ctx.settingsScope.bind({ namespace: SETTINGS_NS });\n } catch (error) {\n return noop;\n }\n return ctx.slots.inject(\"settings.models.provider-card\", function () {\n return ctx.slots.register(\n {\n name: \"settings.models.provider-card\",\n // Every card of this adapter family dispatches with\n // entryKey = settingsNs; hand-declared routes live\n // in this namespace, which is the family claimed.\n key: SETTINGS_NS,\n inject: function () {\n return { scope: scope };\n }\n },\n NoApiKeyToggleCard\n );\n });\n }, \"custom-provider: models card\");\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_react", "import_jsx_runtime", "import_react", "card", "import_react", "noop", "import_react", "import_react", "noop"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host half — the mount.
|
|
3
|
+
*
|
|
4
|
+
* Inert: everything happens in `lib/client.js` (slot registration, the toggle
|
|
5
|
+
* component, the row status dot). Cordis still calls `apply` on every mount —
|
|
6
|
+
* it registers no services, owns no settings section and opens no wire
|
|
7
|
+
* protocol, so this only keeps the two halves loading as one bundle.
|
|
8
|
+
*/
|
|
9
|
+
export declare function apply(): void;
|
|
10
|
+
//# sourceMappingURL=apply.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/host/apply.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,wBAAgB,KAAK,IAAI,IAAI,CAAG"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host half — the mount.
|
|
3
|
+
*
|
|
4
|
+
* Inert: everything happens in `lib/client.js` (slot registration, the toggle
|
|
5
|
+
* component, the row status dot). Cordis still calls `apply` on every mount —
|
|
6
|
+
* it registers no services, owns no settings section and opens no wire
|
|
7
|
+
* protocol, so this only keeps the two halves loading as one bundle.
|
|
8
|
+
*/
|
|
9
|
+
export function apply() { }
|
|
10
|
+
//# sourceMappingURL=apply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/host/apply.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,UAAU,KAAK,KAAU,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host half — the identity this bundle registers under.
|
|
3
|
+
*
|
|
4
|
+
* Cordis reads `name` off the module and uses it as the row id in the profile
|
|
5
|
+
* bundle (see `cordis.patch.yml`, whose `config {}` is inert). Nothing is
|
|
6
|
+
* consumed host-side: the whole feature is web-plane, so `inject` is empty —
|
|
7
|
+
* installing a plugin-owned settings section here would fork the state the
|
|
8
|
+
* browser half reads through the adapter's namespace.
|
|
9
|
+
*/
|
|
10
|
+
/** Cordis row id in the profile bundle (matches `cordis.patch.yml`). */
|
|
11
|
+
export declare const name = "custom-provider";
|
|
12
|
+
/** Nothing consumed host-side. */
|
|
13
|
+
export declare const inject: string[];
|
|
14
|
+
//# sourceMappingURL=plugin-meta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-meta.d.ts","sourceRoot":"","sources":["../../src/host/plugin-meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,wEAAwE;AACxE,eAAO,MAAM,IAAI,oBAAoB,CAAC;AAEtC,kCAAkC;AAClC,eAAO,MAAM,MAAM,EAAE,MAAM,EAAO,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host half — the identity this bundle registers under.
|
|
3
|
+
*
|
|
4
|
+
* Cordis reads `name` off the module and uses it as the row id in the profile
|
|
5
|
+
* bundle (see `cordis.patch.yml`, whose `config {}` is inert). Nothing is
|
|
6
|
+
* consumed host-side: the whole feature is web-plane, so `inject` is empty —
|
|
7
|
+
* installing a plugin-owned settings section here would fork the state the
|
|
8
|
+
* browser half reads through the adapter's namespace.
|
|
9
|
+
*/
|
|
10
|
+
/** Cordis row id in the profile bundle (matches `cordis.patch.yml`). */
|
|
11
|
+
export const name = "custom-provider";
|
|
12
|
+
/** Nothing consumed host-side. */
|
|
13
|
+
export const inject = [];
|
|
14
|
+
//# sourceMappingURL=plugin-meta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-meta.js","sourceRoot":"","sources":["../../src/host/plugin-meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,wEAAwE;AACxE,MAAM,CAAC,MAAM,IAAI,GAAG,iBAAiB,CAAC;AAEtC,kCAAkC;AAClC,MAAM,CAAC,MAAM,MAAM,GAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host half — shared types.
|
|
3
|
+
*
|
|
4
|
+
* Structural only: no cordis value import in this package (bundle purity), so
|
|
5
|
+
* the host-context surface this half never uses is described by shape.
|
|
6
|
+
*/
|
|
7
|
+
/** A host-context dispose function (structural — no cordis value import here). */
|
|
8
|
+
export type Dispose = () => void;
|
|
9
|
+
/** The slice of the host context this half consumes: none. */
|
|
10
|
+
export type HostContext = Record<string, unknown>;
|
|
11
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/host/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,kFAAkF;AAClF,MAAM,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC;AAEjC,8DAA8D;AAC9D,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/host/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @comecaramelos/dsh-custom-provider — host half, public surface.
|
|
3
|
+
*
|
|
4
|
+
* The host half is inert by design: it registers the bundle row (`name` +
|
|
5
|
+
* `inject`) and mounts a no-op, because the whole feature lives in the
|
|
6
|
+
* browser bundle (`lib/client.js`) — slot registration, the "No API key
|
|
7
|
+
* required" toggle and the row status dot are all web-plane, and the
|
|
8
|
+
* namespace they read/write is the `pi-ai` adapter's, already served. A
|
|
9
|
+
* plugin-owned settings section here would fork that state.
|
|
10
|
+
*
|
|
11
|
+
* Re-export only: nothing here decides anything. The modules behind it keep
|
|
12
|
+
* the same contract cordis reads (`name`, `inject`, `apply`) — the row exists
|
|
13
|
+
* only so the bundle (and with it the web plane) loads.
|
|
14
|
+
*
|
|
15
|
+
* @module lib/index
|
|
16
|
+
*/
|
|
17
|
+
export { apply } from "./host/apply.js";
|
|
18
|
+
export { inject, name } from "./host/plugin-meta.js";
|
|
19
|
+
export type { Dispose, HostContext } from "./host/types.js";
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AACrD,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @comecaramelos/dsh-custom-provider — host half, public surface.
|
|
3
|
+
*
|
|
4
|
+
* The host half is inert by design: it registers the bundle row (`name` +
|
|
5
|
+
* `inject`) and mounts a no-op, because the whole feature lives in the
|
|
6
|
+
* browser bundle (`lib/client.js`) — slot registration, the "No API key
|
|
7
|
+
* required" toggle and the row status dot are all web-plane, and the
|
|
8
|
+
* namespace they read/write is the `pi-ai` adapter's, already served. A
|
|
9
|
+
* plugin-owned settings section here would fork that state.
|
|
10
|
+
*
|
|
11
|
+
* Re-export only: nothing here decides anything. The modules behind it keep
|
|
12
|
+
* the same contract cordis reads (`name`, `inject`, `apply`) — the row exists
|
|
13
|
+
* only so the bundle (and with it the web plane) loads.
|
|
14
|
+
*
|
|
15
|
+
* @module lib/index
|
|
16
|
+
*/
|
|
17
|
+
export { apply } from "./host/apply.js";
|
|
18
|
+
export { inject, name } from "./host/plugin-meta.js";
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@comecaramelos/dsh-custom-provider",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "DSH plugin: a \"No API key required\" toggle on saved hand-declared provider cards that writes Authorization: Bearer none so keyless local/self-hosted endpoints stop aborting with \"No API key for provider\"",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dsh",
|
|
7
|
+
"dsh-plugin",
|
|
8
|
+
"providers",
|
|
9
|
+
"llm",
|
|
10
|
+
"pi-ai"
|
|
11
|
+
],
|
|
12
|
+
"author": "Robe ComeCaramelos <hello@comecaramelos.com>",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/ComeCaramelos/dsh-custom-provider.git"
|
|
16
|
+
},
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/ComeCaramelos/dsh-custom-provider/issues"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/ComeCaramelos/dsh-custom-provider#readme",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "lib/index.js",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": "./lib/index.js",
|
|
29
|
+
"./client": "./lib/client.js",
|
|
30
|
+
"./package.json": "./package.json"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"lib",
|
|
34
|
+
"cordis.patch.yml"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc && npm run build:client",
|
|
38
|
+
"build:host": "tsc",
|
|
39
|
+
"build:client": "tsc -p tsconfig.client.json && node scripts/build-client.mjs",
|
|
40
|
+
"clean": "rm -rf lib",
|
|
41
|
+
"dev": "tsc --watch",
|
|
42
|
+
"prepack": "npm run build",
|
|
43
|
+
"test": "npm run build && node --test"
|
|
44
|
+
},
|
|
45
|
+
"dsh": {
|
|
46
|
+
"bundle": {
|
|
47
|
+
"patch": "./cordis.patch.yml"
|
|
48
|
+
},
|
|
49
|
+
"client": {
|
|
50
|
+
"platform": "web",
|
|
51
|
+
"inject": [
|
|
52
|
+
"@deepseek-ai/dsh-client-ui-settings"
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"@deepseek-ai/dsh": "^1.0.0",
|
|
58
|
+
"@deepseek-ai/dsh-client-ui-settings": "^1.0.0",
|
|
59
|
+
"react": "^19.0.0"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"esbuild": "^0.25.12",
|
|
63
|
+
"typescript": "^5.9.3"
|
|
64
|
+
}
|
|
65
|
+
}
|