apiblaze 0.17.21 → 0.17.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/README.md +63 -0
- package/dist/index.js +451 -217
- package/dist/react/index.d.mts +67 -7
- package/dist/react/index.d.ts +67 -7
- package/dist/react/index.js +651 -69
- package/dist/react/index.mjs +651 -69
- package/dist/server/index.d.mts +165 -25
- package/dist/server/index.d.ts +165 -25
- package/dist/server/index.js +207 -35
- package/dist/server/index.mjs +204 -36
- package/package.json +28 -16
package/dist/server/index.d.mts
CHANGED
|
@@ -1,11 +1,143 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* apiblaze/server —
|
|
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: 'create-group';
|
|
78
|
+
name: string;
|
|
79
|
+
description?: string;
|
|
80
|
+
} | {
|
|
81
|
+
action: 'rename-group';
|
|
82
|
+
groupId: string;
|
|
83
|
+
name?: string;
|
|
84
|
+
description?: string;
|
|
85
|
+
} | {
|
|
86
|
+
action: 'delete-group';
|
|
87
|
+
groupId: string;
|
|
88
|
+
} | {
|
|
89
|
+
action: 'add-member';
|
|
90
|
+
groupId: string;
|
|
91
|
+
abzSub: string;
|
|
92
|
+
role?: 'member' | 'admin';
|
|
93
|
+
} | {
|
|
94
|
+
action: 'change-role';
|
|
95
|
+
groupId: string;
|
|
96
|
+
abzSub: string;
|
|
97
|
+
role: 'member' | 'admin';
|
|
98
|
+
} | {
|
|
99
|
+
action: 'remove-member';
|
|
100
|
+
groupId: string;
|
|
101
|
+
abzSub: string;
|
|
102
|
+
} | {
|
|
103
|
+
action: 'add-subgroup';
|
|
104
|
+
groupId: string;
|
|
105
|
+
childGroupId: string;
|
|
106
|
+
} | {
|
|
107
|
+
action: 'remove-subgroup';
|
|
108
|
+
groupId: string;
|
|
109
|
+
childGroupId: string;
|
|
110
|
+
} | {
|
|
111
|
+
action: 'group-detail';
|
|
112
|
+
groupId: string;
|
|
113
|
+
} | {
|
|
114
|
+
action: 'provision-observed';
|
|
115
|
+
consumerUserId: string;
|
|
116
|
+
email?: string;
|
|
117
|
+
displayName?: string;
|
|
118
|
+
groups?: string[];
|
|
119
|
+
};
|
|
120
|
+
declare function createApiblazeGroups(cfg: ApiblazeGroupsConfig): {
|
|
121
|
+
handler: (req: Request) => Promise<Response>;
|
|
122
|
+
run: (user: AppUser, op: GroupsAction) => Promise<{
|
|
123
|
+
status: number;
|
|
124
|
+
data: unknown;
|
|
125
|
+
}>;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* apiblaze/server — the server-side half of the apiblaze widgets.
|
|
3
130
|
*
|
|
4
131
|
* Holds the producer's CP key (server-only, never shipped to the browser) and turns
|
|
5
|
-
* a logged-in user into
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
132
|
+
* a logged-in user into apiblaze operations. The browser widgets (`apiblaze/react`)
|
|
133
|
+
* talk ONLY to your own backend; your backend talks to apiblaze — so there are no
|
|
134
|
+
* cross-domain cookies, no secrets in the client, and no auth wiring beyond
|
|
135
|
+
* "read my session."
|
|
136
|
+
*
|
|
137
|
+
* TWO faces over ONE shared substrate (core.ts — one CP credential, one
|
|
138
|
+
* ensure-tenant/ensure-user path):
|
|
139
|
+
* - createApiblazeKeys → API-key management (<ApiKeyWidget/>)
|
|
140
|
+
* - createApiblazeGroups → users & groups IAM (<UsersGroupsWidget/>)
|
|
9
141
|
*
|
|
10
142
|
* Usage (Next.js App Router — app/api/apiblaze/keys/route.ts):
|
|
11
143
|
*
|
|
@@ -17,34 +149,41 @@
|
|
|
17
149
|
* getUser: async () => {
|
|
18
150
|
* const s = await auth();
|
|
19
151
|
* if (!s?.user) return null;
|
|
20
|
-
* return {
|
|
152
|
+
* return {
|
|
153
|
+
* tenant: s.user.orgId ?? s.user.id,
|
|
154
|
+
* userId: s.user.id,
|
|
155
|
+
* email: s.user.email ?? undefined,
|
|
156
|
+
* // Which key types this person may create. Omit → ['call-only'].
|
|
157
|
+
* // false → no API access. A list of 2+ → the widget shows a picker.
|
|
158
|
+
* keyTypes: s.user.isEngineer ? ['manager', 'call-only'] : undefined,
|
|
159
|
+
* };
|
|
21
160
|
* },
|
|
22
|
-
* resolveScopes: (u) => u.isEngineer ? ['call', 'use-premium'] : ['call'], // optional
|
|
23
161
|
* });
|
|
24
162
|
* export const GET = keys.handler;
|
|
25
163
|
* export const POST = keys.handler;
|
|
164
|
+
*
|
|
165
|
+
* SECURITY: eligibility is decided HERE, on your server, from your session —
|
|
166
|
+
* never from the browser. When a user is eligible for more than one type the
|
|
167
|
+
* browser sends its pick, but this handler only honors it if it's in the user's
|
|
168
|
+
* allowed set; otherwise it's rejected. `keyTypes: false` is enforced server-side
|
|
169
|
+
* (403) before anything is provisioned, not merely hidden in the UI.
|
|
26
170
|
*/
|
|
27
|
-
|
|
28
|
-
/** The producer's stable id for the consumer COMPANY — becomes the tenant (isolation). */
|
|
29
|
-
tenant: string;
|
|
30
|
-
/** The producer's stable id for the PERSON — the key creator/owner (list scope). */
|
|
31
|
-
userId: string;
|
|
32
|
-
/** Optional, stored now for possible future portal parity. */
|
|
33
|
-
email?: string;
|
|
34
|
-
/** Optional display name (cosmetic). */
|
|
35
|
-
label?: string;
|
|
36
|
-
/** Any extra fields your resolveScopes wants (e.g. isEngineer). */
|
|
37
|
-
[k: string]: unknown;
|
|
38
|
-
}
|
|
171
|
+
|
|
39
172
|
interface ApiblazeKeysConfig {
|
|
40
|
-
/** The producer CP key from the apiblaze dashboard Developers section. Server-only.
|
|
173
|
+
/** The producer CP key from the apiblaze dashboard Developers section. Server-only.
|
|
174
|
+
* Use a purpose-built "widget" key (not a full admin key) so the platform's own
|
|
175
|
+
* subset rule is a real backstop under your eligibility logic. */
|
|
41
176
|
cpKey: string;
|
|
42
177
|
/** Return the logged-in user from the request/session, or null if unauthenticated. */
|
|
43
178
|
getUser: (req: Request) => Promise<AppUser | null> | AppUser | null;
|
|
44
|
-
/**
|
|
45
|
-
*
|
|
46
|
-
|
|
47
|
-
|
|
179
|
+
/** Optional override for eligibility, if you'd rather compute it here than inline
|
|
180
|
+
* in getUser. Same contract as AppUser.keyTypes (undefined → default, false/[] → deny).
|
|
181
|
+
* Takes precedence over user.keyTypes when provided. */
|
|
182
|
+
resolveKeyTypes?: (user: AppUser) => (string[] | false) | Promise<string[] | false>;
|
|
183
|
+
/** Key lifetime in seconds. Omit for a DURABLE key (no expiry) — the right
|
|
184
|
+
* default for a production API key a developer embeds, so it never silently
|
|
185
|
+
* stops working. A durable key is shown ONCE at creation (not re-revealable);
|
|
186
|
+
* set an expiry if you want keys that stay revealable until they expire. */
|
|
48
187
|
keyExpiresInSeconds?: number;
|
|
49
188
|
/** Override the apiblaze base (tests/self-host). Default https://apikeys.apiblaze.com */
|
|
50
189
|
base?: string;
|
|
@@ -53,6 +192,7 @@ type Action = {
|
|
|
53
192
|
action: 'list';
|
|
54
193
|
} | {
|
|
55
194
|
action: 'create';
|
|
195
|
+
keyType?: string;
|
|
56
196
|
} | {
|
|
57
197
|
action: 'reveal';
|
|
58
198
|
keyId: string;
|
|
@@ -71,4 +211,4 @@ declare function createApiblazeKeys(cfg: ApiblazeKeysConfig): {
|
|
|
71
211
|
}>;
|
|
72
212
|
};
|
|
73
213
|
|
|
74
|
-
export { type ApiblazeKeysConfig, type AppUser, createApiblazeKeys };
|
|
214
|
+
export { type ApiblazeGroupsConfig, type ApiblazeKeysConfig, type AppUser, type GroupsAction, PlaneError, createApiblazeGroups, createApiblazeKeys };
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,11 +1,143 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* apiblaze/server —
|
|
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: 'create-group';
|
|
78
|
+
name: string;
|
|
79
|
+
description?: string;
|
|
80
|
+
} | {
|
|
81
|
+
action: 'rename-group';
|
|
82
|
+
groupId: string;
|
|
83
|
+
name?: string;
|
|
84
|
+
description?: string;
|
|
85
|
+
} | {
|
|
86
|
+
action: 'delete-group';
|
|
87
|
+
groupId: string;
|
|
88
|
+
} | {
|
|
89
|
+
action: 'add-member';
|
|
90
|
+
groupId: string;
|
|
91
|
+
abzSub: string;
|
|
92
|
+
role?: 'member' | 'admin';
|
|
93
|
+
} | {
|
|
94
|
+
action: 'change-role';
|
|
95
|
+
groupId: string;
|
|
96
|
+
abzSub: string;
|
|
97
|
+
role: 'member' | 'admin';
|
|
98
|
+
} | {
|
|
99
|
+
action: 'remove-member';
|
|
100
|
+
groupId: string;
|
|
101
|
+
abzSub: string;
|
|
102
|
+
} | {
|
|
103
|
+
action: 'add-subgroup';
|
|
104
|
+
groupId: string;
|
|
105
|
+
childGroupId: string;
|
|
106
|
+
} | {
|
|
107
|
+
action: 'remove-subgroup';
|
|
108
|
+
groupId: string;
|
|
109
|
+
childGroupId: string;
|
|
110
|
+
} | {
|
|
111
|
+
action: 'group-detail';
|
|
112
|
+
groupId: string;
|
|
113
|
+
} | {
|
|
114
|
+
action: 'provision-observed';
|
|
115
|
+
consumerUserId: string;
|
|
116
|
+
email?: string;
|
|
117
|
+
displayName?: string;
|
|
118
|
+
groups?: string[];
|
|
119
|
+
};
|
|
120
|
+
declare function createApiblazeGroups(cfg: ApiblazeGroupsConfig): {
|
|
121
|
+
handler: (req: Request) => Promise<Response>;
|
|
122
|
+
run: (user: AppUser, op: GroupsAction) => Promise<{
|
|
123
|
+
status: number;
|
|
124
|
+
data: unknown;
|
|
125
|
+
}>;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* apiblaze/server — the server-side half of the apiblaze widgets.
|
|
3
130
|
*
|
|
4
131
|
* Holds the producer's CP key (server-only, never shipped to the browser) and turns
|
|
5
|
-
* a logged-in user into
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
132
|
+
* a logged-in user into apiblaze operations. The browser widgets (`apiblaze/react`)
|
|
133
|
+
* talk ONLY to your own backend; your backend talks to apiblaze — so there are no
|
|
134
|
+
* cross-domain cookies, no secrets in the client, and no auth wiring beyond
|
|
135
|
+
* "read my session."
|
|
136
|
+
*
|
|
137
|
+
* TWO faces over ONE shared substrate (core.ts — one CP credential, one
|
|
138
|
+
* ensure-tenant/ensure-user path):
|
|
139
|
+
* - createApiblazeKeys → API-key management (<ApiKeyWidget/>)
|
|
140
|
+
* - createApiblazeGroups → users & groups IAM (<UsersGroupsWidget/>)
|
|
9
141
|
*
|
|
10
142
|
* Usage (Next.js App Router — app/api/apiblaze/keys/route.ts):
|
|
11
143
|
*
|
|
@@ -17,34 +149,41 @@
|
|
|
17
149
|
* getUser: async () => {
|
|
18
150
|
* const s = await auth();
|
|
19
151
|
* if (!s?.user) return null;
|
|
20
|
-
* return {
|
|
152
|
+
* return {
|
|
153
|
+
* tenant: s.user.orgId ?? s.user.id,
|
|
154
|
+
* userId: s.user.id,
|
|
155
|
+
* email: s.user.email ?? undefined,
|
|
156
|
+
* // Which key types this person may create. Omit → ['call-only'].
|
|
157
|
+
* // false → no API access. A list of 2+ → the widget shows a picker.
|
|
158
|
+
* keyTypes: s.user.isEngineer ? ['manager', 'call-only'] : undefined,
|
|
159
|
+
* };
|
|
21
160
|
* },
|
|
22
|
-
* resolveScopes: (u) => u.isEngineer ? ['call', 'use-premium'] : ['call'], // optional
|
|
23
161
|
* });
|
|
24
162
|
* export const GET = keys.handler;
|
|
25
163
|
* export const POST = keys.handler;
|
|
164
|
+
*
|
|
165
|
+
* SECURITY: eligibility is decided HERE, on your server, from your session —
|
|
166
|
+
* never from the browser. When a user is eligible for more than one type the
|
|
167
|
+
* browser sends its pick, but this handler only honors it if it's in the user's
|
|
168
|
+
* allowed set; otherwise it's rejected. `keyTypes: false` is enforced server-side
|
|
169
|
+
* (403) before anything is provisioned, not merely hidden in the UI.
|
|
26
170
|
*/
|
|
27
|
-
|
|
28
|
-
/** The producer's stable id for the consumer COMPANY — becomes the tenant (isolation). */
|
|
29
|
-
tenant: string;
|
|
30
|
-
/** The producer's stable id for the PERSON — the key creator/owner (list scope). */
|
|
31
|
-
userId: string;
|
|
32
|
-
/** Optional, stored now for possible future portal parity. */
|
|
33
|
-
email?: string;
|
|
34
|
-
/** Optional display name (cosmetic). */
|
|
35
|
-
label?: string;
|
|
36
|
-
/** Any extra fields your resolveScopes wants (e.g. isEngineer). */
|
|
37
|
-
[k: string]: unknown;
|
|
38
|
-
}
|
|
171
|
+
|
|
39
172
|
interface ApiblazeKeysConfig {
|
|
40
|
-
/** The producer CP key from the apiblaze dashboard Developers section. Server-only.
|
|
173
|
+
/** The producer CP key from the apiblaze dashboard Developers section. Server-only.
|
|
174
|
+
* Use a purpose-built "widget" key (not a full admin key) so the platform's own
|
|
175
|
+
* subset rule is a real backstop under your eligibility logic. */
|
|
41
176
|
cpKey: string;
|
|
42
177
|
/** Return the logged-in user from the request/session, or null if unauthenticated. */
|
|
43
178
|
getUser: (req: Request) => Promise<AppUser | null> | AppUser | null;
|
|
44
|
-
/**
|
|
45
|
-
*
|
|
46
|
-
|
|
47
|
-
|
|
179
|
+
/** Optional override for eligibility, if you'd rather compute it here than inline
|
|
180
|
+
* in getUser. Same contract as AppUser.keyTypes (undefined → default, false/[] → deny).
|
|
181
|
+
* Takes precedence over user.keyTypes when provided. */
|
|
182
|
+
resolveKeyTypes?: (user: AppUser) => (string[] | false) | Promise<string[] | false>;
|
|
183
|
+
/** Key lifetime in seconds. Omit for a DURABLE key (no expiry) — the right
|
|
184
|
+
* default for a production API key a developer embeds, so it never silently
|
|
185
|
+
* stops working. A durable key is shown ONCE at creation (not re-revealable);
|
|
186
|
+
* set an expiry if you want keys that stay revealable until they expire. */
|
|
48
187
|
keyExpiresInSeconds?: number;
|
|
49
188
|
/** Override the apiblaze base (tests/self-host). Default https://apikeys.apiblaze.com */
|
|
50
189
|
base?: string;
|
|
@@ -53,6 +192,7 @@ type Action = {
|
|
|
53
192
|
action: 'list';
|
|
54
193
|
} | {
|
|
55
194
|
action: 'create';
|
|
195
|
+
keyType?: string;
|
|
56
196
|
} | {
|
|
57
197
|
action: 'reveal';
|
|
58
198
|
keyId: string;
|
|
@@ -71,4 +211,4 @@ declare function createApiblazeKeys(cfg: ApiblazeKeysConfig): {
|
|
|
71
211
|
}>;
|
|
72
212
|
};
|
|
73
213
|
|
|
74
|
-
export { type ApiblazeKeysConfig, type AppUser, createApiblazeKeys };
|
|
214
|
+
export { type ApiblazeGroupsConfig, type ApiblazeKeysConfig, type AppUser, type GroupsAction, PlaneError, createApiblazeGroups, createApiblazeKeys };
|