@luckystack/core 0.10.2 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/AGENTS.md +11 -0
  2. package/CHANGELOG.md +7 -0
  3. package/README.md +2 -88
  4. package/dist/apiInterceptors.d.ts +36 -0
  5. package/dist/apiMethodMapRegistry.d.ts +5 -0
  6. package/dist/apiRequest.d.ts +71 -0
  7. package/dist/apiTypeStubs.d.ts +3 -5
  8. package/dist/avatarConfig.d.ts +22 -0
  9. package/dist/bindAddress.d.ts +15 -0
  10. package/dist/bootUuid.d.ts +24 -0
  11. package/dist/cancelRegistry.d.ts +7 -0
  12. package/dist/checkOrigin.d.ts +6 -0
  13. package/dist/client.d.ts +46 -335
  14. package/dist/client.js +2 -2
  15. package/dist/client.js.map +1 -1
  16. package/dist/clientHookBus.d.ts +62 -0
  17. package/dist/clients.d.ts +16 -0
  18. package/dist/config.d.ts +8 -2
  19. package/dist/configUtils.d.ts +16 -0
  20. package/dist/consoleLog.d.ts +1 -0
  21. package/dist/cookies.d.ts +28 -0
  22. package/dist/createRegistry.d.ts +39 -0
  23. package/dist/csrf.d.ts +30 -0
  24. package/dist/csrfConfig.d.ts +32 -0
  25. package/dist/db.d.ts +12 -0
  26. package/dist/dbHealthCheck.d.ts +6 -0
  27. package/dist/{config-CwW3KY9r.d.ts → deployConfigRegistry.d.ts} +8 -43
  28. package/dist/emailRegistry.d.ts +139 -0
  29. package/dist/env.d.ts +38 -0
  30. package/dist/errorFormatterRegistry.d.ts +54 -0
  31. package/dist/errorTrackerIdentity.d.ts +14 -0
  32. package/dist/errorTrackerRegistry.d.ts +85 -0
  33. package/dist/escapeHtml.d.ts +6 -0
  34. package/dist/eslint/index.d.ts +5 -8
  35. package/dist/eslint/internal/hasPackage.d.ts +1 -0
  36. package/dist/eslint/internal/ruleTypes.d.ts +4 -0
  37. package/dist/eslint/rules/no-arbitrary-tailwind-color.d.ts +3 -0
  38. package/dist/eslint/rules/no-direct-prisma-import-in-components.d.ts +3 -0
  39. package/dist/eslint/rules/no-local-socket-enumeration.d.ts +3 -0
  40. package/dist/eslint/rules/no-raw-fetch-in-src.d.ts +3 -0
  41. package/dist/eslint/rules/no-raw-try-catch.d.ts +3 -0
  42. package/dist/eslint/rules/no-unsafe-api-wrappers.d.ts +3 -0
  43. package/dist/eslint/rules/no-unsafe-sync-wrappers.d.ts +3 -0
  44. package/dist/eslint/rules/prefer-luckystack-confirm.d.ts +3 -0
  45. package/dist/eslint/rules/prefer-luckystack-dropdown.d.ts +3 -0
  46. package/dist/eslint/rules/prefer-luckystack-notify.d.ts +3 -0
  47. package/dist/extractToken.d.ts +12 -0
  48. package/dist/extractTokenFromRequest.d.ts +12 -0
  49. package/dist/getParams.d.ts +9 -0
  50. package/dist/hooks/registry.d.ts +12 -0
  51. package/dist/hooks/types.d.ts +446 -0
  52. package/dist/httpApiUtils.d.ts +54 -0
  53. package/dist/index.d.ts +110 -1892
  54. package/dist/index.js.map +1 -1
  55. package/dist/lease.d.ts +18 -0
  56. package/dist/localSocketEnumerationGuard.d.ts +22 -0
  57. package/dist/localeReloader.d.ts +3 -0
  58. package/dist/localesRegistry.d.ts +8 -0
  59. package/dist/localizedNormalizer.d.ts +50 -0
  60. package/dist/loggerRegistry.d.ts +12 -0
  61. package/dist/middlewareRegistry.d.ts +45 -0
  62. package/dist/notifier.d.ts +17 -0
  63. package/dist/offlineQueue.d.ts +48 -0
  64. package/dist/oneTimeToken.d.ts +43 -0
  65. package/dist/pageRouteValidation.d.ts +37 -0
  66. package/dist/paths.d.ts +35 -0
  67. package/dist/peerDeps.d.ts +23 -0
  68. package/dist/portOverrideRegistry.d.ts +3 -0
  69. package/dist/processUpload.d.ts +44 -0
  70. package/dist/{sessionTypes-DanjuPaE.d.ts → projectConfig.d.ts} +32 -129
  71. package/dist/rateLimiter.d.ts +90 -0
  72. package/dist/react/AvatarProvider.d.ts +11 -0
  73. package/dist/react/Middleware.d.ts +10 -0
  74. package/dist/react/Router.d.ts +1 -0
  75. package/dist/react/TranslationProvider.d.ts +22 -0
  76. package/dist/react/notify.d.ts +12 -0
  77. package/dist/react/sessionContext.d.ts +31 -0
  78. package/dist/react/useTheme.d.ts +5 -0
  79. package/dist/redactedLogKeys.d.ts +22 -0
  80. package/dist/redis.d.ts +15 -0
  81. package/dist/redisKeyFormatter.d.ts +7 -0
  82. package/dist/resolveClientIp.d.ts +51 -0
  83. package/dist/responseNormalizer.d.ts +33 -0
  84. package/dist/roomNameFormatterRegistry.d.ts +36 -0
  85. package/dist/roomSockets.d.ts +23 -0
  86. package/dist/routedDataQuery.d.ts +7 -0
  87. package/dist/routedHttpInvocation.d.ts +20 -0
  88. package/dist/runtimeMapsRegistry.d.ts +18 -0
  89. package/dist/runtimeTypeValidation.d.ts +13 -0
  90. package/dist/secretsResolved.d.ts +3 -0
  91. package/dist/sentrySetup.d.ts +21 -0
  92. package/dist/serveAvatars.d.ts +5 -0
  93. package/dist/serviceRoute.d.ts +27 -0
  94. package/dist/servicesConfigRegistry.d.ts +22 -0
  95. package/dist/sessionProviderRegistry.d.ts +46 -0
  96. package/dist/sessionTypes.d.ts +79 -0
  97. package/dist/sleep.d.ts +1 -0
  98. package/dist/socketEvents.d.ts +37 -0
  99. package/dist/socketMiddlewareRegistry.d.ts +20 -0
  100. package/dist/socketRedisAdapter.d.ts +21 -0
  101. package/dist/socketState.d.ts +5 -0
  102. package/dist/socketStatusTypes.d.ts +6 -0
  103. package/dist/socketTypes.d.ts +34 -0
  104. package/dist/synchronizedEnvHashes.d.ts +66 -0
  105. package/dist/testFileConvention.d.ts +11 -0
  106. package/dist/testResetTargets.d.ts +5 -0
  107. package/dist/tryCatch.d.ts +1 -0
  108. package/dist/tryCatchClient.d.ts +1 -0
  109. package/dist/tryCatchSync.d.ts +1 -0
  110. package/dist/validateRequest.d.ts +50 -0
  111. package/docs/app-bootstrap.md +4 -449
  112. package/docs/config-registry.md +3 -346
  113. package/docs/csrf-config.md +3 -86
  114. package/docs/error-tracker-registry.md +3 -192
  115. package/docs/hooks.md +2 -295
  116. package/docs/rate-limit-strategy.md +3 -168
  117. package/docs/redis-adapter.md +5 -110
  118. package/docs/session-types.md +3 -178
  119. package/docs/socket-bootstrap.md +5 -385
  120. package/package.json +2 -2
  121. package/CLAUDE.md +0 -256
  122. package/dist/pageRouteValidation-B4Cmtfjv.d.ts +0 -280
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Acquire an exclusive lease named `name` for `ttlMs` milliseconds. Returns an
3
+ * opaque owner token on success, or `null` when another owner already holds it.
4
+ * `SET key token PX ttl NX` is atomic, so concurrent acquirers race safely.
5
+ * Keep the returned token to `renewLease` / `releaseLease`.
6
+ */
7
+ export declare const acquireLease: (name: string, ttlMs: number) => Promise<string | null>;
8
+ /**
9
+ * Extend a held lease by `ttlMs` (sliding ownership). Returns true when the
10
+ * supplied `token` still owns the lease and the TTL was applied, false
11
+ * otherwise (lost ownership, expired, or Redis error).
12
+ */
13
+ export declare const renewLease: (name: string, token: string, ttlMs: number) => Promise<boolean>;
14
+ /**
15
+ * Release a held lease. Owner-checked: only succeeds (returns true) when
16
+ * `token` is the current holder. Returns false on mismatch or Redis error.
17
+ */
18
+ export declare const releaseLease: (name: string, token: string) => Promise<boolean>;
@@ -0,0 +1,22 @@
1
+ /** Thrown (outside production) when consumer code touches a per-instance socket map. */
2
+ export declare class LocalSocketEnumerationError extends Error {
3
+ constructor(surface: string);
4
+ }
5
+ /**
6
+ * Structural subset of a Socket.io `Server` the guard needs. Typed this way so
7
+ * the real server AND a structural test double both satisfy it without a cast.
8
+ */
9
+ export interface GuardableSocketServer {
10
+ sockets: {
11
+ adapter: object;
12
+ sockets: Map<string, unknown>;
13
+ };
14
+ }
15
+ /**
16
+ * Wrap a Socket.io server so that the per-instance surfaces
17
+ * (`sockets.adapter.rooms`, `sockets.adapter.sids`, enumerating `sockets.sockets`)
18
+ * throw {@link LocalSocketEnumerationError}. Everything else — `in()`, `to()`,
19
+ * `fetchSockets()`, `emit()`, `sockets.sockets.get(id)` — passes through
20
+ * unchanged. Identity of the wrapper is NOT stable across calls; callers cache it.
21
+ */
22
+ export declare const guardLocalSocketEnumeration: <T extends GuardableSocketServer>(io: T) => T;
@@ -0,0 +1,3 @@
1
+ export type LocaleReloader = () => void | Promise<void>;
2
+ export declare const registerLocaleReloader: (reloader: LocaleReloader) => LocaleReloader;
3
+ export declare const getLocaleReloader: () => LocaleReloader | null;
@@ -0,0 +1,8 @@
1
+ export type LocalesMap = Record<string, unknown>;
2
+ export type LanguageSource = () => string | null | undefined;
3
+ export declare const registerLocales: (locales: LocalesMap) => void;
4
+ export declare const getRegisteredLocales: () => LocalesMap;
5
+ export declare const getDefaultLocale: () => string;
6
+ export declare const registerLanguageSource: (fn: LanguageSource) => void;
7
+ export declare const getActiveLanguage: () => string;
8
+ export declare const getLocaleByCode: (code: string) => unknown;
@@ -0,0 +1,50 @@
1
+ import type { ErrorParam, ErrorResponseInput, NormalizedErrorResponse } from './responseNormalizer.js';
2
+ export type LanguageCode = string;
3
+ export interface TranslateInput {
4
+ language: LanguageCode;
5
+ key: string;
6
+ params?: ErrorParam[];
7
+ }
8
+ export type TranslateFunction = (input: TranslateInput) => string;
9
+ export interface NormalizeErrorResponseInput {
10
+ response: ErrorResponseInput;
11
+ preferredLocale?: string | null;
12
+ userLanguage?: string | null;
13
+ fallbackHttpStatus?: number;
14
+ }
15
+ export interface LocalizedNormalizer {
16
+ normalizeErrorResponse: (input: NormalizeErrorResponseInput) => NormalizedErrorResponse;
17
+ resolveErrorMessage: (input: {
18
+ errorCode: string;
19
+ errorParams?: ErrorParam[];
20
+ preferredLocale?: string | null;
21
+ userLanguage?: string | null;
22
+ }) => string;
23
+ extractLanguageFromHeader: (header?: string | string[]) => LanguageCode | null;
24
+ }
25
+ export interface CreateLocalizedNormalizerInput {
26
+ translate: TranslateFunction;
27
+ /**
28
+ * Language the framework falls back to when the caller provides no
29
+ * language hints. Defaults to 'en'.
30
+ */
31
+ defaultLanguage?: LanguageCode;
32
+ /**
33
+ * Decide whether a given string is an acceptable language code. Defaults
34
+ * to accepting any non-empty short-form code (ISO 639-1 style). Projects
35
+ * that only support a closed set should pass a narrower predicate.
36
+ */
37
+ isSupportedLanguage?: (code: string) => boolean;
38
+ }
39
+ export declare const createLocalizedNormalizer: (input: CreateLocalizedNormalizerInput) => LocalizedNormalizer;
40
+ export declare const registerLocalizedNormalizer: (normalizer: LocalizedNormalizer) => void;
41
+ export declare const getLocalizedNormalizer: () => LocalizedNormalizer;
42
+ export declare const isLocalizedNormalizerRegistered: () => boolean;
43
+ export declare const normalizeErrorResponse: (input: NormalizeErrorResponseInput) => NormalizedErrorResponse;
44
+ export declare const resolveErrorMessage: (input: {
45
+ errorCode: string;
46
+ errorParams?: ErrorParam[];
47
+ preferredLocale?: string | null;
48
+ userLanguage?: string | null;
49
+ }) => string;
50
+ export declare const extractLanguageFromHeader: (header?: string | string[]) => LanguageCode | null;
@@ -0,0 +1,12 @@
1
+ export type LoggerContext = Record<string, unknown>;
2
+ export interface Logger {
3
+ debug: (message: string, context?: LoggerContext) => void;
4
+ info: (message: string, context?: LoggerContext) => void;
5
+ warn: (message: string, context?: LoggerContext) => void;
6
+ error: (message: string, error?: unknown, context?: LoggerContext) => void;
7
+ }
8
+ export declare const createDevLogger: () => Logger;
9
+ export declare const registerLogger: (logger: Logger) => void;
10
+ export declare const getLogger: () => Logger;
11
+ export declare const isLoggerRegistered: () => boolean;
12
+ export declare const resetLoggerForTests: () => void;
@@ -0,0 +1,45 @@
1
+ import type { BaseSessionLayout } from './sessionTypes.js';
2
+ export interface MiddlewareInput {
3
+ location: string;
4
+ searchParams: Record<string, string>;
5
+ session: BaseSessionLayout | null;
6
+ }
7
+ export type MiddlewareResult = {
8
+ success: true;
9
+ redirect?: undefined;
10
+ status?: undefined;
11
+ } | {
12
+ success: false;
13
+ redirect: string;
14
+ status?: undefined;
15
+ } | {
16
+ success: false;
17
+ redirect?: undefined;
18
+ status: number;
19
+ } | undefined;
20
+ /** Normalized decision derived from a {@link MiddlewareResult}. */
21
+ export type MiddlewareOutcome = {
22
+ kind: 'allow';
23
+ } | {
24
+ kind: 'redirect';
25
+ to: string;
26
+ } | {
27
+ kind: 'deny';
28
+ status: number;
29
+ } | {
30
+ kind: 'fallback';
31
+ };
32
+ export declare const resolveMiddlewareOutcome: (result: MiddlewareResult) => MiddlewareOutcome;
33
+ export type MiddlewareHandler = (input: MiddlewareInput) => MiddlewareResult | Promise<MiddlewareResult>;
34
+ export declare const registerMiddlewareHandler: (handler: MiddlewareHandler) => void;
35
+ export declare const getMiddlewareHandler: () => MiddlewareHandler;
36
+ export type PageMiddleware<TSession extends BaseSessionLayout = BaseSessionLayout> = (input: {
37
+ location: string;
38
+ searchParams: Record<string, string>;
39
+ session: TSession | null;
40
+ }) => MiddlewareResult | Promise<MiddlewareResult>;
41
+ export declare const registerPageMiddleware: (path: string, middleware: PageMiddleware) => void;
42
+ export declare const getPageMiddleware: (path: string) => PageMiddleware | undefined;
43
+ export declare const hasPageMiddleware: (path: string) => boolean;
44
+ /** Test helper — drop every registered per-page middleware. */
45
+ export declare const clearPageMiddlewaresForTests: () => void;
@@ -0,0 +1,17 @@
1
+ export interface NotifyParam {
2
+ key: string;
3
+ value: string | number | boolean;
4
+ }
5
+ export interface NotifyInput {
6
+ key: string;
7
+ params?: NotifyParam[];
8
+ }
9
+ export interface Notifier {
10
+ success: (input: NotifyInput) => void;
11
+ error: (input: NotifyInput) => void;
12
+ info: (input: NotifyInput) => void;
13
+ warning: (input: NotifyInput) => void;
14
+ }
15
+ export declare const registerNotifier: (notifier: Notifier) => void;
16
+ export declare const getNotifier: () => Notifier;
17
+ export declare const notify: Notifier;
@@ -0,0 +1,48 @@
1
+ import { Socket } from "socket.io-client";
2
+ /** Why a queued item was dropped (handed to its `onDrop` callback). */
3
+ export type QueueDropReason = 'expired' | 'queue-full';
4
+ interface ApiQueueItem {
5
+ id: string;
6
+ key: string;
7
+ run: (socketInstance: Socket) => void;
8
+ createdAt: number;
9
+ /**
10
+ * Per-request override of `projectConfig.offlineQueue.dropPolicy`. See
11
+ * `SyncQueueItem.dropPolicy` for details.
12
+ */
13
+ dropPolicy?: 'drop-oldest' | 'drop-newest' | 'reject';
14
+ /**
15
+ * Optional callback invoked when THIS item is dropped (evicted for age or
16
+ * because the queue was full / rejected) instead of ever running (SYNC-09).
17
+ * The transport wires this to settle the pending `syncRequest`/`apiRequest`
18
+ * promise with an error envelope, so an evicted offline request resolves
19
+ * rather than hanging forever. Invoked at most once; failures are swallowed.
20
+ */
21
+ onDrop?: (reason: QueueDropReason) => void;
22
+ }
23
+ interface SyncQueueItem {
24
+ id: string;
25
+ key: string;
26
+ run: (socketInstance: Socket) => void;
27
+ createdAt: number;
28
+ /**
29
+ * Per-request override of `projectConfig.offlineQueue.dropPolicy`. Lets a
30
+ * specific sync ("editor cursor move") pick `'drop-oldest'` while the app
31
+ * default stays `'reject'` for safer sends. When omitted, falls back to
32
+ * the global config.
33
+ */
34
+ dropPolicy?: 'drop-oldest' | 'drop-newest' | 'reject';
35
+ /** See {@link ApiQueueItem.onDrop} (SYNC-09). */
36
+ onDrop?: (reason: QueueDropReason) => void;
37
+ }
38
+ export declare const isOnline: () => boolean;
39
+ export declare const enqueueApiRequest: (item: ApiQueueItem) => boolean;
40
+ export declare const enqueueSyncRequest: (item: SyncQueueItem) => boolean;
41
+ export declare const removeApiQueueItem: (id: string) => void;
42
+ export declare const removeSyncQueueItem: (id: string) => void;
43
+ export declare const removeApiQueueItemsByKey: (key: string) => void;
44
+ export declare const flushApiQueue: (canRun: () => boolean, socketInstance: Socket) => void;
45
+ export declare const flushSyncQueue: (canRun: () => boolean, socketInstance: Socket) => void;
46
+ export declare const getApiQueueSize: () => number;
47
+ export declare const getSyncQueueSize: () => number;
48
+ export {};
@@ -0,0 +1,43 @@
1
+ /** Build the namespaced Redis key for a token's HASH (never the raw token). */
2
+ declare const tokenKey: (namespace: string, token: string) => string;
3
+ /**
4
+ * Handle returned by {@link issueOneTimeToken}. `token` is the RAW token to hand
5
+ * to the caller (embed in the emailed URL); call `store()` to persist its hash
6
+ * to Redis with the configured TTL. Persisting is a separate step so the caller
7
+ * can run veto logic (hooks, validation) between minting and committing without
8
+ * leaving an orphan Redis key.
9
+ */
10
+ export interface OneTimeTokenHandle {
11
+ /** The raw, single-use token. Returned exactly once; never stored verbatim. */
12
+ token: string;
13
+ /** Persist `sha256(token)` -> `payload` in Redis with the issue TTL. */
14
+ store(): Promise<void>;
15
+ }
16
+ /**
17
+ * Mint a one-time token in `namespace` carrying `payload`, redeemable for `ttl`
18
+ * seconds. Returns the raw token plus a `store()` committer. The payload is
19
+ * serialised to a string (objects via JSON); on redemption it is returned as a
20
+ * string and the caller parses it (or use {@link consumeOneTimeTokenJson}).
21
+ *
22
+ * @param namespace Key namespace (e.g. `'-pwreset'`, `'-email-change'`) — routed
23
+ * through `formatKey` so the active key formatter / project prefix applies.
24
+ * @param ttlSeconds Time-to-live in seconds for the stored hash.
25
+ * @param payload Value bound to the token. A string is stored verbatim; any
26
+ * other value is `JSON.stringify`-d.
27
+ */
28
+ export declare const issueOneTimeToken: (namespace: string, ttlSeconds: number, payload: string | Record<string, unknown>) => OneTimeTokenHandle;
29
+ /**
30
+ * Atomically validate + consume a one-time token from `namespace`. Returns the
31
+ * stored payload STRING on success (and deletes the entry, so it can never be
32
+ * reused), or `null` when the token is missing / expired / malformed / already
33
+ * consumed. A single `MULTI` `GET`+`DEL` guarantees at-most-once redemption.
34
+ */
35
+ export declare const consumeOneTimeToken: (namespace: string, token: string) => Promise<string | null>;
36
+ /**
37
+ * Convenience wrapper over {@link consumeOneTimeToken} that JSON-parses the
38
+ * stored payload into `T`. Returns `null` on miss OR on a malformed JSON
39
+ * payload. Use when the token was issued with an object payload.
40
+ */
41
+ export declare const consumeOneTimeTokenJson: <T>(namespace: string, token: string) => Promise<T | null>;
42
+ export declare const oneTimeTokenKey: typeof tokenKey;
43
+ export {};
@@ -0,0 +1,37 @@
1
+ export interface PageRouteRules {
2
+ /**
3
+ * Single-character prefix that marks a folder as **invisible-parent** for
4
+ * page routing. Default: `'_'`.
5
+ */
6
+ privateFolderPrefix: string;
7
+ /**
8
+ * Folder names that are reserved for framework-internal use and may NEVER
9
+ * host a `page.tsx`, nested or otherwise. Scaffold + page-discovery emit
10
+ * a hard error when a page is placed inside one.
11
+ */
12
+ scaffoldIgnoredFolders: readonly string[];
13
+ }
14
+ export declare const DEFAULT_PAGE_ROUTE_RULES: PageRouteRules;
15
+ export interface PagePathValidationResult {
16
+ /** `true` when the page file produces a routeable URL. */
17
+ valid: boolean;
18
+ /** Computed URL when `valid`. Always begins with `/`. `/` for root page. */
19
+ route?: string;
20
+ /** Human-readable explanation when `!valid`. */
21
+ reason?: string;
22
+ }
23
+ /**
24
+ * Validate a `page.tsx` file path relative to `src/`. Accepts both
25
+ * forward and back slashes, with or without a leading `./` or `/`.
26
+ * The filename **must** be `page.tsx` (or `page.jsx`); other filenames
27
+ * return `valid: false`.
28
+ *
29
+ * Examples (defaults):
30
+ * admin/page.tsx -> { valid: true, route: '/admin' }
31
+ * _housing/renting/page.tsx -> { valid: true, route: '/renting' }
32
+ * _housing/page.tsx -> { valid: false, reason: 'no URL segment left after stripping underscore folders' }
33
+ * _api/something/page.tsx -> { valid: false, reason: 'page.tsx cannot live inside reserved folder _api' }
34
+ * page.tsx -> { valid: true, route: '/' }
35
+ * some/route.tsx -> { valid: false, reason: 'not a page file (expected page.tsx)' }
36
+ */
37
+ export declare const validatePagePath: (srcRelativePath: string, rules?: PageRouteRules) => PagePathValidationResult;
@@ -0,0 +1,35 @@
1
+ export declare const ROOT_DIR: string;
2
+ export declare const getSrcDir: () => string;
3
+ export declare const getServerDir: () => string;
4
+ export declare const getSharedDir: () => string;
5
+ export declare const getUploadsDir: () => string;
6
+ export declare const getPublicDir: () => string;
7
+ export declare const getServerFunctionDirs: () => string[];
8
+ /**
9
+ * @deprecated Use `getServerFunctionDirs()` instead. Returns the first
10
+ * directory from the array, or `'functions'` resolved against the workspace
11
+ * root when no directories are configured.
12
+ */
13
+ export declare const getServerFunctionsDir: () => string;
14
+ export declare const getGeneratedSocketTypesPath: () => string;
15
+ export declare const getGeneratedApiSchemasPath: () => string;
16
+ export declare const getGeneratedApiDocsPath: () => string;
17
+ export declare const SRC_DIR: string;
18
+ /** @deprecated use `getServerDir()` instead. */
19
+ export declare const SERVER_DIR: string;
20
+ /** @deprecated use `getSharedDir()` instead. */
21
+ export declare const SHARED_DIR: string;
22
+ /** @deprecated use `getUploadsDir()` instead. */
23
+ export declare const UPLOADS_DIR: string;
24
+ /** @deprecated use `getPublicDir()` instead. */
25
+ export declare const PUBLIC_DIR: string;
26
+ /** @deprecated use `getServerFunctionsDir()` instead. */
27
+ export declare const SERVER_FUNCTIONS_DIR: string;
28
+ /** @deprecated use `getGeneratedSocketTypesPath()` instead. */
29
+ export declare const GENERATED_SOCKET_TYPES_PATH: string;
30
+ /** @deprecated use `getGeneratedApiSchemasPath()` instead. */
31
+ export declare const GENERATED_API_SCHEMAS_PATH: string;
32
+ /** @deprecated use `getGeneratedApiDocsPath()` instead. */
33
+ export declare const GENERATED_API_DOCS_PATH: string;
34
+ export declare const TSCONFIG_ALIAS_FILES: string[];
35
+ export declare const resolveFromRoot: (...segments: string[]) => string;
@@ -0,0 +1,23 @@
1
+ /** Minimal shape of a Node `require` with the `.resolve` member these guards use. */
2
+ export interface PeerRequire {
3
+ (id: string): unknown;
4
+ resolve: (id: string) => string;
5
+ }
6
+ /**
7
+ * Assert that an optional peer package is installed, throwing a consistent,
8
+ * actionable error when it is not. Does NOT load the module — use `loadPeer`
9
+ * for that. Pass `requireFn` (a `createRequire(import.meta.url)` from the
10
+ * calling adapter) so resolution happens from the consumer's perspective.
11
+ *
12
+ * `hint` is appended to the standard "package X is not installed" sentence —
13
+ * e.g. `'Run `npm install resend`, or pick a different EmailSender adapter.'`.
14
+ */
15
+ export declare const ensurePeerDepInstalled: (packageName: string, hint: string, requireFn?: PeerRequire) => void;
16
+ /**
17
+ * Synchronously load an optional peer package, asserting it is installed
18
+ * first (so a missing dependency fails with the actionable `hint` rather than
19
+ * a raw `MODULE_NOT_FOUND`). Returns the module typed as `T`. Pass `requireFn`
20
+ * (built with `createRequire(import.meta.url)` at the call site) so resolution
21
+ * + load happen relative to the calling module.
22
+ */
23
+ export declare const loadPeer: <T>(packageName: string, hint: string, requireFn?: PeerRequire) => T;
@@ -0,0 +1,3 @@
1
+ export declare const registerPortOverride: (port: number | null) => void;
2
+ export declare const getPortOverride: () => number | undefined;
3
+ export declare const resetPortOverrideForTests: () => void;
@@ -0,0 +1,44 @@
1
+ export interface ProcessUploadInput {
2
+ /** User the upload is associated with. */
3
+ userId: string;
4
+ /** Content type from the source (e.g. parsed from a data URL prefix). */
5
+ contentType: string;
6
+ /** Raw upload bytes — used for `sizeBytes` and passed to the encoder. */
7
+ buffer: Buffer;
8
+ /** Identifier for the upload category. Defaults to `'avatar'`. */
9
+ uploadKind?: string;
10
+ /** Final file name written to disk (used in the `onUploadComplete` payload). */
11
+ fileName: string;
12
+ /**
13
+ * Project-supplied encode + write step. Receives the raw buffer, does
14
+ * whatever encoding/resizing the installer wants (sharp, ffmpeg, raw fs
15
+ * write, S3 upload, etc.), and returns the final byte size on disk —
16
+ * pass through `buffer.byteLength` if you don't have a meaningful
17
+ * post-encode size.
18
+ */
19
+ encodeAndSave: (buffer: Buffer) => Promise<number>;
20
+ }
21
+ export type ProcessUploadResult = {
22
+ status: 'success';
23
+ sizeBytes: number;
24
+ } | {
25
+ status: 'rejected';
26
+ errorCode: string;
27
+ } | {
28
+ status: 'error';
29
+ reason: string;
30
+ cause?: unknown;
31
+ };
32
+ /**
33
+ * Run a project-side upload through the framework's hook contract.
34
+ *
35
+ * Order of operations:
36
+ * 1. Dispatch `onUploadStart` — handlers may return a stop signal to reject
37
+ * the upload (content moderation, virus scanner, quota check).
38
+ * 2. Run the project-supplied `encodeAndSave` callback (wrapped in tryCatch).
39
+ * 3. Dispatch `onUploadComplete` with the final `sizeBytes`.
40
+ *
41
+ * Returns one of three statuses so the caller can map to its own response
42
+ * envelope without inspecting hook internals.
43
+ */
44
+ export declare const processUpload: (input: ProcessUploadInput) => Promise<ProcessUploadResult>;