@stackframe/stack-shared 2.5.2 → 2.5.4

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.
Files changed (81) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/crud.d.ts +10 -3
  3. package/dist/helpers/production-mode.d.ts +6 -0
  4. package/dist/helpers/production-mode.js +43 -0
  5. package/dist/index.d.ts +4 -4
  6. package/dist/index.js +4 -4
  7. package/dist/interface/adminInterface.d.ts +28 -67
  8. package/dist/interface/adminInterface.js +63 -22
  9. package/dist/interface/clientInterface.d.ts +21 -133
  10. package/dist/interface/clientInterface.js +92 -119
  11. package/dist/interface/crud/api-keys.d.ts +134 -0
  12. package/dist/interface/crud/api-keys.js +61 -0
  13. package/dist/interface/crud/current-user.d.ts +47 -11
  14. package/dist/interface/crud/current-user.js +7 -3
  15. package/dist/interface/crud/email-templates.d.ts +53 -34
  16. package/dist/interface/crud/email-templates.js +37 -24
  17. package/dist/interface/crud/oauth.d.ts +8 -9
  18. package/dist/interface/crud/oauth.js +5 -5
  19. package/dist/interface/crud/projects.d.ts +446 -0
  20. package/dist/interface/crud/projects.js +110 -0
  21. package/dist/interface/crud/team-memberships.d.ts +22 -0
  22. package/dist/interface/crud/team-memberships.js +22 -0
  23. package/dist/interface/crud/team-permissions.d.ts +129 -0
  24. package/dist/interface/crud/team-permissions.js +83 -0
  25. package/dist/interface/crud/teams.d.ts +148 -0
  26. package/dist/interface/crud/teams.js +80 -0
  27. package/dist/interface/crud/users.d.ts +88 -33
  28. package/dist/interface/crud/users.js +22 -14
  29. package/dist/interface/crud-deprecated/api-keys.d.ts +134 -0
  30. package/dist/interface/crud-deprecated/api-keys.js +61 -0
  31. package/dist/interface/crud-deprecated/current-user.d.ts +127 -0
  32. package/dist/interface/crud-deprecated/current-user.js +49 -0
  33. package/dist/interface/crud-deprecated/email-templates.d.ts +75 -0
  34. package/dist/interface/crud-deprecated/email-templates.js +41 -0
  35. package/dist/interface/crud-deprecated/oauth.d.ts +24 -0
  36. package/dist/interface/crud-deprecated/oauth.js +12 -0
  37. package/dist/interface/crud-deprecated/projects.d.ts +440 -0
  38. package/dist/interface/crud-deprecated/projects.js +109 -0
  39. package/dist/interface/crud-deprecated/team-memberships.d.ts +22 -0
  40. package/dist/interface/crud-deprecated/team-memberships.js +22 -0
  41. package/dist/interface/crud-deprecated/team-permissions.d.ts +129 -0
  42. package/dist/interface/crud-deprecated/team-permissions.js +83 -0
  43. package/dist/interface/crud-deprecated/teams.d.ts +126 -0
  44. package/dist/interface/crud-deprecated/teams.js +78 -0
  45. package/dist/interface/crud-deprecated/users.d.ts +201 -0
  46. package/dist/interface/crud-deprecated/users.js +75 -0
  47. package/dist/interface/serverInterface.d.ts +33 -60
  48. package/dist/interface/serverInterface.js +74 -102
  49. package/dist/known-errors.d.ts +43 -26
  50. package/dist/known-errors.js +135 -92
  51. package/dist/schema-fields.d.ts +53 -4
  52. package/dist/schema-fields.js +156 -26
  53. package/dist/sessions.d.ts +1 -0
  54. package/dist/sessions.js +20 -26
  55. package/dist/utils/arrays.d.ts +4 -0
  56. package/dist/utils/arrays.js +10 -0
  57. package/dist/utils/caches.js +11 -18
  58. package/dist/utils/compile-time.d.ts +3 -1
  59. package/dist/utils/compile-time.js +3 -1
  60. package/dist/utils/errors.d.ts +8 -1
  61. package/dist/utils/errors.js +58 -47
  62. package/dist/utils/globals.js +3 -0
  63. package/dist/utils/maps.js +8 -5
  64. package/dist/utils/numbers.js +5 -5
  65. package/dist/utils/objects.d.ts +4 -1
  66. package/dist/utils/objects.js +16 -8
  67. package/dist/utils/promises.js +6 -2
  68. package/dist/utils/proxies.d.ts +1 -0
  69. package/dist/utils/proxies.js +65 -0
  70. package/dist/utils/react.d.ts +1 -1
  71. package/dist/utils/react.js +2 -2
  72. package/dist/utils/results.js +0 -1
  73. package/dist/utils/stores.js +7 -10
  74. package/dist/utils/strings.js +7 -2
  75. package/dist/utils/urls.d.ts +1 -0
  76. package/dist/utils/urls.js +8 -0
  77. package/dist/utils/uuids.d.ts +1 -1
  78. package/dist/utils/uuids.js +2 -1
  79. package/package.json +2 -2
  80. package/dist/utils/yup.d.ts +0 -3
  81. package/dist/utils/yup.js +0 -13
@@ -1,9 +1,9 @@
1
1
  const magnitudes = [
2
- [1_000_000_000_000_000, "trln"],
3
- [1_000_000_000_000, "bln"],
4
- [1_000_000_000, "bn"],
5
- [1_000_000, "M"],
6
- [1_000, "k"],
2
+ [1000000000000000, "trln"],
3
+ [1000000000000, "bln"],
4
+ [1000000000, "bn"],
5
+ [1000000, "M"],
6
+ [1000, "k"],
7
7
  ];
8
8
  export function prettyPrintWithMagnitudes(num) {
9
9
  if (typeof num !== "number")
@@ -6,7 +6,9 @@ export type DeepPartial<T> = T extends object ? {
6
6
  *
7
7
  * Note that since they are assumed to be plain objects, this function does not compare prototypes.
8
8
  */
9
- export declare function deepPlainEquals<T>(obj1: T, obj2: unknown): obj2 is T;
9
+ export declare function deepPlainEquals<T>(obj1: T, obj2: unknown, options?: {
10
+ ignoreUndefinedValues?: boolean;
11
+ }): obj2 is T;
10
12
  export declare function deepPlainClone<T>(obj: T): T;
11
13
  export declare function deepPlainSnakeCaseToCamelCase(snakeCaseObj: any): any;
12
14
  export declare function deepPlainCamelCaseToSnakeCase(camelCaseObj: any): any;
@@ -27,3 +29,4 @@ export type FilterUndefined<T> = {
27
29
  export declare function filterUndefined<T extends {}>(obj: T): FilterUndefined<T>;
28
30
  export declare function pick<T extends {}, K extends keyof T>(obj: T, keys: K[]): Pick<T, K>;
29
31
  export declare function omit<T extends {}, K extends keyof T>(obj: T, keys: K[]): Omit<T, K>;
32
+ export declare function split<T extends {}, K extends keyof T>(obj: T, keys: K[]): [Pick<T, K>, Omit<T, K>];
@@ -5,7 +5,7 @@ import { camelCaseToSnakeCase, snakeCaseToCamelCase } from "./strings";
5
5
  *
6
6
  * Note that since they are assumed to be plain objects, this function does not compare prototypes.
7
7
  */
8
- export function deepPlainEquals(obj1, obj2) {
8
+ export function deepPlainEquals(obj1, obj2, options = {}) {
9
9
  if (typeof obj1 !== typeof obj2)
10
10
  return false;
11
11
  if (obj1 === obj2)
@@ -19,13 +19,18 @@ export function deepPlainEquals(obj1, obj2) {
19
19
  return false;
20
20
  if (obj1.length !== obj2.length)
21
21
  return false;
22
- return obj1.every((v, i) => deepPlainEquals(v, obj2[i]));
22
+ return obj1.every((v, i) => deepPlainEquals(v, obj2[i], options));
23
23
  }
24
- const keys1 = Object.keys(obj1);
25
- const keys2 = Object.keys(obj2);
26
- if (keys1.length !== keys2.length)
24
+ const entries1 = Object.entries(obj1).filter(([k, v]) => !options.ignoreUndefinedValues || v !== undefined);
25
+ const entries2 = Object.entries(obj2).filter(([k, v]) => !options.ignoreUndefinedValues || v !== undefined);
26
+ if (entries1.length !== entries2.length)
27
27
  return false;
28
- return keys1.every((k) => k in obj2 && deepPlainEquals(obj1[k], obj2[k]));
28
+ return entries1.every(([k, v1]) => {
29
+ const e2 = entries2.find(([k2]) => k === k2);
30
+ if (!e2)
31
+ return false;
32
+ return deepPlainEquals(v1, e2[1], options);
33
+ });
29
34
  }
30
35
  case 'undefined':
31
36
  case 'string':
@@ -58,7 +63,7 @@ export function deepPlainSnakeCaseToCamelCase(snakeCaseObj) {
58
63
  if (typeof snakeCaseObj !== 'object' || !snakeCaseObj)
59
64
  return snakeCaseObj;
60
65
  if (Array.isArray(snakeCaseObj))
61
- return snakeCaseObj.map(deepPlainSnakeCaseToCamelCase);
66
+ return snakeCaseObj.map(o => deepPlainSnakeCaseToCamelCase(o));
62
67
  return Object.fromEntries(Object.entries(snakeCaseObj).map(([k, v]) => [snakeCaseToCamelCase(k), deepPlainSnakeCaseToCamelCase(v)]));
63
68
  }
64
69
  export function deepPlainCamelCaseToSnakeCase(camelCaseObj) {
@@ -67,7 +72,7 @@ export function deepPlainCamelCaseToSnakeCase(camelCaseObj) {
67
72
  if (typeof camelCaseObj !== 'object' || !camelCaseObj)
68
73
  return camelCaseObj;
69
74
  if (Array.isArray(camelCaseObj))
70
- return camelCaseObj.map(deepPlainCamelCaseToSnakeCase);
75
+ return camelCaseObj.map(o => deepPlainCamelCaseToSnakeCase(o));
71
76
  return Object.fromEntries(Object.entries(camelCaseObj).map(([k, v]) => [camelCaseToSnakeCase(k), deepPlainCamelCaseToSnakeCase(v)]));
72
77
  }
73
78
  export function typedEntries(obj) {
@@ -98,3 +103,6 @@ export function pick(obj, keys) {
98
103
  export function omit(obj, keys) {
99
104
  return Object.fromEntries(Object.entries(obj).filter(([k]) => !keys.includes(k)));
100
105
  }
106
+ export function split(obj, keys) {
107
+ return [pick(obj, keys), omit(obj, keys)];
108
+ }
@@ -118,7 +118,6 @@ export function runAsynchronously(promiseOrFunc, options = {}) {
118
118
  });
119
119
  }
120
120
  class TimeoutError extends Error {
121
- ms;
122
121
  constructor(ms) {
123
122
  super(`Timeout after ${ms}ms`);
124
123
  this.ms = ms;
@@ -160,7 +159,12 @@ export function rateLimited(func, options) {
160
159
  const end = performance.now();
161
160
  waitUntil = Math.max(waitUntil, start + (options.throttleMs ?? 0), end + (options.gapMs ?? 0));
162
161
  for (const nextFunc of nextFuncs) {
163
- value.status === "ok" ? nextFunc[0](value.data) : nextFunc[1](value.error);
162
+ if (value.status === "ok") {
163
+ nextFunc[0](value.data);
164
+ }
165
+ else {
166
+ nextFunc[1](value.error);
167
+ }
164
168
  }
165
169
  };
166
170
  runAsynchronously(async () => {
@@ -1 +1,2 @@
1
1
  export declare function logged<T extends object>(name: string, toLog: T, options?: {}): T;
2
+ export declare function createLazyProxy<FactoryResult>(factory: () => FactoryResult): FactoryResult;
@@ -57,3 +57,68 @@ export function logged(name, toLog, options = {}) {
57
57
  });
58
58
  return proxy;
59
59
  }
60
+ export function createLazyProxy(factory) {
61
+ let cache = undefined;
62
+ let initialized = false;
63
+ function initializeIfNeeded() {
64
+ if (!initialized) {
65
+ cache = factory();
66
+ initialized = true;
67
+ }
68
+ return cache;
69
+ }
70
+ return new Proxy({}, {
71
+ get(target, prop, receiver) {
72
+ const instance = initializeIfNeeded();
73
+ return Reflect.get(instance, prop, receiver);
74
+ },
75
+ set(target, prop, value, receiver) {
76
+ const instance = initializeIfNeeded();
77
+ return Reflect.set(instance, prop, value, receiver);
78
+ },
79
+ has(target, prop) {
80
+ const instance = initializeIfNeeded();
81
+ return Reflect.has(instance, prop);
82
+ },
83
+ deleteProperty(target, prop) {
84
+ const instance = initializeIfNeeded();
85
+ return Reflect.deleteProperty(instance, prop);
86
+ },
87
+ ownKeys(target) {
88
+ const instance = initializeIfNeeded();
89
+ return Reflect.ownKeys(instance);
90
+ },
91
+ getOwnPropertyDescriptor(target, prop) {
92
+ const instance = initializeIfNeeded();
93
+ return Reflect.getOwnPropertyDescriptor(instance, prop);
94
+ },
95
+ defineProperty(target, prop, descriptor) {
96
+ const instance = initializeIfNeeded();
97
+ return Reflect.defineProperty(instance, prop, descriptor);
98
+ },
99
+ getPrototypeOf(target) {
100
+ const instance = initializeIfNeeded();
101
+ return Reflect.getPrototypeOf(instance);
102
+ },
103
+ setPrototypeOf(target, proto) {
104
+ const instance = initializeIfNeeded();
105
+ return Reflect.setPrototypeOf(instance, proto);
106
+ },
107
+ isExtensible(target) {
108
+ const instance = initializeIfNeeded();
109
+ return Reflect.isExtensible(instance);
110
+ },
111
+ preventExtensions(target) {
112
+ const instance = initializeIfNeeded();
113
+ return Reflect.preventExtensions(instance);
114
+ },
115
+ apply(target, thisArg, argumentsList) {
116
+ const instance = initializeIfNeeded();
117
+ return Reflect.apply(instance, thisArg, argumentsList);
118
+ },
119
+ construct(target, argumentsList, newTarget) {
120
+ const instance = initializeIfNeeded();
121
+ return Reflect.construct(instance, argumentsList, newTarget);
122
+ }
123
+ });
124
+ }
@@ -1,4 +1,4 @@
1
- /// <reference types="react" />
1
+ import React from "react";
2
2
  export declare function getNodeText(node: React.ReactNode): string;
3
3
  /**
4
4
  * Suspends the currently rendered component indefinitely. Will not unsuspend unless the component rerenders.
@@ -1,4 +1,4 @@
1
- import { use } from "react";
1
+ import React from "react";
2
2
  import { neverResolve } from "./promises";
3
3
  import { deindent } from "./strings";
4
4
  import { isBrowserLike } from "./env";
@@ -23,7 +23,7 @@ export function getNodeText(node) {
23
23
  * You can use this to translate older query- or AsyncResult-based code to new the Suspense system, for example: `if (query.isLoading) suspend();`
24
24
  */
25
25
  export function suspend() {
26
- use(neverResolve());
26
+ React.use(neverResolve());
27
27
  throw new Error("Somehow a Promise that never resolves was resolved?");
28
28
  }
29
29
  /**
@@ -85,7 +85,6 @@ function mapResult(result, fn) {
85
85
  return Result.ok(fn(result.data));
86
86
  }
87
87
  class RetryError extends AggregateError {
88
- errors;
89
88
  constructor(errors) {
90
89
  super(errors, deindent `
91
90
  Error after retrying ${errors.length} times.
@@ -2,10 +2,9 @@ import { AsyncResult, Result } from "./results";
2
2
  import { generateUuid } from "./uuids";
3
3
  import { pending, rejected, resolved } from "./promises";
4
4
  export class Store {
5
- _value;
6
- _callbacks = new Map();
7
5
  constructor(_value) {
8
6
  this._value = _value;
7
+ this._callbacks = new Map();
9
8
  }
10
9
  get() {
11
10
  return this._value;
@@ -38,15 +37,13 @@ export class Store {
38
37
  }
39
38
  }
40
39
  export class AsyncStore {
41
- _isAvailable;
42
- _mostRecentOkValue = undefined;
43
- _isRejected = false;
44
- _rejectionError;
45
- _waitingRejectFunctions = new Map();
46
- _callbacks = new Map();
47
- _updateCounter = 0;
48
- _lastSuccessfulUpdate = -1;
49
40
  constructor(...args) {
41
+ this._mostRecentOkValue = undefined;
42
+ this._isRejected = false;
43
+ this._waitingRejectFunctions = new Map();
44
+ this._callbacks = new Map();
45
+ this._updateCounter = 0;
46
+ this._lastSuccessfulUpdate = -1;
50
47
  if (args.length === 0) {
51
48
  this._isAvailable = false;
52
49
  }
@@ -1,3 +1,4 @@
1
+ import { findLastIndex } from "./arrays";
1
2
  import { StackAssertionError } from "./errors";
2
3
  import { filterUndefined } from "./objects";
3
4
  export function typedToLowercase(s) {
@@ -42,7 +43,7 @@ export function trimEmptyLinesStart(s) {
42
43
  */
43
44
  export function trimEmptyLinesEnd(s) {
44
45
  const lines = s.split("\n");
45
- const lastNonEmptyLineIndex = lines.findLastIndex((line) => line.trim() !== "");
46
+ const lastNonEmptyLineIndex = findLastIndex(lines, (line) => line.trim() !== "");
46
47
  return lines.slice(0, lastNonEmptyLineIndex + 1).join("\n");
47
48
  }
48
49
  /**
@@ -105,9 +106,13 @@ export function mergeScopeStrings(...scopes) {
105
106
  return extractScopes(allScope).join(" ");
106
107
  }
107
108
  export function snakeCaseToCamelCase(snakeCase) {
109
+ if (snakeCase.match(/[A-Z]/))
110
+ return snakeCase; // TODO next-release: this is a hack for fixing the email templates, remove this after v2 migration
108
111
  return snakeCase.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
109
112
  }
110
113
  export function camelCaseToSnakeCase(camelCase) {
114
+ if (camelCase.match(/_/))
115
+ return camelCase; // TODO next-release: this is a hack for fixing the email templates, remove this after v2 migration
111
116
  return camelCase.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
112
117
  }
113
118
  /**
@@ -251,7 +256,7 @@ function nicifyPropertyString(str) {
251
256
  return JSON.stringify(str);
252
257
  }
253
258
  function getNicifiableKeys(value) {
254
- return ("getNicifiableKeys" in value ? value.getNicifiableKeys : null)?.() ?? Object.keys(value).sort();
259
+ return ("getNicifiableKeys" in value ? value.getNicifiableKeys?.bind(value) : null)?.() ?? Object.keys(value).sort();
255
260
  }
256
261
  function getNicifiableEntries(value) {
257
262
  const recordLikes = [Headers];
@@ -0,0 +1 @@
1
+ export declare function isLocalhost(urlOrString: string | URL): boolean;
@@ -0,0 +1,8 @@
1
+ export function isLocalhost(urlOrString) {
2
+ const url = new URL(urlOrString);
3
+ if (url.hostname === "localhost" || url.hostname.endsWith(".localhost"))
4
+ return true;
5
+ if (url.hostname.match(/^127\.\d+\.\d+\.\d+$/))
6
+ return true;
7
+ return false;
8
+ }
@@ -1 +1 @@
1
- export declare function generateUuid(): any;
1
+ export declare function generateUuid(): string;
@@ -1,4 +1,5 @@
1
1
  import { globalVar } from "./globals";
2
2
  export function generateUuid() {
3
- return globalVar.crypto.randomUUID();
3
+ // crypto.randomUuid is not supported in all browsers, so this is a polyfill
4
+ return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c => (+c ^ globalVar.crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> +c / 4).toString(16));
4
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackframe/stack-shared",
3
- "version": "2.5.2",
3
+ "version": "2.5.4",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [
@@ -36,7 +36,7 @@
36
36
  "jose": "^5.2.2",
37
37
  "oauth4webapi": "^2.10.3",
38
38
  "uuid": "^9.0.1",
39
- "@stackframe/stack-sc": "2.5.2"
39
+ "@stackframe/stack-sc": "2.5.4"
40
40
  },
41
41
  "devDependencies": {
42
42
  "rimraf": "^5.0.5",
@@ -1,3 +0,0 @@
1
- import * as yup from "yup";
2
- export declare const yupJson: yup.MixedSchema<{} | null, yup.AnyObject, undefined, "">;
3
- export declare const yupJsonValidator: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
package/dist/utils/yup.js DELETED
@@ -1,13 +0,0 @@
1
- import * as yup from "yup";
2
- export const yupJson = yup.mixed().nullable().defined().transform((value) => JSON.parse(JSON.stringify(value)));
3
- export const yupJsonValidator = yup.string().test("json", "Invalid JSON format", (value) => {
4
- if (!value)
5
- return true;
6
- try {
7
- JSON.parse(value);
8
- return true;
9
- }
10
- catch (error) {
11
- return false;
12
- }
13
- });