@stackframe/stack-shared 2.6.38 → 2.7.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/CHANGELOG.md +17 -0
- package/dist/interface/adminInterface.d.ts +16 -1
- package/dist/interface/adminInterface.js +16 -0
- package/dist/interface/crud/projects.d.ts +17 -0
- package/dist/interface/crud/projects.js +1 -1
- package/dist/utils/caches.js +0 -2
- package/dist/utils/dates.d.ts +1 -0
- package/dist/utils/dates.js +3 -0
- package/dist/utils/locks.d.ts +14 -0
- package/dist/utils/locks.js +62 -0
- package/dist/utils/stores.d.ts +3 -1
- package/dist/utils/stores.js +8 -4
- package/dist/utils/unicode.d.ts +1 -0
- package/dist/utils/unicode.js +10 -0
- package/package.json +9 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @stackframe/stack-shared
|
|
2
2
|
|
|
3
|
+
## 2.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Various changes
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- @stackframe/stack-sc@2.7.0
|
|
12
|
+
|
|
13
|
+
## 2.6.39
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Various changes
|
|
18
|
+
- @stackframe/stack-sc@2.6.39
|
|
19
|
+
|
|
3
20
|
## 2.6.38
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
|
@@ -25,7 +25,7 @@ export type ApiKeyCreateCrudResponse = ApiKeysCrud["Admin"]["Read"] & {
|
|
|
25
25
|
export declare class StackAdminInterface extends StackServerInterface {
|
|
26
26
|
readonly options: AdminAuthApplicationOptions;
|
|
27
27
|
constructor(options: AdminAuthApplicationOptions);
|
|
28
|
-
|
|
28
|
+
sendAdminRequest(path: string, options: RequestInit, session: InternalSession | null, requestType?: "admin"): Promise<Response & {
|
|
29
29
|
usedTokens: {
|
|
30
30
|
accessToken: import("../sessions").AccessToken;
|
|
31
31
|
refreshToken: import("../sessions").RefreshToken | null;
|
|
@@ -46,4 +46,19 @@ export declare class StackAdminInterface extends StackServerInterface {
|
|
|
46
46
|
deletePermissionDefinition(permissionId: string): Promise<void>;
|
|
47
47
|
getSvixToken(): Promise<SvixTokenCrud["Admin"]["Read"]>;
|
|
48
48
|
deleteProject(): Promise<void>;
|
|
49
|
+
getMetrics(): Promise<any>;
|
|
50
|
+
sendTestEmail(data: {
|
|
51
|
+
recipient_email: string;
|
|
52
|
+
email_config: {
|
|
53
|
+
host: string;
|
|
54
|
+
port: number;
|
|
55
|
+
username: string;
|
|
56
|
+
password: string;
|
|
57
|
+
sender_email: string;
|
|
58
|
+
sender_name: string;
|
|
59
|
+
};
|
|
60
|
+
}): Promise<{
|
|
61
|
+
success: boolean;
|
|
62
|
+
error_message?: string;
|
|
63
|
+
}>;
|
|
49
64
|
}
|
|
@@ -120,4 +120,20 @@ export class StackAdminInterface extends StackServerInterface {
|
|
|
120
120
|
method: "DELETE",
|
|
121
121
|
}, null);
|
|
122
122
|
}
|
|
123
|
+
async getMetrics() {
|
|
124
|
+
const response = await this.sendAdminRequest("/internal/metrics", {
|
|
125
|
+
method: "GET",
|
|
126
|
+
}, null);
|
|
127
|
+
return await response.json();
|
|
128
|
+
}
|
|
129
|
+
async sendTestEmail(data) {
|
|
130
|
+
const response = await this.sendAdminRequest(`/internal/send-test-email`, {
|
|
131
|
+
method: "POST",
|
|
132
|
+
headers: {
|
|
133
|
+
"content-type": "application/json",
|
|
134
|
+
},
|
|
135
|
+
body: JSON.stringify(data),
|
|
136
|
+
}, null);
|
|
137
|
+
return await response.json();
|
|
138
|
+
}
|
|
123
139
|
}
|
|
@@ -1,4 +1,21 @@
|
|
|
1
1
|
import { CrudTypeOf } from "../../crud";
|
|
2
|
+
export declare const emailConfigSchema: import("yup").ObjectSchema<{
|
|
3
|
+
type: "shared" | "standard";
|
|
4
|
+
host: string | undefined;
|
|
5
|
+
port: number | undefined;
|
|
6
|
+
username: string | undefined;
|
|
7
|
+
password: string | undefined;
|
|
8
|
+
sender_name: string | undefined;
|
|
9
|
+
sender_email: string | undefined;
|
|
10
|
+
}, import("yup").AnyObject, {
|
|
11
|
+
type: undefined;
|
|
12
|
+
host: undefined;
|
|
13
|
+
port: undefined;
|
|
14
|
+
username: undefined;
|
|
15
|
+
password: undefined;
|
|
16
|
+
sender_name: undefined;
|
|
17
|
+
sender_email: undefined;
|
|
18
|
+
}, "">;
|
|
2
19
|
export declare const projectsCrudAdminReadSchema: import("yup").ObjectSchema<{
|
|
3
20
|
id: string;
|
|
4
21
|
display_name: string;
|
|
@@ -17,7 +17,7 @@ const oauthProviderSchema = yupObject({
|
|
|
17
17
|
const enabledOAuthProviderSchema = yupObject({
|
|
18
18
|
id: schemaFields.oauthIdSchema.defined(),
|
|
19
19
|
});
|
|
20
|
-
const emailConfigSchema = yupObject({
|
|
20
|
+
export const emailConfigSchema = yupObject({
|
|
21
21
|
type: schemaFields.emailTypeSchema.defined(),
|
|
22
22
|
host: yupDefinedWhen(schemaFields.emailHostSchema, 'type', 'standard'),
|
|
23
23
|
port: yupDefinedWhen(schemaFields.emailPortSchema, 'type', 'standard'),
|
package/dist/utils/caches.js
CHANGED
|
@@ -146,7 +146,6 @@ class AsyncValueCache {
|
|
|
146
146
|
});
|
|
147
147
|
this._unsubscribers.push(unsubscribe);
|
|
148
148
|
}
|
|
149
|
-
console.log("add", this._subscriptionsCount, new Date().toISOString());
|
|
150
149
|
let hasUnsubscribed = false;
|
|
151
150
|
return {
|
|
152
151
|
unsubscribe: () => {
|
|
@@ -154,7 +153,6 @@ class AsyncValueCache {
|
|
|
154
153
|
return;
|
|
155
154
|
hasUnsubscribed = true;
|
|
156
155
|
storeObj.unsubscribe();
|
|
157
|
-
console.log("remove", this._subscriptionsCount - 1, new Date().toISOString());
|
|
158
156
|
if (--this._subscriptionsCount === 0) {
|
|
159
157
|
for (const unsubscribe of this._unsubscribers) {
|
|
160
158
|
unsubscribe();
|
package/dist/utils/dates.d.ts
CHANGED
package/dist/utils/dates.js
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type LockCallback<T> = () => Promise<T>;
|
|
2
|
+
export declare class ReadWriteLock {
|
|
3
|
+
private semaphore;
|
|
4
|
+
private readers;
|
|
5
|
+
private readersMutex;
|
|
6
|
+
constructor();
|
|
7
|
+
withReadLock<T>(callback: LockCallback<T>): Promise<T>;
|
|
8
|
+
withWriteLock<T>(callback: LockCallback<T>): Promise<T>;
|
|
9
|
+
private _acquireReadLock;
|
|
10
|
+
private _releaseReadLock;
|
|
11
|
+
private _acquireWriteLock;
|
|
12
|
+
private _releaseWriteLock;
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Semaphore } from 'async-mutex';
|
|
2
|
+
export class ReadWriteLock {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.semaphore = new Semaphore(1); // Semaphore with 1 permit
|
|
5
|
+
this.readers = 0; // Track the number of readers
|
|
6
|
+
this.readersMutex = new Semaphore(1); // Protect access to `readers` count
|
|
7
|
+
}
|
|
8
|
+
async withReadLock(callback) {
|
|
9
|
+
await this._acquireReadLock();
|
|
10
|
+
try {
|
|
11
|
+
return await callback();
|
|
12
|
+
}
|
|
13
|
+
finally {
|
|
14
|
+
await this._releaseReadLock();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async withWriteLock(callback) {
|
|
18
|
+
await this._acquireWriteLock();
|
|
19
|
+
try {
|
|
20
|
+
return await callback();
|
|
21
|
+
}
|
|
22
|
+
finally {
|
|
23
|
+
await this._releaseWriteLock();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async _acquireReadLock() {
|
|
27
|
+
// Increment the readers count
|
|
28
|
+
await this.readersMutex.acquire();
|
|
29
|
+
try {
|
|
30
|
+
this.readers += 1;
|
|
31
|
+
// If this is the first reader, block writers
|
|
32
|
+
if (this.readers === 1) {
|
|
33
|
+
await this.semaphore.acquire();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
this.readersMutex.release();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async _releaseReadLock() {
|
|
41
|
+
// Decrement the readers count
|
|
42
|
+
await this.readersMutex.acquire();
|
|
43
|
+
try {
|
|
44
|
+
this.readers -= 1;
|
|
45
|
+
// If this was the last reader, release the writer block
|
|
46
|
+
if (this.readers === 0) {
|
|
47
|
+
this.semaphore.release();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
this.readersMutex.release();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async _acquireWriteLock() {
|
|
55
|
+
// Writers acquire the main semaphore exclusively
|
|
56
|
+
await this.semaphore.acquire();
|
|
57
|
+
}
|
|
58
|
+
async _releaseWriteLock() {
|
|
59
|
+
// Writers release the main semaphore
|
|
60
|
+
this.semaphore.release();
|
|
61
|
+
}
|
|
62
|
+
}
|
package/dist/utils/stores.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ReadWriteLock } from "./locks";
|
|
2
2
|
import { ReactPromise } from "./promises";
|
|
3
|
+
import { AsyncResult, Result } from "./results";
|
|
3
4
|
export type ReadonlyStore<T> = {
|
|
4
5
|
get(): T;
|
|
5
6
|
onChange(callback: (value: T, oldValue: T | undefined) => void): {
|
|
@@ -45,6 +46,7 @@ export declare class Store<T> implements ReadonlyStore<T> {
|
|
|
45
46
|
unsubscribe: () => void;
|
|
46
47
|
};
|
|
47
48
|
}
|
|
49
|
+
export declare const storeLock: ReadWriteLock;
|
|
48
50
|
export declare class AsyncStore<T> implements ReadonlyAsyncStore<T> {
|
|
49
51
|
private _isAvailable;
|
|
50
52
|
private _mostRecentOkValue;
|
package/dist/utils/stores.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { ReadWriteLock } from "./locks";
|
|
2
|
+
import { pending, rejected, resolved } from "./promises";
|
|
1
3
|
import { AsyncResult, Result } from "./results";
|
|
2
4
|
import { generateUuid } from "./uuids";
|
|
3
|
-
import { pending, rejected, resolved } from "./promises";
|
|
4
5
|
export class Store {
|
|
5
6
|
constructor(_value) {
|
|
6
7
|
this._value = _value;
|
|
@@ -36,6 +37,7 @@ export class Store {
|
|
|
36
37
|
return { unsubscribe };
|
|
37
38
|
}
|
|
38
39
|
}
|
|
40
|
+
export const storeLock = new ReadWriteLock();
|
|
39
41
|
export class AsyncStore {
|
|
40
42
|
constructor(...args) {
|
|
41
43
|
this._mostRecentOkValue = undefined;
|
|
@@ -135,9 +137,11 @@ export class AsyncStore {
|
|
|
135
137
|
return value;
|
|
136
138
|
}
|
|
137
139
|
async setAsync(promise) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
140
|
+
return await storeLock.withReadLock(async () => {
|
|
141
|
+
const curCounter = ++this._updateCounter;
|
|
142
|
+
const result = await Result.fromPromise(promise);
|
|
143
|
+
return this._setIfLatest(result, curCounter);
|
|
144
|
+
});
|
|
141
145
|
}
|
|
142
146
|
setUnavailable() {
|
|
143
147
|
this._lastSuccessfulUpdate = ++this._updateCounter;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getFlagEmoji(twoLetterCountryCode: string): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { StackAssertionError } from "./errors";
|
|
2
|
+
export function getFlagEmoji(twoLetterCountryCode) {
|
|
3
|
+
if (!/^[a-zA-Z][a-zA-Z]$/.test(twoLetterCountryCode))
|
|
4
|
+
throw new StackAssertionError("Country code must be two alphabetical letters");
|
|
5
|
+
const codePoints = twoLetterCountryCode
|
|
6
|
+
.toUpperCase()
|
|
7
|
+
.split('')
|
|
8
|
+
.map(char => 127397 + char.charCodeAt(0));
|
|
9
|
+
return String.fromCodePoint(...codePoints);
|
|
10
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stackframe/stack-shared",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
|
-
"react": ">=18.2 || >=19.0.0-rc.0",
|
|
24
|
-
"react-dom": ">=18.2 || >=19.0.0-rc.0",
|
|
25
23
|
"@types/react": ">=18.2 || >=19.0.0-rc.0",
|
|
26
24
|
"@types/react-dom": ">=18.2 || >=19.0.0-rc.0",
|
|
27
25
|
"next": ">=14.1.0 || >=15.0.0-rc.0",
|
|
26
|
+
"react": ">=18.2 || >=19.0.0-rc.0",
|
|
27
|
+
"react-dom": ">=18.2 || >=19.0.0-rc.0",
|
|
28
28
|
"yup": "^1.4.0"
|
|
29
29
|
},
|
|
30
30
|
"peerDependenciesMeta": {
|
|
@@ -43,26 +43,27 @@
|
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@simplewebauthn/browser": "^11.0.0",
|
|
46
|
+
"async-mutex": "^0.5.0",
|
|
46
47
|
"bcrypt": "^5.1.1",
|
|
47
48
|
"elliptic": "^6.5.7",
|
|
48
|
-
"jose": "^5.2.2",
|
|
49
49
|
"ip-regex": "^5.0.0",
|
|
50
|
+
"jose": "^5.2.2",
|
|
50
51
|
"oauth4webapi": "^2.10.3",
|
|
51
52
|
"semver": "^7.6.3",
|
|
52
53
|
"uuid": "^9.0.1",
|
|
53
|
-
"@stackframe/stack-sc": "2.
|
|
54
|
+
"@stackframe/stack-sc": "2.7.0"
|
|
54
55
|
},
|
|
55
56
|
"devDependencies": {
|
|
57
|
+
"@sentry/nextjs": "^8.40.0",
|
|
56
58
|
"@simplewebauthn/types": "^11.0.0",
|
|
57
59
|
"@types/bcrypt": "^5.0.2",
|
|
58
60
|
"@types/elliptic": "^6.4.18",
|
|
59
61
|
"@types/semver": "^7.5.8",
|
|
60
62
|
"@types/uuid": "^9.0.8",
|
|
61
|
-
"
|
|
63
|
+
"next": "^14.1.0",
|
|
62
64
|
"react": "^18.2",
|
|
63
65
|
"react-dom": "^18.2",
|
|
64
|
-
"
|
|
65
|
-
"@sentry/nextjs": "^8.40.0"
|
|
66
|
+
"rimraf": "^5.0.5"
|
|
66
67
|
},
|
|
67
68
|
"scripts": {
|
|
68
69
|
"build": "tsc",
|