@baseworks/iam 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-26XPWBFV.js → chunk-NAVQMKZ3.js} +7 -0
- package/dist/client.d.ts +50 -4
- package/dist/client.js +27 -2
- package/dist/events.d.ts +10 -0
- package/dist/events.js +1 -1
- package/dist/projections.js +4 -1
- package/package.json +2 -2
- package/src/client.ts +42 -4
- package/src/events.ts +7 -0
- package/src/projections.ts +3 -0
- package/src/types.ts +19 -1
|
@@ -17,6 +17,13 @@ var UserEvents = defineAggregate("user", {
|
|
|
17
17
|
name: z.string().nullable(),
|
|
18
18
|
picture: z.string().nullable(),
|
|
19
19
|
at: z.number().int()
|
|
20
|
+
}),
|
|
21
|
+
// The person chose what they are called here (iam-service 0.5). Kept apart
|
|
22
|
+
// from `name`, which the identity provider sends on every sign-in and would
|
|
23
|
+
// otherwise overwrite it. `null` means "back to what the provider says".
|
|
24
|
+
UserRenamed: z.object({
|
|
25
|
+
displayName: z.string().min(1).nullable(),
|
|
26
|
+
at: z.number().int()
|
|
20
27
|
})
|
|
21
28
|
});
|
|
22
29
|
var TOKEN_TYPES = ["user", "service", "cli", "agent"];
|
package/dist/client.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ interface UserRow {
|
|
|
10
10
|
email: string;
|
|
11
11
|
name: string | null;
|
|
12
12
|
picture: string | null;
|
|
13
|
+
/** What the person chose to be called here; null or absent: the provider's `name`. */
|
|
14
|
+
display_name?: string | null;
|
|
13
15
|
created_at: number;
|
|
14
16
|
updated_at: number;
|
|
15
17
|
}
|
|
@@ -38,12 +40,27 @@ interface User {
|
|
|
38
40
|
created_at: number;
|
|
39
41
|
updated_at: number;
|
|
40
42
|
}
|
|
41
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Public-safe identity projection (returned by /users/lookup and
|
|
45
|
+
* /users/resolve). `name` is what the person chose to be called, else what
|
|
46
|
+
* their identity provider says.
|
|
47
|
+
*/
|
|
42
48
|
interface PublicUser {
|
|
43
49
|
id: string;
|
|
44
50
|
email: string;
|
|
45
51
|
name: string | null;
|
|
46
52
|
}
|
|
53
|
+
/** A person's own account, as `/me` gives it to them and to nobody else. */
|
|
54
|
+
interface Me extends PublicUser {
|
|
55
|
+
/** The name the identity provider sends; what `name` falls back to. */
|
|
56
|
+
provider_name: string | null;
|
|
57
|
+
/** True when `name` is one the person set here. */
|
|
58
|
+
name_is_own: boolean;
|
|
59
|
+
picture: string | null;
|
|
60
|
+
/** The identity provider this account signs in with. */
|
|
61
|
+
issuer: string;
|
|
62
|
+
created_at: number;
|
|
63
|
+
}
|
|
47
64
|
/** An OIDC identity presented to POST /sync (before a user id exists). */
|
|
48
65
|
interface OidcIdentity {
|
|
49
66
|
subject: string;
|
|
@@ -137,8 +154,15 @@ declare class IamClient {
|
|
|
137
154
|
api<T>(method: string, path: string, body?: unknown, extra?: Record<string, string>): Promise<T>;
|
|
138
155
|
/** Generic ApiClient (get/post/del) — used by the CLI plugin. */
|
|
139
156
|
get http(): HttpClient;
|
|
140
|
-
/** The signed-in user's own
|
|
141
|
-
me(): Promise<
|
|
157
|
+
/** The signed-in user's own account (no orgs — those live in @baseworks/org). */
|
|
158
|
+
me(): Promise<Me>;
|
|
159
|
+
/**
|
|
160
|
+
* Set what the signed-in person is called here. `null` goes back to the name
|
|
161
|
+
* their identity provider sends. Email and picture are the provider's.
|
|
162
|
+
*/
|
|
163
|
+
updateMe(input: {
|
|
164
|
+
name: string | null;
|
|
165
|
+
}): Promise<Me>;
|
|
142
166
|
/** Upsert an OIDC identity → the platform user. Called by auth-service (no auth). */
|
|
143
167
|
sync(identity: OidcIdentity): Promise<{
|
|
144
168
|
id: string;
|
|
@@ -169,10 +193,32 @@ declare class IamClient {
|
|
|
169
193
|
org_id?: string;
|
|
170
194
|
}): Promise<ApiToken[]>;
|
|
171
195
|
revokeToken(id: string): Promise<void>;
|
|
196
|
+
/**
|
|
197
|
+
* The keys that belong to an organization. Needs `iam:org_key.read` there,
|
|
198
|
+
* which org-service decides; the answer says whether the caller may also
|
|
199
|
+
* manage them. A person's token: a service uses `listTokens({ org_id })`.
|
|
200
|
+
*/
|
|
201
|
+
listOrgKeys(orgRef: string): Promise<{
|
|
202
|
+
org_id: string;
|
|
203
|
+
role: string;
|
|
204
|
+
can_manage: boolean;
|
|
205
|
+
keys: ApiToken[];
|
|
206
|
+
}>;
|
|
207
|
+
/** Create a key for an organization; the secret is returned once. Needs `iam:org_key.manage`. */
|
|
208
|
+
createOrgKey(orgRef: string, input: {
|
|
209
|
+
name: string;
|
|
210
|
+
type?: 'service' | 'agent';
|
|
211
|
+
access?: 'read' | 'write';
|
|
212
|
+
/** The role the key acts with; never above the caller's, never owner. Default `member`. */
|
|
213
|
+
role?: 'viewer' | 'member' | 'admin';
|
|
214
|
+
expires_at?: number | null;
|
|
215
|
+
}): Promise<IssuedToken>;
|
|
216
|
+
/** Revoke one of an organization's keys. Needs `iam:org_key.manage`. */
|
|
217
|
+
revokeOrgKey(orgRef: string, id: string): Promise<void>;
|
|
172
218
|
/** Verify a raw token secret → its principal, or throw IamError(401). */
|
|
173
219
|
verifyToken(secret: string): Promise<TokenPrincipal>;
|
|
174
220
|
}
|
|
175
221
|
/** Factory used by the SDK capability registry. */
|
|
176
222
|
declare function createIamClient(opts: IamClientOptions): IamClient;
|
|
177
223
|
|
|
178
|
-
export { type ApiToken, type ApiTokenRow, type AuthContext, type HttpClient, IamClient, type IamClientOptions, IamError, type IssuedToken, type OidcIdentity, type PublicUser, type TokenPrincipal, TokenType, type User, type UserRow, createIamClient };
|
|
224
|
+
export { type ApiToken, type ApiTokenRow, type AuthContext, type HttpClient, IamClient, type IamClientOptions, IamError, type IssuedToken, type Me, type OidcIdentity, type PublicUser, type TokenPrincipal, TokenType, type User, type UserRow, createIamClient };
|
package/dist/client.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TOKEN_TYPES
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-NAVQMKZ3.js";
|
|
4
4
|
|
|
5
5
|
// src/client.ts
|
|
6
6
|
var IamError = class extends Error {
|
|
@@ -62,11 +62,19 @@ var IamClient = class _IamClient {
|
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
64
|
// ── identity ────────────────────────────────────────────────────────────────
|
|
65
|
-
/** The signed-in user's own
|
|
65
|
+
/** The signed-in user's own account (no orgs — those live in @baseworks/org). */
|
|
66
66
|
async me() {
|
|
67
67
|
const { user } = await this.api("GET", "/me");
|
|
68
68
|
return user;
|
|
69
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Set what the signed-in person is called here. `null` goes back to the name
|
|
72
|
+
* their identity provider sends. Email and picture are the provider's.
|
|
73
|
+
*/
|
|
74
|
+
async updateMe(input) {
|
|
75
|
+
const { user } = await this.api("PATCH", "/me", input);
|
|
76
|
+
return user;
|
|
77
|
+
}
|
|
70
78
|
/** Upsert an OIDC identity → the platform user. Called by auth-service (no auth). */
|
|
71
79
|
async sync(identity) {
|
|
72
80
|
const { user } = await this.api("POST", "/sync", identity);
|
|
@@ -104,6 +112,23 @@ var IamClient = class _IamClient {
|
|
|
104
112
|
async revokeToken(id) {
|
|
105
113
|
await this.api("DELETE", `/tokens/${encodeURIComponent(id)}`);
|
|
106
114
|
}
|
|
115
|
+
// ── an organization's keys (a realm with an org-service only) ───────────────
|
|
116
|
+
/**
|
|
117
|
+
* The keys that belong to an organization. Needs `iam:org_key.read` there,
|
|
118
|
+
* which org-service decides; the answer says whether the caller may also
|
|
119
|
+
* manage them. A person's token: a service uses `listTokens({ org_id })`.
|
|
120
|
+
*/
|
|
121
|
+
async listOrgKeys(orgRef) {
|
|
122
|
+
return this.api("GET", `/orgs/${encodeURIComponent(orgRef)}/keys`);
|
|
123
|
+
}
|
|
124
|
+
/** Create a key for an organization; the secret is returned once. Needs `iam:org_key.manage`. */
|
|
125
|
+
async createOrgKey(orgRef, input) {
|
|
126
|
+
return this.api("POST", `/orgs/${encodeURIComponent(orgRef)}/keys`, input);
|
|
127
|
+
}
|
|
128
|
+
/** Revoke one of an organization's keys. Needs `iam:org_key.manage`. */
|
|
129
|
+
async revokeOrgKey(orgRef, id) {
|
|
130
|
+
await this.api("DELETE", `/orgs/${encodeURIComponent(orgRef)}/keys/${encodeURIComponent(id)}`);
|
|
131
|
+
}
|
|
107
132
|
/** Verify a raw token secret → its principal, or throw IamError(401). */
|
|
108
133
|
async verifyToken(secret) {
|
|
109
134
|
const { principal } = await this.api("POST", "/tokens/verify", { token: secret });
|
package/dist/events.d.ts
CHANGED
|
@@ -55,6 +55,16 @@ declare const UserEvents: _baseworks_foldbase.EventCatalog<{
|
|
|
55
55
|
name: string | null;
|
|
56
56
|
picture: string | null;
|
|
57
57
|
}>;
|
|
58
|
+
UserRenamed: z.ZodObject<{
|
|
59
|
+
displayName: z.ZodNullable<z.ZodString>;
|
|
60
|
+
at: z.ZodNumber;
|
|
61
|
+
}, "strip", z.ZodTypeAny, {
|
|
62
|
+
at: number;
|
|
63
|
+
displayName: string | null;
|
|
64
|
+
}, {
|
|
65
|
+
at: number;
|
|
66
|
+
displayName: string | null;
|
|
67
|
+
}>;
|
|
58
68
|
}> & {
|
|
59
69
|
newId(): string;
|
|
60
70
|
};
|
package/dist/events.js
CHANGED
package/dist/projections.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ApiTokenEvents,
|
|
3
3
|
UserEvents
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-NAVQMKZ3.js";
|
|
5
5
|
|
|
6
6
|
// src/projections.ts
|
|
7
7
|
import { defineProjection } from "@baseworks/foldbase";
|
|
@@ -18,6 +18,9 @@ var readUsers = defineProjection("users", UserEvents, (on) => ({
|
|
|
18
18
|
email: e.email,
|
|
19
19
|
name: e.name,
|
|
20
20
|
picture: e.picture
|
|
21
|
+
})),
|
|
22
|
+
UserRenamed: on.UserRenamed.upsert((e) => ({
|
|
23
|
+
display_name: e.displayName
|
|
21
24
|
}))
|
|
22
25
|
}));
|
|
23
26
|
var readApiTokens = defineProjection("api_tokens", ApiTokenEvents, (on) => ({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@baseworks/iam",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "IAM capability: identity (users) + credentials (api tokens). Typed HTTP client, foldbase event catalog, projections, and CLI plugin for iam-service. Contract-first, versioned with the service. Roles/PDP live in @baseworks/org.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"@baseworks/cli": "^0.2.0",
|
|
21
21
|
"commander": "^15.0.0",
|
|
22
22
|
"zod": "^3.25.76",
|
|
23
|
-
"@baseworks/foldbase": "0.
|
|
23
|
+
"@baseworks/foldbase": "0.2.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@types/node": "^22.20.0",
|
package/src/client.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PublicUser, OidcIdentity, ApiToken, IssuedToken, TokenPrincipal, TokenType } from './types.js'
|
|
1
|
+
import type { PublicUser, Me, OidcIdentity, ApiToken, IssuedToken, TokenPrincipal, TokenType } from './types.js'
|
|
2
2
|
|
|
3
3
|
// Value re-export (a runtime const, not just a type) so consumers can build
|
|
4
4
|
// validators from it, e.g. `z.enum(TOKEN_TYPES)`.
|
|
@@ -7,6 +7,7 @@ export { TOKEN_TYPES } from './types.js'
|
|
|
7
7
|
export type {
|
|
8
8
|
User,
|
|
9
9
|
PublicUser,
|
|
10
|
+
Me,
|
|
10
11
|
OidcIdentity,
|
|
11
12
|
ApiToken,
|
|
12
13
|
IssuedToken,
|
|
@@ -112,9 +113,18 @@ export class IamClient {
|
|
|
112
113
|
|
|
113
114
|
// ── identity ────────────────────────────────────────────────────────────────
|
|
114
115
|
|
|
115
|
-
/** The signed-in user's own
|
|
116
|
-
async me(): Promise<
|
|
117
|
-
const { user } = await this.api<{ user:
|
|
116
|
+
/** The signed-in user's own account (no orgs — those live in @baseworks/org). */
|
|
117
|
+
async me(): Promise<Me> {
|
|
118
|
+
const { user } = await this.api<{ user: Me }>('GET', '/me')
|
|
119
|
+
return user
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Set what the signed-in person is called here. `null` goes back to the name
|
|
124
|
+
* their identity provider sends. Email and picture are the provider's.
|
|
125
|
+
*/
|
|
126
|
+
async updateMe(input: { name: string | null }): Promise<Me> {
|
|
127
|
+
const { user } = await this.api<{ user: Me }>('PATCH', '/me', input)
|
|
118
128
|
return user
|
|
119
129
|
}
|
|
120
130
|
|
|
@@ -170,6 +180,34 @@ export class IamClient {
|
|
|
170
180
|
await this.api('DELETE', `/tokens/${encodeURIComponent(id)}`)
|
|
171
181
|
}
|
|
172
182
|
|
|
183
|
+
// ── an organization's keys (a realm with an org-service only) ───────────────
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* The keys that belong to an organization. Needs `iam:org_key.read` there,
|
|
187
|
+
* which org-service decides; the answer says whether the caller may also
|
|
188
|
+
* manage them. A person's token: a service uses `listTokens({ org_id })`.
|
|
189
|
+
*/
|
|
190
|
+
async listOrgKeys(orgRef: string): Promise<{ org_id: string; role: string; can_manage: boolean; keys: ApiToken[] }> {
|
|
191
|
+
return this.api('GET', `/orgs/${encodeURIComponent(orgRef)}/keys`)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** Create a key for an organization; the secret is returned once. Needs `iam:org_key.manage`. */
|
|
195
|
+
async createOrgKey(orgRef: string, input: {
|
|
196
|
+
name: string
|
|
197
|
+
type?: 'service' | 'agent'
|
|
198
|
+
access?: 'read' | 'write'
|
|
199
|
+
/** The role the key acts with; never above the caller's, never owner. Default `member`. */
|
|
200
|
+
role?: 'viewer' | 'member' | 'admin'
|
|
201
|
+
expires_at?: number | null
|
|
202
|
+
}): Promise<IssuedToken> {
|
|
203
|
+
return this.api<IssuedToken>('POST', `/orgs/${encodeURIComponent(orgRef)}/keys`, input)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** Revoke one of an organization's keys. Needs `iam:org_key.manage`. */
|
|
207
|
+
async revokeOrgKey(orgRef: string, id: string): Promise<void> {
|
|
208
|
+
await this.api('DELETE', `/orgs/${encodeURIComponent(orgRef)}/keys/${encodeURIComponent(id)}`)
|
|
209
|
+
}
|
|
210
|
+
|
|
173
211
|
/** Verify a raw token secret → its principal, or throw IamError(401). */
|
|
174
212
|
async verifyToken(secret: string): Promise<TokenPrincipal> {
|
|
175
213
|
const { principal } = await this.api<{ principal: TokenPrincipal }>('POST', '/tokens/verify', { token: secret })
|
package/src/events.ts
CHANGED
|
@@ -36,6 +36,13 @@ export const UserEvents = defineAggregate('user', {
|
|
|
36
36
|
picture: z.string().nullable(),
|
|
37
37
|
at: z.number().int(),
|
|
38
38
|
}),
|
|
39
|
+
// The person chose what they are called here (iam-service 0.5). Kept apart
|
|
40
|
+
// from `name`, which the identity provider sends on every sign-in and would
|
|
41
|
+
// otherwise overwrite it. `null` means "back to what the provider says".
|
|
42
|
+
UserRenamed: z.object({
|
|
43
|
+
displayName: z.string().min(1).nullable(),
|
|
44
|
+
at: z.number().int(),
|
|
45
|
+
}),
|
|
39
46
|
})
|
|
40
47
|
|
|
41
48
|
// ── api_token ───────────────────────────────────────────────────────────────
|
package/src/projections.ts
CHANGED
|
@@ -25,6 +25,9 @@ export const readUsers = defineProjection('users', UserEvents, (on) => ({
|
|
|
25
25
|
name: e.name,
|
|
26
26
|
picture: e.picture,
|
|
27
27
|
})),
|
|
28
|
+
UserRenamed: on.UserRenamed.upsert((e) => ({
|
|
29
|
+
display_name: e.displayName,
|
|
30
|
+
})),
|
|
28
31
|
}))
|
|
29
32
|
|
|
30
33
|
export const readApiTokens = defineProjection('api_tokens', ApiTokenEvents, (on) => ({
|
package/src/types.ts
CHANGED
|
@@ -14,6 +14,8 @@ export interface UserRow {
|
|
|
14
14
|
email: string
|
|
15
15
|
name: string | null
|
|
16
16
|
picture: string | null
|
|
17
|
+
/** What the person chose to be called here; null or absent: the provider's `name`. */
|
|
18
|
+
display_name?: string | null
|
|
17
19
|
created_at: number
|
|
18
20
|
updated_at: number
|
|
19
21
|
}
|
|
@@ -51,13 +53,29 @@ export interface User {
|
|
|
51
53
|
updated_at: number
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* Public-safe identity projection (returned by /users/lookup and
|
|
58
|
+
* /users/resolve). `name` is what the person chose to be called, else what
|
|
59
|
+
* their identity provider says.
|
|
60
|
+
*/
|
|
55
61
|
export interface PublicUser {
|
|
56
62
|
id: string
|
|
57
63
|
email: string
|
|
58
64
|
name: string | null
|
|
59
65
|
}
|
|
60
66
|
|
|
67
|
+
/** A person's own account, as `/me` gives it to them and to nobody else. */
|
|
68
|
+
export interface Me extends PublicUser {
|
|
69
|
+
/** The name the identity provider sends; what `name` falls back to. */
|
|
70
|
+
provider_name: string | null
|
|
71
|
+
/** True when `name` is one the person set here. */
|
|
72
|
+
name_is_own: boolean
|
|
73
|
+
picture: string | null
|
|
74
|
+
/** The identity provider this account signs in with. */
|
|
75
|
+
issuer: string
|
|
76
|
+
created_at: number
|
|
77
|
+
}
|
|
78
|
+
|
|
61
79
|
/** An OIDC identity presented to POST /sync (before a user id exists). */
|
|
62
80
|
export interface OidcIdentity {
|
|
63
81
|
subject: string
|