@frogbotai/plugin-api-keys 0.33.0 → 0.35.0
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/README.md +1 -1
- package/dist/client/ApiKeysManager.d.ts.map +1 -1
- package/dist/client/ApiKeysManager.js +174 -172
- package/dist/client/ApiKeysManager.js.map +1 -1
- package/dist/client/styles.css +33 -65
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +15 -1
- package/dist/collection.js.map +1 -1
- package/dist/server/services.d.ts +3 -2
- package/dist/server/services.d.ts.map +1 -1
- package/dist/server/services.js +12 -2
- package/dist/server/services.js.map +1 -1
- package/package.json +12 -12
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ Authorization: Bearer fb_...
|
|
|
21
21
|
X-API-Key: fb_...
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
Plaintext keys are returned only when created. The collection stores SHA-256 hashes and supports multiple independently revoked keys per user.
|
|
24
|
+
Plaintext keys are returned only when created. The collection stores SHA-256 hashes and supports multiple independently revoked keys per user. Minting and rotating need a signed-in session: a request authenticated by an API key gets `403`, so a leaked key can't leave new keys behind. A key can still list, rename, and revoke keys.
|
|
25
25
|
|
|
26
26
|
A key has no budget or model limits of its own; requests use the owner's AI policy. With AI configured, usage rows include an optional `apiKey` relationship to the authenticating key. Cookie-authenticated requests omit it, and the relationship follows `collectionSlug`.
|
|
27
27
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApiKeysManager.d.ts","sourceRoot":"","sources":["../../src/client/ApiKeysManager.tsx"],"names":[],"mappings":"AAEA,OAAO,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"ApiKeysManager.d.ts","sourceRoot":"","sources":["../../src/client/ApiKeysManager.tsx"],"names":[],"mappings":"AAEA,OAAO,cAAc,CAAC;AAkBtB,wBAAgB,cAAc,4CAyJ7B;AAED,wBAAgB,YAAY,CAAC,EAC3B,OAAO,GACR,EAAE;IACD,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CAC5E,2CAkEA"}
|
|
@@ -1,30 +1,33 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import './styles.css';
|
|
4
|
-
import { Button,
|
|
5
|
-
import {
|
|
6
|
-
|
|
4
|
+
import { Button, Dialog, DialogContent, DialogDescription, DialogFooter, DialogTitle, DialogTrigger, Input, Label, Tooltip } from '@frogbotai/ui';
|
|
5
|
+
import { useConfig, useListQuery, useRouteCache } from '@frogbotai/ui/admin';
|
|
6
|
+
import { CopyIcon } from '@frogbotai/ui/icons';
|
|
7
|
+
import { useId, useState } from 'react';
|
|
7
8
|
export function ApiKeysManager() {
|
|
8
9
|
const { config } = useConfig();
|
|
9
10
|
const { collectionSlug } = useListQuery();
|
|
10
|
-
const { closeModal, openModal } = useModal();
|
|
11
11
|
const { clearRouteCache } = useRouteCache();
|
|
12
|
+
const nameId = useId();
|
|
13
|
+
const [open, setOpen] = useState(false);
|
|
12
14
|
const [name, setName] = useState('');
|
|
13
15
|
const [token, setToken] = useState();
|
|
14
16
|
const [error, setError] = useState();
|
|
15
17
|
const [loading, setLoading] = useState(false);
|
|
16
18
|
const [copied, setCopied] = useState(false);
|
|
17
19
|
const [hoveredControl, setHoveredControl] = useState();
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
function changeOpen(next) {
|
|
21
|
+
if (next) {
|
|
22
|
+
setName('');
|
|
23
|
+
setToken(undefined);
|
|
24
|
+
setError(undefined);
|
|
25
|
+
setCopied(false);
|
|
26
|
+
setHoveredControl(undefined);
|
|
27
|
+
} else if (token) {
|
|
28
|
+
clearRouteCache();
|
|
29
|
+
}
|
|
30
|
+
setOpen(next);
|
|
28
31
|
}
|
|
29
32
|
async function createKey() {
|
|
30
33
|
if (loading || !name.trim()) return;
|
|
@@ -65,111 +68,114 @@ export function ApiKeysManager() {
|
|
|
65
68
|
}
|
|
66
69
|
};
|
|
67
70
|
}
|
|
68
|
-
return /*#__PURE__*/ _jsxs(
|
|
71
|
+
return /*#__PURE__*/ _jsxs(Dialog, {
|
|
72
|
+
open: open,
|
|
73
|
+
onOpenChange: changeOpen,
|
|
69
74
|
children: [
|
|
70
|
-
/*#__PURE__*/ _jsx(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
/*#__PURE__*/ _jsx(DialogTrigger, {
|
|
76
|
+
asChild: true,
|
|
77
|
+
children: /*#__PURE__*/ _jsx(Button, {
|
|
78
|
+
variant: "secondary",
|
|
79
|
+
type: "button",
|
|
80
|
+
children: "Create API key"
|
|
81
|
+
})
|
|
76
82
|
}),
|
|
77
|
-
/*#__PURE__*/
|
|
78
|
-
className: "api-keys-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
className: "api-keys-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
/*#__PURE__*/ _jsxs("button", {
|
|
118
|
-
"aria-label": "Copy API key",
|
|
119
|
-
className: "api-keys-clear-button api-keys-slide-up-1 api-keys-modal__copy",
|
|
120
|
-
type: "button",
|
|
121
|
-
...copyHandlers('icon'),
|
|
122
|
-
children: [
|
|
123
|
-
/*#__PURE__*/ _jsx(CopyIcon, {}),
|
|
124
|
-
/*#__PURE__*/ _jsx(Tooltip, {
|
|
125
|
-
delay: copied ? 0 : undefined,
|
|
126
|
-
show: hoveredControl === 'icon',
|
|
127
|
-
children: copied ? 'Copied' : 'Copy'
|
|
128
|
-
})
|
|
129
|
-
]
|
|
130
|
-
})
|
|
131
|
-
]
|
|
83
|
+
/*#__PURE__*/ _jsxs(DialogContent, {
|
|
84
|
+
className: "api-keys-dialog",
|
|
85
|
+
withCloseButton: false,
|
|
86
|
+
children: [
|
|
87
|
+
/*#__PURE__*/ _jsx(DialogTitle, {
|
|
88
|
+
children: "Create API Key"
|
|
89
|
+
}),
|
|
90
|
+
token ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
91
|
+
children: [
|
|
92
|
+
/*#__PURE__*/ _jsx(DialogDescription, {
|
|
93
|
+
className: "api-keys-dialog__warning",
|
|
94
|
+
role: "alert",
|
|
95
|
+
children: "Key generated! Copy it now — you won't see it again."
|
|
96
|
+
}),
|
|
97
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
98
|
+
className: "api-keys-dialog__token-row",
|
|
99
|
+
children: [
|
|
100
|
+
/*#__PURE__*/ _jsx(Tooltip, {
|
|
101
|
+
label: copied ? 'Copied' : 'Click to copy',
|
|
102
|
+
open: hoveredControl === 'token',
|
|
103
|
+
children: /*#__PURE__*/ _jsx("button", {
|
|
104
|
+
"aria-label": "Click to copy API key",
|
|
105
|
+
className: "api-keys-dialog__token",
|
|
106
|
+
type: "button",
|
|
107
|
+
...copyHandlers('token'),
|
|
108
|
+
children: /*#__PURE__*/ _jsx("code", {
|
|
109
|
+
children: token
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
}),
|
|
113
|
+
/*#__PURE__*/ _jsx(Tooltip, {
|
|
114
|
+
label: copied ? 'Copied' : 'Copy',
|
|
115
|
+
open: hoveredControl === 'icon',
|
|
116
|
+
children: /*#__PURE__*/ _jsx(Button, {
|
|
117
|
+
"aria-label": "Copy API key",
|
|
118
|
+
size: "icon",
|
|
119
|
+
type: "button",
|
|
120
|
+
variant: "ghost",
|
|
121
|
+
...copyHandlers('icon'),
|
|
122
|
+
children: /*#__PURE__*/ _jsx(CopyIcon, {})
|
|
132
123
|
})
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
124
|
+
})
|
|
125
|
+
]
|
|
126
|
+
})
|
|
127
|
+
]
|
|
128
|
+
}) : /*#__PURE__*/ _jsxs(_Fragment, {
|
|
129
|
+
children: [
|
|
130
|
+
/*#__PURE__*/ _jsx(DialogDescription, {
|
|
131
|
+
children: "Name the key after the script or tool that uses it."
|
|
132
|
+
}),
|
|
133
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
134
|
+
className: "api-keys-dialog__field",
|
|
135
|
+
children: [
|
|
136
|
+
/*#__PURE__*/ _jsx(Label, {
|
|
137
|
+
htmlFor: nameId,
|
|
138
|
+
children: "Key name"
|
|
139
|
+
}),
|
|
140
|
+
/*#__PURE__*/ _jsx(Input, {
|
|
141
|
+
id: nameId,
|
|
142
|
+
placeholder: "Key name (e.g. My MacBook CLI)",
|
|
143
|
+
readOnly: loading,
|
|
144
|
+
value: name,
|
|
145
|
+
onChange: (event)=>setName(event.target.value),
|
|
146
|
+
onKeyDown: (event)=>{
|
|
147
|
+
if (event.key === 'Enter') {
|
|
148
|
+
event.preventDefault();
|
|
149
|
+
void createKey();
|
|
150
|
+
}
|
|
145
151
|
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
152
|
+
})
|
|
153
|
+
]
|
|
154
|
+
})
|
|
155
|
+
]
|
|
156
|
+
}),
|
|
157
|
+
error ? /*#__PURE__*/ _jsx("p", {
|
|
158
|
+
className: "api-keys-dialog__error",
|
|
159
|
+
role: "alert",
|
|
160
|
+
children: error
|
|
161
|
+
}) : null,
|
|
162
|
+
/*#__PURE__*/ _jsxs(DialogFooter, {
|
|
163
|
+
children: [
|
|
164
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
165
|
+
variant: "secondary",
|
|
166
|
+
onClick: ()=>changeOpen(false),
|
|
167
|
+
type: "button",
|
|
168
|
+
children: token ? 'Close' : 'Dismiss'
|
|
169
|
+
}),
|
|
170
|
+
token ? null : /*#__PURE__*/ _jsx(Button, {
|
|
171
|
+
disabled: loading || !name.trim(),
|
|
172
|
+
onClick: createKey,
|
|
173
|
+
type: "button",
|
|
174
|
+
children: loading ? 'Generating…' : 'Generate'
|
|
175
|
+
})
|
|
176
|
+
]
|
|
177
|
+
})
|
|
178
|
+
]
|
|
173
179
|
})
|
|
174
180
|
]
|
|
175
181
|
});
|
|
@@ -177,12 +183,15 @@ export function ApiKeysManager() {
|
|
|
177
183
|
export function RevokeApiKey({ rowData }) {
|
|
178
184
|
const { config } = useConfig();
|
|
179
185
|
const { collectionSlug } = useListQuery();
|
|
180
|
-
const { closeModal, openModal } = useModal();
|
|
181
186
|
const { clearRouteCache } = useRouteCache();
|
|
187
|
+
const [open, setOpen] = useState(false);
|
|
182
188
|
const [loading, setLoading] = useState(false);
|
|
183
189
|
const [revoked, setRevoked] = useState(false);
|
|
184
190
|
const [error, setError] = useState();
|
|
185
|
-
|
|
191
|
+
function changeOpen(next) {
|
|
192
|
+
if (next) setError(undefined);
|
|
193
|
+
setOpen(next);
|
|
194
|
+
}
|
|
186
195
|
async function revoke() {
|
|
187
196
|
setLoading(true);
|
|
188
197
|
setError(undefined);
|
|
@@ -195,69 +204,62 @@ export function RevokeApiKey({ rowData }) {
|
|
|
195
204
|
setError(result.error ?? 'Unable to revoke API key');
|
|
196
205
|
return;
|
|
197
206
|
}
|
|
198
|
-
|
|
207
|
+
setOpen(false);
|
|
199
208
|
setRevoked(true);
|
|
200
209
|
clearRouteCache();
|
|
201
210
|
}
|
|
202
211
|
if (revoked || rowData.revokedAt) return /*#__PURE__*/ _jsx("span", {
|
|
203
212
|
children: "Revoked"
|
|
204
213
|
});
|
|
205
|
-
return /*#__PURE__*/ _jsxs(
|
|
214
|
+
return /*#__PURE__*/ _jsxs(Dialog, {
|
|
215
|
+
open: open,
|
|
216
|
+
onOpenChange: changeOpen,
|
|
206
217
|
children: [
|
|
207
|
-
/*#__PURE__*/ _jsx(
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}),
|
|
215
|
-
/*#__PURE__*/ _jsx(Modal, {
|
|
216
|
-
className: "api-keys-modal",
|
|
217
|
-
closeOnBlur: true,
|
|
218
|
-
onClose: ()=>closeModal(confirmSlug),
|
|
219
|
-
slug: confirmSlug,
|
|
220
|
-
children: /*#__PURE__*/ _jsxs("div", {
|
|
221
|
-
className: "api-keys-modal__wrapper",
|
|
222
|
-
children: [
|
|
223
|
-
/*#__PURE__*/ _jsxs("div", {
|
|
224
|
-
className: "api-keys-modal__content",
|
|
225
|
-
children: [
|
|
226
|
-
/*#__PURE__*/ _jsx("h1", {
|
|
227
|
-
children: "Revoke API Key"
|
|
228
|
-
}),
|
|
229
|
-
/*#__PURE__*/ _jsxs("p", {
|
|
230
|
-
children: [
|
|
231
|
-
"This will immediately disable ",
|
|
232
|
-
rowData.name ?? 'this key',
|
|
233
|
-
". Any scripts or tools using this key will stop working. This cannot be undone."
|
|
234
|
-
]
|
|
235
|
-
}),
|
|
236
|
-
error ? /*#__PURE__*/ _jsx("p", {
|
|
237
|
-
role: "alert",
|
|
238
|
-
children: error
|
|
239
|
-
}) : null
|
|
240
|
-
]
|
|
241
|
-
}),
|
|
242
|
-
/*#__PURE__*/ _jsxs("div", {
|
|
243
|
-
className: "api-keys-modal__controls",
|
|
244
|
-
children: [
|
|
245
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
246
|
-
buttonStyle: "secondary",
|
|
247
|
-
onClick: ()=>closeModal(confirmSlug),
|
|
248
|
-
type: "button",
|
|
249
|
-
children: "Cancel"
|
|
250
|
-
}),
|
|
251
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
252
|
-
disabled: loading,
|
|
253
|
-
onClick: revoke,
|
|
254
|
-
type: "button",
|
|
255
|
-
children: loading ? 'Revoking…' : 'Revoke key'
|
|
256
|
-
})
|
|
257
|
-
]
|
|
258
|
-
})
|
|
259
|
-
]
|
|
218
|
+
/*#__PURE__*/ _jsx(DialogTrigger, {
|
|
219
|
+
asChild: true,
|
|
220
|
+
children: /*#__PURE__*/ _jsx(Button, {
|
|
221
|
+
size: "sm",
|
|
222
|
+
type: "button",
|
|
223
|
+
variant: "secondary",
|
|
224
|
+
children: "Revoke"
|
|
260
225
|
})
|
|
226
|
+
}),
|
|
227
|
+
/*#__PURE__*/ _jsxs(DialogContent, {
|
|
228
|
+
className: "api-keys-dialog",
|
|
229
|
+
withCloseButton: false,
|
|
230
|
+
children: [
|
|
231
|
+
/*#__PURE__*/ _jsx(DialogTitle, {
|
|
232
|
+
children: "Revoke API Key"
|
|
233
|
+
}),
|
|
234
|
+
/*#__PURE__*/ _jsxs(DialogDescription, {
|
|
235
|
+
children: [
|
|
236
|
+
"This will immediately disable ",
|
|
237
|
+
rowData.name ?? 'this key',
|
|
238
|
+
". Any scripts or tools using this key will stop working. This cannot be undone."
|
|
239
|
+
]
|
|
240
|
+
}),
|
|
241
|
+
error ? /*#__PURE__*/ _jsx("p", {
|
|
242
|
+
className: "api-keys-dialog__error",
|
|
243
|
+
role: "alert",
|
|
244
|
+
children: error
|
|
245
|
+
}) : null,
|
|
246
|
+
/*#__PURE__*/ _jsxs(DialogFooter, {
|
|
247
|
+
children: [
|
|
248
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
249
|
+
variant: "secondary",
|
|
250
|
+
onClick: ()=>changeOpen(false),
|
|
251
|
+
type: "button",
|
|
252
|
+
children: "Cancel"
|
|
253
|
+
}),
|
|
254
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
255
|
+
disabled: loading,
|
|
256
|
+
onClick: revoke,
|
|
257
|
+
type: "button",
|
|
258
|
+
children: loading ? 'Revoking…' : 'Revoke key'
|
|
259
|
+
})
|
|
260
|
+
]
|
|
261
|
+
})
|
|
262
|
+
]
|
|
261
263
|
})
|
|
262
264
|
]
|
|
263
265
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/client/ApiKeysManager.tsx"],"names":["Button","
|
|
1
|
+
{"version":3,"sources":["../../src/client/ApiKeysManager.tsx"],"names":["Button","Dialog","DialogContent","DialogDescription","DialogFooter","DialogTitle","DialogTrigger","Input","Label","Tooltip","useConfig","useListQuery","useRouteCache","CopyIcon","useId","useState","ApiKeysManager","config","collectionSlug","clearRouteCache","nameId","open","setOpen","name","setName","token","setToken","error","setError","loading","setLoading","copied","setCopied","hoveredControl","setHoveredControl","changeOpen","next","undefined","createKey","trim","response","fetch","routes","api","method","headers","body","JSON","stringify","result","json","ok","copyToken","navigator","clipboard","writeText","copyHandlers","control","onClick","onMouseEnter","onMouseLeave","onOpenChange","asChild","variant","type","className","withCloseButton","role","div","label","button","aria-label","code","size","htmlFor","id","placeholder","readOnly","value","onChange","event","target","onKeyDown","key","preventDefault","p","disabled","RevokeApiKey","rowData","revoked","setRevoked","revoke","revokedAt","span"],"mappings":"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","file":"ApiKeysManager.js"}
|
package/dist/client/styles.css
CHANGED
|
@@ -1,91 +1,59 @@
|
|
|
1
1
|
@layer frogbot {
|
|
2
|
-
.api-keys-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
background: color-mix(in srgb, var(--theme-elevation-0) 80%, transparent);
|
|
6
|
-
display: flex;
|
|
7
|
-
height: 100%;
|
|
8
|
-
justify-content: center;
|
|
2
|
+
.fb-dialog__content.api-keys-dialog {
|
|
3
|
+
gap: 1rem;
|
|
4
|
+
max-width: 45rem;
|
|
9
5
|
}
|
|
10
6
|
|
|
11
|
-
.api-keys-
|
|
12
|
-
background: var(--theme-elevation-50);
|
|
13
|
-
border: 1px solid var(--theme-elevation-150);
|
|
14
|
-
border-radius: var(--style-radius-m);
|
|
7
|
+
.api-keys-dialog__field {
|
|
15
8
|
display: flex;
|
|
16
9
|
flex-direction: column;
|
|
17
|
-
gap:
|
|
18
|
-
max-width: 720px;
|
|
19
|
-
padding: 32px;
|
|
20
|
-
position: relative;
|
|
21
|
-
width: min(90vw, 720px);
|
|
22
|
-
z-index: 1;
|
|
10
|
+
gap: 0.5rem;
|
|
23
11
|
}
|
|
24
12
|
|
|
25
|
-
.api-keys-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
gap: 12px;
|
|
13
|
+
.fb-dialog__description.api-keys-dialog__warning {
|
|
14
|
+
color: var(--color-text);
|
|
15
|
+
font-weight: 600;
|
|
29
16
|
}
|
|
30
17
|
|
|
31
|
-
.api-keys-
|
|
18
|
+
.api-keys-dialog__error {
|
|
32
19
|
margin: 0;
|
|
20
|
+
color: var(--color-text-danger);
|
|
21
|
+
font-size: var(--fb-text-sm);
|
|
22
|
+
line-height: var(--fb-text-sm--line-height);
|
|
33
23
|
}
|
|
34
24
|
|
|
35
|
-
.api-keys-
|
|
36
|
-
color: var(--theme-success-500);
|
|
37
|
-
font-weight: 600;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.api-keys-modal__token-row {
|
|
41
|
-
align-items: center;
|
|
42
|
-
background: var(--theme-elevation-0);
|
|
43
|
-
border: 1px solid var(--theme-elevation-150);
|
|
44
|
-
border-radius: var(--style-radius-m);
|
|
25
|
+
.api-keys-dialog__token-row {
|
|
45
26
|
display: flex;
|
|
46
|
-
|
|
47
|
-
|
|
27
|
+
align-items: center;
|
|
28
|
+
gap: 0.5rem;
|
|
29
|
+
min-width: 0;
|
|
30
|
+
padding: 0.25rem 0.25rem 0.25rem 1rem;
|
|
31
|
+
background: var(--color-bg-secondary);
|
|
32
|
+
border: 1px solid var(--color-border);
|
|
33
|
+
border-radius: var(--fb-radius-lg);
|
|
48
34
|
transition: border-color 200ms ease-out;
|
|
49
35
|
}
|
|
50
36
|
|
|
51
|
-
.api-keys-
|
|
52
|
-
border-color: var(--
|
|
37
|
+
.api-keys-dialog__token-row:hover {
|
|
38
|
+
border-color: var(--special-border-translucent-strong);
|
|
53
39
|
}
|
|
54
40
|
|
|
55
|
-
.api-keys-
|
|
41
|
+
.api-keys-dialog__token {
|
|
56
42
|
flex: 1;
|
|
57
|
-
|
|
58
|
-
padding:
|
|
59
|
-
|
|
43
|
+
min-width: 0;
|
|
44
|
+
padding: 0.5rem 0;
|
|
45
|
+
color: inherit;
|
|
46
|
+
font: inherit;
|
|
47
|
+
line-height: 1.4;
|
|
60
48
|
text-align: left;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
.api-keys-modal__copy {
|
|
64
|
-
padding: 9px;
|
|
65
|
-
position: relative;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.api-keys-modal__controls {
|
|
69
|
-
display: flex;
|
|
70
|
-
gap: 12px;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
.api-keys-clear-button {
|
|
49
|
+
overflow-wrap: anywhere;
|
|
50
|
+
cursor: pointer;
|
|
74
51
|
background: none;
|
|
75
52
|
border: none;
|
|
76
|
-
box-shadow: none;
|
|
77
|
-
box-sizing: border-box;
|
|
78
|
-
cursor: pointer;
|
|
79
|
-
line-height: 1;
|
|
80
|
-
margin: 0;
|
|
81
|
-
outline: none;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
.api-keys-slide-up-1 {
|
|
85
|
-
transition: transform 200ms ease-out;
|
|
86
53
|
}
|
|
87
54
|
|
|
88
|
-
.api-keys-
|
|
89
|
-
|
|
55
|
+
.api-keys-dialog__token:focus-visible {
|
|
56
|
+
outline: 2px solid var(--accessibility-focus-color);
|
|
57
|
+
outline-offset: 2px;
|
|
90
58
|
}
|
|
91
59
|
}
|
package/dist/collection.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EAIrB,KAAK,cAAc,EAEpB,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EAIrB,KAAK,cAAc,EAEpB,MAAM,SAAS,CAAC;AAYjB,KAAK,iBAAiB,GAAG;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtE,UAAU,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACvC,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B,CAAC;AAyJF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAqHpF"}
|
package/dist/collection.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { moneyField } from 'frogbot';
|
|
2
|
-
import { ApiKeyServiceError, mintApiKey, revokeApiKey, rotateApiKey } from './server/services.js';
|
|
2
|
+
import { ApiKeyServiceError, isApiKeyRequest, mintApiKey, revokeApiKey, rotateApiKey } from './server/services.js';
|
|
3
3
|
const MANAGER_COMPONENT = '@frogbotai/plugin-api-keys/client#ApiKeysManager';
|
|
4
|
+
const sessionRequired = ()=>Response.json({
|
|
5
|
+
error: 'An API key cannot mint or rotate API keys. Sign in to manage keys.'
|
|
6
|
+
}, {
|
|
7
|
+
status: 403
|
|
8
|
+
});
|
|
4
9
|
const ownKeys = ({ req })=>req.user ? {
|
|
5
10
|
owner: {
|
|
6
11
|
equals: req.user.id
|
|
@@ -64,6 +69,7 @@ function createEndpoints({ collectionSlug, tokenPrefix, canRevokeAnyKey }) {
|
|
|
64
69
|
}, {
|
|
65
70
|
status: 401
|
|
66
71
|
});
|
|
72
|
+
if (isApiKeyRequest(req)) return sessionRequired();
|
|
67
73
|
const body = await req.json?.().catch(()=>null) ?? null;
|
|
68
74
|
const name = typeof body?.name === 'string' ? body.name.trim() : '';
|
|
69
75
|
if (!name) return Response.json({
|
|
@@ -146,6 +152,7 @@ function createEndpoints({ collectionSlug, tokenPrefix, canRevokeAnyKey }) {
|
|
|
146
152
|
}, {
|
|
147
153
|
status: 401
|
|
148
154
|
});
|
|
155
|
+
if (isApiKeyRequest(req)) return sessionRequired();
|
|
149
156
|
const id = req.routeParams?.id;
|
|
150
157
|
if (typeof id !== 'string' || !id) {
|
|
151
158
|
return Response.json({
|
|
@@ -303,6 +310,13 @@ export function createApiKeysCollection(options) {
|
|
|
303
310
|
plural: 'API Keys'
|
|
304
311
|
},
|
|
305
312
|
timestamps: true,
|
|
313
|
+
versions: false,
|
|
314
|
+
authorship: false,
|
|
315
|
+
custom: {
|
|
316
|
+
frogbot: {
|
|
317
|
+
internal: true
|
|
318
|
+
}
|
|
319
|
+
},
|
|
306
320
|
...existing,
|
|
307
321
|
...collection,
|
|
308
322
|
access: {
|
package/dist/collection.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/collection.ts"],"names":["moneyField","ApiKeyServiceError","mintApiKey","revokeApiKey","rotateApiKey","MANAGER_COMPONENT","ownKeys","req","user","owner","equals","id","mergeFields","groups","fields","Map","group","field","key","name","JSON","stringify","set","values","createViews","usageCollection","views","length","type","defaultFields","components","beforeTable","index","findIndex","view","map","position","createEndpoints","collectionSlug","tokenPrefix","canRevokeAnyKey","method","path","handler","
|
|
1
|
+
{"version":3,"sources":["../src/collection.ts"],"names":["moneyField","ApiKeyServiceError","isApiKeyRequest","mintApiKey","revokeApiKey","rotateApiKey","MANAGER_COMPONENT","sessionRequired","Response","json","error","status","ownKeys","req","user","owner","equals","id","mergeFields","groups","fields","Map","group","field","key","name","JSON","stringify","set","values","createViews","usageCollection","views","length","type","defaultFields","components","beforeTable","index","findIndex","view","map","position","createEndpoints","collectionSlug","tokenPrefix","canRevokeAnyKey","method","path","handler","body","catch","trim","code","routeParams","anyOwner","_name","_owner","result","createApiKeysCollection","options","authCollection","collection","existing","required","relationTo","access","update","admin","readOnly","unique","read","hidden","condition","_","siblingData","Boolean","revokedAt","label","virtual","hooks","afterRead","data","undefined","frogbot","find","depth","overrideAccess","pagination","where","apiKey","docs","reduce","total","doc","cost","costUSD","Cell","endpoints","slug","labels","singular","plural","timestamps","versions","authorship","custom","internal","create","delete","icon","useAsTitle"],"mappings":"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","file":"collection.js"}
|
|
@@ -12,9 +12,10 @@ export type RevokeApiKeyOptions = {
|
|
|
12
12
|
anyOwner?: boolean;
|
|
13
13
|
};
|
|
14
14
|
export declare class ApiKeyServiceError extends Error {
|
|
15
|
-
readonly code: 'authentication_required' | 'not_found';
|
|
16
|
-
constructor(code: 'authentication_required' | 'not_found');
|
|
15
|
+
readonly code: 'authentication_required' | 'not_found' | 'session_required';
|
|
16
|
+
constructor(code: 'authentication_required' | 'not_found' | 'session_required');
|
|
17
17
|
}
|
|
18
|
+
export declare function isApiKeyRequest(req: FrogBotRequest): boolean;
|
|
18
19
|
export declare function mintApiKey(options: MintApiKeyOptions): Promise<{
|
|
19
20
|
id: unknown;
|
|
20
21
|
name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/server/services.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/server/services.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAK9C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,cAAc,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,GAAG,EAAE,cAAc,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,qBAAa,kBAAmB,SAAQ,KAAK;aACf,IAAI,EAAE,yBAAyB,GAAG,WAAW,GAAG,kBAAkB;gBAAlE,IAAI,EAAE,yBAAyB,GAAG,WAAW,GAAG,kBAAkB;CAG/F;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAE5D;AA+BD,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB;;;;;;GAU1D;AAED,MAAM,MAAM,mBAAmB,GAAG,mBAAmB,GAAG;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhF,wBAAsB,YAAY,CAAC,EACjC,GAAG,EACH,cAAc,EACd,EAAE,EACF,WAAW,EACX,QAAQ,GACT,EAAE,mBAAmB;;;;;;GAWrB;AAED,wBAAsB,YAAY,CAAC,EAAE,GAAG,EAAE,cAAc,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,mBAAmB;;;;;GAmC5F"}
|
package/dist/server/services.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { apiKeyStrategyName } from '../strategy.js';
|
|
1
2
|
import { createApiKeyToken, getApiKeyPrefix, hashApiKeyToken } from './token.js';
|
|
2
3
|
export class ApiKeyServiceError extends Error {
|
|
3
4
|
code;
|
|
@@ -5,6 +6,15 @@ export class ApiKeyServiceError extends Error {
|
|
|
5
6
|
super(code), this.code = code;
|
|
6
7
|
}
|
|
7
8
|
}
|
|
9
|
+
export function isApiKeyRequest(req) {
|
|
10
|
+
return req.user?._strategy === apiKeyStrategyName;
|
|
11
|
+
}
|
|
12
|
+
function requireSessionOwner(req) {
|
|
13
|
+
const owner = req.user?.id;
|
|
14
|
+
if (owner === undefined) throw new ApiKeyServiceError('authentication_required');
|
|
15
|
+
if (isApiKeyRequest(req)) throw new ApiKeyServiceError('session_required');
|
|
16
|
+
return owner;
|
|
17
|
+
}
|
|
8
18
|
async function mintForOwner({ req, collectionSlug, tokenPrefix, name, owner }) {
|
|
9
19
|
const token = createApiKeyToken({
|
|
10
20
|
tokenPrefix
|
|
@@ -30,8 +40,7 @@ async function mintForOwner({ req, collectionSlug, tokenPrefix, name, owner }) {
|
|
|
30
40
|
};
|
|
31
41
|
}
|
|
32
42
|
export async function mintApiKey(options) {
|
|
33
|
-
const owner = options.req
|
|
34
|
-
if (owner === undefined) throw new ApiKeyServiceError('authentication_required');
|
|
43
|
+
const owner = requireSessionOwner(options.req);
|
|
35
44
|
return mintForOwner({
|
|
36
45
|
req: options.req,
|
|
37
46
|
collectionSlug: options.collectionSlug,
|
|
@@ -41,6 +50,7 @@ export async function mintApiKey(options) {
|
|
|
41
50
|
});
|
|
42
51
|
}
|
|
43
52
|
export async function rotateApiKey({ req, collectionSlug, id, tokenPrefix, anyOwner }) {
|
|
53
|
+
requireSessionOwner(req);
|
|
44
54
|
const revoked = await revokeApiKey({
|
|
45
55
|
req,
|
|
46
56
|
collectionSlug,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server/services.ts"],"names":["createApiKeyToken","getApiKeyPrefix","hashApiKeyToken","ApiKeyServiceError","Error","code","
|
|
1
|
+
{"version":3,"sources":["../../src/server/services.ts"],"names":["apiKeyStrategyName","createApiKeyToken","getApiKeyPrefix","hashApiKeyToken","ApiKeyServiceError","Error","code","isApiKeyRequest","req","user","_strategy","requireSessionOwner","owner","id","undefined","mintForOwner","collectionSlug","tokenPrefix","name","token","prefix","doc","frogbot","create","collection","data","tokenHash","overrideAccess","createdAt","mintApiKey","options","rotateApiKey","anyOwner","revoked","revokeApiKey","result","find","depth","limit","where","equals","and","key","docs","revokedAt","Date","toISOString","update"],"mappings":"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","file":"services.js"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frogbotai/plugin-api-keys",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"description": "Multiple named API keys for FrogBot.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Colby Gilbert",
|
|
@@ -32,25 +32,25 @@
|
|
|
32
32
|
"*.css"
|
|
33
33
|
],
|
|
34
34
|
"engines": {
|
|
35
|
-
"node": ">=
|
|
35
|
+
"node": ">=24.21.0"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
|
-
"@payloadcms/ui": "3.90.1",
|
|
39
38
|
"react": "^19.0.1 || ^19.1.2 || ^19.2.1",
|
|
40
39
|
"react-dom": "^19.0.1 || ^19.1.2 || ^19.2.1",
|
|
41
|
-
"@frogbotai/gateway": "0.
|
|
42
|
-
"frogbot": "0.
|
|
40
|
+
"@frogbotai/gateway": "0.35.0",
|
|
41
|
+
"frogbot": "0.35.0",
|
|
42
|
+
"@frogbotai/ui": "0.35.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@payloadcms/ui": "3.90.1",
|
|
46
45
|
"@testing-library/react": "^16.3.0",
|
|
47
46
|
"@types/react": "19.2.14",
|
|
48
|
-
"react": "19.
|
|
49
|
-
"react-dom": "19.
|
|
50
|
-
"typescript": "
|
|
51
|
-
"@frogbotai/
|
|
52
|
-
"@frogbotai/
|
|
53
|
-
"
|
|
47
|
+
"react": "19.3.1",
|
|
48
|
+
"react-dom": "19.3.1",
|
|
49
|
+
"typescript": "6.0.3",
|
|
50
|
+
"@frogbotai/plugin-roles": "0.35.0",
|
|
51
|
+
"@frogbotai/gateway": "0.35.0",
|
|
52
|
+
"@frogbotai/ui": "0.35.0",
|
|
53
|
+
"frogbot": "0.35.0"
|
|
54
54
|
},
|
|
55
55
|
"publishConfig": {
|
|
56
56
|
"access": "public"
|