@stackframe/stack-shared 2.6.7 → 2.6.10
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/CHANGELOG.md +25 -0
- package/dist/hooks/use-hash.d.ts +1 -0
- package/dist/hooks/use-hash.js +9 -0
- package/dist/interface/crud/contact-channels.d.ts +165 -0
- package/dist/interface/crud/contact-channels.js +62 -0
- package/dist/interface/crud/users.js +8 -0
- package/dist/utils/bytes.d.ts +3 -0
- package/dist/utils/bytes.js +18 -0
- package/dist/utils/jwt.js +4 -4
- package/dist/utils/promises.js +6 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @stackframe/stack-shared
|
|
2
2
|
|
|
3
|
+
## 2.6.10
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Various bugfixes
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @stackframe/stack-sc@2.6.10
|
|
10
|
+
|
|
11
|
+
## 2.6.9
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- - New contact channel API
|
|
16
|
+
- Fixed some visual gitches and typos
|
|
17
|
+
- Bug fixes
|
|
18
|
+
- Updated dependencies
|
|
19
|
+
- @stackframe/stack-sc@2.6.9
|
|
20
|
+
|
|
21
|
+
## 2.6.8
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- Bugfixes
|
|
26
|
+
- @stackframe/stack-sc@2.6.8
|
|
27
|
+
|
|
3
28
|
## 2.6.7
|
|
4
29
|
|
|
5
30
|
### Patch Changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const useHash: () => string | undefined;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { useParams } from "next/navigation";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
const getHash = () => typeof window === "undefined" ? undefined : window.location.hash.substring(1);
|
|
4
|
+
export const useHash = () => {
|
|
5
|
+
const params = useParams();
|
|
6
|
+
const [hash, setHash] = useState(getHash());
|
|
7
|
+
useEffect(() => setHash(getHash()), [params]);
|
|
8
|
+
return hash;
|
|
9
|
+
};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { CrudTypeOf } from "../../crud";
|
|
2
|
+
export declare const contactChannelsClientReadSchema: import("yup").ObjectSchema<{
|
|
3
|
+
user_id: string;
|
|
4
|
+
id: string;
|
|
5
|
+
value: string;
|
|
6
|
+
type: "email";
|
|
7
|
+
used_for_auth: NonNullable<boolean | undefined>;
|
|
8
|
+
is_verified: NonNullable<boolean | undefined>;
|
|
9
|
+
is_primary: NonNullable<boolean | undefined>;
|
|
10
|
+
}, import("yup").AnyObject, {
|
|
11
|
+
user_id: undefined;
|
|
12
|
+
id: undefined;
|
|
13
|
+
value: undefined;
|
|
14
|
+
type: undefined;
|
|
15
|
+
used_for_auth: undefined;
|
|
16
|
+
is_verified: undefined;
|
|
17
|
+
is_primary: undefined;
|
|
18
|
+
}, "">;
|
|
19
|
+
export declare const contactChannelsCrudClientUpdateSchema: import("yup").ObjectSchema<{
|
|
20
|
+
value: string | undefined;
|
|
21
|
+
type: "email" | undefined;
|
|
22
|
+
used_for_auth: boolean | undefined;
|
|
23
|
+
is_primary: boolean | undefined;
|
|
24
|
+
}, import("yup").AnyObject, {
|
|
25
|
+
value: undefined;
|
|
26
|
+
type: undefined;
|
|
27
|
+
used_for_auth: undefined;
|
|
28
|
+
is_primary: undefined;
|
|
29
|
+
}, "">;
|
|
30
|
+
export declare const contactChannelsCrudServerUpdateSchema: import("yup").ObjectSchema<{
|
|
31
|
+
value: string | undefined;
|
|
32
|
+
type: "email" | undefined;
|
|
33
|
+
used_for_auth: boolean | undefined;
|
|
34
|
+
is_primary: boolean | undefined;
|
|
35
|
+
} & {
|
|
36
|
+
is_verified: boolean | undefined;
|
|
37
|
+
}, import("yup").AnyObject, {
|
|
38
|
+
value: undefined;
|
|
39
|
+
type: undefined;
|
|
40
|
+
used_for_auth: undefined;
|
|
41
|
+
is_primary: undefined;
|
|
42
|
+
is_verified: undefined;
|
|
43
|
+
}, "">;
|
|
44
|
+
export declare const contactChannelsCrudClientCreateSchema: import("yup").ObjectSchema<{
|
|
45
|
+
user_id: string;
|
|
46
|
+
value: string;
|
|
47
|
+
type: "email";
|
|
48
|
+
used_for_auth: NonNullable<boolean | undefined>;
|
|
49
|
+
is_primary: boolean | undefined;
|
|
50
|
+
}, import("yup").AnyObject, {
|
|
51
|
+
user_id: undefined;
|
|
52
|
+
value: undefined;
|
|
53
|
+
type: undefined;
|
|
54
|
+
used_for_auth: undefined;
|
|
55
|
+
is_primary: undefined;
|
|
56
|
+
}, "">;
|
|
57
|
+
export declare const contactChannelsCrudServerCreateSchema: import("yup").ObjectSchema<{
|
|
58
|
+
user_id: string;
|
|
59
|
+
value: string;
|
|
60
|
+
type: "email";
|
|
61
|
+
used_for_auth: NonNullable<boolean | undefined>;
|
|
62
|
+
is_primary: boolean | undefined;
|
|
63
|
+
} & {
|
|
64
|
+
is_verified: boolean | undefined;
|
|
65
|
+
}, import("yup").AnyObject, {
|
|
66
|
+
user_id: undefined;
|
|
67
|
+
value: undefined;
|
|
68
|
+
type: undefined;
|
|
69
|
+
used_for_auth: undefined;
|
|
70
|
+
is_primary: undefined;
|
|
71
|
+
is_verified: undefined;
|
|
72
|
+
}, "">;
|
|
73
|
+
export declare const contactChannelsCrudClientDeleteSchema: import("yup").MixedSchema<{} | undefined, import("yup").AnyObject, undefined, "">;
|
|
74
|
+
export declare const contactChannelsCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
75
|
+
clientReadSchema: import("yup").ObjectSchema<{
|
|
76
|
+
user_id: string;
|
|
77
|
+
id: string;
|
|
78
|
+
value: string;
|
|
79
|
+
type: "email";
|
|
80
|
+
used_for_auth: NonNullable<boolean | undefined>;
|
|
81
|
+
is_verified: NonNullable<boolean | undefined>;
|
|
82
|
+
is_primary: NonNullable<boolean | undefined>;
|
|
83
|
+
}, import("yup").AnyObject, {
|
|
84
|
+
user_id: undefined;
|
|
85
|
+
id: undefined;
|
|
86
|
+
value: undefined;
|
|
87
|
+
type: undefined;
|
|
88
|
+
used_for_auth: undefined;
|
|
89
|
+
is_verified: undefined;
|
|
90
|
+
is_primary: undefined;
|
|
91
|
+
}, "">;
|
|
92
|
+
clientUpdateSchema: import("yup").ObjectSchema<{
|
|
93
|
+
value: string | undefined;
|
|
94
|
+
type: "email" | undefined;
|
|
95
|
+
used_for_auth: boolean | undefined;
|
|
96
|
+
is_primary: boolean | undefined;
|
|
97
|
+
}, import("yup").AnyObject, {
|
|
98
|
+
value: undefined;
|
|
99
|
+
type: undefined;
|
|
100
|
+
used_for_auth: undefined;
|
|
101
|
+
is_primary: undefined;
|
|
102
|
+
}, "">;
|
|
103
|
+
clientCreateSchema: import("yup").ObjectSchema<{
|
|
104
|
+
user_id: string;
|
|
105
|
+
value: string;
|
|
106
|
+
type: "email";
|
|
107
|
+
used_for_auth: NonNullable<boolean | undefined>;
|
|
108
|
+
is_primary: boolean | undefined;
|
|
109
|
+
}, import("yup").AnyObject, {
|
|
110
|
+
user_id: undefined;
|
|
111
|
+
value: undefined;
|
|
112
|
+
type: undefined;
|
|
113
|
+
used_for_auth: undefined;
|
|
114
|
+
is_primary: undefined;
|
|
115
|
+
}, "">;
|
|
116
|
+
clientDeleteSchema: import("yup").MixedSchema<{} | undefined, import("yup").AnyObject, undefined, "">;
|
|
117
|
+
serverUpdateSchema: import("yup").ObjectSchema<{
|
|
118
|
+
value: string | undefined;
|
|
119
|
+
type: "email" | undefined;
|
|
120
|
+
used_for_auth: boolean | undefined;
|
|
121
|
+
is_primary: boolean | undefined;
|
|
122
|
+
} & {
|
|
123
|
+
is_verified: boolean | undefined;
|
|
124
|
+
}, import("yup").AnyObject, {
|
|
125
|
+
value: undefined;
|
|
126
|
+
type: undefined;
|
|
127
|
+
used_for_auth: undefined;
|
|
128
|
+
is_primary: undefined;
|
|
129
|
+
is_verified: undefined;
|
|
130
|
+
}, "">;
|
|
131
|
+
serverCreateSchema: import("yup").ObjectSchema<{
|
|
132
|
+
user_id: string;
|
|
133
|
+
value: string;
|
|
134
|
+
type: "email";
|
|
135
|
+
used_for_auth: NonNullable<boolean | undefined>;
|
|
136
|
+
is_primary: boolean | undefined;
|
|
137
|
+
} & {
|
|
138
|
+
is_verified: boolean | undefined;
|
|
139
|
+
}, import("yup").AnyObject, {
|
|
140
|
+
user_id: undefined;
|
|
141
|
+
value: undefined;
|
|
142
|
+
type: undefined;
|
|
143
|
+
used_for_auth: undefined;
|
|
144
|
+
is_primary: undefined;
|
|
145
|
+
is_verified: undefined;
|
|
146
|
+
}, "">;
|
|
147
|
+
docs: {
|
|
148
|
+
clientRead: {
|
|
149
|
+
hidden: true;
|
|
150
|
+
};
|
|
151
|
+
clientCreate: {
|
|
152
|
+
hidden: true;
|
|
153
|
+
};
|
|
154
|
+
clientUpdate: {
|
|
155
|
+
hidden: true;
|
|
156
|
+
};
|
|
157
|
+
clientDelete: {
|
|
158
|
+
hidden: true;
|
|
159
|
+
};
|
|
160
|
+
clientList: {
|
|
161
|
+
hidden: true;
|
|
162
|
+
};
|
|
163
|
+
};
|
|
164
|
+
}>;
|
|
165
|
+
export type ContactChannelsCrud = CrudTypeOf<typeof contactChannelsCrud>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { createCrud } from "../../crud";
|
|
2
|
+
import { userIdOrMeSchema, userIdSchema, yupBoolean, yupMixed, yupObject, yupString } from "../../schema-fields";
|
|
3
|
+
const contactChannelsTypes = ['email'];
|
|
4
|
+
const type = yupString().oneOf(contactChannelsTypes);
|
|
5
|
+
const value = yupString().when('type', {
|
|
6
|
+
is: 'email',
|
|
7
|
+
then: (schema) => schema.email(),
|
|
8
|
+
});
|
|
9
|
+
export const contactChannelsClientReadSchema = yupObject({
|
|
10
|
+
user_id: userIdSchema.required(),
|
|
11
|
+
id: yupString().required(),
|
|
12
|
+
value: value.required(),
|
|
13
|
+
type: type.required(),
|
|
14
|
+
used_for_auth: yupBoolean().required(),
|
|
15
|
+
is_verified: yupBoolean().required(),
|
|
16
|
+
is_primary: yupBoolean().required(),
|
|
17
|
+
}).required();
|
|
18
|
+
export const contactChannelsCrudClientUpdateSchema = yupObject({
|
|
19
|
+
value: value.optional(),
|
|
20
|
+
type: type.optional(),
|
|
21
|
+
used_for_auth: yupBoolean().optional(),
|
|
22
|
+
is_primary: yupBoolean().optional(),
|
|
23
|
+
}).required();
|
|
24
|
+
export const contactChannelsCrudServerUpdateSchema = contactChannelsCrudClientUpdateSchema.concat(yupObject({
|
|
25
|
+
is_verified: yupBoolean().optional(),
|
|
26
|
+
}));
|
|
27
|
+
export const contactChannelsCrudClientCreateSchema = yupObject({
|
|
28
|
+
user_id: userIdOrMeSchema.required(),
|
|
29
|
+
value: value.required(),
|
|
30
|
+
type: type.required(),
|
|
31
|
+
used_for_auth: yupBoolean().required(),
|
|
32
|
+
is_primary: yupBoolean().optional(),
|
|
33
|
+
}).required();
|
|
34
|
+
export const contactChannelsCrudServerCreateSchema = contactChannelsCrudClientCreateSchema.concat(yupObject({
|
|
35
|
+
is_verified: yupBoolean().optional(),
|
|
36
|
+
}));
|
|
37
|
+
export const contactChannelsCrudClientDeleteSchema = yupMixed();
|
|
38
|
+
export const contactChannelsCrud = createCrud({
|
|
39
|
+
clientReadSchema: contactChannelsClientReadSchema,
|
|
40
|
+
clientUpdateSchema: contactChannelsCrudClientUpdateSchema,
|
|
41
|
+
clientCreateSchema: contactChannelsCrudClientCreateSchema,
|
|
42
|
+
clientDeleteSchema: contactChannelsCrudClientDeleteSchema,
|
|
43
|
+
serverUpdateSchema: contactChannelsCrudServerUpdateSchema,
|
|
44
|
+
serverCreateSchema: contactChannelsCrudServerCreateSchema,
|
|
45
|
+
docs: {
|
|
46
|
+
clientRead: {
|
|
47
|
+
hidden: true,
|
|
48
|
+
},
|
|
49
|
+
clientCreate: {
|
|
50
|
+
hidden: true,
|
|
51
|
+
},
|
|
52
|
+
clientUpdate: {
|
|
53
|
+
hidden: true,
|
|
54
|
+
},
|
|
55
|
+
clientDelete: {
|
|
56
|
+
hidden: true,
|
|
57
|
+
},
|
|
58
|
+
clientList: {
|
|
59
|
+
hidden: true,
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
@@ -14,6 +14,14 @@ export const usersCrudServerUpdateSchema = fieldSchema.yupObject({
|
|
|
14
14
|
totp_secret_base64: fieldSchema.base64Schema.nullable().meta({ openapiField: { description: 'A TOTP secret for the user, overwriting the old one (if it exists). Set to null to disable 2FA.', exampleValue: 'dG90cC1zZWNyZXQ=' } }),
|
|
15
15
|
selected_team_id: fieldSchema.selectedTeamIdSchema.nullable().optional(),
|
|
16
16
|
}).required();
|
|
17
|
+
const contactChannelSchema = fieldSchema.yupObject({
|
|
18
|
+
id: fieldSchema.yupString().required(),
|
|
19
|
+
type: fieldSchema.yupString().required(),
|
|
20
|
+
value: fieldSchema.yupString().required(),
|
|
21
|
+
is_primary: fieldSchema.yupBoolean().required(),
|
|
22
|
+
is_verified: fieldSchema.yupBoolean().required(),
|
|
23
|
+
used_for_auth: fieldSchema.yupBoolean().required(),
|
|
24
|
+
}).required();
|
|
17
25
|
export const usersCrudServerReadSchema = fieldSchema.yupObject({
|
|
18
26
|
id: fieldSchema.userIdSchema.required(),
|
|
19
27
|
primary_email: fieldSchema.primaryEmailSchema.nullable().defined(),
|
package/dist/utils/bytes.d.ts
CHANGED
|
@@ -2,5 +2,8 @@ export declare function encodeBase32(input: Uint8Array): string;
|
|
|
2
2
|
export declare function decodeBase32(input: string): Uint8Array;
|
|
3
3
|
export declare function encodeBase64(input: Uint8Array): string;
|
|
4
4
|
export declare function decodeBase64(input: string): Uint8Array;
|
|
5
|
+
export declare function encodeBase64Url(input: Uint8Array): string;
|
|
6
|
+
export declare function decodeBase64Url(input: string): Uint8Array;
|
|
5
7
|
export declare function isBase32(input: string): boolean;
|
|
6
8
|
export declare function isBase64(input: string): boolean;
|
|
9
|
+
export declare function isBase64Url(input: string): boolean;
|
package/dist/utils/bytes.js
CHANGED
|
@@ -68,6 +68,20 @@ export function decodeBase64(input) {
|
|
|
68
68
|
}
|
|
69
69
|
return new Uint8Array(atob(input).split("").map((char) => char.charCodeAt(0)));
|
|
70
70
|
}
|
|
71
|
+
export function encodeBase64Url(input) {
|
|
72
|
+
const res = encodeBase64(input).replace(/=+$/, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
73
|
+
// sanity check
|
|
74
|
+
if (!isBase64Url(res)) {
|
|
75
|
+
throw new StackAssertionError("Invalid base64url output; this should never happen");
|
|
76
|
+
}
|
|
77
|
+
return res;
|
|
78
|
+
}
|
|
79
|
+
export function decodeBase64Url(input) {
|
|
80
|
+
if (!isBase64Url(input)) {
|
|
81
|
+
throw new StackAssertionError("Invalid base64url string");
|
|
82
|
+
}
|
|
83
|
+
return decodeBase64(input.replace(/-/g, "+").replace(/_/g, "/") + "====".slice((input.length - 1) % 4 + 1));
|
|
84
|
+
}
|
|
71
85
|
export function isBase32(input) {
|
|
72
86
|
for (const char of input) {
|
|
73
87
|
if (char === " ")
|
|
@@ -82,3 +96,7 @@ export function isBase64(input) {
|
|
|
82
96
|
const regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
|
|
83
97
|
return regex.test(input);
|
|
84
98
|
}
|
|
99
|
+
export function isBase64Url(input) {
|
|
100
|
+
const regex = /^[0-9a-zA-Z_-]+$/;
|
|
101
|
+
return regex.test(input);
|
|
102
|
+
}
|
package/dist/utils/jwt.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import elliptic from "elliptic";
|
|
2
2
|
import * as jose from "jose";
|
|
3
|
-
import {
|
|
3
|
+
import { encodeBase64Url } from "./bytes";
|
|
4
4
|
import { getEnvVariable } from "./env";
|
|
5
5
|
import { globalVar } from "./globals";
|
|
6
6
|
import { pick } from "./objects";
|
|
@@ -60,9 +60,9 @@ export async function getPrivateJwk(secret) {
|
|
|
60
60
|
return {
|
|
61
61
|
kty: 'EC',
|
|
62
62
|
crv: 'P-256',
|
|
63
|
-
d:
|
|
64
|
-
x:
|
|
65
|
-
y:
|
|
63
|
+
d: encodeBase64Url(priv),
|
|
64
|
+
x: encodeBase64Url(publicKey.getX().toBuffer()),
|
|
65
|
+
y: encodeBase64Url(publicKey.getY().toBuffer()),
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
68
|
export async function getPublicJwkSet(secret) {
|
package/dist/utils/promises.js
CHANGED
|
@@ -90,6 +90,12 @@ export function ignoreUnhandledRejection(promise) {
|
|
|
90
90
|
return promise;
|
|
91
91
|
}
|
|
92
92
|
export async function wait(ms) {
|
|
93
|
+
if (!Number.isFinite(ms) || ms < 0) {
|
|
94
|
+
throw new StackAssertionError(`wait() requires a non-negative integer number of milliseconds to wait. (found: ${ms}ms)`);
|
|
95
|
+
}
|
|
96
|
+
if (ms >= 2 ** 31) {
|
|
97
|
+
throw new StackAssertionError("The maximum timeout for wait() is 2147483647ms (2**31 - 1). (found: ${ms}ms)");
|
|
98
|
+
}
|
|
93
99
|
return await new Promise(resolve => setTimeout(resolve, ms));
|
|
94
100
|
}
|
|
95
101
|
export async function waitUntil(date) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stackframe/stack-shared",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.10",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"oauth4webapi": "^2.10.3",
|
|
39
39
|
"semver": "^7.6.3",
|
|
40
40
|
"uuid": "^9.0.1",
|
|
41
|
-
"@stackframe/stack-sc": "2.6.
|
|
41
|
+
"@stackframe/stack-sc": "2.6.10"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/bcrypt": "^5.0.2",
|