@stackframe/stack-shared 2.6.19 → 2.6.21

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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # @stackframe/stack-shared
2
2
 
3
+ ## 2.6.21
4
+
5
+ ### Patch Changes
6
+
7
+ - Fixed inviteUser
8
+ - Updated dependencies
9
+ - @stackframe/stack-sc@2.6.21
10
+
11
+ ## 2.6.20
12
+
13
+ ### Patch Changes
14
+
15
+ - Next.js 15 fixes
16
+ - Updated dependencies
17
+ - @stackframe/stack-sc@2.6.20
18
+
3
19
  ## 2.6.19
4
20
 
5
21
  ### Patch Changes
@@ -90,7 +90,7 @@ export declare class StackClientInterface {
90
90
  email: string;
91
91
  teamId: string;
92
92
  callbackUrl: string;
93
- session: InternalSession | null;
93
+ session: InternalSession;
94
94
  }): Promise<void>;
95
95
  acceptTeamInvitation<T extends 'use' | 'details' | 'check'>(options: {
96
96
  code: string;
@@ -162,7 +162,7 @@ export class StackClientInterface {
162
162
  let adminSession = "projectOwnerSession" in this.options ? this.options.projectOwnerSession : null;
163
163
  let adminTokenObj = adminSession ? await adminSession.getPotentiallyExpiredTokens() : null;
164
164
  // all requests should be dynamic to prevent Next.js caching
165
- cookies?.();
165
+ await cookies?.();
166
166
  const url = this.getApiUrl() + path;
167
167
  const params = {
168
168
  /**
@@ -77,6 +77,11 @@ export declare class StackServerInterface extends StackClientInterface {
77
77
  teamId: string;
78
78
  userId: string;
79
79
  }): Promise<void>;
80
+ updateServerTeamMemberProfile(options: {
81
+ teamId: string;
82
+ userId: string;
83
+ profile: TeamMemberProfilesCrud['Server']['Update'];
84
+ }): Promise<void>;
80
85
  grantServerTeamUserPermission(teamId: string, userId: string, permissionId: string): Promise<void>;
81
86
  revokeServerTeamUserPermission(teamId: string, userId: string, permissionId: string): Promise<void>;
82
87
  deleteServerServerUser(userId: string): Promise<void>;
@@ -85,4 +90,9 @@ export declare class StackServerInterface extends StackClientInterface {
85
90
  deleteServerContactChannel(userId: string, contactChannelId: string): Promise<void>;
86
91
  listServerContactChannels(userId: string): Promise<ContactChannelsCrud['Server']['Read'][]>;
87
92
  sendServerContactChannelVerificationEmail(userId: string, contactChannelId: string, callbackUrl: string): Promise<void>;
93
+ sendServerTeamInvitation(options: {
94
+ email: string;
95
+ teamId: string;
96
+ callbackUrl: string;
97
+ }): Promise<void>;
88
98
  }
@@ -199,6 +199,15 @@ export class StackServerInterface extends StackClientInterface {
199
199
  body: JSON.stringify({}),
200
200
  }, null);
201
201
  }
202
+ async updateServerTeamMemberProfile(options) {
203
+ await this.sendServerRequest(`/team-member-profiles/${options.teamId}/${options.userId}`, {
204
+ method: "PATCH",
205
+ headers: {
206
+ "content-type": "application/json",
207
+ },
208
+ body: JSON.stringify(options.profile),
209
+ }, null);
210
+ }
202
211
  async grantServerTeamUserPermission(teamId, userId, permissionId) {
203
212
  await this.sendServerRequest(`/team-permissions/${teamId}/${userId}/${permissionId}`, {
204
213
  method: "POST",
@@ -267,4 +276,17 @@ export class StackServerInterface extends StackClientInterface {
267
276
  body: JSON.stringify({ callback_url: callbackUrl }),
268
277
  }, null);
269
278
  }
279
+ async sendServerTeamInvitation(options) {
280
+ await this.sendServerRequest("/team-invitations/send-code", {
281
+ method: "POST",
282
+ headers: {
283
+ "Content-Type": "application/json"
284
+ },
285
+ body: JSON.stringify({
286
+ email: options.email,
287
+ team_id: options.teamId,
288
+ callback_url: options.callbackUrl,
289
+ }),
290
+ }, null);
291
+ }
270
292
  }
@@ -14,6 +14,7 @@ export declare class AsyncCache<D extends any[], T> {
14
14
  });
15
15
  private _createKeyed;
16
16
  getValueCache(dependencies: D): AsyncValueCache<T>;
17
+ refreshWhere(predicate: (dependencies: D) => boolean): Promise<void>;
17
18
  readonly isCacheAvailable: (key: D) => boolean;
18
19
  readonly getIfCached: (key: D) => ({
19
20
  status: "pending";
@@ -48,6 +48,15 @@ export class AsyncCache {
48
48
  }
49
49
  return cache;
50
50
  }
51
+ async refreshWhere(predicate) {
52
+ const promises = [];
53
+ for (const [dependencies, cache] of this._map) {
54
+ if (predicate(dependencies)) {
55
+ promises.push(cache.refresh());
56
+ }
57
+ }
58
+ await Promise.all(promises);
59
+ }
51
60
  }
52
61
  class AsyncValueCache {
53
62
  constructor(fetcher, _options = {}) {
@@ -1,3 +1,30 @@
1
+ export declare class WeakRefIfAvailable<T extends object> {
2
+ private readonly _ref;
3
+ constructor(value: T);
4
+ deref(): T | undefined;
5
+ }
6
+ /**
7
+ * A WeakMap-like object that can be iterated over.
8
+ *
9
+ * Note that it relies on WeakRef, and always falls back to the regular Map behavior (ie. no GC) in browsers that don't support it.
10
+ */
11
+ export declare class IterableWeakMap<K extends object, V> {
12
+ private readonly _weakMap;
13
+ private readonly _keyRefs;
14
+ constructor(entries?: readonly (readonly [K, V])[] | null);
15
+ get(key: K): V | undefined;
16
+ set(key: K, value: V): this;
17
+ delete(key: K): boolean;
18
+ has(key: K): boolean;
19
+ [Symbol.iterator](): IterableIterator<[K, V]>;
20
+ [Symbol.toStringTag]: string;
21
+ }
22
+ /**
23
+ * A map that is a IterableWeakMap for object keys and a regular Map for primitive keys. Also provides iteration over both
24
+ * object and primitive keys.
25
+ *
26
+ * Note that, just like IterableWeakMap, older browsers without support for WeakRef will use a regular Map for object keys.
27
+ */
1
28
  export declare class MaybeWeakMap<K, V> {
2
29
  private readonly _primitiveMap;
3
30
  private readonly _weakMap;
@@ -7,17 +34,24 @@ export declare class MaybeWeakMap<K, V> {
7
34
  set(key: K, value: V): this;
8
35
  delete(key: K): boolean;
9
36
  has(key: K): boolean;
37
+ [Symbol.iterator](): IterableIterator<[K, V]>;
10
38
  [Symbol.toStringTag]: string;
11
39
  }
40
+ /**
41
+ * A map that stores values indexed by an array of keys. If the keys are objects and the environment supports WeakRefs,
42
+ * they are stored in a WeakMap.
43
+ */
12
44
  export declare class DependenciesMap<K extends any[], V> {
13
45
  private _inner;
14
46
  private _valueToResult;
15
47
  private _unwrapFromInner;
16
48
  private _setInInner;
49
+ private _iterateInner;
17
50
  get(dependencies: K): V | undefined;
18
51
  set(dependencies: K, value: V): this;
19
52
  delete(dependencies: K): boolean;
20
53
  has(dependencies: K): boolean;
21
54
  clear(): void;
55
+ [Symbol.iterator](): IterableIterator<[K, V]>;
22
56
  [Symbol.toStringTag]: string;
23
57
  }
@@ -1,11 +1,79 @@
1
- var _a, _b;
1
+ var _a, _b, _c;
2
2
  import { Result } from "./results";
3
+ export class WeakRefIfAvailable {
4
+ constructor(value) {
5
+ if (typeof WeakRef === "undefined") {
6
+ this._ref = { deref: () => value };
7
+ }
8
+ else {
9
+ this._ref = new WeakRef(value);
10
+ }
11
+ }
12
+ deref() {
13
+ return this._ref.deref();
14
+ }
15
+ }
16
+ /**
17
+ * A WeakMap-like object that can be iterated over.
18
+ *
19
+ * Note that it relies on WeakRef, and always falls back to the regular Map behavior (ie. no GC) in browsers that don't support it.
20
+ */
21
+ export class IterableWeakMap {
22
+ constructor(entries) {
23
+ this[_a] = "IterableWeakMap";
24
+ const mappedEntries = entries?.map((e) => [e[0], { value: e[1], keyRef: new WeakRefIfAvailable(e[0]) }]);
25
+ this._weakMap = new WeakMap(mappedEntries ?? []);
26
+ this._keyRefs = new Set(mappedEntries?.map((e) => e[1].keyRef) ?? []);
27
+ }
28
+ get(key) {
29
+ return this._weakMap.get(key)?.value;
30
+ }
31
+ set(key, value) {
32
+ const existing = this._weakMap.get(key);
33
+ const updated = { value, keyRef: existing?.keyRef ?? new WeakRefIfAvailable(key) };
34
+ this._weakMap.set(key, updated);
35
+ this._keyRefs.add(updated.keyRef);
36
+ return this;
37
+ }
38
+ delete(key) {
39
+ const res = this._weakMap.get(key);
40
+ if (res) {
41
+ this._weakMap.delete(key);
42
+ this._keyRefs.delete(res.keyRef);
43
+ return true;
44
+ }
45
+ return false;
46
+ }
47
+ has(key) {
48
+ return this._weakMap.has(key) && this._keyRefs.has(this._weakMap.get(key).keyRef);
49
+ }
50
+ *[Symbol.iterator]() {
51
+ for (const keyRef of this._keyRefs) {
52
+ const key = keyRef.deref();
53
+ const existing = key ? this._weakMap.get(key) : undefined;
54
+ if (!key) {
55
+ // This can happen if the key was GCed. Remove it so the next iteration is faster.
56
+ this._keyRefs.delete(keyRef);
57
+ }
58
+ else if (existing) {
59
+ yield [key, existing.value];
60
+ }
61
+ }
62
+ }
63
+ }
64
+ _a = Symbol.toStringTag;
65
+ /**
66
+ * A map that is a IterableWeakMap for object keys and a regular Map for primitive keys. Also provides iteration over both
67
+ * object and primitive keys.
68
+ *
69
+ * Note that, just like IterableWeakMap, older browsers without support for WeakRef will use a regular Map for object keys.
70
+ */
3
71
  export class MaybeWeakMap {
4
72
  constructor(entries) {
5
- this[_a] = "MaybeWeakMap";
73
+ this[_b] = "MaybeWeakMap";
6
74
  const entriesArray = [...entries ?? []];
7
75
  this._primitiveMap = new Map(entriesArray.filter((e) => !this._isAllowedInWeakMap(e[0])));
8
- this._weakMap = new WeakMap(entriesArray.filter((e) => this._isAllowedInWeakMap(e[0])));
76
+ this._weakMap = new IterableWeakMap(entriesArray.filter((e) => this._isAllowedInWeakMap(e[0])));
9
77
  }
10
78
  _isAllowedInWeakMap(key) {
11
79
  return (typeof key === "object" && key !== null) || (typeof key === "symbol" && Symbol.keyFor(key) === undefined);
@@ -43,12 +111,20 @@ export class MaybeWeakMap {
43
111
  return this._primitiveMap.has(key);
44
112
  }
45
113
  }
114
+ *[Symbol.iterator]() {
115
+ yield* this._primitiveMap;
116
+ yield* this._weakMap;
117
+ }
46
118
  }
47
- _a = Symbol.toStringTag;
119
+ _b = Symbol.toStringTag;
120
+ /**
121
+ * A map that stores values indexed by an array of keys. If the keys are objects and the environment supports WeakRefs,
122
+ * they are stored in a WeakMap.
123
+ */
48
124
  export class DependenciesMap {
49
125
  constructor() {
50
126
  this._inner = { map: new MaybeWeakMap(), hasValue: false, value: undefined };
51
- this[_b] = "DependenciesMap";
127
+ this[_c] = "DependenciesMap";
52
128
  }
53
129
  _valueToResult(inner) {
54
130
  if (inner.hasValue) {
@@ -93,6 +169,14 @@ export class DependenciesMap {
93
169
  return this._setInInner(rest, value, newInner);
94
170
  }
95
171
  }
172
+ *_iterateInner(dependencies, inner) {
173
+ if (inner.hasValue) {
174
+ yield [dependencies, inner.value];
175
+ }
176
+ for (const [key, value] of inner.map) {
177
+ yield* this._iterateInner([...dependencies, key], value);
178
+ }
179
+ }
96
180
  get(dependencies) {
97
181
  return Result.or(this._unwrapFromInner(dependencies, this._inner), undefined);
98
182
  }
@@ -109,5 +193,8 @@ export class DependenciesMap {
109
193
  clear() {
110
194
  this._inner = { map: new MaybeWeakMap(), hasValue: false, value: undefined };
111
195
  }
196
+ *[Symbol.iterator]() {
197
+ yield* this._iterateInner([], this._inner);
198
+ }
112
199
  }
113
- _b = Symbol.toStringTag;
200
+ _c = Symbol.toStringTag;
@@ -1,4 +1,7 @@
1
1
  import React from "react";
2
+ export declare function forwardRefIfNeeded<T, P = {}>(render: React.ForwardRefRenderFunction<T, P>): React.FC<P & {
3
+ ref?: React.Ref<T>;
4
+ }>;
2
5
  export declare function getNodeText(node: React.ReactNode): string;
3
6
  /**
4
7
  * Suspends the currently rendered component indefinitely. Will not unsuspend unless the component rerenders.
@@ -2,6 +2,17 @@ import React from "react";
2
2
  import { neverResolve } from "./promises";
3
3
  import { deindent } from "./strings";
4
4
  import { isBrowserLike } from "./env";
5
+ export function forwardRefIfNeeded(render) {
6
+ // TODO: when we drop support for react 18, remove this
7
+ const version = React.version;
8
+ const major = parseInt(version.split(".")[0]);
9
+ if (major < 19) {
10
+ return React.forwardRef(render);
11
+ }
12
+ else {
13
+ return ((props) => render(props, props.ref));
14
+ }
15
+ }
5
16
  export function getNodeText(node) {
6
17
  if (["number", "string"].includes(typeof node)) {
7
18
  return `${node}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackframe/stack-shared",
3
- "version": "2.6.19",
3
+ "version": "2.6.21",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [
@@ -21,12 +21,22 @@
21
21
  },
22
22
  "peerDependencies": {
23
23
  "react": ">=18.2",
24
+ "react-dom": ">=18.2",
25
+ "@types/react": ">=18.2",
26
+ "@types/react-dom": ">=18.2",
27
+ "next": ">=14.1.0",
24
28
  "yup": "^1.4.0"
25
29
  },
26
30
  "peerDependenciesMeta": {
27
31
  "react": {
28
32
  "optional": true
29
33
  },
34
+ "@types/react": {
35
+ "optional": true
36
+ },
37
+ "@types/react-dom": {
38
+ "optional": true
39
+ },
30
40
  "yup": {
31
41
  "optional": true
32
42
  }
@@ -39,18 +49,18 @@
39
49
  "oauth4webapi": "^2.10.3",
40
50
  "semver": "^7.6.3",
41
51
  "uuid": "^9.0.1",
42
- "@stackframe/stack-sc": "2.6.19"
52
+ "@stackframe/stack-sc": "2.6.21"
43
53
  },
44
54
  "devDependencies": {
45
55
  "@simplewebauthn/types": "^11.0.0",
46
56
  "@types/bcrypt": "^5.0.2",
47
57
  "@types/elliptic": "^6.4.18",
48
- "@types/react": "^18.2.66",
49
58
  "@types/semver": "^7.5.8",
50
59
  "@types/uuid": "^9.0.8",
51
- "next": "^14.1.0",
52
- "react": "^18.2.0",
53
- "rimraf": "^5.0.5"
60
+ "rimraf": "^5.0.5",
61
+ "react": "^18.2",
62
+ "react-dom": "^18.2",
63
+ "next": "^14.1.0"
54
64
  },
55
65
  "scripts": {
56
66
  "build": "tsc",