@take-out/helpers 0.2.2 → 0.2.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.
- package/package.json +2 -1
- package/types/array/getRandomItem.d.ts.map +2 -2
- package/types/array/takeLast.d.ts.map +2 -2
- package/types/array/uniqBy.d.ts.map +2 -2
- package/types/assert.d.ts.map +2 -2
- package/types/async/abortable.d.ts.map +2 -2
- package/types/async/asyncContext.d.ts.map +4 -4
- package/types/async/asyncContext.native.d.ts.map +2 -2
- package/types/async/idle.d.ts.map +2 -2
- package/types/async/interval.d.ts.map +2 -2
- package/types/async/isAborted.d.ts.map +2 -2
- package/types/async/sleep.d.ts.map +2 -2
- package/types/async/useAsync.d.ts.map +2 -2
- package/types/async/useAsyncEffect.d.ts.map +4 -4
- package/types/async/useLazyMount.d.ts +1 -1
- package/types/async/useLazyMount.d.ts.map +3 -3
- package/types/async/useLazyValue.d.ts +1 -1
- package/types/async/useLazyValue.d.ts.map +3 -3
- package/types/browser/clearIndexedDB.d.ts.map +2 -2
- package/types/browser/isActiveElementFormField.d.ts.map +2 -2
- package/types/browser/openPopup.d.ts.map +2 -2
- package/types/client-only.d.ts.map +2 -2
- package/types/clipboard/clipboard.d.ts.map +2 -2
- package/types/clipboard/clipboard.native.d.ts.map +2 -2
- package/types/color/extractOpacityFromColor.d.ts.map +2 -2
- package/types/color/generateColors.d.ts.map +2 -2
- package/types/color/lum.d.ts.map +2 -2
- package/types/color/toHex.d.ts.map +2 -2
- package/types/constants.d.ts +1 -1
- package/types/constants.d.ts.map +5 -11
- package/types/debug/debugLog.d.ts.map +2 -2
- package/types/debug/debugUseState.d.ts +1 -1
- package/types/debug/debugUseState.d.ts.map +3 -3
- package/types/emitter.d.ts.map +4 -4
- package/types/ensure/ensure.d.ts.map +2 -2
- package/types/ensure/ensureOne.d.ts.map +2 -2
- package/types/error/errors.d.ts +16 -0
- package/types/error/errors.d.ts.map +4 -4
- package/types/function/emptyFn.d.ts.map +2 -2
- package/types/function/identityFn.d.ts.map +2 -2
- package/types/function/throttle.d.ts.map +2 -2
- package/types/global/globalEffect.d.ts.map +2 -2
- package/types/global/globalValue.d.ts.map +2 -2
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +4 -4
- package/types/number/formatNumber.d.ts.map +2 -2
- package/types/object/decorateObject.d.ts.map +2 -2
- package/types/object/isEqualDeep.d.ts.map +4 -7
- package/types/object/isEqualIdentity.d.ts.map +2 -2
- package/types/object/isEqualJSON.d.ts.map +2 -2
- package/types/object/isEqualNever.d.ts.map +2 -2
- package/types/object/mapObject.d.ts.map +2 -2
- package/types/object/object.d.ts.map +2 -2
- package/types/object/objectUniqueKey.d.ts.map +2 -2
- package/types/react/createGlobalContext.d.ts.map +2 -2
- package/types/react/getCurrentComponentStack.d.ts.map +3 -3
- package/types/server/ensureEnv.d.ts.map +2 -2
- package/types/server/getHeaders.d.ts.map +2 -2
- package/types/server/isServerRuntime.d.ts +3 -0
- package/types/server/isServerRuntime.d.ts.map +11 -0
- package/types/server/prettyPrintRequest.d.ts.map +2 -2
- package/types/server/prettyPrintResponse.d.ts.map +2 -2
- package/types/server/streamToString.d.ts.map +2 -2
- package/types/server-only.d.ts.map +2 -2
- package/types/storage/createStorage.d.ts +2 -2
- package/types/storage/createStorage.d.ts.map +4 -4
- package/types/storage/driver.d.ts.map +2 -2
- package/types/storage/storage.test.d.ts.map +2 -2
- package/types/storage/types.d.ts.map +2 -2
- package/types/string/dedent.d.ts.map +2 -2
- package/types/string/ellipsis.d.ts.map +2 -2
- package/types/string/hash.d.ts.map +2 -2
- package/types/string/insertAtIndex.d.ts.map +2 -2
- package/types/string/nbspLastWord.d.ts.map +2 -2
- package/types/string/pickLast.d.ts.map +2 -2
- package/types/string/pluralize.d.ts.map +2 -2
- package/types/string/pluralize.native.d.ts.map +4 -6
- package/types/string/randomId.d.ts.map +2 -2
- package/types/string/slugify.d.ts.map +2 -2
- package/types/string/truncateList.d.ts.map +2 -2
- package/types/time/formatDate.d.ts.map +2 -2
- package/types/time/formatDateRelative.d.ts.map +2 -2
- package/types/time/formatDistanceToNow.d.ts.map +2 -2
- package/types/time/time.d.ts.map +4 -6
- package/types/time/useTimer.d.ts.map +2 -2
- package/types/types/NullToOptional.d.ts.map +2 -2
- package/types/types/object.d.ts.map +2 -2
- package/types/types/react.d.ts.map +2 -2
- package/types/types/timer.d.ts.map +2 -2
- package/types/types/tuple.d.ts.map +2 -2
- package/types/url/urlSanitize.d.ts.map +2 -2
- package/types/url/urlValidate.d.ts.map +2 -2
package/types/error/errors.d.ts
CHANGED
|
@@ -4,5 +4,21 @@ export declare class AbortError extends Error {
|
|
|
4
4
|
export declare class EnsureError extends Error {
|
|
5
5
|
constructor(message: string);
|
|
6
6
|
}
|
|
7
|
+
export type ErrorCode = "CONTENT_POLICY_VIOLATION" | "PROFANITY_DETECTED" | "NOT_AUTHENTICATED" | "NOT_AUTHORIZED" | "VALIDATION_ERROR" | "RATE_LIMITED" | "NOT_FOUND" | "INTERNAL_ERROR";
|
|
8
|
+
export declare class AppError extends Error {
|
|
9
|
+
code: ErrorCode;
|
|
10
|
+
details?: Record<string, unknown>;
|
|
11
|
+
constructor(code: ErrorCode, message: string, details?: Record<string, unknown>);
|
|
12
|
+
toJSON(): {
|
|
13
|
+
code: ErrorCode;
|
|
14
|
+
message: string;
|
|
15
|
+
details: Record<string, unknown> | undefined;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export declare function isAppError(error: unknown): error is AppError;
|
|
19
|
+
export declare function getErrorInfo(error: unknown): {
|
|
20
|
+
code: ErrorCode;
|
|
21
|
+
message: string;
|
|
22
|
+
};
|
|
7
23
|
|
|
8
24
|
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"mappings": "AAAA,OAAO,cAAM,mBAAmB,MAAM;CACpC,YAAY;;AAMd,OAAO,cAAM,oBAAoB,MAAM;CACrC,YAAY",
|
|
2
|
+
"mappings": "AAAA,OAAO,cAAM,mBAAmB,MAAM;CACpC,YAAY;;AAMd,OAAO,cAAM,oBAAoB,MAAM;CACrC,YAAY;;AAMd,YAAY,YACR,6BACA,uBACA,sBACA,mBACA,qBACA,iBACA,cACA;AAEJ,OAAO,cAAM,iBAAiB,MAAM;CAClC,MAAM;CACN,UAAU;CAEV,YAAY,MAAM,WAAW,iBAAiB,UAAU;CAOxD,UAAU;EACR,MAAM;EACN;EACA,SAAS;;;AAMb,OAAO,iBAAS,WAAW,iBAAiB,SAAS;AAIrD,OAAO,iBAAS,aAAa,iBAAiB;CAAE,MAAM;CAAW",
|
|
3
3
|
"names": [],
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/error/errors.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
|
-
"export class AbortError extends Error {\n constructor(message = '') {\n super(message)\n this.name = 'AbortError'\n }\n}\n\nexport class EnsureError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'EnsureError'\n }\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
9
|
+
"export class AbortError extends Error {\n constructor(message = '') {\n super(message)\n this.name = 'AbortError'\n }\n}\n\nexport class EnsureError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'EnsureError'\n }\n}\n\nexport type ErrorCode =\n | 'CONTENT_POLICY_VIOLATION'\n | 'PROFANITY_DETECTED'\n | 'NOT_AUTHENTICATED'\n | 'NOT_AUTHORIZED'\n | 'VALIDATION_ERROR'\n | 'RATE_LIMITED'\n | 'NOT_FOUND'\n | 'INTERNAL_ERROR'\n\nexport class AppError extends Error {\n code: ErrorCode\n details?: Record<string, unknown>\n\n constructor(code: ErrorCode, message: string, details?: Record<string, unknown>) {\n super(message)\n this.name = 'AppError'\n this.code = code\n this.details = details\n }\n\n toJSON(): {\n code: ErrorCode\n message: string\n details: Record<string, unknown> | undefined\n } {\n return { code: this.code, message: this.message, details: this.details }\n }\n}\n\nexport function isAppError(error: unknown): error is AppError {\n return error instanceof AppError\n}\n\nexport function getErrorInfo(error: unknown): { code: ErrorCode; message: string } {\n if (isAppError(error)) {\n return { code: error.code, message: error.message }\n }\n if (error instanceof Error) {\n return { code: 'INTERNAL_ERROR', message: error.message }\n }\n return { code: 'INTERNAL_ERROR', message: String(error) }\n}\n"
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/function/throttle.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"// via @github/mini-throttle https://raw.githubusercontent.com/github/mini-throttle/refs/heads/main/index.ts\n\nimport type { Timer } from '../types/timer'\n\nexport interface ThrottleOptions {\n /**\n * Fire immediately on the first call.\n */\n start?: boolean\n /**\n * Fire as soon as `wait` has passed.\n */\n middle?: boolean\n /**\n * Cancel after the first successful call.\n */\n once?: boolean\n}\n\ninterface Throttler<T extends unknown[]> {\n (...args: T): void\n cancel(): void\n}\n\nexport function throttle<T extends unknown[]>(\n callback: (...args: T) => unknown,\n wait = 0,\n { start = true, middle = true, once = false }: ThrottleOptions = {}\n): Throttler<T> {\n let innerStart = start\n let last = 0\n let timer: Timer\n let cancelled = false\n function fn(this: unknown, ...args: T) {\n if (cancelled) return\n const delta = Date.now() - last\n last = Date.now()\n\n if (start && middle && delta >= wait) {\n innerStart = true\n }\n\n if (innerStart) {\n innerStart = false\n callback.apply(this, args)\n if (once) fn.cancel()\n } else if ((middle && delta < wait) || !middle) {\n clearTimeout(timer)\n timer = setTimeout(\n () => {\n last = Date.now()\n callback.apply(this, args)\n if (once) fn.cancel()\n },\n !middle ? wait : wait - delta\n )\n }\n }\n fn.cancel = () => {\n clearTimeout(timer)\n cancelled = true\n }\n return fn\n}\n\nexport function debounce<T extends unknown[]>(\n callback: (...args: T) => unknown,\n wait = 0,\n { start = false, middle = false, once = false }: ThrottleOptions = {}\n): Throttler<T> {\n return throttle(callback, wait, { start, middle, once })\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/global/globalEffect.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"export function globalEffect(key: string, factory: () => void | (() => void)): void {\n const disposeKey = Symbol.for(key)\n const g = globalThis as Record<symbol, () => void>\n\n if (g[disposeKey]) {\n g[disposeKey]?.()\n }\n\n const dispose = factory()\n\n if (dispose) {\n g[disposeKey] = dispose\n }\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/global/globalValue.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"/**\n * Helper to store a value that's not duplicated within the global context Uses\n * a symbol stored on `globalThis` to achieve it.\n *\n * There's two main uses for this (for us, so far):\n *\n * - in dev mode, HMR re-runs files, but you may want to preserve globals\n *\n * - in published node modules, sometimes Vite or other bundlers can cause\n * duplicate dependencies either through bad setup or heuristics, they may\n * compile a module but then another code path doesn't compile it, so you\n * have duplicate modules. in this case it can be good to just use a\n * globalValue and warn the end-user. because you can't account for ever\n * possible weird configuration, and often fixing that config can be a\n * massive pain in the ass, it's better to retain functionality while\n * warning them so they can fix it at their own pace. this often happens\n * with WeakMaps.\n *\n */\n\nexport function globalValue<T>(\n key: string,\n factory: () => T,\n opts?: {\n warnMessage?: string\n }\n): T {\n const symbolKey = Symbol.for(key)\n const g = globalThis as Record<symbol, unknown>\n\n if (!g[symbolKey]) {\n g[symbolKey] = factory()\n } else {\n if (opts?.warnMessage) {\n console.warn(`[globalValue] ${opts.warnMessage}`)\n }\n }\n\n return g[symbolKey] as T\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
package/types/index.d.ts
CHANGED
|
@@ -47,6 +47,7 @@ export * from "./react/getCurrentComponentStack";
|
|
|
47
47
|
export * from "./storage/createStorage";
|
|
48
48
|
export * from "./storage/driver";
|
|
49
49
|
export type { StorageDriver } from "./storage/types";
|
|
50
|
+
export * from "./server/isServerRuntime";
|
|
50
51
|
export * from "./server/ensureEnv";
|
|
51
52
|
export * from "./server/getHeaders";
|
|
52
53
|
export * from "./server/prettyPrintRequest";
|
package/types/index.d.ts.map
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"mappings": "AAAA,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AAGd,cAAc;AAKd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,SAAS,uBAAuB;AAChC,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc,qBAAqB;AAGnC,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,mBAAmB;AACnB,mBAAmB;AACnB,mBAAmB;AACnB,mBAAmB;AACnB,mBAAmB;AAGnB,cAAc;AACd,cAAc",
|
|
2
|
+
"mappings": "AAAA,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AAGd,cAAc;AAKd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,SAAS,uBAAuB;AAChC,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc,qBAAqB;AAGnC,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,mBAAmB;AACnB,mBAAmB;AACnB,mBAAmB;AACnB,mBAAmB;AACnB,mBAAmB;AAGnB,cAAc;AACd,cAAc",
|
|
3
3
|
"names": [],
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/index.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
|
-
"export * from './constants'\nexport * from './emitter'\n\n// array\nexport * from './array/getRandomItem'\nexport * from './array/takeLast'\nexport * from './array/uniqBy'\n\n// assert\nexport * from './assert'\n\n// async\nexport * from './async/abortable'\nexport * from './async/asyncContext'\nexport * from './async/idle'\nexport * from './async/interval'\nexport * from './async/isAborted'\nexport * from './async/sleep'\nexport * from './async/useAsync'\nexport * from './async/useAsyncEffect'\nexport * from './async/useLazyMount'\nexport * from './async/useLazyValue'\n\n// browser\nexport * from './browser/clearIndexedDB'\n\n// clipboard\nexport * from './clipboard/clipboard'\n\n// color\nexport * from './color/toHex'\nexport * from './color/generateColors'\nexport * from './color/lum'\nexport * from './color/extractOpacityFromColor'\nexport * from './browser/isActiveElementFormField'\nexport * from './browser/openPopup'\n\n// debug\nexport * from './debug/debugLog'\nexport * from './debug/debugUseState'\n\n// ensure\nexport * from './ensure/ensure'\nexport * from './ensure/ensureOne'\n\n// error\nexport * from './error/errors'\n\n// files\n\n// function\nexport * from './function/emptyFn'\nexport * from './function/identityFn'\nexport * from './function/throttle'\n\n// global\nexport * from './global/globalEffect'\nexport * from './global/globalValue'\n\n// number\nexport * from './number/formatNumber'\n\n// object\nexport * from './object/decorateObject'\nexport * from './object/isEqualDeep'\nexport { isEqualDeepLite } from './object/isEqualDeep'\nexport * from './object/isEqualIdentity'\nexport * from './object/isEqualJSON'\nexport * from './object/isEqualNever'\nexport * from './object/mapObject'\nexport * from './object/object'\nexport * from './object/objectUniqueKey'\n\n// react\nexport * from './react/createGlobalContext'\nexport * from './react/getCurrentComponentStack'\n\n// storage\nexport * from './storage/createStorage'\nexport * from './storage/driver'\nexport type { StorageDriver } from './storage/types'\n\n// server\nexport * from './server/ensureEnv'\nexport * from './server/getHeaders'\nexport * from './server/prettyPrintRequest'\nexport * from './server/prettyPrintResponse'\nexport * from './server/streamToString'\n\n// string\nexport * from './string/dedent'\nexport * from './string/ellipsis'\nexport * from './string/hash'\nexport * from './string/insertAtIndex'\nexport * from './string/nbspLastWord'\nexport * from './string/pickLast'\nexport * from './string/pluralize'\nexport * from './string/randomId'\nexport * from './string/slugify'\nexport * from './string/truncateList'\n\n// time\nexport * from './time/formatDate'\nexport * from './time/formatDateRelative'\nexport * from './time/formatDistanceToNow'\nexport * from './time/time'\nexport * from './time/useTimer'\n\n// types\nexport type * from './types/NullToOptional'\nexport type * from './types/object'\nexport type * from './types/react'\nexport type * from './types/timer'\nexport type * from './types/tuple'\n\n// url\nexport * from './url/urlSanitize'\nexport * from './url/urlValidate'\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
9
|
+
"export * from './constants'\nexport * from './emitter'\n\n// array\nexport * from './array/getRandomItem'\nexport * from './array/takeLast'\nexport * from './array/uniqBy'\n\n// assert\nexport * from './assert'\n\n// async\nexport * from './async/abortable'\nexport * from './async/asyncContext'\nexport * from './async/idle'\nexport * from './async/interval'\nexport * from './async/isAborted'\nexport * from './async/sleep'\nexport * from './async/useAsync'\nexport * from './async/useAsyncEffect'\nexport * from './async/useLazyMount'\nexport * from './async/useLazyValue'\n\n// browser\nexport * from './browser/clearIndexedDB'\n\n// clipboard\nexport * from './clipboard/clipboard'\n\n// color\nexport * from './color/toHex'\nexport * from './color/generateColors'\nexport * from './color/lum'\nexport * from './color/extractOpacityFromColor'\nexport * from './browser/isActiveElementFormField'\nexport * from './browser/openPopup'\n\n// debug\nexport * from './debug/debugLog'\nexport * from './debug/debugUseState'\n\n// ensure\nexport * from './ensure/ensure'\nexport * from './ensure/ensureOne'\n\n// error\nexport * from './error/errors'\n\n// files\n\n// function\nexport * from './function/emptyFn'\nexport * from './function/identityFn'\nexport * from './function/throttle'\n\n// global\nexport * from './global/globalEffect'\nexport * from './global/globalValue'\n\n// number\nexport * from './number/formatNumber'\n\n// object\nexport * from './object/decorateObject'\nexport * from './object/isEqualDeep'\nexport { isEqualDeepLite } from './object/isEqualDeep'\nexport * from './object/isEqualIdentity'\nexport * from './object/isEqualJSON'\nexport * from './object/isEqualNever'\nexport * from './object/mapObject'\nexport * from './object/object'\nexport * from './object/objectUniqueKey'\n\n// react\nexport * from './react/createGlobalContext'\nexport * from './react/getCurrentComponentStack'\n\n// storage\nexport * from './storage/createStorage'\nexport * from './storage/driver'\nexport type { StorageDriver } from './storage/types'\n\n// server\nexport * from './server/isServerRuntime'\nexport * from './server/ensureEnv'\nexport * from './server/getHeaders'\nexport * from './server/prettyPrintRequest'\nexport * from './server/prettyPrintResponse'\nexport * from './server/streamToString'\n\n// string\nexport * from './string/dedent'\nexport * from './string/ellipsis'\nexport * from './string/hash'\nexport * from './string/insertAtIndex'\nexport * from './string/nbspLastWord'\nexport * from './string/pickLast'\nexport * from './string/pluralize'\nexport * from './string/randomId'\nexport * from './string/slugify'\nexport * from './string/truncateList'\n\n// time\nexport * from './time/formatDate'\nexport * from './time/formatDateRelative'\nexport * from './time/formatDistanceToNow'\nexport * from './time/time'\nexport * from './time/useTimer'\n\n// types\nexport type * from './types/NullToOptional'\nexport type * from './types/object'\nexport type * from './types/react'\nexport type * from './types/timer'\nexport type * from './types/tuple'\n\n// url\nexport * from './url/urlSanitize'\nexport * from './url/urlValidate'\n"
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/number/formatNumber.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"export interface FormatNumberOptions {\n locale?: string\n maximumFractionDigits?: number\n minimumFractionDigits?: number\n forceCompact?: boolean\n}\n\nexport function formatNumber(value: number, options: FormatNumberOptions = {}): string {\n const {\n locale = 'en-US',\n maximumFractionDigits = 1,\n minimumFractionDigits = 0,\n forceCompact = false,\n } = options\n\n if (!forceCompact && Math.abs(value) < 1000) {\n return new Intl.NumberFormat(locale, {\n maximumFractionDigits,\n minimumFractionDigits,\n }).format(value)\n }\n\n return new Intl.NumberFormat(locale, {\n notation: 'compact',\n compactDisplay: 'short',\n maximumFractionDigits,\n minimumFractionDigits,\n }).format(value)\n}\n\nexport function abbreviateNumber(value: number): string {\n return formatNumber(value, { maximumFractionDigits: 1 })\n}\n\nexport function formatCount(value: number): string {\n return formatNumber(value, {\n maximumFractionDigits: 0,\n forceCompact: value >= 1000,\n })\n}\n\nexport function formatReactionCount(value: number | string): string {\n if (typeof value === 'string') return value\n if (value >= 1000000) {\n return `${(value / 1000000).toFixed(1)}M`\n }\n if (value >= 1000) {\n return `${(value / 1000).toFixed(1)}K`\n }\n return value.toString()\n}\n\nexport function formatPhoneNumber(value: string): string {\n return value\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/object/decorateObject.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"export function decorateObject<T extends Record<string, any>>(\n obj: T,\n decorator: (fn: Function) => Function\n): T {\n const decorated = {} as T\n\n for (const [key, value] of Object.entries(obj)) {\n if (typeof value === 'function') {\n ;(decorated as any)[key] = decorator(value)\n } else {\n ;(decorated as any)[key] = value\n }\n }\n\n return decorated\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"mappings": "KAGK,cAAc,UAAU;AAE7B,OAAO,
|
|
3
|
-
"names": [
|
|
4
|
-
"isEqualDeep: EqualityFn",
|
|
5
|
-
"isEqualDeepLite: EqualityFn"
|
|
6
|
-
],
|
|
2
|
+
"mappings": "KAGK,cAAc,UAAU;AAE7B,OAAO,cAAM,aAAa;AAC1B,OAAO,cAAM,iBAAiB",
|
|
3
|
+
"names": [],
|
|
7
4
|
"sources": [
|
|
8
5
|
"src/object/isEqualDeep.ts"
|
|
9
6
|
],
|
|
7
|
+
"version": 3,
|
|
10
8
|
"sourcesContent": [
|
|
11
9
|
"import { dequal } from 'dequal'\nimport { dequal as dequalLite } from 'dequal/lite'\n\ntype EqualityFn = (foo: any, bar: any) => boolean\n\nexport const isEqualDeep: EqualityFn = dequal\nexport const isEqualDeepLite: EqualityFn = dequalLite\n"
|
|
12
|
-
]
|
|
13
|
-
"version": 3
|
|
10
|
+
]
|
|
14
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/object/mapObject.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"export function mapObject<T extends Record<string, any>, R>(\n obj: T,\n fn: <K extends keyof T>(value: T[K], key: K) => R\n): { [K in keyof T]: R } {\n const result = {} as { [K in keyof T]: R }\n\n for (const key in obj) {\n if (Object.hasOwn(obj, key)) {\n result[key] = fn(obj[key], key)\n }\n }\n\n return result\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/object/object.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"import type {\n EntriesToObject,\n EntriesType,\n ObjectEntries,\n ObjectType,\n} from '../types/object'\n\nexport function postfixObjKeys<A extends { [key: string]: string }, B extends string>(\n obj: A,\n postfix: B\n): {\n [Key in `${keyof A extends string ? keyof A : never}${B}`]: string\n} {\n return Object.fromEntries(\n Object.entries(obj).map(([k, v]) => [`${k}${postfix}`, v])\n ) as any\n}\n\nexport function objectFromEntries<ARR_T extends EntriesType>(\n arr: ARR_T\n): EntriesToObject<ARR_T> {\n return Object.fromEntries(arr) as EntriesToObject<ARR_T>\n}\n\nexport function objectKeys<O extends object>(obj: O) {\n return Object.keys(obj) as Array<keyof O>\n}\n\nexport function objectEntries<OBJ_T extends ObjectType>(\n obj: OBJ_T\n): ObjectEntries<OBJ_T> {\n return Object.entries(obj) as ObjectEntries<OBJ_T>\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/object/objectUniqueKey.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"const w = new WeakMap<any, string>()\n\nexport const objectUniqueKey = (item: any): string => {\n return (\n w.get(item) ??\n (() => {\n const k = `${Math.random()}`\n w.set(item, k)\n return k\n })()\n )\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/react/createGlobalContext.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"import { type Context, createContext } from 'react'\n\nimport { globalValue } from '../global/globalValue'\n\n// create or retrieve a React context that is stored on `globalThis`.\n// this ensures a stable singleton that survives hot-reloads during development.\n\nexport function createGlobalContext<T>(key: string, defaultValue: T): Context<T> {\n return globalValue(key, () => createContext<T>(defaultValue))\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/react/getCurrentComponentStack.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
|
-
"import React from 'react'\n\nexport const getCurrentComponentStack = (format?: 'short'): string => {\n if (process.env.NODE_ENV === 'development') {\n const
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
9
|
+
"import React from 'react'\n\nexport const getCurrentComponentStack = (format?: 'short'): string => {\n if (process.env.NODE_ENV === 'development') {\n // react 19.1+ exposes captureOwnerStack as a public api\n const captureOwnerStack = (React as Record<string, any>).captureOwnerStack\n const stack = typeof captureOwnerStack === 'function' ? captureOwnerStack() : null\n\n if (!stack) return ''\n\n if (format === 'short') {\n return formatStackToShort(stack)\n }\n\n return stack\n }\n\n return `(prod, no stack)`\n}\n\nconst formatStackToShort = (stack: string): string => {\n if (process.env.NODE_ENV === 'development') {\n const lines = stack\n // huge stack was causing issues\n .slice(0, 6000)\n .split('\\n')\n\n const componentNames: string[] = []\n\n for (const line of lines) {\n // Extract component names from patterns like \"at ComponentName (\"\n // Also handle cases like \"at Route((chat))\" or \"Route() (\"\n const match = line.match(/\\s*at\\s+([A-Z][a-zA-Z0-9_]*)\\s*\\(/)\n if (match) {\n const componentName = match[1]\n // Filter out framework internals and keep user components\n if (\n componentName &&\n componentName !== 'Array' &&\n componentName !== 'Root' &&\n componentName !== 'Route'\n ) {\n componentNames.push(componentName)\n if (componentNames.length > 10) {\n // avoid too many\n break\n }\n }\n }\n }\n\n return componentNames.join(' < ')\n }\n\n return stack\n}\n"
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/server/ensureEnv.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"// note doesnt work on client because Vite injects process.env\n\nexport function ensureEnv(name: string, defaultValue?: string): string {\n if (typeof process.env[name] === 'string') {\n return process.env[name] || defaultValue || ''\n }\n if (defaultValue !== undefined) {\n return defaultValue\n }\n if (process.env.ALLOW_MISSING_ENV) {\n return ''\n }\n if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {\n if (typeof defaultValue === 'undefined') {\n console.warn(` - missing env ${name}`)\n }\n return ''\n }\n throw new Error(`Environment variable ${name} not set.`)\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/server/getHeaders.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"export function getHeaders(headers: Headers): Record<string, unknown> {\n const headersOut: Record<string, unknown> = {}\n headers.forEach((value, key) => {\n headersOut[key] = value\n })\n return headersOut\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mappings": "AAAA,OAAO,iBAAS",
|
|
3
|
+
"names": [],
|
|
4
|
+
"sources": [
|
|
5
|
+
"src/server/isServerRuntime.ts"
|
|
6
|
+
],
|
|
7
|
+
"version": 3,
|
|
8
|
+
"sourcesContent": [
|
|
9
|
+
"export function isServerRuntime(): boolean {\n // explicit env override (vite replaces at build time, enabling DCE)\n if (process.env.VITE_ENVIRONMENT === 'ssr') return true\n if (process.env.VITE_ENVIRONMENT === 'client') return false\n // auto-detect node/bun server runtime\n return (\n typeof process !== 'undefined' &&\n !!process.versions &&\n !!(process.versions.node || (process.versions as any).bun)\n )\n}\n"
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/server/prettyPrintRequest.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"// import { getHeaders } from './getHeaders'\n// import { streamToString } from './streamToString'\n\nexport async function prettyPrintRequest(request: Request): Promise<void> {\n // one bug potentially, clone casues: Unhandled rejection at [object Promise] TypeError: unusable\n // const request = requestIn.clone()\n\n // const requestDetails = {\n // method: request.method,\n // url: request.url,\n // headers: getHeaders(requestIn.headers),\n // body: request.body ? await streamToString(request.body) : null,\n // }\n\n console.info(request)\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/server/prettyPrintResponse.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"import { getHeaders } from './getHeaders'\nimport { streamToString } from './streamToString'\n\nexport async function prettyPrintResponse(responseIn: Response): Promise<void> {\n const response = responseIn.clone()\n\n const responseDetails = {\n status: response.status,\n statusText: response.statusText,\n headers: getHeaders(responseIn.headers),\n body: response.body ? await streamToString(response.body) : null,\n }\n\n console.info(responseDetails)\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/server/streamToString.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"export async function streamToString(stream: ReadableStream): Promise<string> {\n const reader = stream.getReader()\n const decoder = new TextDecoder()\n let result = ''\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n result += decoder.decode(value, { stream: true })\n }\n } catch (error) {\n console.error('Error reading the stream:', error)\n } finally {\n reader.releaseLock()\n }\n\n return result\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -25,8 +25,8 @@ export interface Storage<
|
|
|
25
25
|
setItem(key: K, value: string): void;
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
|
-
* create a namespaced storage instance
|
|
29
|
-
* @param namespace - unique prefix for all keys
|
|
28
|
+
* create a namespaced storage instance (hmr-safe, returns existing instance if already created)
|
|
29
|
+
* @param namespace - unique prefix for all keys
|
|
30
30
|
* @returns storage instance with get/set (JSON) and getItem/setItem (raw) methods
|
|
31
31
|
* @example
|
|
32
32
|
* const store = createStorage<'token' | 'user', string>('auth')
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"mappings": ";;;;;
|
|
2
|
+
"mappings": ";;;;;AAiBA,iBAAiB;CAAQ;CAA2B;EAAa;;CAE/D,IAAI,KAAK,IAAI;;CAEb,IAAI,KAAK,GAAG,OAAO;;CAEnB,OAAO,KAAK;;CAEZ,IAAI,KAAK;;CAET,QAAQ;;CAER;;CAEA,QAAQ,KAAK;;CAEb,QAAQ,KAAK,GAAG;;;;;;;;;;;AAYlB,OAAO,iBAAS;CAAc;CAAkB;EAAG,oBAAoB,QAAQ,GAAG;;;;;AAiFlF,iBAAiB,aAAa,GAAG;;CAE/B,OAAO;;CAEP,IAAI,OAAO;;CAEX;;CAEA;;;;;;;;;;;AAYF,OAAO,iBAAS,mBAAmB,GAAG,cAAc,aAAa",
|
|
3
3
|
"names": [],
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/storage/createStorage.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
|
-
"import { getStorageDriver } from './driver'\n\nconst
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
9
|
+
"import { getStorageDriver } from './driver'\n\n// hmr-safe: store caches on globalThis so they survive module reloads\nconst globalKey = '__takeout_storage__'\nconst globalCache = ((globalThis as any)[globalKey] ??= {\n namespaces: new Set<string>(),\n instances: new Map<string, Storage<any, any>>(),\n}) as {\n namespaces: Set<string>\n instances: Map<string, Storage<any, any>>\n}\n\n/**\n * namespaced storage interface with JSON serialization\n * @template K - key type (string literal union for type-safe keys)\n * @template V - value type (automatically JSON serialized/deserialized)\n */\nexport interface Storage<K extends string = string, V = unknown> {\n /** get a JSON-parsed value by key */\n get(key: K): V | undefined\n /** set a value (JSON serialized) */\n set(key: K, value: V): void\n /** remove a key */\n remove(key: K): void\n /** check if key exists */\n has(key: K): boolean\n /** get all keys in this namespace */\n keys(): K[]\n /** remove all keys in this namespace */\n clear(): void\n /** get raw string value (no JSON parsing) - localStorage compatible */\n getItem(key: K): string | null\n /** set raw string value (no JSON serialization) - localStorage compatible */\n setItem(key: K, value: string): void\n}\n\n/**\n * create a namespaced storage instance (hmr-safe, returns existing instance if already created)\n * @param namespace - unique prefix for all keys\n * @returns storage instance with get/set (JSON) and getItem/setItem (raw) methods\n * @example\n * const store = createStorage<'token' | 'user', string>('auth')\n * store.set('token', 'abc123')\n * store.get('token') // 'abc123'\n */\nexport function createStorage<K extends string, V>(namespace: string): Storage<K, V> {\n // return existing instance for hmr safety\n const existing = globalCache.instances.get(namespace)\n if (existing) {\n return existing as Storage<K, V>\n }\n\n globalCache.namespaces.add(namespace)\n\n const prefix = `${namespace}:`\n const prefixKey = (key: string) => `${prefix}${key}`\n\n const storage: Storage<K, V> = {\n get(key: K): V | undefined {\n const driver = getStorageDriver()\n if (!driver) return undefined\n const raw = driver.getItem(prefixKey(key))\n if (raw == null) return undefined\n try {\n return JSON.parse(raw)\n } catch {\n return undefined\n }\n },\n\n set(key: K, value: V): void {\n const driver = getStorageDriver()\n if (!driver) return\n driver.setItem(prefixKey(key), JSON.stringify(value))\n },\n\n remove(key: K): void {\n const driver = getStorageDriver()\n if (!driver) return\n driver.removeItem(prefixKey(key))\n },\n\n has(key: K): boolean {\n const driver = getStorageDriver()\n if (!driver) return false\n return driver.getItem(prefixKey(key)) != null\n },\n\n keys(): K[] {\n const driver = getStorageDriver()\n if (!driver) return []\n return driver\n .getAllKeys()\n .filter((k) => k.startsWith(prefix))\n .map((k) => k.slice(prefix.length) as K)\n },\n\n clear(): void {\n const driver = getStorageDriver()\n if (!driver) return\n for (const key of this.keys()) {\n driver.removeItem(prefixKey(key))\n }\n },\n\n getItem(key: K): string | null {\n const driver = getStorageDriver()\n if (!driver) return null\n return driver.getItem(prefixKey(key)) ?? null\n },\n\n setItem(key: K, value: string): void {\n const driver = getStorageDriver()\n if (!driver) return\n driver.setItem(prefixKey(key), value)\n },\n }\n\n globalCache.instances.set(namespace, storage)\n return storage\n}\n\n/**\n * single-value storage interface\n * @template T - value type (automatically JSON serialized/deserialized)\n */\nexport interface StorageValue<T> {\n /** get the stored value */\n get(): T | undefined\n /** set the value */\n set(value: T): void\n /** remove the value */\n remove(): void\n /** check if value exists */\n has(): boolean\n}\n\n/**\n * create a single-value storage (wrapper around createStorage)\n * @param key - unique storage key\n * @returns storage value instance\n * @example\n * const token = createStorageValue<string>('auth-token')\n * token.set('abc123')\n * token.get() // 'abc123'\n */\nexport function createStorageValue<T>(key: string): StorageValue<T> {\n const storage = createStorage<'value', T>(`_v:${key}`)\n return {\n get: (): T | undefined => storage.get('value'),\n set: (value: T): void => storage.set('value', value),\n remove: (): void => storage.remove('value'),\n has: (): boolean => storage.has('value'),\n }\n}\n"
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/storage/driver.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"import type { StorageDriver } from './types'\n\nlet driver: StorageDriver | null = null\n\nexport function setStorageDriver(d: StorageDriver): void {\n driver = d\n}\n\nexport function getStorageDriver(): StorageDriver | null {\n if (driver) return driver\n if (typeof localStorage !== 'undefined' && typeof localStorage.getItem === 'function') {\n return {\n getItem: (key) => localStorage.getItem(key),\n setItem: (key, value) => localStorage.setItem(key, value),\n removeItem: (key) => localStorage.removeItem(key),\n getAllKeys: () => Object.keys(localStorage),\n }\n }\n return null\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/storage/storage.test.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"import { beforeEach, describe, expect, it } from 'vitest'\n\nimport { createStorage } from './createStorage'\nimport { getStorageDriver, setStorageDriver } from './driver'\n\n// test the storage driver system to ensure it works correctly\n// this regression test validates that the storage system initializes properly\n// which is critical for native auth to work\n\ndescribe('storage driver system', () => {\n describe('driver initialization', () => {\n it('getStorageDriver should return localStorage fallback on web', () => {\n // web environment has localStorage which should be used as fallback\n const driver = getStorageDriver()\n // in node/vitest environment, localStorage might not exist\n // but if it does, the driver should work\n if (typeof localStorage !== 'undefined') {\n expect(driver).toBeTruthy()\n }\n })\n\n it('should use custom driver when set', () => {\n const mockStorage = new Map<string, string>()\n const mockDriver = {\n getItem: (key: string) => mockStorage.get(key) ?? null,\n setItem: (key: string, value: string) => mockStorage.set(key, value),\n removeItem: (key: string) => mockStorage.delete(key),\n getAllKeys: () => Array.from(mockStorage.keys()),\n }\n\n setStorageDriver(mockDriver)\n const driver = getStorageDriver()\n expect(driver).toBe(mockDriver)\n })\n })\n\n describe('createStorage with driver', () => {\n let mockStorage: Map<string, string>\n\n beforeEach(() => {\n mockStorage = new Map<string, string>()\n const mockDriver = {\n getItem: (key: string) => mockStorage.get(key) ?? null,\n setItem: (key: string, value: string) => mockStorage.set(key, value),\n removeItem: (key: string) => mockStorage.delete(key),\n getAllKeys: () => Array.from(mockStorage.keys()),\n }\n setStorageDriver(mockDriver)\n })\n\n it('should store and retrieve values', () => {\n const storage = createStorage<'token', string>(`test-${Date.now()}-1`)\n storage.set('token', 'test-value')\n expect(storage.get('token')).toBe('test-value')\n })\n\n it('should use namespace prefix', () => {\n const namespace = `test-${Date.now()}-2`\n const storage = createStorage<'key', string>(namespace)\n storage.set('key', 'value')\n\n // verify the key in the underlying storage has the namespace prefix\n expect(mockStorage.has(`${namespace}:key`)).toBe(true)\n })\n\n it('should handle JSON serialization', () => {\n const storage = createStorage<'obj', { name: string; count: number }>(\n `test-${Date.now()}-3`\n )\n const obj = { name: 'test', count: 42 }\n storage.set('obj', obj)\n expect(storage.get('obj')).toEqual(obj)\n })\n\n it('should support raw string operations', () => {\n const storage = createStorage<'raw', string>(`test-${Date.now()}-4`)\n storage.setItem('raw', 'raw-value')\n expect(storage.getItem('raw')).toBe('raw-value')\n })\n\n it('should return undefined for missing keys', () => {\n const storage = createStorage<'missing', string>(`test-${Date.now()}-5`)\n expect(storage.get('missing')).toBeUndefined()\n })\n\n it('should support has() check', () => {\n const storage = createStorage<'exists', string>(`test-${Date.now()}-6`)\n expect(storage.has('exists')).toBe(false)\n storage.set('exists', 'value')\n expect(storage.has('exists')).toBe(true)\n })\n\n it('should support remove()', () => {\n const storage = createStorage<'removable', string>(`test-${Date.now()}-7`)\n storage.set('removable', 'value')\n expect(storage.has('removable')).toBe(true)\n storage.remove('removable')\n expect(storage.has('removable')).toBe(false)\n })\n\n it('should list keys in namespace', () => {\n const storage = createStorage<'a' | 'b' | 'c', string>(`test-${Date.now()}-8`)\n storage.set('a', '1')\n storage.set('b', '2')\n storage.set('c', '3')\n expect(storage.keys().sort()).toEqual(['a', 'b', 'c'])\n })\n\n it('should clear only namespace keys', () => {\n const ns1 = `test-${Date.now()}-9a`\n const ns2 = `test-${Date.now()}-9b`\n const storage1 = createStorage<'key', string>(ns1)\n const storage2 = createStorage<'key', string>(ns2)\n\n storage1.set('key', 'value1')\n storage2.set('key', 'value2')\n\n storage1.clear()\n\n expect(storage1.has('key')).toBe(false)\n expect(storage2.has('key')).toBe(true)\n })\n })\n\n describe('createStorage without driver (simulates native without setup)', () => {\n // this test simulates what happens on native when setupStorage.native.ts\n // is not imported before auth initialization\n\n it('should handle gracefully when operations fail', () => {\n // when driver returns null, operations should not throw\n // they should just silently fail (return undefined, do nothing)\n // this is the current behavior but we want to document it\n const storage = createStorage<'key', string>(`test-no-driver-${Date.now()}`)\n\n // these should not throw even without a driver\n expect(() => storage.get('key')).not.toThrow()\n expect(() => storage.set('key', 'value')).not.toThrow()\n expect(() => storage.remove('key')).not.toThrow()\n expect(() => storage.has('key')).not.toThrow()\n expect(() => storage.keys()).not.toThrow()\n expect(() => storage.clear()).not.toThrow()\n expect(() => storage.getItem('key')).not.toThrow()\n expect(() => storage.setItem('key', 'value')).not.toThrow()\n })\n })\n})\n\ndescribe('auth storage requirements', () => {\n // these tests document the requirements for auth storage to work correctly\n\n it('storage must be initialized before auth client creates storage instances', () => {\n // the expo auth client creates storage at module load time:\n // const expoStorage = createStorage('expo-auth-client')\n //\n // if setStorageDriver is not called before this, storage operations will fail\n // this is why setupClient.ts must run before any auth code\n\n // we verify this requirement is documented and understood\n expect(true).toBe(true)\n })\n\n it('native platforms require explicit storage driver setup', () => {\n // unlike web which has localStorage fallback, native platforms need\n // MMKV or AsyncStorage to be configured via setStorageDriver()\n //\n // this happens in setupStorage.native.ts which must be imported\n // before platformClient.native.ts creates its storage instance\n\n // we verify this requirement is documented and understood\n expect(true).toBe(true)\n })\n})\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/storage/types.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"export interface StorageDriver {\n getItem(key: string): string | null | undefined\n setItem(key: string, value: string): void\n removeItem(key: string): void\n getAllKeys(): string[]\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/string/dedent.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"export function dedent(strings: TemplateStringsArray | string, ...values: any[]): string {\n // If called as a normal function with a string\n if (typeof strings === 'string') {\n return dedentString(strings)\n }\n\n // If called as a template tag\n const result = strings.reduce((acc, str, i) => {\n return acc + str + (values[i] !== undefined ? values[i] : '')\n }, '')\n\n return dedentString(result)\n}\n\nfunction dedentString(text: string): string {\n let lines = text.replace(/^\\n/, '').split('\\n')\n\n // Find common indentation from non-empty lines\n const indentLengths = lines\n .filter((line) => line.trim().length > 0)\n .map((line) => line.match(/^[ \\t]*/)?.[0].length ?? 0)\n\n const minIndent = indentLengths.length > 0 ? Math.min(...indentLengths) : 0\n\n if (minIndent > 0) {\n lines = lines.map((line) => line.slice(minIndent))\n }\n\n return lines.join('\\n').trimEnd()\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/string/ellipsis.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"export const ellipsis = (str: string, maxLength: number): string => {\n // avoid running replace on huge string if its long\n const shortened = str.length > 500 ? str.slice(0, 500) : str\n const cleaned = shortened.replace(/\\s+/g, ' ').trim()\n if (cleaned.length > maxLength) {\n return cleaned.substring(0, maxLength - 3) + '…'\n }\n return cleaned\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/string/hash.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"// simple reversible encoding - alphanumeric only\n\nexport function hashString(str: string): string {\n // convert to hex (0-9a-f)\n return str\n .split('')\n .map((c) => c.charCodeAt(0).toString(16).padStart(2, '0'))\n .join('')\n}\n\nexport function unhashString(encoded: string): string {\n // convert from hex back to string\n return (\n encoded\n .match(/.{2}/g)\n ?.map((h) => String.fromCharCode(parseInt(h, 16)))\n .join('') || ''\n )\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/string/insertAtIndex.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"export function insertAtIndex(original: string, index: number, toInsert: string): string {\n if (index < 0 || index > original.length) {\n throw new Error('Index out of bounds')\n }\n\n return original.slice(0, index) + toInsert + original.slice(index)\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/string/nbspLastWord.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"/**\n * replaces the last space in a string with a non-breaking space\n * to prevent orphaned words at the end of text blocks\n */\nexport const nbspLastWord = (text: string): string => {\n if (!text) return text\n const words = text.split(' ')\n if (words.length <= 1) return text\n return words.slice(0, -1).join(' ') + '\\u00A0' + words[words.length - 1]\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/string/pickLast.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"export function pickLast<T extends string | null | undefined>(\n a: T,\n b: T\n): T extends string ? string : T {\n if (a == null && b == null) return undefined as any\n if (a == null) return b as any\n if (b == null) return a as any\n return (b.localeCompare(a) > 0 ? b : a) as any\n}\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/string/pluralize.ts"
|
|
6
6
|
],
|
|
7
|
+
"version": 3,
|
|
7
8
|
"sourcesContent": [
|
|
8
9
|
"let pluralRules = new Intl.PluralRules('en-US')\n\nexport function pluralize(count: number, singular: string, plural: string): string {\n const grammaticalNumber = pluralRules.select(count)\n switch (grammaticalNumber) {\n case 'one':\n return `${count} ${singular}`\n case 'other':\n return `${count} ${plural}`\n default:\n throw new Error(\n `Can't pluralize: ${grammaticalNumber} for ${count} / ${singular} / ${plural}`\n )\n }\n}\n\nexport function setPluralizeLocale(locale: Intl.LocalesArgument): void {\n pluralRules = new Intl.PluralRules(locale)\n}\n\nexport type PluralizeFn = typeof pluralize\n"
|
|
9
|
-
]
|
|
10
|
-
"version": 3
|
|
10
|
+
]
|
|
11
11
|
}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"mappings": "AAAA,cAAc,mBAAmB;AAEjC,OAAO,
|
|
3
|
-
"names": [
|
|
4
|
-
"pluralize: PluralizeFn"
|
|
5
|
-
],
|
|
2
|
+
"mappings": "AAAA,cAAc,mBAAmB;AAEjC,OAAO,cAAM,WAAW",
|
|
3
|
+
"names": [],
|
|
6
4
|
"sources": [
|
|
7
5
|
"src/string/pluralize.native.ts"
|
|
8
6
|
],
|
|
7
|
+
"version": 3,
|
|
9
8
|
"sourcesContent": [
|
|
10
9
|
"import type { PluralizeFn } from './pluralize'\n\nexport const pluralize: PluralizeFn = (count, singular, plural) => {\n console.info('pluralize.native.ts: TODO', count, singular, plural)\n return plural\n}\n"
|
|
11
|
-
]
|
|
12
|
-
"version": 3
|
|
10
|
+
]
|
|
13
11
|
}
|