@stackframe/stack-shared 2.8.3 → 2.8.5

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.
@@ -5,8 +5,8 @@ declare module "yup" {
5
5
  empty(): StringSchema<TType, TContext, TDefault, TFlags>;
6
6
  }
7
7
  interface Schema<TType, TContext, TDefault, TFlags> {
8
- getNested<K extends keyof TType>(path: K): yup.Schema<TType[K], TContext, TDefault, TFlags>;
9
- concat<U extends yup.AnySchema>(schema: U): yup.Schema<Omit<TType, keyof yup.InferType<U>> & yup.InferType<U>, TContext, TDefault, TFlags>;
8
+ getNested<K extends keyof NonNullable<TType>>(path: K): yup.Schema<NonNullable<TType>[K], TContext, TDefault, TFlags>;
9
+ concat<U extends yup.AnySchema>(schema: U): yup.Schema<Omit<NonNullable<TType>, keyof yup.InferType<U>> & yup.InferType<U> | (TType & (null | undefined)), TContext, TDefault, TFlags>;
10
10
  }
11
11
  }
12
12
  export declare function yupValidate<S extends yup.ISchema<any>>(schema: S, obj: unknown, options?: yup.ValidateOptions & {
@@ -27,6 +27,7 @@ export declare function yupTuple<T extends [unknown, ...unknown[]]>(...args: Par
27
27
  export declare function yupObject<A extends yup.Maybe<yup.AnyObject>, B extends yup.ObjectShape>(...args: Parameters<typeof yup.object<A, B>>): yup.ObjectSchema<yup.TypeFromShape<B, yup.AnyObject> extends infer T ? T extends yup.TypeFromShape<B, yup.AnyObject> ? T extends {} ? { [k in keyof T]: T[k]; } : T : never : never, yup.AnyObject, yup.DefaultFromShape<B> extends infer T_1 ? T_1 extends yup.DefaultFromShape<B> ? T_1 extends {} ? { [k_1 in keyof T_1]: T_1[k_1]; } : T_1 : never : never, "">;
28
28
  export declare function yupNever(): yup.MixedSchema<never>;
29
29
  export declare function yupUnion<T extends yup.ISchema<any>[]>(...args: T): yup.MixedSchema<yup.InferType<T[number]>>;
30
+ export declare function yupRecord<K extends yup.StringSchema, T extends yup.AnySchema>(keySchema: K, valueSchema: T): yup.MixedSchema<Record<string, yup.InferType<T>>>;
30
31
  export declare function ensureObjectSchema<T extends yup.AnyObject>(schema: yup.Schema<T>): yup.ObjectSchema<T> & typeof schema;
31
32
  export declare const adaptSchema: yup.MixedSchema<typeof StackAdaptSentinel | undefined, yup.AnyObject, undefined, "">;
32
33
  /**
@@ -65,7 +66,7 @@ export declare const projectClientTeamCreationEnabledSchema: yup.BooleanSchema<b
65
66
  export declare const projectClientUserDeletionEnabledSchema: yup.BooleanSchema<boolean | undefined, yup.AnyObject, undefined, "">;
66
67
  export declare const projectSignUpEnabledSchema: yup.BooleanSchema<boolean | undefined, yup.AnyObject, undefined, "">;
67
68
  export declare const projectCredentialEnabledSchema: yup.BooleanSchema<boolean | undefined, yup.AnyObject, undefined, "">;
68
- export declare const oauthIdSchema: yup.StringSchema<"google" | "github" | "microsoft" | "spotify" | "facebook" | "discord" | "gitlab" | "bitbucket" | "linkedin" | "apple" | "x" | undefined, yup.AnyObject, undefined, "">;
69
+ export declare const oauthIdSchema: yup.StringSchema<"apple" | "x" | "google" | "github" | "microsoft" | "spotify" | "facebook" | "discord" | "gitlab" | "bitbucket" | "linkedin" | undefined, yup.AnyObject, undefined, "">;
69
70
  export declare const oauthEnabledSchema: yup.BooleanSchema<boolean | undefined, yup.AnyObject, undefined, "">;
70
71
  export declare const oauthTypeSchema: yup.StringSchema<"shared" | "standard" | undefined, yup.AnyObject, undefined, "">;
71
72
  export declare const oauthClientIdSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
@@ -99,7 +100,7 @@ export declare const userClientReadOnlyMetadataSchema: yup.MixedSchema<{} | null
99
100
  export declare const userServerMetadataSchema: yup.MixedSchema<{} | null, yup.AnyObject, undefined, "">;
100
101
  export declare const userOAuthProviderSchema: yup.ObjectSchema<{
101
102
  id: string;
102
- type: "google" | "github" | "microsoft" | "spotify" | "facebook" | "discord" | "gitlab" | "bitbucket" | "linkedin" | "apple" | "x";
103
+ type: "apple" | "x" | "google" | "github" | "microsoft" | "spotify" | "facebook" | "discord" | "gitlab" | "bitbucket" | "linkedin";
103
104
  provider_user_id: string;
104
105
  }, yup.AnyObject, {
105
106
  id: undefined;
@@ -118,9 +118,9 @@ export function yupObject(...args) {
118
118
  if (unknownKeys.length > 0) {
119
119
  // TODO "did you mean XYZ"
120
120
  return context.createError({
121
- message: `${context.path} contains unknown properties: ${unknownKeys.join(', ')}`,
121
+ message: `${context.path || "Object"} contains unknown properties: ${unknownKeys.join(', ')}`,
122
122
  path: context.path,
123
- params: { unknownKeys },
123
+ params: { unknownKeys, availableKeys },
124
124
  });
125
125
  }
126
126
  }
@@ -160,6 +160,38 @@ export function yupUnion(...args) {
160
160
  });
161
161
  });
162
162
  }
163
+ export function yupRecord(keySchema, valueSchema) {
164
+ return yupObject().unknown(true).test('record', '${path} must be a record of valid values', async function (value, context) {
165
+ if (value == null)
166
+ return true;
167
+ const { path, createError } = this;
168
+ if (typeof value !== 'object') {
169
+ return createError({ message: `${path} must be an object` });
170
+ }
171
+ // Validate each property using the provided valueSchema
172
+ for (const key of Object.keys(value)) {
173
+ // Validate the key
174
+ await yupValidate(keySchema, key, context.options);
175
+ // Validate the value
176
+ try {
177
+ await yupValidate(valueSchema, value[key], {
178
+ ...context.options,
179
+ context: {
180
+ ...context.options.context,
181
+ path: path ? `${path}.${key}` : key,
182
+ },
183
+ });
184
+ }
185
+ catch (e) {
186
+ return createError({
187
+ path: path ? `${path}.${key}` : key,
188
+ message: e.message,
189
+ });
190
+ }
191
+ }
192
+ return true;
193
+ });
194
+ }
163
195
  export function ensureObjectSchema(schema) {
164
196
  if (!(schema instanceof yup.ObjectSchema))
165
197
  throw new StackAssertionError(`assertObjectSchema: schema is not an ObjectSchema: ${schema.describe().type}`);
@@ -8,7 +8,8 @@ const API_KEY_LENGTHS = {
8
8
  SECRET_PART: 45,
9
9
  ID_PART: 32,
10
10
  TYPE_PART: 4,
11
- SCANNER_AND_MARKER: 10,
11
+ SCANNER: 1,
12
+ MARKER: 9,
12
13
  CHECKSUM: 8,
13
14
  };
14
15
  function createChecksumSync(checksummablePart) {
@@ -27,22 +28,22 @@ function createApiKeyParts(options) {
27
28
  return { checksummablePart, idPart, prefix, scannerAndMarker, type };
28
29
  }
29
30
  function parseApiKeyParts(secret) {
30
- const regex = new RegExp(`^([^_]+)_` + // prefix
31
- `(.{${API_KEY_LENGTHS.SECRET_PART}})` + // secretPart
32
- `(.{${API_KEY_LENGTHS.ID_PART}})` + // idPart
33
- `(.{${API_KEY_LENGTHS.TYPE_PART}})` + // type
34
- `(.{${API_KEY_LENGTHS.SCANNER_AND_MARKER}})` + // scannerAndMarker
35
- `(.{${API_KEY_LENGTHS.CHECKSUM}})$` // checksum
31
+ const regex = new RegExp(`^([a-zA-Z0-9_]+)_` + // prefix
32
+ `([a-zA-Z0-9_]{${API_KEY_LENGTHS.SECRET_PART}})` + // secretPart
33
+ `([a-zA-Z0-9_]{${API_KEY_LENGTHS.ID_PART}})` + // idPart
34
+ `([a-zA-Z0-9_]{${API_KEY_LENGTHS.TYPE_PART}})` + // type
35
+ `([a-zA-Z0-9_]{${API_KEY_LENGTHS.SCANNER}})` + // scanner
36
+ `(${STACK_AUTH_MARKER})` + // marker
37
+ `([a-zA-Z0-9_]{${API_KEY_LENGTHS.CHECKSUM}})$` // checksum
36
38
  );
37
39
  const match = secret.match(regex);
38
40
  if (!match) {
39
41
  throw new StackAssertionError("Invalid API key format");
40
42
  }
41
- const [, prefix, secretPart, idPart, type, scannerAndMarker, checksum] = match;
42
- const scannerFlag = scannerAndMarker.replace(STACK_AUTH_MARKER, "");
43
+ const [, prefix, secretPart, idPart, type, scannerFlag, marker, checksum] = match;
43
44
  const isCloudVersion = parseInt(scannerFlag, 32) % 2 === 0;
44
45
  const isPublic = (parseInt(scannerFlag, 32) & 2) !== 0;
45
- const checksummablePart = `${prefix}_${secretPart}${idPart}${type}${scannerAndMarker}`;
46
+ const checksummablePart = `${prefix}_${secretPart}${idPart}${type}${scannerFlag}${marker}`;
46
47
  const restored_id = idPart.replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, "$1-$2-$3-$4-$5");
47
48
  if (!["user", "team"].includes(type)) {
48
49
  throw new StackAssertionError("Invalid type");
@@ -17,16 +17,16 @@ export declare class AsyncCache<D extends any[], T> {
17
17
  refreshWhere(predicate: (dependencies: D) => boolean): Promise<void>;
18
18
  readonly isCacheAvailable: (key: D) => boolean;
19
19
  readonly getIfCached: (key: D) => ({
20
- status: "error";
21
- error: unknown;
22
- } & {
23
- status: "error";
24
- }) | ({
25
20
  status: "pending";
26
21
  } & {
27
22
  progress: void;
28
23
  } & {
29
24
  status: "pending";
25
+ }) | ({
26
+ status: "error";
27
+ error: unknown;
28
+ } & {
29
+ status: "error";
30
30
  }) | ({
31
31
  status: "ok";
32
32
  data: T;
@@ -57,16 +57,16 @@ declare class AsyncValueCache<T> {
57
57
  });
58
58
  isCacheAvailable(): boolean;
59
59
  getIfCached(): ({
60
- status: "error";
61
- error: unknown;
62
- } & {
63
- status: "error";
64
- }) | ({
65
60
  status: "pending";
66
61
  } & {
67
62
  progress: void;
68
63
  } & {
69
64
  status: "pending";
65
+ }) | ({
66
+ status: "error";
67
+ error: unknown;
68
+ } & {
69
+ status: "error";
70
70
  }) | ({
71
71
  status: "ok";
72
72
  data: T;
@@ -2,6 +2,9 @@ export declare function isNotNull<T>(value: T): value is NonNullable<T>;
2
2
  export type DeepPartial<T> = T extends object ? {
3
3
  [P in keyof T]?: DeepPartial<T[P]>;
4
4
  } : T;
5
+ export type DeepRequired<T> = T extends object ? {
6
+ [P in keyof T]-?: DeepRequired<T[P]>;
7
+ } : T;
5
8
  /**
6
9
  * Assumes both objects are primitives, arrays, or non-function plain objects, and compares them deeply.
7
10
  *
@@ -10,9 +13,16 @@ export type DeepPartial<T> = T extends object ? {
10
13
  export declare function deepPlainEquals<T>(obj1: T, obj2: unknown, options?: {
11
14
  ignoreUndefinedValues?: boolean;
12
15
  }): obj2 is T;
16
+ export declare function isCloneable<T>(obj: T): obj is Exclude<T, symbol | Function>;
17
+ export declare function shallowClone<T extends object>(obj: T): T;
13
18
  export declare function deepPlainClone<T>(obj: T): T;
19
+ export type DeepMerge<T, U> = Omit<T, keyof U> & Omit<U, keyof T> & DeepMergeInner<Pick<T, keyof U & keyof T>, Pick<U, keyof U & keyof T>>;
20
+ type DeepMergeInner<T, U> = {
21
+ [K in keyof U]-?: undefined extends U[K] ? K extends keyof T ? T[K] extends object ? Exclude<U[K], undefined> extends object ? DeepMerge<T[K], Exclude<U[K], undefined>> : T[K] | Exclude<U[K], undefined> : T[K] | Exclude<U[K], undefined> : Exclude<U[K], undefined> : K extends keyof T ? T[K] extends object ? U[K] extends object ? DeepMerge<T[K], U[K]> : U[K] : U[K] : U[K];
22
+ };
23
+ export declare function deepMerge<T extends {}, U extends {}>(baseObj: T, mergeObj: U): DeepMerge<T, U>;
14
24
  export declare function typedEntries<T extends {}>(obj: T): [keyof T, T[keyof T]][];
15
- export declare function typedFromEntries<K extends PropertyKey, V>(entries: [K, V][]): Record<K, V>;
25
+ export declare function typedFromEntries<K extends PropertyKey, V>(entries: (readonly [K, V])[]): Record<K, V>;
16
26
  export declare function typedKeys<T extends {}>(obj: T): (keyof T)[];
17
27
  export declare function typedValues<T extends {}>(obj: T): T[keyof T][];
18
28
  export declare function typedAssign<T extends {}, U extends {}>(target: T, source: U): T & U;
@@ -25,7 +35,7 @@ export type FilterUndefined<T> = {
25
35
  * Returns a new object with all undefined values removed. Useful when spreading optional parameters on an object, as
26
36
  * TypeScript's `Partial<XYZ>` type allows `undefined` values.
27
37
  */
28
- export declare function filterUndefined<T extends {}>(obj: T): FilterUndefined<T>;
38
+ export declare function filterUndefined<T extends object>(obj: T): FilterUndefined<T>;
29
39
  export type FilterUndefinedOrNull<T> = FilterUndefined<{
30
40
  [k in keyof T]: null extends T[k] ? NonNullable<T[k]> | undefined : T[k];
31
41
  }>;
@@ -33,7 +43,22 @@ export type FilterUndefinedOrNull<T> = FilterUndefined<{
33
43
  * Returns a new object with all undefined and null values removed. Useful when spreading optional parameters on an object, as
34
44
  * TypeScript's `Partial<XYZ>` type allows `undefined` values.
35
45
  */
36
- export declare function filterUndefinedOrNull<T extends {}>(obj: T): FilterUndefinedOrNull<T>;
46
+ export declare function filterUndefinedOrNull<T extends object>(obj: T): FilterUndefinedOrNull<T>;
47
+ export type DeepFilterUndefined<T> = T extends object ? FilterUndefined<{
48
+ [K in keyof T]: DeepFilterUndefined<T[K]>;
49
+ }> : T;
50
+ export declare function deepFilterUndefined<T extends object>(obj: T): DeepFilterUndefined<T>;
37
51
  export declare function pick<T extends {}, K extends keyof T>(obj: T, keys: K[]): Pick<T, K>;
38
52
  export declare function omit<T extends {}, K extends keyof T>(obj: T, keys: K[]): Omit<T, K>;
39
53
  export declare function split<T extends {}, K extends keyof T>(obj: T, keys: K[]): [Pick<T, K>, Omit<T, K>];
54
+ export declare function set<T extends object, K extends keyof T>(obj: T, key: K, value: T[K]): void;
55
+ export declare function get<T extends object, K extends keyof T>(obj: T, key: K): T[K];
56
+ export declare function has<T extends object, K extends keyof T>(obj: T, key: K): obj is T & {
57
+ [k in K]: unknown;
58
+ };
59
+ export declare function hasAndNotUndefined<T extends object, K extends keyof T>(obj: T, key: K): obj is T & {
60
+ [k in K]: Exclude<T[K], undefined>;
61
+ };
62
+ export declare function deleteKey<T extends object, K extends keyof T>(obj: T, key: K): void;
63
+ export declare function isObjectLike(value: unknown): value is object;
64
+ export {};
@@ -1,4 +1,5 @@
1
1
  import { StackAssertionError } from "./errors";
2
+ import { identity } from "./functions";
2
3
  export function isNotNull(value) {
3
4
  return value !== null && value !== undefined;
4
5
  }
@@ -78,6 +79,21 @@ import.meta.vitest?.test("deepPlainEquals", ({ expect }) => {
78
79
  expect(deepPlainEquals({ a: 1, b: undefined }, { a: 1 }, { ignoreUndefinedValues: true })).toBe(true);
79
80
  expect(deepPlainEquals({ a: 1, b: undefined }, { a: 1 })).toBe(false);
80
81
  });
82
+ export function isCloneable(obj) {
83
+ return typeof obj !== 'symbol' && typeof obj !== 'function';
84
+ }
85
+ export function shallowClone(obj) {
86
+ if (!isCloneable(obj))
87
+ throw new StackAssertionError("shallowClone does not support symbols or functions", { obj });
88
+ if (Array.isArray(obj))
89
+ return obj.map(identity);
90
+ return { ...obj };
91
+ }
92
+ import.meta.vitest?.test("shallowClone", ({ expect }) => {
93
+ expect(shallowClone({ a: 1, b: 2 })).toEqual({ a: 1, b: 2 });
94
+ expect(shallowClone([1, 2, 3])).toEqual([1, 2, 3]);
95
+ expect(() => shallowClone(() => { })).toThrow();
96
+ });
81
97
  export function deepPlainClone(obj) {
82
98
  if (typeof obj === 'function')
83
99
  throw new StackAssertionError("deepPlainClone does not support functions");
@@ -116,6 +132,75 @@ import.meta.vitest?.test("deepPlainClone", ({ expect }) => {
116
132
  expect(() => deepPlainClone(() => { })).toThrow();
117
133
  expect(() => deepPlainClone(Symbol())).toThrow();
118
134
  });
135
+ export function deepMerge(baseObj, mergeObj) {
136
+ if ([baseObj, mergeObj, ...Object.values(baseObj), ...Object.values(mergeObj)].some(o => !isCloneable(o)))
137
+ throw new StackAssertionError("deepMerge does not support functions or symbols", { baseObj, mergeObj });
138
+ const res = shallowClone(baseObj);
139
+ for (const [key, mergeValue] of Object.entries(mergeObj)) {
140
+ if (has(res, key)) {
141
+ const baseValue = get(res, key);
142
+ if (isObjectLike(baseValue) && isObjectLike(mergeValue)) {
143
+ set(res, key, deepMerge(baseValue, mergeValue));
144
+ continue;
145
+ }
146
+ }
147
+ set(res, key, mergeValue);
148
+ }
149
+ return res;
150
+ }
151
+ import.meta.vitest?.test("deepMerge", ({ expect }) => {
152
+ // Test merging flat objects
153
+ expect(deepMerge({ a: 1 }, { b: 2 })).toEqual({ a: 1, b: 2 });
154
+ expect(deepMerge({ a: 1 }, { a: 2 })).toEqual({ a: 2 });
155
+ expect(deepMerge({ a: 1, b: 2 }, { b: 3, c: 4 })).toEqual({ a: 1, b: 3, c: 4 });
156
+ // Test with nested objects
157
+ expect(deepMerge({ a: { x: 1, y: 2 }, b: 3 }, { a: { y: 3, z: 4 }, c: 5 })).toEqual({ a: { x: 1, y: 3, z: 4 }, b: 3, c: 5 });
158
+ // Test with arrays
159
+ expect(deepMerge({ a: [1, 2], b: 3 }, { a: [3, 4], c: 5 })).toEqual({ a: [3, 4], b: 3, c: 5 });
160
+ // Test with null values
161
+ expect(deepMerge({ a: { x: 1 }, b: null }, { a: { y: 2 }, b: { z: 3 } })).toEqual({ a: { x: 1, y: 2 }, b: { z: 3 } });
162
+ // Test with undefined values
163
+ expect(deepMerge({ a: 1, b: undefined }, { b: 2, c: 3 })).toEqual({ a: 1, b: 2, c: 3 });
164
+ // Test deeply nested structures
165
+ expect(deepMerge({
166
+ a: {
167
+ x: { deep: 1 },
168
+ y: [1, 2]
169
+ },
170
+ b: 2
171
+ }, {
172
+ a: {
173
+ x: { deeper: 3 },
174
+ y: [3, 4]
175
+ },
176
+ c: 3
177
+ })).toEqual({
178
+ a: {
179
+ x: { deep: 1, deeper: 3 },
180
+ y: [3, 4]
181
+ },
182
+ b: 2,
183
+ c: 3
184
+ });
185
+ // Test with empty objects
186
+ expect(deepMerge({}, { a: 1 })).toEqual({ a: 1 });
187
+ expect(deepMerge({ a: 1 }, {})).toEqual({ a: 1 });
188
+ expect(deepMerge({}, {})).toEqual({});
189
+ // Test that original objects are not modified
190
+ const base = { a: { x: 1 }, b: 2 };
191
+ const merge = { a: { y: 2 }, c: 3 };
192
+ const baseClone = deepPlainClone(base);
193
+ const mergeClone = deepPlainClone(merge);
194
+ const result = deepMerge(base, merge);
195
+ expect(base).toEqual(baseClone);
196
+ expect(merge).toEqual(mergeClone);
197
+ expect(result).toEqual({ a: { x: 1, y: 2 }, b: 2, c: 3 });
198
+ // Test error cases
199
+ expect(() => deepMerge({ a: () => { } }, { b: 2 })).toThrow();
200
+ expect(() => deepMerge({ a: 1 }, { b: () => { } })).toThrow();
201
+ expect(() => deepMerge({ a: Symbol() }, { b: 2 })).toThrow();
202
+ expect(() => deepMerge({ a: 1 }, { b: Symbol() })).toThrow();
203
+ });
119
204
  export function typedEntries(obj) {
120
205
  return Object.entries(obj);
121
206
  }
@@ -226,6 +311,12 @@ import.meta.vitest?.test("filterUndefinedOrNull", ({ expect }) => {
226
311
  expect(filterUndefinedOrNull({})).toEqual({});
227
312
  expect(filterUndefinedOrNull({ a: 1, b: 2 })).toEqual({ a: 1, b: 2 });
228
313
  });
314
+ export function deepFilterUndefined(obj) {
315
+ return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined).map(([k, v]) => [k, isObjectLike(v) ? deepFilterUndefined(v) : v]));
316
+ }
317
+ import.meta.vitest?.test("deepFilterUndefined", ({ expect }) => {
318
+ expect(deepFilterUndefined({ a: 1, b: undefined })).toEqual({ a: 1 });
319
+ });
229
320
  export function pick(obj, keys) {
230
321
  return Object.fromEntries(Object.entries(obj).filter(([k]) => keys.includes(k)));
231
322
  }
@@ -259,3 +350,29 @@ import.meta.vitest?.test("split", ({ expect }) => {
259
350
  // Use type assertion for empty object to avoid TypeScript error
260
351
  expect(split({}, ["a"])).toEqual([{}, {}]);
261
352
  });
353
+ export function set(obj, key, value) {
354
+ Object.defineProperty(obj, key, { value, writable: true, configurable: true, enumerable: true });
355
+ }
356
+ export function get(obj, key) {
357
+ const descriptor = Object.getOwnPropertyDescriptor(obj, key);
358
+ if (!descriptor)
359
+ throw new StackAssertionError(`get: key ${String(key)} does not exist`, { obj, key });
360
+ return descriptor.value;
361
+ }
362
+ export function has(obj, key) {
363
+ return Object.prototype.hasOwnProperty.call(obj, key);
364
+ }
365
+ export function hasAndNotUndefined(obj, key) {
366
+ return has(obj, key) && get(obj, key) !== undefined;
367
+ }
368
+ export function deleteKey(obj, key) {
369
+ if (has(obj, key)) {
370
+ Reflect.deleteProperty(obj, key);
371
+ }
372
+ else {
373
+ throw new StackAssertionError(`deleteKey: key ${String(key)} does not exist`, { obj, key });
374
+ }
375
+ }
376
+ export function isObjectLike(value) {
377
+ return (typeof value === 'object' || typeof value === 'function') && value !== null;
378
+ }
@@ -31,7 +31,7 @@ export declare function pending<T>(promise: Promise<T>, options?: {
31
31
  *
32
32
  * Vercel kills serverless functions on unhandled promise rejection errors, so this is important.
33
33
  */
34
- export declare function ignoreUnhandledRejection<T extends Promise<any>>(promise: T): T;
34
+ export declare function ignoreUnhandledRejection<T extends Promise<any>>(promise: T): void;
35
35
  export declare function wait(ms: number): Promise<void>;
36
36
  export declare function waitUntil(date: Date): Promise<void>;
37
37
  export declare function runAsynchronouslyWithAlert(...args: Parameters<typeof runAsynchronously>): void;
@@ -114,7 +114,9 @@ export function rejected(reason) {
114
114
  if (rejectedCache.has([reason])) {
115
115
  return rejectedCache.get([reason]);
116
116
  }
117
- const res = Object.assign(ignoreUnhandledRejection(Promise.reject(reason)), {
117
+ const promise = Promise.reject(reason);
118
+ ignoreUnhandledRejection(promise);
119
+ const res = Object.assign(promise, {
118
120
  status: "rejected",
119
121
  reason: reason,
120
122
  });
@@ -191,22 +193,19 @@ import.meta.vitest?.test("pending", async ({ expect }) => {
191
193
  */
192
194
  export function ignoreUnhandledRejection(promise) {
193
195
  promise.catch(() => { });
194
- return promise;
195
196
  }
196
197
  import.meta.vitest?.test("ignoreUnhandledRejection", async ({ expect }) => {
197
198
  // Test with a promise that resolves
198
199
  const resolvePromise = Promise.resolve(42);
199
- const ignoredResolvePromise = ignoreUnhandledRejection(resolvePromise);
200
- expect(ignoredResolvePromise).toBe(resolvePromise); // Should return the same promise
201
- expect(await ignoredResolvePromise).toBe(42); // Should still resolve to the same value
200
+ ignoreUnhandledRejection(resolvePromise);
201
+ expect(await resolvePromise).toBe(42); // Should still resolve to the same value
202
202
  // Test with a promise that rejects
203
- const error = new Error("Test error");
204
- const rejectPromise = Promise.reject(error);
205
- const ignoredRejectPromise = ignoreUnhandledRejection(rejectPromise);
206
- expect(ignoredRejectPromise).toBe(rejectPromise); // Should return the same promise
207
203
  // The promise should still reject, but the rejection is caught internally
208
204
  // so it doesn't cause an unhandled rejection error
209
- await expect(ignoredRejectPromise).rejects.toBe(error);
205
+ const error = new Error("Test error");
206
+ const rejectPromise = Promise.reject(error);
207
+ ignoreUnhandledRejection(rejectPromise);
208
+ await expect(rejectPromise).rejects.toBe(error);
210
209
  });
211
210
  export async function wait(ms) {
212
211
  if (!Number.isFinite(ms) || ms < 0) {
@@ -60,6 +60,12 @@ export declare class AsyncStore<T> implements ReadonlyAsyncStore<T> {
60
60
  isAvailable(): boolean;
61
61
  isRejected(): boolean;
62
62
  get(): ({
63
+ status: "pending";
64
+ } & {
65
+ progress: void;
66
+ } & {
67
+ status: "pending";
68
+ }) | ({
63
69
  status: "error";
64
70
  error: unknown;
65
71
  } & {
@@ -69,12 +75,6 @@ export declare class AsyncStore<T> implements ReadonlyAsyncStore<T> {
69
75
  data: T;
70
76
  } & {
71
77
  status: "ok";
72
- }) | ({
73
- status: "pending";
74
- } & {
75
- progress: void;
76
- } & {
77
- status: "pending";
78
78
  });
79
79
  getOrWait(): ReactPromise<T>;
80
80
  _setIfLatest(result: Result<T>, curCounter: number): boolean;
@@ -16,6 +16,6 @@ export type IfAndOnlyIf<Value, Extends, Then, Otherwise> = (Value extends Extend
16
16
  /**
17
17
  * Can be used to prettify a type in the IDE; for example, some complicated intersected types can be flattened into a single type.
18
18
  */
19
- export type PrettifyType<T> = {
19
+ export type PrettifyType<T> = T extends object ? {
20
20
  [K in keyof T]: T[K];
21
- } & {};
21
+ } & {} : T;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackframe/stack-shared",
3
- "version": "2.8.3",
3
+ "version": "2.8.5",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "type": "module",