@willyim/idp 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -12
- package/dist/src/api.d.ts +31 -55
- package/dist/src/api.d.ts.map +1 -1
- package/dist/src/api.js +16 -11
- package/dist/src/claims.d.ts +9 -34
- package/dist/src/claims.d.ts.map +1 -1
- package/dist/src/claims.js +12 -40
- package/dist/src/client.d.ts +30 -34
- package/dist/src/client.d.ts.map +1 -1
- package/dist/src/client.js +16 -22
- package/dist/src/drizzle/index.d.ts +78 -13
- package/dist/src/drizzle/index.d.ts.map +1 -1
- package/dist/src/errors.d.ts +8 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +12 -0
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -1
- package/dist/src/schemas/index.d.ts +323 -0
- package/dist/src/schemas/index.d.ts.map +1 -0
- package/dist/src/schemas/index.js +207 -0
- package/dist/src/schemas/openapi.d.ts +31 -0
- package/dist/src/schemas/openapi.d.ts.map +1 -0
- package/dist/src/schemas/openapi.js +111 -0
- package/dist/src/schemas/operations.d.ts +502 -0
- package/dist/src/schemas/operations.d.ts.map +1 -0
- package/dist/src/schemas/operations.js +213 -0
- package/dist/src/session.d.ts +17 -3
- package/dist/src/session.d.ts.map +1 -1
- package/dist/src/session.js +12 -1
- package/dist/src/user-keys.d.ts +124 -0
- package/dist/src/user-keys.d.ts.map +1 -0
- package/dist/src/user-keys.js +174 -0
- package/dist/src/validate.d.ts +13 -0
- package/dist/src/validate.d.ts.map +1 -0
- package/dist/src/validate.js +28 -0
- package/dist/src/wire.d.ts +164 -0
- package/dist/src/wire.d.ts.map +1 -0
- package/dist/src/wire.js +100 -0
- package/openapi/idp-api.json +1110 -17
- package/package.json +16 -7
- package/dist/src/generated/idp-api.d.ts +0 -1022
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The OIDC wire, as zod schemas: discovery, the token endpoint, and the claim
|
|
3
|
+
* set. These are not in `./schemas` with the management API because they are
|
|
4
|
+
* standards-defined — nothing generates them, and they never appear in our
|
|
5
|
+
* OpenAPI document.
|
|
6
|
+
*
|
|
7
|
+
* Two different postures live here on purpose:
|
|
8
|
+
*
|
|
9
|
+
* - **Strict** on anything we act on. Without `token_endpoint` there is no
|
|
10
|
+
* flow to run, and an `access_token` that is absent must not become `""`
|
|
11
|
+
* and get written to a session row.
|
|
12
|
+
* - **Tolerant** on claims. A user with no permissions, no workspaces, or no
|
|
13
|
+
* display name is ordinary, not an error — those degrade to empty. Only
|
|
14
|
+
* `sub` is genuinely required, since it is the identity.
|
|
15
|
+
*
|
|
16
|
+
* Unknown fields pass through everywhere: an IdP is allowed to grow.
|
|
17
|
+
*/
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
export declare const PERMISSIONS_CLAIM = "https://willy.im/permissions";
|
|
20
|
+
export declare const WORKSPACES_CLAIM = "https://willy.im/workspaces";
|
|
21
|
+
/** The subset of the discovery document we use, plus the fields we may. */
|
|
22
|
+
export declare const DiscoverySchema: z.ZodObject<{
|
|
23
|
+
issuer: z.ZodString;
|
|
24
|
+
authorization_endpoint: z.ZodString;
|
|
25
|
+
token_endpoint: z.ZodString;
|
|
26
|
+
userinfo_endpoint: z.ZodString;
|
|
27
|
+
end_session_endpoint: z.ZodOptional<z.ZodString>;
|
|
28
|
+
jwks_uri: z.ZodOptional<z.ZodString>;
|
|
29
|
+
/**
|
|
30
|
+
* Per-app session ceiling, in seconds. Not standard OIDC — an IdP extension
|
|
31
|
+
* the SDK clamps `session.expiresIn` against when present.
|
|
32
|
+
*/
|
|
33
|
+
session_max_age: z.ZodOptional<z.ZodNumber>;
|
|
34
|
+
}, z.core.$loose>;
|
|
35
|
+
export type Discovery = z.output<typeof DiscoverySchema>;
|
|
36
|
+
/** Token-endpoint output, camelCased so app code never sees the wire shape. */
|
|
37
|
+
export declare const TokensSchema: z.ZodPipe<z.ZodObject<{
|
|
38
|
+
access_token: z.ZodString;
|
|
39
|
+
token_type: z.ZodDefault<z.ZodString>;
|
|
40
|
+
expires_in: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
41
|
+
refresh_token: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
42
|
+
id_token: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
43
|
+
scope: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
44
|
+
}, z.core.$loose>, z.ZodTransform<{
|
|
45
|
+
accessToken: string;
|
|
46
|
+
tokenType: string;
|
|
47
|
+
/** Seconds until the access token expires, when the IdP says. */
|
|
48
|
+
expiresIn: number | null;
|
|
49
|
+
refreshToken: string | null;
|
|
50
|
+
idToken: string | null;
|
|
51
|
+
scope: string | null;
|
|
52
|
+
}, {
|
|
53
|
+
[x: string]: unknown;
|
|
54
|
+
access_token: string;
|
|
55
|
+
token_type: string;
|
|
56
|
+
expires_in?: number | null | undefined;
|
|
57
|
+
refresh_token?: string | null | undefined;
|
|
58
|
+
id_token?: string | null | undefined;
|
|
59
|
+
scope?: string | null | undefined;
|
|
60
|
+
}>>;
|
|
61
|
+
export type Tokens = z.output<typeof TokensSchema>;
|
|
62
|
+
/** A tenant inside THIS app. `domain` is set for multi-domain apps, else null. */
|
|
63
|
+
export declare const WorkspaceSchema: z.ZodObject<{
|
|
64
|
+
id: z.ZodString;
|
|
65
|
+
slug: z.ZodDefault<z.ZodString>;
|
|
66
|
+
name: z.ZodDefault<z.ZodString>;
|
|
67
|
+
domain: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>;
|
|
68
|
+
role: z.ZodDefault<z.ZodString>;
|
|
69
|
+
}, z.core.$loose>;
|
|
70
|
+
export type Workspace = z.output<typeof WorkspaceSchema>;
|
|
71
|
+
/**
|
|
72
|
+
* The RFC 8693 `act` claim: present while an IdP admin is impersonating the
|
|
73
|
+
* user. Audit-only — tag your logs with it, never branch authorization on it.
|
|
74
|
+
*/
|
|
75
|
+
export declare const ActorSchema: z.ZodObject<{
|
|
76
|
+
sub: z.ZodString;
|
|
77
|
+
email: z.ZodOptional<z.ZodString>;
|
|
78
|
+
}, z.core.$loose>;
|
|
79
|
+
export type Actor = z.output<typeof ActorSchema>;
|
|
80
|
+
/**
|
|
81
|
+
* Wire claims -> `Claims`. The `https://willy.im/*` namespace is unwrapped
|
|
82
|
+
* here: namespaced URI claims are an OIDC requirement, not something app code
|
|
83
|
+
* should ever have to type.
|
|
84
|
+
*/
|
|
85
|
+
export declare const ClaimsSchema: z.ZodPipe<z.ZodObject<{
|
|
86
|
+
sub: z.ZodString;
|
|
87
|
+
email: z.ZodCatch<z.ZodString>;
|
|
88
|
+
email_verified: z.ZodCatch<z.ZodBoolean>;
|
|
89
|
+
name: z.ZodCatch<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
90
|
+
picture: z.ZodCatch<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
91
|
+
image: z.ZodCatch<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
92
|
+
"https://willy.im/permissions": z.ZodPipe<z.ZodCatch<z.ZodArray<z.ZodCatch<z.ZodNullable<z.ZodString>>>>, z.ZodTransform<string[], (string | null)[]>>;
|
|
93
|
+
"https://willy.im/workspaces": z.ZodPipe<z.ZodCatch<z.ZodArray<z.ZodCatch<z.ZodNullable<z.ZodObject<{
|
|
94
|
+
id: z.ZodString;
|
|
95
|
+
slug: z.ZodDefault<z.ZodString>;
|
|
96
|
+
name: z.ZodDefault<z.ZodString>;
|
|
97
|
+
domain: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>;
|
|
98
|
+
role: z.ZodDefault<z.ZodString>;
|
|
99
|
+
}, z.core.$loose>>>>>, z.ZodTransform<{
|
|
100
|
+
[x: string]: unknown;
|
|
101
|
+
id: string;
|
|
102
|
+
slug: string;
|
|
103
|
+
name: string;
|
|
104
|
+
domain: string | null;
|
|
105
|
+
role: string;
|
|
106
|
+
}[], ({
|
|
107
|
+
[x: string]: unknown;
|
|
108
|
+
id: string;
|
|
109
|
+
slug: string;
|
|
110
|
+
name: string;
|
|
111
|
+
domain: string | null;
|
|
112
|
+
role: string;
|
|
113
|
+
} | null)[]>>;
|
|
114
|
+
act: z.ZodCatch<z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
115
|
+
sub: z.ZodString;
|
|
116
|
+
email: z.ZodOptional<z.ZodString>;
|
|
117
|
+
}, z.core.$loose>>>>;
|
|
118
|
+
}, z.core.$loose>, z.ZodTransform<{
|
|
119
|
+
sub: string;
|
|
120
|
+
email: string;
|
|
121
|
+
emailVerified: boolean;
|
|
122
|
+
name: string | null;
|
|
123
|
+
image: string | null;
|
|
124
|
+
/** Product permissions granted in this app. Unwrapped from the namespace. */
|
|
125
|
+
permissions: string[];
|
|
126
|
+
/** Workspaces the user belongs to in this app. Unwrapped from the namespace. */
|
|
127
|
+
workspaces: {
|
|
128
|
+
[x: string]: unknown;
|
|
129
|
+
id: string;
|
|
130
|
+
slug: string;
|
|
131
|
+
name: string;
|
|
132
|
+
domain: string | null;
|
|
133
|
+
role: string;
|
|
134
|
+
}[];
|
|
135
|
+
actor: {
|
|
136
|
+
[x: string]: unknown;
|
|
137
|
+
sub: string;
|
|
138
|
+
email?: string | undefined;
|
|
139
|
+
} | null;
|
|
140
|
+
}, {
|
|
141
|
+
[x: string]: unknown;
|
|
142
|
+
sub: string;
|
|
143
|
+
email: string;
|
|
144
|
+
email_verified: boolean;
|
|
145
|
+
"https://willy.im/permissions": string[];
|
|
146
|
+
"https://willy.im/workspaces": {
|
|
147
|
+
[x: string]: unknown;
|
|
148
|
+
id: string;
|
|
149
|
+
slug: string;
|
|
150
|
+
name: string;
|
|
151
|
+
domain: string | null;
|
|
152
|
+
role: string;
|
|
153
|
+
}[];
|
|
154
|
+
name?: string | null | undefined;
|
|
155
|
+
picture?: string | null | undefined;
|
|
156
|
+
image?: string | null | undefined;
|
|
157
|
+
act?: {
|
|
158
|
+
[x: string]: unknown;
|
|
159
|
+
sub: string;
|
|
160
|
+
email?: string | undefined;
|
|
161
|
+
} | null | undefined;
|
|
162
|
+
}>>;
|
|
163
|
+
export type Claims = z.output<typeof ClaimsSchema>;
|
|
164
|
+
//# sourceMappingURL=wire.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wire.d.ts","sourceRoot":"","sources":["../../src/wire.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,eAAO,MAAM,iBAAiB,iCAAiC,CAAA;AAC/D,eAAO,MAAM,gBAAgB,gCAAgC,CAAA;AAE7D,2EAA2E;AAC3E,eAAO,MAAM,eAAe;;;;;;;IAO1B;;;OAGG;;iBAEH,CAAA;AAEF,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,eAAe,CAAC,CAAA;AAExD,+EAA+E;AAC/E,eAAO,MAAM,YAAY;;;;;;;;;;IAYrB,iEAAiE;;;;;;;;;;;;;GAKhE,CAAA;AAEL,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,YAAY,CAAC,CAAA;AAElD,kFAAkF;AAClF,eAAO,MAAM,eAAe;;;;;;iBAM1B,CAAA;AAEF,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,eAAe,CAAC,CAAA;AAExD;;;GAGG;AACH,eAAO,MAAM,WAAW;;;iBAGtB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,WAAW,CAAC,CAAA;AAMhD;;;;GAIG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAkBrB,6EAA6E;;IAE7E,gFAAgF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAG/E,CAAA;AAEL,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,YAAY,CAAC,CAAA"}
|
package/dist/src/wire.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The OIDC wire, as zod schemas: discovery, the token endpoint, and the claim
|
|
3
|
+
* set. These are not in `./schemas` with the management API because they are
|
|
4
|
+
* standards-defined — nothing generates them, and they never appear in our
|
|
5
|
+
* OpenAPI document.
|
|
6
|
+
*
|
|
7
|
+
* Two different postures live here on purpose:
|
|
8
|
+
*
|
|
9
|
+
* - **Strict** on anything we act on. Without `token_endpoint` there is no
|
|
10
|
+
* flow to run, and an `access_token` that is absent must not become `""`
|
|
11
|
+
* and get written to a session row.
|
|
12
|
+
* - **Tolerant** on claims. A user with no permissions, no workspaces, or no
|
|
13
|
+
* display name is ordinary, not an error — those degrade to empty. Only
|
|
14
|
+
* `sub` is genuinely required, since it is the identity.
|
|
15
|
+
*
|
|
16
|
+
* Unknown fields pass through everywhere: an IdP is allowed to grow.
|
|
17
|
+
*/
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
export const PERMISSIONS_CLAIM = "https://willy.im/permissions";
|
|
20
|
+
export const WORKSPACES_CLAIM = "https://willy.im/workspaces";
|
|
21
|
+
/** The subset of the discovery document we use, plus the fields we may. */
|
|
22
|
+
export const DiscoverySchema = z.looseObject({
|
|
23
|
+
issuer: z.string(),
|
|
24
|
+
authorization_endpoint: z.string().url(),
|
|
25
|
+
token_endpoint: z.string().url(),
|
|
26
|
+
userinfo_endpoint: z.string().url(),
|
|
27
|
+
end_session_endpoint: z.string().url().optional(),
|
|
28
|
+
jwks_uri: z.string().url().optional(),
|
|
29
|
+
/**
|
|
30
|
+
* Per-app session ceiling, in seconds. Not standard OIDC — an IdP extension
|
|
31
|
+
* the SDK clamps `session.expiresIn` against when present.
|
|
32
|
+
*/
|
|
33
|
+
session_max_age: z.number().optional(),
|
|
34
|
+
});
|
|
35
|
+
/** Token-endpoint output, camelCased so app code never sees the wire shape. */
|
|
36
|
+
export const TokensSchema = z
|
|
37
|
+
.looseObject({
|
|
38
|
+
access_token: z.string().min(1),
|
|
39
|
+
token_type: z.string().default("Bearer"),
|
|
40
|
+
expires_in: z.number().nullish(),
|
|
41
|
+
refresh_token: z.string().nullish(),
|
|
42
|
+
id_token: z.string().nullish(),
|
|
43
|
+
scope: z.string().nullish(),
|
|
44
|
+
})
|
|
45
|
+
.transform((raw) => ({
|
|
46
|
+
accessToken: raw.access_token,
|
|
47
|
+
tokenType: raw.token_type,
|
|
48
|
+
/** Seconds until the access token expires, when the IdP says. */
|
|
49
|
+
expiresIn: raw.expires_in ?? null,
|
|
50
|
+
refreshToken: raw.refresh_token ?? null,
|
|
51
|
+
idToken: raw.id_token ?? null,
|
|
52
|
+
scope: raw.scope ?? null,
|
|
53
|
+
}));
|
|
54
|
+
/** A tenant inside THIS app. `domain` is set for multi-domain apps, else null. */
|
|
55
|
+
export const WorkspaceSchema = z.looseObject({
|
|
56
|
+
id: z.string(),
|
|
57
|
+
slug: z.string().default(""),
|
|
58
|
+
name: z.string().default(""),
|
|
59
|
+
domain: z.string().nullish().transform((value) => value || null),
|
|
60
|
+
role: z.string().default("member"),
|
|
61
|
+
});
|
|
62
|
+
/**
|
|
63
|
+
* The RFC 8693 `act` claim: present while an IdP admin is impersonating the
|
|
64
|
+
* user. Audit-only — tag your logs with it, never branch authorization on it.
|
|
65
|
+
*/
|
|
66
|
+
export const ActorSchema = z.looseObject({
|
|
67
|
+
sub: z.string().min(1),
|
|
68
|
+
email: z.string().optional(),
|
|
69
|
+
});
|
|
70
|
+
/** `.catch` per field, so one bad element degrades instead of failing a login. */
|
|
71
|
+
const tolerantArray = (item) => z.array(item.nullable().catch(null)).catch([]).transform((values) => values.filter((v) => v !== null));
|
|
72
|
+
/**
|
|
73
|
+
* Wire claims -> `Claims`. The `https://willy.im/*` namespace is unwrapped
|
|
74
|
+
* here: namespaced URI claims are an OIDC requirement, not something app code
|
|
75
|
+
* should ever have to type.
|
|
76
|
+
*/
|
|
77
|
+
export const ClaimsSchema = z
|
|
78
|
+
.looseObject({
|
|
79
|
+
sub: z.string().min(1),
|
|
80
|
+
email: z.string().catch(""),
|
|
81
|
+
email_verified: z.boolean().catch(false),
|
|
82
|
+
name: z.string().nullish().catch(null),
|
|
83
|
+
picture: z.string().nullish().catch(null),
|
|
84
|
+
image: z.string().nullish().catch(null),
|
|
85
|
+
[PERMISSIONS_CLAIM]: tolerantArray(z.string()),
|
|
86
|
+
[WORKSPACES_CLAIM]: tolerantArray(WorkspaceSchema),
|
|
87
|
+
act: ActorSchema.nullish().catch(null),
|
|
88
|
+
})
|
|
89
|
+
.transform((raw) => ({
|
|
90
|
+
sub: raw.sub,
|
|
91
|
+
email: raw.email,
|
|
92
|
+
emailVerified: raw.email_verified,
|
|
93
|
+
name: raw.name || null,
|
|
94
|
+
image: raw.picture || raw.image || null,
|
|
95
|
+
/** Product permissions granted in this app. Unwrapped from the namespace. */
|
|
96
|
+
permissions: raw[PERMISSIONS_CLAIM],
|
|
97
|
+
/** Workspaces the user belongs to in this app. Unwrapped from the namespace. */
|
|
98
|
+
workspaces: raw[WORKSPACES_CLAIM],
|
|
99
|
+
actor: raw.act ?? null,
|
|
100
|
+
}));
|