apiblaze 0.20.21 → 0.20.23
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/dist/index.js +19 -4
- package/package.json +1 -1
- package/dist/react/index.d.mts +0 -205
- package/dist/react/index.d.ts +0 -205
- package/dist/server/index.d.mts +0 -309
- package/dist/server/index.d.ts +0 -309
- package/dist/sidecar/index.d.mts +0 -30
- package/dist/sidecar/index.d.ts +0 -30
package/dist/index.js
CHANGED
|
@@ -1024,7 +1024,7 @@ var import_commander = require("commander");
|
|
|
1024
1024
|
var import_chalk54 = __toESM(require("chalk"));
|
|
1025
1025
|
|
|
1026
1026
|
// package.json
|
|
1027
|
-
var version = "0.20.
|
|
1027
|
+
var version = "0.20.23";
|
|
1028
1028
|
|
|
1029
1029
|
// src/index.ts
|
|
1030
1030
|
init_types();
|
|
@@ -3751,7 +3751,12 @@ async function openServerProxy(project) {
|
|
|
3751
3751
|
proxyUrl: `https://${project.projectId}.abz.run/${version2}/${environment}`,
|
|
3752
3752
|
anon: false,
|
|
3753
3753
|
// Reusing an owned proxy: logged-in apichat doors default to invite-only.
|
|
3754
|
-
access: "invite"
|
|
3754
|
+
access: "invite",
|
|
3755
|
+
// Identity domain — needed to authorize an external client's registration
|
|
3756
|
+
// (and by anything else that acts on the tenant). Dropping these made the
|
|
3757
|
+
// registration authorization silently skip.
|
|
3758
|
+
tenant: tenant2,
|
|
3759
|
+
teamId: project.teamId
|
|
3755
3760
|
};
|
|
3756
3761
|
const spinner = (0, import_ora4.default)("Preparing the chat\u2026").start();
|
|
3757
3762
|
try {
|
|
@@ -3925,7 +3930,12 @@ async function noArgsMenu(opts) {
|
|
|
3925
3930
|
proxyUrl: void 0,
|
|
3926
3931
|
anon: a.anon,
|
|
3927
3932
|
// Saved sessions predate the access field: mirror the provisioning default.
|
|
3928
|
-
access: a.anon ? "open" : "invite"
|
|
3933
|
+
access: a.anon ? "open" : "invite",
|
|
3934
|
+
// The tenant we just re-derived above (and the owning team): without them
|
|
3935
|
+
// the registration authorization can't name a tenant and silently skips.
|
|
3936
|
+
tenant: savedTenant,
|
|
3937
|
+
teamId: resumeTeamId,
|
|
3938
|
+
endUserId: a.endUserId
|
|
3929
3939
|
};
|
|
3930
3940
|
return { p, messages };
|
|
3931
3941
|
}
|
|
@@ -4157,10 +4167,15 @@ async function authorizeClientRegistration(p, cliLabel) {
|
|
|
4157
4167
|
if (!p.consumerAuth) return;
|
|
4158
4168
|
const teamId = p.teamId ?? loadCredentials()?.teamId;
|
|
4159
4169
|
const tenant2 = p.tenant;
|
|
4160
|
-
if (!teamId || !tenant2)
|
|
4170
|
+
if (!teamId || !tenant2) {
|
|
4171
|
+
console.log(import_chalk14.default.dim(` (Can't pre-authorize ${cliLabel}'s registration \u2014 tenant unknown for this proxy. If sign-in says the app needs verifying: apiblaze allowoauthregistration --tenant <slug>, then retry.)`));
|
|
4172
|
+
return;
|
|
4173
|
+
}
|
|
4161
4174
|
const ok = await openRegistrationAuthorization(teamId, tenant2, 600);
|
|
4162
4175
|
if (ok) {
|
|
4163
4176
|
console.log(import_chalk14.default.dim(` Authorized ${cliLabel}'s sign-in registration on tenant ${import_chalk14.default.bold(tenant2)} (single use).`));
|
|
4177
|
+
} else {
|
|
4178
|
+
console.log(import_chalk14.default.yellow(` Could not pre-authorize the registration on ${tenant2} \u2014 if sign-in says the app needs verifying, run: apiblaze allowoauthregistration --tenant ${tenant2}`));
|
|
4164
4179
|
}
|
|
4165
4180
|
}
|
|
4166
4181
|
async function ensureInstallableDoor(p, opts) {
|
package/package.json
CHANGED
package/dist/react/index.d.mts
DELETED
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* apiblaze/react — <UsersGroupsWidget/>. Drop it into your site next to (or
|
|
5
|
-
* instead of) <ApiKeyWidget/>; it talks ONLY to your own backend route (which
|
|
6
|
-
* holds the same one CP widget key, mounted via createApiblazeGroups().handler).
|
|
7
|
-
*
|
|
8
|
-
* import { UsersGroupsWidget } from 'apiblaze/react';
|
|
9
|
-
* <UsersGroupsWidget theme={{ accent: '#e11d48' }} />
|
|
10
|
-
*
|
|
11
|
-
* Who sees what: apiblaze authorizes the LOGGED-IN USER server-side — only a
|
|
12
|
-
* tenant admin (an email on the tenant's admin-emails allowlist) can manage.
|
|
13
|
-
* Anyone else gets the "admin access pending" panel; nothing in this component
|
|
14
|
-
* (or your page) can elevate them.
|
|
15
|
-
*
|
|
16
|
-
* Default view = flat groups + members (the right ceiling for a handful of
|
|
17
|
-
* admins). Delegation (per-group admins) and nesting (subgroups) are there,
|
|
18
|
-
* one level down. Strictly users + groups — no authorization-rule authoring.
|
|
19
|
-
*
|
|
20
|
-
* `endpoint` defaults to /api/apiblaze/groups.
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
type UsersGroupsWidgetTheme = ApiKeyWidgetTheme;
|
|
24
|
-
interface UsersGroupsWidgetProps {
|
|
25
|
-
endpoint?: string;
|
|
26
|
-
theme?: UsersGroupsWidgetTheme;
|
|
27
|
-
/** Heading text. Default "Users & groups". */
|
|
28
|
-
title?: string;
|
|
29
|
-
/** Auto-expand the group with this NAME on first load (if it exists) — e.g.
|
|
30
|
-
* a demo landing the user on the group it just talked about. One-shot: the
|
|
31
|
-
* user can still collapse it; later refreshes don't force it back open. */
|
|
32
|
-
defaultOpenGroup?: string;
|
|
33
|
-
className?: string;
|
|
34
|
-
}
|
|
35
|
-
interface UsersGroupsWidgetHandle {
|
|
36
|
-
refresh: () => void;
|
|
37
|
-
}
|
|
38
|
-
declare const UsersGroupsWidget: React.ForwardRefExoticComponent<UsersGroupsWidgetProps & React.RefAttributes<UsersGroupsWidgetHandle>>;
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* apiblaze/react — <ChatWidget/>. The third widget face (with <ApiKeyWidget/>
|
|
42
|
-
* and <UsersGroupsWidget/>): a drop-in AI chat window for an API proxied
|
|
43
|
-
* through APIblaze, speaking the AI SDK UI Message Stream wire protocol
|
|
44
|
-
* (specs/chatwidget/sse/wire-compatibility-with-AI-SDK-UI.MD).
|
|
45
|
-
*
|
|
46
|
-
* Two integration modes (chatwidget_prd.md):
|
|
47
|
-
*
|
|
48
|
-
* MODE 1 — direct (JWT-door proxy; zero backend code). The end user is
|
|
49
|
-
* already logged into YOUR site; pass their session token and the proxy
|
|
50
|
-
* verifies it against the issuer you registered (iam_v2 §4.4):
|
|
51
|
-
*
|
|
52
|
-
* <ChatWidget project="ninopizza" getToken={() => session.token} />
|
|
53
|
-
*
|
|
54
|
-
* MODE 2 — relay (api_key-door proxy). Mount createApiblazeChat() from
|
|
55
|
-
* apiblaze/server (it holds the key server-side) and point the widget at it:
|
|
56
|
-
*
|
|
57
|
-
* <ChatWidget endpoint="/api/apiblaze/chat" />
|
|
58
|
-
*
|
|
59
|
-
* Zero runtime dependencies, inline styles, white-label through `theme` tokens —
|
|
60
|
-
* the same packaging discipline as the other two widgets. Producers who want a
|
|
61
|
-
* fully custom UI don't need this component at all: the endpoint speaks the
|
|
62
|
-
* standard protocol, so assistant-ui / useChat work directly against it.
|
|
63
|
-
*
|
|
64
|
-
* Safety properties this component RELIES ON (and never re-implements):
|
|
65
|
-
* tool calls execute server-side with the caller's own credential (OpenFGA
|
|
66
|
-
* applies), funding/quotas are the proxy's chat_sponsorship, and the system
|
|
67
|
-
* prompt (+ producer steering) is server-owned — nothing here can change it.
|
|
68
|
-
*/
|
|
69
|
-
|
|
70
|
-
interface ChatWidgetTheme {
|
|
71
|
-
/** Accent / primary action color (send button, launcher). */
|
|
72
|
-
accent?: string;
|
|
73
|
-
/** Text/icon color ON accent surfaces. Default #fff. */
|
|
74
|
-
accentText?: string;
|
|
75
|
-
/** Panel body color. */
|
|
76
|
-
surface?: string;
|
|
77
|
-
/** Header strip color. Defaults to `surface`. */
|
|
78
|
-
headerBackground?: string;
|
|
79
|
-
/** Primary text color. */
|
|
80
|
-
text?: string;
|
|
81
|
-
/** Secondary / muted text color. */
|
|
82
|
-
muted?: string;
|
|
83
|
-
/** Border + divider color. */
|
|
84
|
-
border?: string;
|
|
85
|
-
/** User bubble background / text. */
|
|
86
|
-
userBubble?: string;
|
|
87
|
-
userBubbleText?: string;
|
|
88
|
-
/** Assistant bubble background / text. */
|
|
89
|
-
assistantBubble?: string;
|
|
90
|
-
assistantBubbleText?: string;
|
|
91
|
-
/** Floating launcher colors (bubble mode). */
|
|
92
|
-
launcherBackground?: string;
|
|
93
|
-
launcherIcon?: string;
|
|
94
|
-
/** Corner radius of the panel, e.g. "16px". */
|
|
95
|
-
radius?: string;
|
|
96
|
-
/** Body font stack. */
|
|
97
|
-
fontFamily?: string;
|
|
98
|
-
/** Monospace stack for code. */
|
|
99
|
-
monoFontFamily?: string;
|
|
100
|
-
}
|
|
101
|
-
interface ChatWidgetProps {
|
|
102
|
-
/** MODE 2: your mounted createApiblazeChat() route. */
|
|
103
|
-
endpoint?: string;
|
|
104
|
-
/** MODE 1: project handle — the widget talks straight to {project}.mcp.{host}. */
|
|
105
|
-
project?: string;
|
|
106
|
-
/** MODE 1: returns the end user's CURRENT session JWT (your own issuer,
|
|
107
|
-
* registered on the proxy). Called per message so refreshed tokens win. */
|
|
108
|
-
getToken?: () => string | Promise<string>;
|
|
109
|
-
/** MODE 1 extras. */
|
|
110
|
-
apiVersion?: string;
|
|
111
|
-
environment?: string;
|
|
112
|
-
host?: string;
|
|
113
|
-
/** 'bubble' = floating launcher (default) · 'inline' = a card in your layout. */
|
|
114
|
-
mode?: 'bubble' | 'inline';
|
|
115
|
-
/** Heading. Default "Chat". */
|
|
116
|
-
title?: string;
|
|
117
|
-
/** Emoji/short avatar in the header + launcher. Default "💬". */
|
|
118
|
-
avatar?: string;
|
|
119
|
-
/** First assistant message shown before any exchange. */
|
|
120
|
-
welcome?: string;
|
|
121
|
-
/** Suggested prompt chips (≤4 shown). */
|
|
122
|
-
suggestions?: string[];
|
|
123
|
-
/** Inline mode panel height. Default 560. */
|
|
124
|
-
height?: number;
|
|
125
|
-
/** Bubble mode: offset from the viewport edge, px. Default 20. */
|
|
126
|
-
offset?: number;
|
|
127
|
-
/** Bubble mode: z-index of launcher+panel. Default 2147483000. */
|
|
128
|
-
zIndex?: number;
|
|
129
|
-
/** Show the "powered by APIblaze" footer credit. Default true. */
|
|
130
|
-
branding?: boolean;
|
|
131
|
-
theme?: ChatWidgetTheme;
|
|
132
|
-
className?: string;
|
|
133
|
-
/** sessionStorage key override. DEFAULT derives from project/endpoint ONLY —
|
|
134
|
-
* on a shared machine that lets the next signed-in user read the previous
|
|
135
|
-
* user's transcript in the same tab, so pass a PER-USER key (e.g.
|
|
136
|
-
* `apiblaze-chat:myapp:${user.id}`) whenever your page has logins. Two
|
|
137
|
-
* widgets with the same key share (and clobber) one transcript. */
|
|
138
|
-
storageKey?: string;
|
|
139
|
-
/** Client-side per-message length hint (server enforces its own cap). Default 2000. */
|
|
140
|
-
maxMessageLength?: number;
|
|
141
|
-
}
|
|
142
|
-
interface ChatWidgetHandle {
|
|
143
|
-
open: () => void;
|
|
144
|
-
close: () => void;
|
|
145
|
-
clear: () => void;
|
|
146
|
-
}
|
|
147
|
-
declare const ChatWidget: React.ForwardRefExoticComponent<ChatWidgetProps & React.RefAttributes<ChatWidgetHandle>>;
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* apiblaze/react — <ApiKeyWidget/>. Drop it into your site (e.g. resiresi.com);
|
|
151
|
-
* it talks ONLY to your own backend route (which holds the CP key). Shows the
|
|
152
|
-
* logged-in user their API keys as a simple list with one always-visible
|
|
153
|
-
* "Create key" action, plus per-key show / rotate / revoke.
|
|
154
|
-
*
|
|
155
|
-
* import { ApiKeyWidget } from 'apiblaze/react';
|
|
156
|
-
* <ApiKeyWidget theme={{ accent: '#e11d48' }} />
|
|
157
|
-
*
|
|
158
|
-
* Fully white-labelable through `theme` alone — every font and color is a token,
|
|
159
|
-
* so you can match your brand (including a dark "codebox" look) without forking
|
|
160
|
-
* the component. See ApiKeyWidgetTheme.
|
|
161
|
-
*
|
|
162
|
-
* `endpoint` defaults to /api/apiblaze/keys (where you mounted createApiblazeKeys().handler).
|
|
163
|
-
*/
|
|
164
|
-
|
|
165
|
-
interface ApiKeyWidgetTheme {
|
|
166
|
-
/** Accent / primary action color. */
|
|
167
|
-
accent?: string;
|
|
168
|
-
/** Text/icon color ON accent buttons. Default #fff. */
|
|
169
|
-
accentText?: string;
|
|
170
|
-
/** Page color behind the card. Default transparent. */
|
|
171
|
-
background?: string;
|
|
172
|
-
/** Card body color. */
|
|
173
|
-
surface?: string;
|
|
174
|
-
/** Header strip color. Defaults to `surface` when unset. */
|
|
175
|
-
headerBackground?: string;
|
|
176
|
-
/** Primary text color. */
|
|
177
|
-
text?: string;
|
|
178
|
-
/** Secondary / muted text color. */
|
|
179
|
-
muted?: string;
|
|
180
|
-
/** Border + divider color. */
|
|
181
|
-
border?: string;
|
|
182
|
-
/** Destructive (revoke) color. */
|
|
183
|
-
danger?: string;
|
|
184
|
-
/** Positive (copied) color. */
|
|
185
|
-
success?: string;
|
|
186
|
-
/** Corner radius of the card, e.g. "12px". */
|
|
187
|
-
radius?: string;
|
|
188
|
-
/** Body font stack. */
|
|
189
|
-
fontFamily?: string;
|
|
190
|
-
/** Monospace font stack for keys and secrets. */
|
|
191
|
-
monoFontFamily?: string;
|
|
192
|
-
}
|
|
193
|
-
interface ApiKeyWidgetProps {
|
|
194
|
-
endpoint?: string;
|
|
195
|
-
theme?: ApiKeyWidgetTheme;
|
|
196
|
-
/** Heading text. Default "Your API keys". */
|
|
197
|
-
title?: string;
|
|
198
|
-
className?: string;
|
|
199
|
-
}
|
|
200
|
-
interface ApiKeyWidgetHandle {
|
|
201
|
-
refresh: () => void;
|
|
202
|
-
}
|
|
203
|
-
declare const ApiKeyWidget: React.ForwardRefExoticComponent<ApiKeyWidgetProps & React.RefAttributes<ApiKeyWidgetHandle>>;
|
|
204
|
-
|
|
205
|
-
export { ApiKeyWidget, type ApiKeyWidgetHandle, type ApiKeyWidgetProps, type ApiKeyWidgetTheme, ChatWidget, type ChatWidgetHandle, type ChatWidgetProps, type ChatWidgetTheme, UsersGroupsWidget, type UsersGroupsWidgetHandle, type UsersGroupsWidgetProps, type UsersGroupsWidgetTheme, ApiKeyWidget as default };
|
package/dist/react/index.d.ts
DELETED
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* apiblaze/react — <UsersGroupsWidget/>. Drop it into your site next to (or
|
|
5
|
-
* instead of) <ApiKeyWidget/>; it talks ONLY to your own backend route (which
|
|
6
|
-
* holds the same one CP widget key, mounted via createApiblazeGroups().handler).
|
|
7
|
-
*
|
|
8
|
-
* import { UsersGroupsWidget } from 'apiblaze/react';
|
|
9
|
-
* <UsersGroupsWidget theme={{ accent: '#e11d48' }} />
|
|
10
|
-
*
|
|
11
|
-
* Who sees what: apiblaze authorizes the LOGGED-IN USER server-side — only a
|
|
12
|
-
* tenant admin (an email on the tenant's admin-emails allowlist) can manage.
|
|
13
|
-
* Anyone else gets the "admin access pending" panel; nothing in this component
|
|
14
|
-
* (or your page) can elevate them.
|
|
15
|
-
*
|
|
16
|
-
* Default view = flat groups + members (the right ceiling for a handful of
|
|
17
|
-
* admins). Delegation (per-group admins) and nesting (subgroups) are there,
|
|
18
|
-
* one level down. Strictly users + groups — no authorization-rule authoring.
|
|
19
|
-
*
|
|
20
|
-
* `endpoint` defaults to /api/apiblaze/groups.
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
type UsersGroupsWidgetTheme = ApiKeyWidgetTheme;
|
|
24
|
-
interface UsersGroupsWidgetProps {
|
|
25
|
-
endpoint?: string;
|
|
26
|
-
theme?: UsersGroupsWidgetTheme;
|
|
27
|
-
/** Heading text. Default "Users & groups". */
|
|
28
|
-
title?: string;
|
|
29
|
-
/** Auto-expand the group with this NAME on first load (if it exists) — e.g.
|
|
30
|
-
* a demo landing the user on the group it just talked about. One-shot: the
|
|
31
|
-
* user can still collapse it; later refreshes don't force it back open. */
|
|
32
|
-
defaultOpenGroup?: string;
|
|
33
|
-
className?: string;
|
|
34
|
-
}
|
|
35
|
-
interface UsersGroupsWidgetHandle {
|
|
36
|
-
refresh: () => void;
|
|
37
|
-
}
|
|
38
|
-
declare const UsersGroupsWidget: React.ForwardRefExoticComponent<UsersGroupsWidgetProps & React.RefAttributes<UsersGroupsWidgetHandle>>;
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* apiblaze/react — <ChatWidget/>. The third widget face (with <ApiKeyWidget/>
|
|
42
|
-
* and <UsersGroupsWidget/>): a drop-in AI chat window for an API proxied
|
|
43
|
-
* through APIblaze, speaking the AI SDK UI Message Stream wire protocol
|
|
44
|
-
* (specs/chatwidget/sse/wire-compatibility-with-AI-SDK-UI.MD).
|
|
45
|
-
*
|
|
46
|
-
* Two integration modes (chatwidget_prd.md):
|
|
47
|
-
*
|
|
48
|
-
* MODE 1 — direct (JWT-door proxy; zero backend code). The end user is
|
|
49
|
-
* already logged into YOUR site; pass their session token and the proxy
|
|
50
|
-
* verifies it against the issuer you registered (iam_v2 §4.4):
|
|
51
|
-
*
|
|
52
|
-
* <ChatWidget project="ninopizza" getToken={() => session.token} />
|
|
53
|
-
*
|
|
54
|
-
* MODE 2 — relay (api_key-door proxy). Mount createApiblazeChat() from
|
|
55
|
-
* apiblaze/server (it holds the key server-side) and point the widget at it:
|
|
56
|
-
*
|
|
57
|
-
* <ChatWidget endpoint="/api/apiblaze/chat" />
|
|
58
|
-
*
|
|
59
|
-
* Zero runtime dependencies, inline styles, white-label through `theme` tokens —
|
|
60
|
-
* the same packaging discipline as the other two widgets. Producers who want a
|
|
61
|
-
* fully custom UI don't need this component at all: the endpoint speaks the
|
|
62
|
-
* standard protocol, so assistant-ui / useChat work directly against it.
|
|
63
|
-
*
|
|
64
|
-
* Safety properties this component RELIES ON (and never re-implements):
|
|
65
|
-
* tool calls execute server-side with the caller's own credential (OpenFGA
|
|
66
|
-
* applies), funding/quotas are the proxy's chat_sponsorship, and the system
|
|
67
|
-
* prompt (+ producer steering) is server-owned — nothing here can change it.
|
|
68
|
-
*/
|
|
69
|
-
|
|
70
|
-
interface ChatWidgetTheme {
|
|
71
|
-
/** Accent / primary action color (send button, launcher). */
|
|
72
|
-
accent?: string;
|
|
73
|
-
/** Text/icon color ON accent surfaces. Default #fff. */
|
|
74
|
-
accentText?: string;
|
|
75
|
-
/** Panel body color. */
|
|
76
|
-
surface?: string;
|
|
77
|
-
/** Header strip color. Defaults to `surface`. */
|
|
78
|
-
headerBackground?: string;
|
|
79
|
-
/** Primary text color. */
|
|
80
|
-
text?: string;
|
|
81
|
-
/** Secondary / muted text color. */
|
|
82
|
-
muted?: string;
|
|
83
|
-
/** Border + divider color. */
|
|
84
|
-
border?: string;
|
|
85
|
-
/** User bubble background / text. */
|
|
86
|
-
userBubble?: string;
|
|
87
|
-
userBubbleText?: string;
|
|
88
|
-
/** Assistant bubble background / text. */
|
|
89
|
-
assistantBubble?: string;
|
|
90
|
-
assistantBubbleText?: string;
|
|
91
|
-
/** Floating launcher colors (bubble mode). */
|
|
92
|
-
launcherBackground?: string;
|
|
93
|
-
launcherIcon?: string;
|
|
94
|
-
/** Corner radius of the panel, e.g. "16px". */
|
|
95
|
-
radius?: string;
|
|
96
|
-
/** Body font stack. */
|
|
97
|
-
fontFamily?: string;
|
|
98
|
-
/** Monospace stack for code. */
|
|
99
|
-
monoFontFamily?: string;
|
|
100
|
-
}
|
|
101
|
-
interface ChatWidgetProps {
|
|
102
|
-
/** MODE 2: your mounted createApiblazeChat() route. */
|
|
103
|
-
endpoint?: string;
|
|
104
|
-
/** MODE 1: project handle — the widget talks straight to {project}.mcp.{host}. */
|
|
105
|
-
project?: string;
|
|
106
|
-
/** MODE 1: returns the end user's CURRENT session JWT (your own issuer,
|
|
107
|
-
* registered on the proxy). Called per message so refreshed tokens win. */
|
|
108
|
-
getToken?: () => string | Promise<string>;
|
|
109
|
-
/** MODE 1 extras. */
|
|
110
|
-
apiVersion?: string;
|
|
111
|
-
environment?: string;
|
|
112
|
-
host?: string;
|
|
113
|
-
/** 'bubble' = floating launcher (default) · 'inline' = a card in your layout. */
|
|
114
|
-
mode?: 'bubble' | 'inline';
|
|
115
|
-
/** Heading. Default "Chat". */
|
|
116
|
-
title?: string;
|
|
117
|
-
/** Emoji/short avatar in the header + launcher. Default "💬". */
|
|
118
|
-
avatar?: string;
|
|
119
|
-
/** First assistant message shown before any exchange. */
|
|
120
|
-
welcome?: string;
|
|
121
|
-
/** Suggested prompt chips (≤4 shown). */
|
|
122
|
-
suggestions?: string[];
|
|
123
|
-
/** Inline mode panel height. Default 560. */
|
|
124
|
-
height?: number;
|
|
125
|
-
/** Bubble mode: offset from the viewport edge, px. Default 20. */
|
|
126
|
-
offset?: number;
|
|
127
|
-
/** Bubble mode: z-index of launcher+panel. Default 2147483000. */
|
|
128
|
-
zIndex?: number;
|
|
129
|
-
/** Show the "powered by APIblaze" footer credit. Default true. */
|
|
130
|
-
branding?: boolean;
|
|
131
|
-
theme?: ChatWidgetTheme;
|
|
132
|
-
className?: string;
|
|
133
|
-
/** sessionStorage key override. DEFAULT derives from project/endpoint ONLY —
|
|
134
|
-
* on a shared machine that lets the next signed-in user read the previous
|
|
135
|
-
* user's transcript in the same tab, so pass a PER-USER key (e.g.
|
|
136
|
-
* `apiblaze-chat:myapp:${user.id}`) whenever your page has logins. Two
|
|
137
|
-
* widgets with the same key share (and clobber) one transcript. */
|
|
138
|
-
storageKey?: string;
|
|
139
|
-
/** Client-side per-message length hint (server enforces its own cap). Default 2000. */
|
|
140
|
-
maxMessageLength?: number;
|
|
141
|
-
}
|
|
142
|
-
interface ChatWidgetHandle {
|
|
143
|
-
open: () => void;
|
|
144
|
-
close: () => void;
|
|
145
|
-
clear: () => void;
|
|
146
|
-
}
|
|
147
|
-
declare const ChatWidget: React.ForwardRefExoticComponent<ChatWidgetProps & React.RefAttributes<ChatWidgetHandle>>;
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* apiblaze/react — <ApiKeyWidget/>. Drop it into your site (e.g. resiresi.com);
|
|
151
|
-
* it talks ONLY to your own backend route (which holds the CP key). Shows the
|
|
152
|
-
* logged-in user their API keys as a simple list with one always-visible
|
|
153
|
-
* "Create key" action, plus per-key show / rotate / revoke.
|
|
154
|
-
*
|
|
155
|
-
* import { ApiKeyWidget } from 'apiblaze/react';
|
|
156
|
-
* <ApiKeyWidget theme={{ accent: '#e11d48' }} />
|
|
157
|
-
*
|
|
158
|
-
* Fully white-labelable through `theme` alone — every font and color is a token,
|
|
159
|
-
* so you can match your brand (including a dark "codebox" look) without forking
|
|
160
|
-
* the component. See ApiKeyWidgetTheme.
|
|
161
|
-
*
|
|
162
|
-
* `endpoint` defaults to /api/apiblaze/keys (where you mounted createApiblazeKeys().handler).
|
|
163
|
-
*/
|
|
164
|
-
|
|
165
|
-
interface ApiKeyWidgetTheme {
|
|
166
|
-
/** Accent / primary action color. */
|
|
167
|
-
accent?: string;
|
|
168
|
-
/** Text/icon color ON accent buttons. Default #fff. */
|
|
169
|
-
accentText?: string;
|
|
170
|
-
/** Page color behind the card. Default transparent. */
|
|
171
|
-
background?: string;
|
|
172
|
-
/** Card body color. */
|
|
173
|
-
surface?: string;
|
|
174
|
-
/** Header strip color. Defaults to `surface` when unset. */
|
|
175
|
-
headerBackground?: string;
|
|
176
|
-
/** Primary text color. */
|
|
177
|
-
text?: string;
|
|
178
|
-
/** Secondary / muted text color. */
|
|
179
|
-
muted?: string;
|
|
180
|
-
/** Border + divider color. */
|
|
181
|
-
border?: string;
|
|
182
|
-
/** Destructive (revoke) color. */
|
|
183
|
-
danger?: string;
|
|
184
|
-
/** Positive (copied) color. */
|
|
185
|
-
success?: string;
|
|
186
|
-
/** Corner radius of the card, e.g. "12px". */
|
|
187
|
-
radius?: string;
|
|
188
|
-
/** Body font stack. */
|
|
189
|
-
fontFamily?: string;
|
|
190
|
-
/** Monospace font stack for keys and secrets. */
|
|
191
|
-
monoFontFamily?: string;
|
|
192
|
-
}
|
|
193
|
-
interface ApiKeyWidgetProps {
|
|
194
|
-
endpoint?: string;
|
|
195
|
-
theme?: ApiKeyWidgetTheme;
|
|
196
|
-
/** Heading text. Default "Your API keys". */
|
|
197
|
-
title?: string;
|
|
198
|
-
className?: string;
|
|
199
|
-
}
|
|
200
|
-
interface ApiKeyWidgetHandle {
|
|
201
|
-
refresh: () => void;
|
|
202
|
-
}
|
|
203
|
-
declare const ApiKeyWidget: React.ForwardRefExoticComponent<ApiKeyWidgetProps & React.RefAttributes<ApiKeyWidgetHandle>>;
|
|
204
|
-
|
|
205
|
-
export { ApiKeyWidget, type ApiKeyWidgetHandle, type ApiKeyWidgetProps, type ApiKeyWidgetTheme, ChatWidget, type ChatWidgetHandle, type ChatWidgetProps, type ChatWidgetTheme, UsersGroupsWidget, type UsersGroupsWidgetHandle, type UsersGroupsWidgetProps, type UsersGroupsWidgetTheme, ApiKeyWidget as default };
|
package/dist/server/index.d.mts
DELETED
|
@@ -1,309 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* apiblaze/server — SHARED widget-server substrate.
|
|
3
|
-
*
|
|
4
|
-
* One CP credential, one getUser contract, one ensure-tenant/ensure-user path —
|
|
5
|
-
* consumed by BOTH widget faces (`createApiblazeKeys` and `createApiblazeGroups`).
|
|
6
|
-
* Factored per iam_toolkit_spec ("share, don't fork" — copy-forking this
|
|
7
|
-
* bootstrap is a spec failure).
|
|
8
|
-
*
|
|
9
|
-
* Trust model: the CP key stays server-side and vouches for the CHANNEL; the
|
|
10
|
-
* acting end-user rides X-End-User-Id / X-End-User-Email. On the apikeys plane
|
|
11
|
-
* the end-user header only narrows (self-scoped key ops); on the iam plane it
|
|
12
|
-
* IS the principal (iam-worker independently checks the resolved user's
|
|
13
|
-
* apiblaze_admins membership before any group op).
|
|
14
|
-
*/
|
|
15
|
-
interface AppUser {
|
|
16
|
-
/** The producer's stable id for the consumer COMPANY — becomes the tenant (isolation). */
|
|
17
|
-
tenant: string;
|
|
18
|
-
/** The producer's stable id for the PERSON — the acting end-user. */
|
|
19
|
-
userId: string;
|
|
20
|
-
/** Optional; REQUIRED in practice for the groups widget — tenant-admin status
|
|
21
|
-
* is granted by email (the tenant's admin-emails allowlist). */
|
|
22
|
-
email?: string;
|
|
23
|
-
/** Optional display name (cosmetic). */
|
|
24
|
-
label?: string;
|
|
25
|
-
/** Key-widget eligibility (see createApiblazeKeys). Ignored by the groups widget. */
|
|
26
|
-
keyTypes?: string[] | false;
|
|
27
|
-
/** Any extra fields your eligibility logic wants (e.g. isEngineer). */
|
|
28
|
-
[k: string]: unknown;
|
|
29
|
-
}
|
|
30
|
-
declare class PlaneError extends Error {
|
|
31
|
-
status: number;
|
|
32
|
-
detail: string;
|
|
33
|
-
constructor(status: number, detail: string);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* createApiblazeGroups — the server-side half of the Users & Groups widget
|
|
38
|
-
* (<UsersGroupsWidget/>), riding the SAME shared substrate (core.ts) and the
|
|
39
|
-
* SAME one CP widget credential as the API-key widget.
|
|
40
|
-
*
|
|
41
|
-
* Usage (Next.js App Router — app/api/apiblaze/groups/route.ts):
|
|
42
|
-
*
|
|
43
|
-
* import { createApiblazeGroups } from 'apiblaze/server';
|
|
44
|
-
* const groups = createApiblazeGroups({
|
|
45
|
-
* cpKey: process.env.APIBLAZE_CP_KEY!, // the SAME key the key widget uses
|
|
46
|
-
* getUser: async () => { ...same contract... return { tenant, userId, email } },
|
|
47
|
-
* });
|
|
48
|
-
* export const GET = groups.handler;
|
|
49
|
-
* export const POST = groups.handler;
|
|
50
|
-
*
|
|
51
|
-
* AUTHORIZATION MODEL (iam_toolkit_spec): unlike key ops (self-scoped), group
|
|
52
|
-
* admin ops are tenant-wide — so the acting END-USER IS THE PRINCIPAL. This
|
|
53
|
-
* server forwards the session user via X-End-User-Id/-Email; apiblaze's iam
|
|
54
|
-
* plane independently verifies that user is a TENANT ADMIN (apiblaze_admins
|
|
55
|
-
* member, granted via the tenant's admin-emails allowlist) before any op. A
|
|
56
|
-
* non-admin gets `access: 'pending'` — nothing here can elevate them, and no
|
|
57
|
-
* producer-side flag can either. The CP key is only the channel.
|
|
58
|
-
*
|
|
59
|
-
* Strictly users + groups — NO authorization-rule authoring (that stays in
|
|
60
|
-
* `apiblaze authz` / the dashboard).
|
|
61
|
-
*/
|
|
62
|
-
|
|
63
|
-
interface ApiblazeGroupsConfig {
|
|
64
|
-
/** The producer CP key — the SAME widget key the API-key widget uses. Server-only. */
|
|
65
|
-
cpKey: string;
|
|
66
|
-
/** Return the logged-in user from the request/session, or null if unauthenticated.
|
|
67
|
-
* `email` is how tenant-admin status is granted (admin-emails allowlist) — pass it. */
|
|
68
|
-
getUser: (req: Request) => Promise<AppUser | null> | AppUser | null;
|
|
69
|
-
/** Override the apikeys plane base (tenant/user provisioning). Default https://apikeys.apiblaze.com */
|
|
70
|
-
base?: string;
|
|
71
|
-
/** Override the iam plane base. Default https://iam.apiblaze.com */
|
|
72
|
-
iamBase?: string;
|
|
73
|
-
}
|
|
74
|
-
type GroupsAction = {
|
|
75
|
-
action: 'snapshot';
|
|
76
|
-
} | {
|
|
77
|
-
action: 'list-groups';
|
|
78
|
-
offset?: number;
|
|
79
|
-
q?: string;
|
|
80
|
-
} | {
|
|
81
|
-
action: 'search-users';
|
|
82
|
-
q?: string;
|
|
83
|
-
limit?: number;
|
|
84
|
-
offset?: number;
|
|
85
|
-
} | {
|
|
86
|
-
action: 'list-observed';
|
|
87
|
-
offset?: number;
|
|
88
|
-
q?: string;
|
|
89
|
-
} | {
|
|
90
|
-
action: 'group-members';
|
|
91
|
-
groupId: string;
|
|
92
|
-
offset?: number;
|
|
93
|
-
} | {
|
|
94
|
-
action: 'create-group';
|
|
95
|
-
name: string;
|
|
96
|
-
description?: string;
|
|
97
|
-
} | {
|
|
98
|
-
action: 'rename-group';
|
|
99
|
-
groupId: string;
|
|
100
|
-
name?: string;
|
|
101
|
-
description?: string;
|
|
102
|
-
} | {
|
|
103
|
-
action: 'delete-group';
|
|
104
|
-
groupId: string;
|
|
105
|
-
} | {
|
|
106
|
-
action: 'add-member';
|
|
107
|
-
groupId: string;
|
|
108
|
-
abzSub: string;
|
|
109
|
-
role?: 'member' | 'admin';
|
|
110
|
-
} | {
|
|
111
|
-
action: 'change-role';
|
|
112
|
-
groupId: string;
|
|
113
|
-
abzSub: string;
|
|
114
|
-
role: 'member' | 'admin';
|
|
115
|
-
} | {
|
|
116
|
-
action: 'remove-member';
|
|
117
|
-
groupId: string;
|
|
118
|
-
abzSub: string;
|
|
119
|
-
} | {
|
|
120
|
-
action: 'add-subgroup';
|
|
121
|
-
groupId: string;
|
|
122
|
-
childGroupId: string;
|
|
123
|
-
} | {
|
|
124
|
-
action: 'remove-subgroup';
|
|
125
|
-
groupId: string;
|
|
126
|
-
childGroupId: string;
|
|
127
|
-
} | {
|
|
128
|
-
action: 'group-detail';
|
|
129
|
-
groupId: string;
|
|
130
|
-
} | {
|
|
131
|
-
action: 'provision-observed';
|
|
132
|
-
consumerUserId: string;
|
|
133
|
-
email?: string;
|
|
134
|
-
displayName?: string;
|
|
135
|
-
groups?: string[];
|
|
136
|
-
} | {
|
|
137
|
-
action: 'create-user';
|
|
138
|
-
ref: string;
|
|
139
|
-
displayName?: string;
|
|
140
|
-
} | {
|
|
141
|
-
action: 'list-admins';
|
|
142
|
-
} | {
|
|
143
|
-
action: 'add-admin';
|
|
144
|
-
email: string;
|
|
145
|
-
} | {
|
|
146
|
-
action: 'remove-admin';
|
|
147
|
-
email: string;
|
|
148
|
-
};
|
|
149
|
-
declare function createApiblazeGroups(cfg: ApiblazeGroupsConfig): {
|
|
150
|
-
handler: (req: Request) => Promise<Response>;
|
|
151
|
-
run: (user: AppUser, op: GroupsAction) => Promise<{
|
|
152
|
-
status: number;
|
|
153
|
-
data: unknown;
|
|
154
|
-
}>;
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* createApiblazeChat — the server-side half of <ChatWidget/> for API-KEY-door
|
|
159
|
-
* proxies (chatwidget_prd.md, Mode 2 "relay"). JWT-door proxies don't need this
|
|
160
|
-
* file at all: the widget sends the end user's own session token straight to
|
|
161
|
-
* the proxy (Mode 1) and per-person quotas/authorization fall out for free.
|
|
162
|
-
*
|
|
163
|
-
* What the relay does — and ALL it does:
|
|
164
|
-
* 1. resolves YOUR user from YOUR session (the same getUser contract as
|
|
165
|
-
* createApiblazeKeys / createApiblazeGroups),
|
|
166
|
-
* 2. attaches the producer DP key (server-only) + X-End-User-Id,
|
|
167
|
-
* 3. PIPES the SSE stream through untouched (streams pass through Next.js
|
|
168
|
-
* route handlers natively — never buffer, never re-frame).
|
|
169
|
-
*
|
|
170
|
-
* DOCUMENTED TRADEOFFS (say them, don't bury them): behind ONE relay key,
|
|
171
|
-
* · the proxy's chat quota meters ALL your end users into ONE daily bucket;
|
|
172
|
-
* · tool calls carry that key's authority (specs/chat_funding.MD: metering
|
|
173
|
-
* keys on the credential; the asserted X-End-User-Id proves nothing);
|
|
174
|
-
* · chat is ONE TURN AT A TIME site-wide — the anti-burst in-flight lock is
|
|
175
|
-
* per credential, so while one user's turn streams (seconds), another
|
|
176
|
-
* user's send is politely refused ("a previous message is still being
|
|
177
|
-
* processed"). Fine for a demo or a low-traffic page; NOT for a busy site.
|
|
178
|
-
* Want per-person buckets, per-person authorization, and real concurrency?
|
|
179
|
-
* Use Mode 1 (register your issuer on the proxy — the user's own JWT is the
|
|
180
|
-
* credential), or mint per-user keys via the key-widget plane.
|
|
181
|
-
*
|
|
182
|
-
* // app/api/apiblaze/chat/route.ts
|
|
183
|
-
* import { createApiblazeChat } from 'apiblaze/server';
|
|
184
|
-
* const chat = createApiblazeChat({
|
|
185
|
-
* project: 'ninopizza',
|
|
186
|
-
* apiKey: process.env.APIBLAZE_DP_KEY!, // a DP key for that proxy — server-only
|
|
187
|
-
* getUser: async (req) => ({ userId: (await session(req)).userId }),
|
|
188
|
-
* });
|
|
189
|
-
* export const POST = chat.handler;
|
|
190
|
-
*/
|
|
191
|
-
interface ChatRelayUser {
|
|
192
|
-
/** Your stable id for the PERSON — forwarded as X-End-User-Id so the proxy's
|
|
193
|
-
* identity gates (identified_traffic_only / pre-approval) and the upstream's
|
|
194
|
-
* x-end-user-id contract see it. */
|
|
195
|
-
userId: string;
|
|
196
|
-
/** Optional display email/label — NOT forwarded; reserved for future use. */
|
|
197
|
-
email?: string;
|
|
198
|
-
}
|
|
199
|
-
interface ApiblazeChatConfig {
|
|
200
|
-
/** Project handle (the proxy's subdomain). */
|
|
201
|
-
project: string;
|
|
202
|
-
/** A DP api key for that proxy. SERVER-ONLY — never expose it to the browser;
|
|
203
|
-
* the whole point of this relay is that the browser never holds it. */
|
|
204
|
-
apiKey: string;
|
|
205
|
-
/** Resolve the acting end user from YOUR request/session. Return null when
|
|
206
|
-
* nobody is signed in (the relay then answers 401 rather than letting an
|
|
207
|
-
* anonymous visitor chat on your key). Return {userId: ''} to explicitly
|
|
208
|
-
* allow UNIDENTIFIED chat (the proxy must not require identification). */
|
|
209
|
-
getUser: (req: Request) => Promise<ChatRelayUser | null> | ChatRelayUser | null;
|
|
210
|
-
/** Defaults: '1.0.0' / 'prod' / 'abz.run'. */
|
|
211
|
-
apiVersion?: string;
|
|
212
|
-
environment?: string;
|
|
213
|
-
host?: string;
|
|
214
|
-
/** Cap on the request body we relay, bytes (default 262144 = the proxy's own
|
|
215
|
-
* non-BYO cap — reject junk before spending upstream bandwidth on it). */
|
|
216
|
-
maxBodyBytes?: number;
|
|
217
|
-
}
|
|
218
|
-
declare function createApiblazeChat(cfg: ApiblazeChatConfig): {
|
|
219
|
-
handler: (req: Request) => Promise<Response>;
|
|
220
|
-
upstream: string;
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* apiblaze/server — the server-side half of the apiblaze widgets.
|
|
225
|
-
*
|
|
226
|
-
* Holds the producer's CP key (server-only, never shipped to the browser) and turns
|
|
227
|
-
* a logged-in user into apiblaze operations. The browser widgets (`apiblaze/react`)
|
|
228
|
-
* talk ONLY to your own backend; your backend talks to apiblaze — so there are no
|
|
229
|
-
* cross-domain cookies, no secrets in the client, and no auth wiring beyond
|
|
230
|
-
* "read my session."
|
|
231
|
-
*
|
|
232
|
-
* TWO faces over ONE shared substrate (core.ts — one CP credential, one
|
|
233
|
-
* ensure-tenant/ensure-user path):
|
|
234
|
-
* - createApiblazeKeys → API-key management (<ApiKeyWidget/>)
|
|
235
|
-
* - createApiblazeGroups → users & groups IAM (<UsersGroupsWidget/>)
|
|
236
|
-
*
|
|
237
|
-
* Usage (Next.js App Router — app/api/apiblaze/keys/route.ts):
|
|
238
|
-
*
|
|
239
|
-
* import { createApiblazeKeys } from 'apiblaze/server';
|
|
240
|
-
* import { auth } from '@/auth'; // NextAuth, Clerk, anything
|
|
241
|
-
*
|
|
242
|
-
* const keys = createApiblazeKeys({
|
|
243
|
-
* cpKey: process.env.APIBLAZE_CP_KEY!,
|
|
244
|
-
* getUser: async () => {
|
|
245
|
-
* const s = await auth();
|
|
246
|
-
* if (!s?.user) return null;
|
|
247
|
-
* return {
|
|
248
|
-
* tenant: s.user.orgId ?? s.user.id,
|
|
249
|
-
* userId: s.user.id,
|
|
250
|
-
* email: s.user.email ?? undefined,
|
|
251
|
-
* // Which key types this person may create. Omit → ['call-only'].
|
|
252
|
-
* // false → no API access. A list of 2+ → the widget shows a picker.
|
|
253
|
-
* keyTypes: s.user.isEngineer ? ['manager', 'call-only'] : undefined,
|
|
254
|
-
* };
|
|
255
|
-
* },
|
|
256
|
-
* });
|
|
257
|
-
* export const GET = keys.handler;
|
|
258
|
-
* export const POST = keys.handler;
|
|
259
|
-
*
|
|
260
|
-
* SECURITY: eligibility is decided HERE, on your server, from your session —
|
|
261
|
-
* never from the browser. When a user is eligible for more than one type the
|
|
262
|
-
* browser sends its pick, but this handler only honors it if it's in the user's
|
|
263
|
-
* allowed set; otherwise it's rejected. `keyTypes: false` is enforced server-side
|
|
264
|
-
* (403) before anything is provisioned, not merely hidden in the UI.
|
|
265
|
-
*/
|
|
266
|
-
|
|
267
|
-
interface ApiblazeKeysConfig {
|
|
268
|
-
/** The producer CP key from the apiblaze dashboard Developers section. Server-only.
|
|
269
|
-
* Use a purpose-built "widget" key (not a full admin key) so the platform's own
|
|
270
|
-
* subset rule is a real backstop under your eligibility logic. */
|
|
271
|
-
cpKey: string;
|
|
272
|
-
/** Return the logged-in user from the request/session, or null if unauthenticated. */
|
|
273
|
-
getUser: (req: Request) => Promise<AppUser | null> | AppUser | null;
|
|
274
|
-
/** Optional override for eligibility, if you'd rather compute it here than inline
|
|
275
|
-
* in getUser. Same contract as AppUser.keyTypes (undefined → default, false/[] → deny).
|
|
276
|
-
* Takes precedence over user.keyTypes when provided. */
|
|
277
|
-
resolveKeyTypes?: (user: AppUser) => (string[] | false) | Promise<string[] | false>;
|
|
278
|
-
/** Key lifetime in seconds. Omit for a DURABLE key (no expiry) — the right
|
|
279
|
-
* default for a production API key a developer embeds, so it never silently
|
|
280
|
-
* stops working. A durable key is shown ONCE at creation (not re-revealable);
|
|
281
|
-
* set an expiry if you want keys that stay revealable until they expire. */
|
|
282
|
-
keyExpiresInSeconds?: number;
|
|
283
|
-
/** Override the apiblaze base (tests/self-host). Default https://apikeys.apiblaze.com */
|
|
284
|
-
base?: string;
|
|
285
|
-
}
|
|
286
|
-
type Action = {
|
|
287
|
-
action: 'list';
|
|
288
|
-
} | {
|
|
289
|
-
action: 'create';
|
|
290
|
-
keyType?: string;
|
|
291
|
-
} | {
|
|
292
|
-
action: 'reveal';
|
|
293
|
-
keyId: string;
|
|
294
|
-
} | {
|
|
295
|
-
action: 'rotate';
|
|
296
|
-
keyId: string;
|
|
297
|
-
} | {
|
|
298
|
-
action: 'revoke';
|
|
299
|
-
keyId: string;
|
|
300
|
-
};
|
|
301
|
-
declare function createApiblazeKeys(cfg: ApiblazeKeysConfig): {
|
|
302
|
-
handler: (req: Request) => Promise<Response>;
|
|
303
|
-
run: (user: AppUser, op: Action) => Promise<{
|
|
304
|
-
status: number;
|
|
305
|
-
data: unknown;
|
|
306
|
-
}>;
|
|
307
|
-
};
|
|
308
|
-
|
|
309
|
-
export { type ApiblazeChatConfig, type ApiblazeGroupsConfig, type ApiblazeKeysConfig, type AppUser, type ChatRelayUser, type GroupsAction, PlaneError, createApiblazeChat, createApiblazeGroups, createApiblazeKeys };
|
package/dist/server/index.d.ts
DELETED
|
@@ -1,309 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* apiblaze/server — SHARED widget-server substrate.
|
|
3
|
-
*
|
|
4
|
-
* One CP credential, one getUser contract, one ensure-tenant/ensure-user path —
|
|
5
|
-
* consumed by BOTH widget faces (`createApiblazeKeys` and `createApiblazeGroups`).
|
|
6
|
-
* Factored per iam_toolkit_spec ("share, don't fork" — copy-forking this
|
|
7
|
-
* bootstrap is a spec failure).
|
|
8
|
-
*
|
|
9
|
-
* Trust model: the CP key stays server-side and vouches for the CHANNEL; the
|
|
10
|
-
* acting end-user rides X-End-User-Id / X-End-User-Email. On the apikeys plane
|
|
11
|
-
* the end-user header only narrows (self-scoped key ops); on the iam plane it
|
|
12
|
-
* IS the principal (iam-worker independently checks the resolved user's
|
|
13
|
-
* apiblaze_admins membership before any group op).
|
|
14
|
-
*/
|
|
15
|
-
interface AppUser {
|
|
16
|
-
/** The producer's stable id for the consumer COMPANY — becomes the tenant (isolation). */
|
|
17
|
-
tenant: string;
|
|
18
|
-
/** The producer's stable id for the PERSON — the acting end-user. */
|
|
19
|
-
userId: string;
|
|
20
|
-
/** Optional; REQUIRED in practice for the groups widget — tenant-admin status
|
|
21
|
-
* is granted by email (the tenant's admin-emails allowlist). */
|
|
22
|
-
email?: string;
|
|
23
|
-
/** Optional display name (cosmetic). */
|
|
24
|
-
label?: string;
|
|
25
|
-
/** Key-widget eligibility (see createApiblazeKeys). Ignored by the groups widget. */
|
|
26
|
-
keyTypes?: string[] | false;
|
|
27
|
-
/** Any extra fields your eligibility logic wants (e.g. isEngineer). */
|
|
28
|
-
[k: string]: unknown;
|
|
29
|
-
}
|
|
30
|
-
declare class PlaneError extends Error {
|
|
31
|
-
status: number;
|
|
32
|
-
detail: string;
|
|
33
|
-
constructor(status: number, detail: string);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* createApiblazeGroups — the server-side half of the Users & Groups widget
|
|
38
|
-
* (<UsersGroupsWidget/>), riding the SAME shared substrate (core.ts) and the
|
|
39
|
-
* SAME one CP widget credential as the API-key widget.
|
|
40
|
-
*
|
|
41
|
-
* Usage (Next.js App Router — app/api/apiblaze/groups/route.ts):
|
|
42
|
-
*
|
|
43
|
-
* import { createApiblazeGroups } from 'apiblaze/server';
|
|
44
|
-
* const groups = createApiblazeGroups({
|
|
45
|
-
* cpKey: process.env.APIBLAZE_CP_KEY!, // the SAME key the key widget uses
|
|
46
|
-
* getUser: async () => { ...same contract... return { tenant, userId, email } },
|
|
47
|
-
* });
|
|
48
|
-
* export const GET = groups.handler;
|
|
49
|
-
* export const POST = groups.handler;
|
|
50
|
-
*
|
|
51
|
-
* AUTHORIZATION MODEL (iam_toolkit_spec): unlike key ops (self-scoped), group
|
|
52
|
-
* admin ops are tenant-wide — so the acting END-USER IS THE PRINCIPAL. This
|
|
53
|
-
* server forwards the session user via X-End-User-Id/-Email; apiblaze's iam
|
|
54
|
-
* plane independently verifies that user is a TENANT ADMIN (apiblaze_admins
|
|
55
|
-
* member, granted via the tenant's admin-emails allowlist) before any op. A
|
|
56
|
-
* non-admin gets `access: 'pending'` — nothing here can elevate them, and no
|
|
57
|
-
* producer-side flag can either. The CP key is only the channel.
|
|
58
|
-
*
|
|
59
|
-
* Strictly users + groups — NO authorization-rule authoring (that stays in
|
|
60
|
-
* `apiblaze authz` / the dashboard).
|
|
61
|
-
*/
|
|
62
|
-
|
|
63
|
-
interface ApiblazeGroupsConfig {
|
|
64
|
-
/** The producer CP key — the SAME widget key the API-key widget uses. Server-only. */
|
|
65
|
-
cpKey: string;
|
|
66
|
-
/** Return the logged-in user from the request/session, or null if unauthenticated.
|
|
67
|
-
* `email` is how tenant-admin status is granted (admin-emails allowlist) — pass it. */
|
|
68
|
-
getUser: (req: Request) => Promise<AppUser | null> | AppUser | null;
|
|
69
|
-
/** Override the apikeys plane base (tenant/user provisioning). Default https://apikeys.apiblaze.com */
|
|
70
|
-
base?: string;
|
|
71
|
-
/** Override the iam plane base. Default https://iam.apiblaze.com */
|
|
72
|
-
iamBase?: string;
|
|
73
|
-
}
|
|
74
|
-
type GroupsAction = {
|
|
75
|
-
action: 'snapshot';
|
|
76
|
-
} | {
|
|
77
|
-
action: 'list-groups';
|
|
78
|
-
offset?: number;
|
|
79
|
-
q?: string;
|
|
80
|
-
} | {
|
|
81
|
-
action: 'search-users';
|
|
82
|
-
q?: string;
|
|
83
|
-
limit?: number;
|
|
84
|
-
offset?: number;
|
|
85
|
-
} | {
|
|
86
|
-
action: 'list-observed';
|
|
87
|
-
offset?: number;
|
|
88
|
-
q?: string;
|
|
89
|
-
} | {
|
|
90
|
-
action: 'group-members';
|
|
91
|
-
groupId: string;
|
|
92
|
-
offset?: number;
|
|
93
|
-
} | {
|
|
94
|
-
action: 'create-group';
|
|
95
|
-
name: string;
|
|
96
|
-
description?: string;
|
|
97
|
-
} | {
|
|
98
|
-
action: 'rename-group';
|
|
99
|
-
groupId: string;
|
|
100
|
-
name?: string;
|
|
101
|
-
description?: string;
|
|
102
|
-
} | {
|
|
103
|
-
action: 'delete-group';
|
|
104
|
-
groupId: string;
|
|
105
|
-
} | {
|
|
106
|
-
action: 'add-member';
|
|
107
|
-
groupId: string;
|
|
108
|
-
abzSub: string;
|
|
109
|
-
role?: 'member' | 'admin';
|
|
110
|
-
} | {
|
|
111
|
-
action: 'change-role';
|
|
112
|
-
groupId: string;
|
|
113
|
-
abzSub: string;
|
|
114
|
-
role: 'member' | 'admin';
|
|
115
|
-
} | {
|
|
116
|
-
action: 'remove-member';
|
|
117
|
-
groupId: string;
|
|
118
|
-
abzSub: string;
|
|
119
|
-
} | {
|
|
120
|
-
action: 'add-subgroup';
|
|
121
|
-
groupId: string;
|
|
122
|
-
childGroupId: string;
|
|
123
|
-
} | {
|
|
124
|
-
action: 'remove-subgroup';
|
|
125
|
-
groupId: string;
|
|
126
|
-
childGroupId: string;
|
|
127
|
-
} | {
|
|
128
|
-
action: 'group-detail';
|
|
129
|
-
groupId: string;
|
|
130
|
-
} | {
|
|
131
|
-
action: 'provision-observed';
|
|
132
|
-
consumerUserId: string;
|
|
133
|
-
email?: string;
|
|
134
|
-
displayName?: string;
|
|
135
|
-
groups?: string[];
|
|
136
|
-
} | {
|
|
137
|
-
action: 'create-user';
|
|
138
|
-
ref: string;
|
|
139
|
-
displayName?: string;
|
|
140
|
-
} | {
|
|
141
|
-
action: 'list-admins';
|
|
142
|
-
} | {
|
|
143
|
-
action: 'add-admin';
|
|
144
|
-
email: string;
|
|
145
|
-
} | {
|
|
146
|
-
action: 'remove-admin';
|
|
147
|
-
email: string;
|
|
148
|
-
};
|
|
149
|
-
declare function createApiblazeGroups(cfg: ApiblazeGroupsConfig): {
|
|
150
|
-
handler: (req: Request) => Promise<Response>;
|
|
151
|
-
run: (user: AppUser, op: GroupsAction) => Promise<{
|
|
152
|
-
status: number;
|
|
153
|
-
data: unknown;
|
|
154
|
-
}>;
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* createApiblazeChat — the server-side half of <ChatWidget/> for API-KEY-door
|
|
159
|
-
* proxies (chatwidget_prd.md, Mode 2 "relay"). JWT-door proxies don't need this
|
|
160
|
-
* file at all: the widget sends the end user's own session token straight to
|
|
161
|
-
* the proxy (Mode 1) and per-person quotas/authorization fall out for free.
|
|
162
|
-
*
|
|
163
|
-
* What the relay does — and ALL it does:
|
|
164
|
-
* 1. resolves YOUR user from YOUR session (the same getUser contract as
|
|
165
|
-
* createApiblazeKeys / createApiblazeGroups),
|
|
166
|
-
* 2. attaches the producer DP key (server-only) + X-End-User-Id,
|
|
167
|
-
* 3. PIPES the SSE stream through untouched (streams pass through Next.js
|
|
168
|
-
* route handlers natively — never buffer, never re-frame).
|
|
169
|
-
*
|
|
170
|
-
* DOCUMENTED TRADEOFFS (say them, don't bury them): behind ONE relay key,
|
|
171
|
-
* · the proxy's chat quota meters ALL your end users into ONE daily bucket;
|
|
172
|
-
* · tool calls carry that key's authority (specs/chat_funding.MD: metering
|
|
173
|
-
* keys on the credential; the asserted X-End-User-Id proves nothing);
|
|
174
|
-
* · chat is ONE TURN AT A TIME site-wide — the anti-burst in-flight lock is
|
|
175
|
-
* per credential, so while one user's turn streams (seconds), another
|
|
176
|
-
* user's send is politely refused ("a previous message is still being
|
|
177
|
-
* processed"). Fine for a demo or a low-traffic page; NOT for a busy site.
|
|
178
|
-
* Want per-person buckets, per-person authorization, and real concurrency?
|
|
179
|
-
* Use Mode 1 (register your issuer on the proxy — the user's own JWT is the
|
|
180
|
-
* credential), or mint per-user keys via the key-widget plane.
|
|
181
|
-
*
|
|
182
|
-
* // app/api/apiblaze/chat/route.ts
|
|
183
|
-
* import { createApiblazeChat } from 'apiblaze/server';
|
|
184
|
-
* const chat = createApiblazeChat({
|
|
185
|
-
* project: 'ninopizza',
|
|
186
|
-
* apiKey: process.env.APIBLAZE_DP_KEY!, // a DP key for that proxy — server-only
|
|
187
|
-
* getUser: async (req) => ({ userId: (await session(req)).userId }),
|
|
188
|
-
* });
|
|
189
|
-
* export const POST = chat.handler;
|
|
190
|
-
*/
|
|
191
|
-
interface ChatRelayUser {
|
|
192
|
-
/** Your stable id for the PERSON — forwarded as X-End-User-Id so the proxy's
|
|
193
|
-
* identity gates (identified_traffic_only / pre-approval) and the upstream's
|
|
194
|
-
* x-end-user-id contract see it. */
|
|
195
|
-
userId: string;
|
|
196
|
-
/** Optional display email/label — NOT forwarded; reserved for future use. */
|
|
197
|
-
email?: string;
|
|
198
|
-
}
|
|
199
|
-
interface ApiblazeChatConfig {
|
|
200
|
-
/** Project handle (the proxy's subdomain). */
|
|
201
|
-
project: string;
|
|
202
|
-
/** A DP api key for that proxy. SERVER-ONLY — never expose it to the browser;
|
|
203
|
-
* the whole point of this relay is that the browser never holds it. */
|
|
204
|
-
apiKey: string;
|
|
205
|
-
/** Resolve the acting end user from YOUR request/session. Return null when
|
|
206
|
-
* nobody is signed in (the relay then answers 401 rather than letting an
|
|
207
|
-
* anonymous visitor chat on your key). Return {userId: ''} to explicitly
|
|
208
|
-
* allow UNIDENTIFIED chat (the proxy must not require identification). */
|
|
209
|
-
getUser: (req: Request) => Promise<ChatRelayUser | null> | ChatRelayUser | null;
|
|
210
|
-
/** Defaults: '1.0.0' / 'prod' / 'abz.run'. */
|
|
211
|
-
apiVersion?: string;
|
|
212
|
-
environment?: string;
|
|
213
|
-
host?: string;
|
|
214
|
-
/** Cap on the request body we relay, bytes (default 262144 = the proxy's own
|
|
215
|
-
* non-BYO cap — reject junk before spending upstream bandwidth on it). */
|
|
216
|
-
maxBodyBytes?: number;
|
|
217
|
-
}
|
|
218
|
-
declare function createApiblazeChat(cfg: ApiblazeChatConfig): {
|
|
219
|
-
handler: (req: Request) => Promise<Response>;
|
|
220
|
-
upstream: string;
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* apiblaze/server — the server-side half of the apiblaze widgets.
|
|
225
|
-
*
|
|
226
|
-
* Holds the producer's CP key (server-only, never shipped to the browser) and turns
|
|
227
|
-
* a logged-in user into apiblaze operations. The browser widgets (`apiblaze/react`)
|
|
228
|
-
* talk ONLY to your own backend; your backend talks to apiblaze — so there are no
|
|
229
|
-
* cross-domain cookies, no secrets in the client, and no auth wiring beyond
|
|
230
|
-
* "read my session."
|
|
231
|
-
*
|
|
232
|
-
* TWO faces over ONE shared substrate (core.ts — one CP credential, one
|
|
233
|
-
* ensure-tenant/ensure-user path):
|
|
234
|
-
* - createApiblazeKeys → API-key management (<ApiKeyWidget/>)
|
|
235
|
-
* - createApiblazeGroups → users & groups IAM (<UsersGroupsWidget/>)
|
|
236
|
-
*
|
|
237
|
-
* Usage (Next.js App Router — app/api/apiblaze/keys/route.ts):
|
|
238
|
-
*
|
|
239
|
-
* import { createApiblazeKeys } from 'apiblaze/server';
|
|
240
|
-
* import { auth } from '@/auth'; // NextAuth, Clerk, anything
|
|
241
|
-
*
|
|
242
|
-
* const keys = createApiblazeKeys({
|
|
243
|
-
* cpKey: process.env.APIBLAZE_CP_KEY!,
|
|
244
|
-
* getUser: async () => {
|
|
245
|
-
* const s = await auth();
|
|
246
|
-
* if (!s?.user) return null;
|
|
247
|
-
* return {
|
|
248
|
-
* tenant: s.user.orgId ?? s.user.id,
|
|
249
|
-
* userId: s.user.id,
|
|
250
|
-
* email: s.user.email ?? undefined,
|
|
251
|
-
* // Which key types this person may create. Omit → ['call-only'].
|
|
252
|
-
* // false → no API access. A list of 2+ → the widget shows a picker.
|
|
253
|
-
* keyTypes: s.user.isEngineer ? ['manager', 'call-only'] : undefined,
|
|
254
|
-
* };
|
|
255
|
-
* },
|
|
256
|
-
* });
|
|
257
|
-
* export const GET = keys.handler;
|
|
258
|
-
* export const POST = keys.handler;
|
|
259
|
-
*
|
|
260
|
-
* SECURITY: eligibility is decided HERE, on your server, from your session —
|
|
261
|
-
* never from the browser. When a user is eligible for more than one type the
|
|
262
|
-
* browser sends its pick, but this handler only honors it if it's in the user's
|
|
263
|
-
* allowed set; otherwise it's rejected. `keyTypes: false` is enforced server-side
|
|
264
|
-
* (403) before anything is provisioned, not merely hidden in the UI.
|
|
265
|
-
*/
|
|
266
|
-
|
|
267
|
-
interface ApiblazeKeysConfig {
|
|
268
|
-
/** The producer CP key from the apiblaze dashboard Developers section. Server-only.
|
|
269
|
-
* Use a purpose-built "widget" key (not a full admin key) so the platform's own
|
|
270
|
-
* subset rule is a real backstop under your eligibility logic. */
|
|
271
|
-
cpKey: string;
|
|
272
|
-
/** Return the logged-in user from the request/session, or null if unauthenticated. */
|
|
273
|
-
getUser: (req: Request) => Promise<AppUser | null> | AppUser | null;
|
|
274
|
-
/** Optional override for eligibility, if you'd rather compute it here than inline
|
|
275
|
-
* in getUser. Same contract as AppUser.keyTypes (undefined → default, false/[] → deny).
|
|
276
|
-
* Takes precedence over user.keyTypes when provided. */
|
|
277
|
-
resolveKeyTypes?: (user: AppUser) => (string[] | false) | Promise<string[] | false>;
|
|
278
|
-
/** Key lifetime in seconds. Omit for a DURABLE key (no expiry) — the right
|
|
279
|
-
* default for a production API key a developer embeds, so it never silently
|
|
280
|
-
* stops working. A durable key is shown ONCE at creation (not re-revealable);
|
|
281
|
-
* set an expiry if you want keys that stay revealable until they expire. */
|
|
282
|
-
keyExpiresInSeconds?: number;
|
|
283
|
-
/** Override the apiblaze base (tests/self-host). Default https://apikeys.apiblaze.com */
|
|
284
|
-
base?: string;
|
|
285
|
-
}
|
|
286
|
-
type Action = {
|
|
287
|
-
action: 'list';
|
|
288
|
-
} | {
|
|
289
|
-
action: 'create';
|
|
290
|
-
keyType?: string;
|
|
291
|
-
} | {
|
|
292
|
-
action: 'reveal';
|
|
293
|
-
keyId: string;
|
|
294
|
-
} | {
|
|
295
|
-
action: 'rotate';
|
|
296
|
-
keyId: string;
|
|
297
|
-
} | {
|
|
298
|
-
action: 'revoke';
|
|
299
|
-
keyId: string;
|
|
300
|
-
};
|
|
301
|
-
declare function createApiblazeKeys(cfg: ApiblazeKeysConfig): {
|
|
302
|
-
handler: (req: Request) => Promise<Response>;
|
|
303
|
-
run: (user: AppUser, op: Action) => Promise<{
|
|
304
|
-
status: number;
|
|
305
|
-
data: unknown;
|
|
306
|
-
}>;
|
|
307
|
-
};
|
|
308
|
-
|
|
309
|
-
export { type ApiblazeChatConfig, type ApiblazeGroupsConfig, type ApiblazeKeysConfig, type AppUser, type ChatRelayUser, type GroupsAction, PlaneError, createApiblazeChat, createApiblazeGroups, createApiblazeKeys };
|
package/dist/sidecar/index.d.mts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* apiblaze/sidecar — the egress sidecar (observe → approve model).
|
|
3
|
-
* Spec: specs/sidecar/apiblaze-sidecar-spec.md §3.
|
|
4
|
-
*
|
|
5
|
-
* // instrumentation.ts
|
|
6
|
-
* import { register as apiblaze } from "apiblaze/sidecar";
|
|
7
|
-
* export function register() { apiblaze(); }
|
|
8
|
-
*
|
|
9
|
-
* At boot it loads the team's APPROVED origins (GET sidecar.abz.run/routes) into
|
|
10
|
-
* an in-memory map. Per request: if the origin is approved it routes through that
|
|
11
|
-
* origin's proxy (carrying the call's own auth); otherwise it goes DIRECT,
|
|
12
|
-
* untouched, and reports the origin once as a candidate. Reads only APIBLAZE_TOKEN.
|
|
13
|
-
* Fail-open: any error → direct. Never breaks the app.
|
|
14
|
-
*/
|
|
15
|
-
interface SidecarOptions {
|
|
16
|
-
token?: string;
|
|
17
|
-
exclude?: string[];
|
|
18
|
-
include?: string[];
|
|
19
|
-
quiet?: boolean;
|
|
20
|
-
/** Explicit on/off. Overrides the APIBLAZE_SIDECAR env toggle when set. */
|
|
21
|
-
enabled?: boolean;
|
|
22
|
-
}
|
|
23
|
-
declare function register(opts?: SidecarOptions): void;
|
|
24
|
-
declare function withApiblaze<T extends Record<string, unknown>>(nextConfig?: T): T;
|
|
25
|
-
declare const _default: {
|
|
26
|
-
register: typeof register;
|
|
27
|
-
withApiblaze: typeof withApiblaze;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export { type SidecarOptions, _default as default, register, withApiblaze };
|
package/dist/sidecar/index.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* apiblaze/sidecar — the egress sidecar (observe → approve model).
|
|
3
|
-
* Spec: specs/sidecar/apiblaze-sidecar-spec.md §3.
|
|
4
|
-
*
|
|
5
|
-
* // instrumentation.ts
|
|
6
|
-
* import { register as apiblaze } from "apiblaze/sidecar";
|
|
7
|
-
* export function register() { apiblaze(); }
|
|
8
|
-
*
|
|
9
|
-
* At boot it loads the team's APPROVED origins (GET sidecar.abz.run/routes) into
|
|
10
|
-
* an in-memory map. Per request: if the origin is approved it routes through that
|
|
11
|
-
* origin's proxy (carrying the call's own auth); otherwise it goes DIRECT,
|
|
12
|
-
* untouched, and reports the origin once as a candidate. Reads only APIBLAZE_TOKEN.
|
|
13
|
-
* Fail-open: any error → direct. Never breaks the app.
|
|
14
|
-
*/
|
|
15
|
-
interface SidecarOptions {
|
|
16
|
-
token?: string;
|
|
17
|
-
exclude?: string[];
|
|
18
|
-
include?: string[];
|
|
19
|
-
quiet?: boolean;
|
|
20
|
-
/** Explicit on/off. Overrides the APIBLAZE_SIDECAR env toggle when set. */
|
|
21
|
-
enabled?: boolean;
|
|
22
|
-
}
|
|
23
|
-
declare function register(opts?: SidecarOptions): void;
|
|
24
|
-
declare function withApiblaze<T extends Record<string, unknown>>(nextConfig?: T): T;
|
|
25
|
-
declare const _default: {
|
|
26
|
-
register: typeof register;
|
|
27
|
-
withApiblaze: typeof withApiblaze;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export { type SidecarOptions, _default as default, register, withApiblaze };
|