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 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.21";
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) return;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apiblaze",
3
- "version": "0.20.21",
3
+ "version": "0.20.23",
4
4
  "description": "APIblaze CLI — Chat with your APIs, Manage your API keys, users and groups with the APIblaze serverless proxy",
5
5
  "keywords": [
6
6
  "apiblaze",
@@ -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 };
@@ -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 };
@@ -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 };
@@ -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 };
@@ -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 };
@@ -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 };