@luckystack/core 0.6.6 → 0.7.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 (42) hide show
  1. package/CHANGELOG.md +148 -107
  2. package/CLAUDE.md +245 -245
  3. package/LICENSE +21 -21
  4. package/README.md +93 -93
  5. package/dist/{chunk-WFABOO6J.js → chunk-AFG7KKMS.js} +3 -3
  6. package/dist/chunk-AFG7KKMS.js.map +1 -0
  7. package/dist/{chunk-3AWP2YEA.js → chunk-J3UOWYT4.js} +2 -28
  8. package/dist/chunk-J3UOWYT4.js.map +1 -0
  9. package/dist/{chunk-LU3IPFTR.js → chunk-LTCDQU5Z.js} +1 -1
  10. package/dist/chunk-LTCDQU5Z.js.map +1 -0
  11. package/dist/chunk-R7IRJFVC.js +67 -0
  12. package/dist/chunk-R7IRJFVC.js.map +1 -0
  13. package/dist/client.d.ts +3 -2
  14. package/dist/client.js +4 -4
  15. package/dist/client.js.map +1 -1
  16. package/dist/config-DZCzBNwP.d.ts +122 -0
  17. package/dist/config.d.ts +2 -0
  18. package/dist/config.js +31 -0
  19. package/dist/eslint/index.js.map +1 -1
  20. package/dist/index.d.ts +21 -149
  21. package/dist/index.js +66 -70
  22. package/dist/index.js.map +1 -1
  23. package/dist/pageRouteValidation-sJJCX-YV.d.ts +270 -0
  24. package/dist/{projectConfig-XL5VB76A.js → projectConfig-DBLSQ3NY.js} +2 -2
  25. package/dist/{sentrySetup-4NTWLN2A.js → sentrySetup-MF6JSVWA.js} +3 -3
  26. package/dist/sentrySetup-MF6JSVWA.js.map +1 -0
  27. package/dist/{pageRouteValidation-gqktrJci.d.ts → sessionTypes-Dzen_rPK.d.ts} +23 -265
  28. package/docs/app-bootstrap.md +418 -418
  29. package/docs/config-registry.md +348 -348
  30. package/docs/csrf-config.md +88 -88
  31. package/docs/error-tracker-registry.md +194 -174
  32. package/docs/hooks.md +298 -298
  33. package/docs/rate-limit-strategy.md +170 -170
  34. package/docs/redis-adapter.md +111 -111
  35. package/docs/session-types.md +180 -180
  36. package/docs/socket-bootstrap.md +366 -366
  37. package/package.json +6 -2
  38. package/dist/chunk-3AWP2YEA.js.map +0 -1
  39. package/dist/chunk-LU3IPFTR.js.map +0 -1
  40. package/dist/chunk-WFABOO6J.js.map +0 -1
  41. /package/dist/{projectConfig-XL5VB76A.js.map → config.js.map} +0 -0
  42. /package/dist/{sentrySetup-4NTWLN2A.js.map → projectConfig-DBLSQ3NY.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/eslint/internal/hasPackage.ts","../../src/eslint/rules/no-arbitrary-tailwind-color.ts","../../src/eslint/rules/no-direct-prisma-import-in-components.ts","../../src/eslint/rules/no-raw-fetch-in-src.ts","../../src/eslint/rules/no-raw-try-catch.ts","../../src/eslint/rules/no-unsafe-api-wrappers.ts","../../src/eslint/rules/no-unsafe-sync-wrappers.ts","../../src/eslint/rules/prefer-luckystack-confirm.ts","../../src/eslint/rules/prefer-luckystack-dropdown.ts","../../src/eslint/rules/prefer-luckystack-notify.ts","../../src/eslint/index.ts"],"sourcesContent":["//? Peer-dep presence probe used to gate package-dependent eslint rules.\r\n//? Resolves against `process.cwd()` so the CONSUMER's node_modules drives\r\n//? activation, not this package's own resolution graph.\r\n//?\r\n//? Implementation: tries `require.resolve` first (works for CJS-compatible\r\n//? packages), falls back to an fs-based `node_modules/<name>/package.json`\r\n//? check for pure-ESM packages whose `exports` map omits the `require`\r\n//? condition (which is the case for the @luckystack/* packages themselves).\r\n\r\nimport { existsSync } from 'node:fs';\r\nimport { createRequire } from 'node:module';\r\nimport path from 'node:path';\r\n\r\nconst localRequire = createRequire(import.meta.url);\r\n\r\nconst checkOnDisk = (name: string): boolean => {\r\n const segments = name.startsWith('@')\r\n ? name.split('/').slice(0, 2)\r\n : [name.split('/')[0] ?? name];\r\n return existsSync(path.join(process.cwd(), 'node_modules', ...segments, 'package.json'));\r\n};\r\n\r\nexport const hasPackage = (name: string): boolean => {\r\n try {\r\n localRequire.resolve(name, { paths: [process.cwd()] });\r\n return true;\r\n } catch {\r\n return checkOnDisk(name);\r\n }\r\n};\r\n","//? Rule: warn on arbitrary Tailwind color values (`text-[#fff]`,\r\n//? `bg-[#abc123]`, `border-[#000]`) inside className strings. The framework\r\n//? mandates colors from `src/index.css` `@theme` block (rule 14). Arbitrary\r\n//? colors break dark-mode auto-switching.\r\n\r\nimport type { Rule } from 'eslint';\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\nconst ARBITRARY_COLOR_PATTERN = /\\b(?:text|bg|border|ring|fill|stroke|from|to|via|outline|decoration|accent|caret|placeholder|divide)-\\[#[0-9a-fA-F]{3,8}\\]/;\r\n\r\n//? This rule reads JSX AST nodes (`JSXAttribute`, `JSXExpressionContainer`,\r\n//? `TemplateLiteral` quasis) that eslint-plugin-react injects into the visitor\r\n//? map at runtime but that eslint's stock `Rule.Node` type doesn't model. The\r\n//? objects ARE real eslint nodes at runtime — `context.report({ node })` only\r\n//? needs `{ type, loc, range, ... }`, all present. This guard narrows an\r\n//? `unknown` to `Rule.Node` in one place so the call sites stay cast-free and\r\n//? the previous file-wide `as unknown as Rule.Node` double-casts are gone.\r\nconst asRuleNode = (node: object): Rule.Node => node as Rule.Node;\r\n\r\n//? JSX AST nodes (JSXAttribute, JSXExpressionContainer, …) are not part of\r\n//? eslint's stock estree AST. eslint-plugin-react extends the visitor map at\r\n//? runtime, but the stock `Rule.RuleListener` type does not know about them,\r\n//? so we describe the shapes we read inline. The actual eslint runtime gives\r\n//? us the right object; this is purely a TS-side annotation.\r\ntype ClassNameValueShape =\r\n | { type: 'Literal'; value: unknown }\r\n | { type: 'JSXExpressionContainer'; expression: ExpressionShape }\r\n | { type: string };\r\n\r\ntype ExpressionShape =\r\n | { type: 'Literal'; value: unknown }\r\n | { type: 'TemplateLiteral'; quasis: readonly { value: { cooked?: string; raw: string } }[] }\r\n | { type: string };\r\n\r\ninterface JsxAttributeShape {\r\n name: { type: string; name?: string };\r\n value?: ClassNameValueShape | null;\r\n}\r\n\r\nconst reportIfArbitrary = (\r\n context: Rule.RuleContext,\r\n node: Rule.Node,\r\n value: string,\r\n): void => {\r\n if (ARBITRARY_COLOR_PATTERN.test(value)) {\r\n context.report({ node, messageId: 'useThemeToken' });\r\n }\r\n};\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'suggestion',\r\n docs: {\r\n description: 'Disallow arbitrary Tailwind color values (`text-[#…]`, `bg-[#…]`, …). Use tokens from `src/index.css` `@theme` block.',\r\n },\r\n messages: {\r\n useThemeToken:\r\n 'Do not use arbitrary Tailwind color values like `text-[#…]`. Use a token from `src/index.css` `@theme` block (e.g. `bg-primary`, `text-title`, `border-divider`). Arbitrary colors break dark-mode auto-switching.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n const listener: Rule.RuleListener = {\r\n JSXAttribute(rawNode: unknown): void {\r\n const node = rawNode as JsxAttributeShape & Rule.Node;\r\n if (node.name.type !== 'JSXIdentifier' || node.name.name !== 'className') return;\r\n const value = node.value;\r\n if (!value) return;\r\n if (value.type === 'Literal' && typeof (value as { value?: unknown }).value === 'string') {\r\n reportIfArbitrary(context, asRuleNode(value), (value as { value: string }).value);\r\n return;\r\n }\r\n if (value.type === 'JSXExpressionContainer') {\r\n const expression = (value as { expression: ExpressionShape }).expression;\r\n if (expression.type === 'TemplateLiteral') {\r\n const quasis = (expression as { quasis: readonly { value: { cooked?: string; raw: string } }[] }).quasis;\r\n for (const quasi of quasis) {\r\n reportIfArbitrary(\r\n context,\r\n asRuleNode(quasi),\r\n quasi.value.cooked ?? quasi.value.raw,\r\n );\r\n }\r\n } else if (expression.type === 'Literal' && typeof (expression as { value?: unknown }).value === 'string') {\r\n reportIfArbitrary(\r\n context,\r\n asRuleNode(expression),\r\n (expression as { value: string }).value,\r\n );\r\n }\r\n }\r\n },\r\n };\r\n return listener;\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: warn on `import … from '@prisma/client'` outside of allowed\r\n//? boundaries. Convention: app code re-exports Prisma model types through\r\n//? `src/_types/<ModelName>.ts` so swapping providers / extending types\r\n//? stays centralised. Direct imports leak Prisma details into UI code.\r\n//?\r\n//? Allowed paths: `src/_types/**`, `server/**`, and any file ending in\r\n//? `Adapter.ts` (legitimate adapter implementations).\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\nconst isAllowedPath = (filename: string): boolean => {\r\n const normalised = filename.replaceAll('\\\\', '/');\r\n if (normalised.includes('/src/_types/')) return true;\r\n if (normalised.includes('/server/')) return true;\r\n if (normalised.endsWith('Adapter.ts') || normalised.endsWith('Adapter.tsx')) return true;\r\n if (normalised.includes('/packages/')) return true;\r\n //? Project-root config files (the LuckyStack `config.ts` convention) and\r\n //? any `*.config.ts` are framework boundaries — Prisma types there are\r\n //? expected and not a \"leaking into component code\" concern.\r\n if (normalised.endsWith('/config.ts') || normalised.endsWith('.config.ts')) return true;\r\n if (normalised.includes('/prisma/')) return true;\r\n return false;\r\n};\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'suggestion',\r\n docs: {\r\n description: 'Re-export Prisma model types through `src/_types/<Model>.ts` rather than importing `@prisma/client` directly in components.',\r\n },\r\n messages: {\r\n reExportThroughTypes:\r\n 'Do not import from `@prisma/client` here. Re-export the type through `src/_types/<ModelName>.ts` and import that instead — keeps Prisma details out of component code.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n if (isAllowedPath(context.filename)) return {};\r\n return {\r\n ImportDeclaration(node) {\r\n if (node.source.value === '@prisma/client') {\r\n context.report({ node, messageId: 'reExportThroughTypes' });\r\n }\r\n },\r\n };\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: forbid direct `fetch(...)` calls to framework `/api/*` or\r\n//? `/sync/*` routes. The framework provides typed transport helpers\r\n//? `apiRequest` (for `_api/` routes) and `syncRequest` (for `_sync/`\r\n//? routes) which preserve route/version generics + auth/CSRF/validation.\r\n//?\r\n//? The rule is deliberately narrow:\r\n//? - Fires when the URL is a literal / template containing `/api/` or\r\n//? `/sync/` (framework route patterns).\r\n//? - Skips URLs whose PATH STARTS with `/auth/` — the framework's auth\r\n//? endpoints (`/auth/api/credentials`, OAuth callbacks) are HTTP-only\r\n//? and intentionally use raw fetch (cookies, headers, redirects). The\r\n//? start-of-path check (not `.includes`) means a consumer's typed\r\n//? route under an `auth/` page folder (URL `/api/auth/...`) still\r\n//? fires correctly.\r\n//? - Skips external URLs (starts with `http://`, `https://`, `//`) —\r\n//? consumers fetching third-party APIs are fine.\r\n//? - Skips dynamic URLs (variable, function call, etc.) — be permissive\r\n//? rather than flag-by-default; consumers can opt in via comments.\r\n//?\r\n//? Gated by hasPackage('@luckystack/api') OR hasPackage('@luckystack/core')\r\n//? at the config-composition layer.\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\ninterface AstNodeShape {\r\n type?: string;\r\n value?: unknown;\r\n quasis?: { value?: { raw?: string; cooked?: string } }[];\r\n}\r\n\r\nconst extractStaticUrlText = (urlNode: unknown): string | null => {\r\n if (!urlNode || typeof urlNode !== 'object') return null;\r\n const n = urlNode as AstNodeShape;\r\n if (n.type === 'Literal' && typeof n.value === 'string') return n.value;\r\n if (n.type === 'TemplateLiteral' && Array.isArray(n.quasis)) {\r\n return n.quasis.map((q) => q.value?.cooked ?? q.value?.raw ?? '').join('|');\r\n }\r\n return null;\r\n};\r\n\r\nconst targetsFrameworkRoute = (urlNode: unknown): boolean => {\r\n const text = extractStaticUrlText(urlNode);\r\n if (text === null) return false;\r\n if (/^(https?:)?\\/\\//.test(text)) return false;\r\n //? Skip only when the path STARTS with `/auth/` (framework's special\r\n //? endpoints). The leading `|` accounts for `extractStaticUrlText`'s\r\n //? template-literal join when the first quasi is empty, e.g.\r\n //? `${backendUrl}/auth/api/credentials` joins to `|/auth/api/credentials`.\r\n if (/^(?:\\|)?\\/auth\\//.test(text)) return false;\r\n return /(?:^|[^A-Za-z])\\/(?:api|sync)\\//.test(text);\r\n};\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'problem',\r\n docs: {\r\n description: 'Disallow raw `fetch(...)` to framework `/api/*` and `/sync/*` routes. Use `apiRequest` / `syncRequest` instead.',\r\n },\r\n messages: {\r\n useApiRequest:\r\n 'Do not call `fetch` directly for framework `/api/*` routes. Use `apiRequest({ name, version, data })` for typed inference, or `httpFetch(...)` from `@luckystack/core` if you need a raw same-origin request.',\r\n useSyncRequest:\r\n 'Do not call `fetch` directly for framework `/sync/*` routes. Use `syncRequest({ name, version, data, receiver })` instead.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n return {\r\n CallExpression(node) {\r\n const callee = node.callee;\r\n const isFetchCall =\r\n (callee.type === 'Identifier' && callee.name === 'fetch') ||\r\n (callee.type === 'MemberExpression' &&\r\n callee.object.type === 'Identifier' &&\r\n callee.object.name === 'window' &&\r\n callee.property.type === 'Identifier' &&\r\n callee.property.name === 'fetch');\r\n if (!isFetchCall) return;\r\n const url = node.arguments[0];\r\n if (!targetsFrameworkRoute(url)) return;\r\n const text = extractStaticUrlText(url) ?? '';\r\n const messageId = text.includes('/sync/') ? 'useSyncRequest' : 'useApiRequest';\r\n context.report({ node, messageId });\r\n },\r\n };\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: forbid raw `try { … } catch` inside src/server/shared code.\r\n//? The framework provides `tryCatch` from @luckystack/core (and the API/sync\r\n//? handler `functions.tryCatch` injection) that handles Sentry capture +\r\n//? normalised tuple returns. Raw try/catch bypasses that.\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'problem',\r\n docs: {\r\n description: 'Disallow raw `try { … } catch` blocks — use the framework `tryCatch` helper instead.',\r\n },\r\n messages: {\r\n useTryCatch:\r\n 'Do not use raw try/catch. Import `tryCatch` from `@luckystack/core` (client) or `server/functions/tryCatch` (server), or use the injected `functions.tryCatch` in API / sync handlers.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n return {\r\n TryStatement(node) {\r\n //? Only fire when an actual catch clause is present. `try { } finally { }`\r\n //? is a different construct (cleanup, not error handling) and the\r\n //? `tryCatch` helper is not a substitute.\r\n if (node.handler) {\r\n context.report({ node, messageId: 'useTryCatch' });\r\n }\r\n },\r\n };\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: forbid local wrappers around `apiRequest` whose parameter types\r\n//? erase the route/version generics. The framework's type system relies on\r\n//? literal `name`/`version` strings to infer `serverOutput` / `clientOutput`.\r\n//? A wrapper like:\r\n//?\r\n//? const unsafeApi = (name: string, version: string, data: unknown) =>\r\n//? apiRequest({ name: name as any, ... });\r\n//?\r\n//? destroys that inference. Always call `apiRequest` directly with route\r\n//? literals, or write a wrapper that preserves the generics.\r\n//?\r\n//? Gated by hasPackage('@luckystack/api') at the config-composition layer.\r\n\r\n//? Double-cast + any-spread disabled file-wide: bridges `Rule.Node` to specific\r\n//? AST shapes; the spread iterates over `Object.entries(node)` whose values are\r\n//? typed as `any` because eslint's AST shape varies by node kind.\r\n/* eslint-disable no-restricted-syntax, @typescript-eslint/no-unsafe-argument */\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\nconst SUSPECT_PARAM_NAMES = new Set(['name', 'version', 'route', 'apiName']);\r\n\r\n//? AST keys that point to parents or non-AST metadata. Including them in\r\n//? a recursive descent causes infinite loops because eslint adds `parent`\r\n//? pointers during traversal.\r\nconst SKIP_KEYS = new Set(['parent', 'loc', 'range', 'tokens', 'comments']);\r\n\r\nconst containsApiRequestCall = (body: unknown): boolean => {\r\n if (!body || typeof body !== 'object') return false;\r\n const visited = new WeakSet<object>();\r\n const stack: unknown[] = [body];\r\n while (stack.length > 0) {\r\n const node = stack.pop() as Record<string, unknown> | null;\r\n if (!node || typeof node !== 'object') continue;\r\n if (visited.has(node)) continue;\r\n visited.add(node);\r\n const callee = (node as { type?: string; callee?: { type?: string; name?: string } }).callee;\r\n if (\r\n (node as { type?: string }).type === 'CallExpression' &&\r\n callee?.type === 'Identifier' &&\r\n (callee.name === 'apiRequest' || callee.name === 'syncRequest')\r\n ) {\r\n return true;\r\n }\r\n for (const [key, value] of Object.entries(node)) {\r\n if (SKIP_KEYS.has(key)) continue;\r\n if (Array.isArray(value)) stack.push(...value);\r\n else if (value && typeof value === 'object') stack.push(value);\r\n }\r\n }\r\n return false;\r\n};\r\n\r\nconst isSuspectFunction = (node: {\r\n params?: { type?: string; name?: string; typeAnnotation?: { typeAnnotation?: { type?: string } } }[];\r\n body?: unknown;\r\n}): boolean => {\r\n if (!node.params || node.params.length === 0) return false;\r\n const hasSuspectStringParam = node.params.some((p) => {\r\n if (p.type !== 'Identifier' || !p.name) return false;\r\n if (!SUSPECT_PARAM_NAMES.has(p.name)) return false;\r\n const annotation = p.typeAnnotation?.typeAnnotation?.type;\r\n return annotation === 'TSStringKeyword';\r\n });\r\n if (!hasSuspectStringParam) return false;\r\n return containsApiRequestCall(node.body);\r\n};\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'problem',\r\n docs: {\r\n description: 'Disallow local wrappers around `apiRequest` / `syncRequest` whose `name`/`version` params are typed as plain `string` — this erases the generic route/version inference.',\r\n },\r\n messages: {\r\n unsafeWrapper:\r\n 'This wrapper around `apiRequest` / `syncRequest` accepts `{{paramName}}: string` and erases the route/version generic inference. Call the framework helper directly with literal route names, or type the parameter as a literal union (e.g. `name: \\'examples/getUserData\\'`).',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n return {\r\n FunctionDeclaration(node) {\r\n if (isSuspectFunction(node)) {\r\n const suspect = (node.params as { name?: string }[]).find((p) => p.name && SUSPECT_PARAM_NAMES.has(p.name));\r\n context.report({ node, messageId: 'unsafeWrapper', data: { paramName: suspect?.name ?? 'name' } });\r\n }\r\n },\r\n ArrowFunctionExpression(node) {\r\n if (isSuspectFunction(node)) {\r\n const suspect = (node.params as { name?: string }[]).find((p) => p.name && SUSPECT_PARAM_NAMES.has(p.name));\r\n context.report({ node, messageId: 'unsafeWrapper', data: { paramName: suspect?.name ?? 'name' } });\r\n }\r\n },\r\n };\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: same shape as no-unsafe-api-wrappers, but targeting wrappers\r\n//? around `syncRequest` and `upsertSyncEventCallback`. Gated by\r\n//? hasPackage('@luckystack/sync') at the config-composition layer.\r\n//?\r\n//? Note: the api-wrappers rule already covers the `syncRequest` call site;\r\n//? this rule additionally catches `upsertSyncEventCallback` wrappers and\r\n//? exists as a distinct identity so the sync-only rule can be disabled\r\n//? independently when a consumer uses api but not sync.\r\n\r\n//? Double-cast + any-spread disabled file-wide: bridges `Rule.Node` to specific\r\n//? AST shapes; the spread iterates over `Object.entries(node)` whose values are\r\n//? typed as `any` because eslint's AST shape varies by node kind.\r\n/* eslint-disable no-restricted-syntax, @typescript-eslint/no-unsafe-argument */\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\nconst SUSPECT_PARAM_NAMES = new Set(['name', 'version', 'route', 'syncName']);\r\nconst SUSPECT_CALLEES = new Set(['syncRequest', 'upsertSyncEventCallback']);\r\n\r\n//? AST keys that point to parents or non-AST metadata. Skipped to avoid\r\n//? infinite loops when eslint adds `parent` pointers during traversal.\r\nconst SKIP_KEYS = new Set(['parent', 'loc', 'range', 'tokens', 'comments']);\r\n\r\nconst containsSuspectCall = (body: unknown): boolean => {\r\n if (!body || typeof body !== 'object') return false;\r\n const visited = new WeakSet<object>();\r\n const stack: unknown[] = [body];\r\n while (stack.length > 0) {\r\n const node = stack.pop() as Record<string, unknown> | null;\r\n if (!node || typeof node !== 'object') continue;\r\n if (visited.has(node)) continue;\r\n visited.add(node);\r\n const callee = (node as { type?: string; callee?: { type?: string; name?: string } }).callee;\r\n if (\r\n (node as { type?: string }).type === 'CallExpression' &&\r\n callee?.type === 'Identifier' &&\r\n SUSPECT_CALLEES.has(callee.name ?? '')\r\n ) {\r\n return true;\r\n }\r\n for (const [key, value] of Object.entries(node)) {\r\n if (SKIP_KEYS.has(key)) continue;\r\n if (Array.isArray(value)) stack.push(...value);\r\n else if (value && typeof value === 'object') stack.push(value);\r\n }\r\n }\r\n return false;\r\n};\r\n\r\nconst isSuspect = (node: {\r\n params?: { type?: string; name?: string; typeAnnotation?: { typeAnnotation?: { type?: string } } }[];\r\n body?: unknown;\r\n}): boolean => {\r\n if (!node.params || node.params.length === 0) return false;\r\n const hasSuspectStringParam = node.params.some((p) => {\r\n if (p.type !== 'Identifier' || !p.name) return false;\r\n if (!SUSPECT_PARAM_NAMES.has(p.name)) return false;\r\n return p.typeAnnotation?.typeAnnotation?.type === 'TSStringKeyword';\r\n });\r\n if (!hasSuspectStringParam) return false;\r\n return containsSuspectCall(node.body);\r\n};\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'problem',\r\n docs: {\r\n description: 'Disallow local wrappers around `syncRequest` / `upsertSyncEventCallback` whose `name`/`version` params are typed as plain `string`.',\r\n },\r\n messages: {\r\n unsafeSyncWrapper:\r\n 'This wrapper around `syncRequest` / `upsertSyncEventCallback` accepts a `string` route param and erases the generic event-payload inference. Call the framework helper directly with literal route names.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n return {\r\n FunctionDeclaration(node) {\r\n if (isSuspect(node)) {\r\n context.report({ node, messageId: 'unsafeSyncWrapper' });\r\n }\r\n },\r\n ArrowFunctionExpression(node) {\r\n if (isSuspect(node)) {\r\n context.report({ node, messageId: 'unsafeSyncWrapper' });\r\n }\r\n },\r\n };\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: warn on `confirm(...)` / `window.confirm(...)` calls. The framework\r\n//? provides `menuHandler.confirm({ title, content, input? })` from\r\n//? `src/_functions/menuHandler.ts` which renders a styled, theme-aware,\r\n//? Promise-returning confirm dialog and respects keyboard / accessibility.\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'suggestion',\r\n docs: {\r\n description: 'Prefer `menuHandler.confirm({ title, content })` over the native `confirm()` dialog.',\r\n },\r\n messages: {\r\n useMenuHandlerConfirm:\r\n 'Use `menuHandler.confirm({ title, content })` from `src/_functions/menuHandler.ts` instead of native `confirm()`. Returns a `Promise<boolean>` with proper theming.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n return {\r\n CallExpression(node) {\r\n const callee = node.callee;\r\n if (callee.type === 'Identifier' && callee.name === 'confirm') {\r\n context.report({ node, messageId: 'useMenuHandlerConfirm' });\r\n return;\r\n }\r\n if (\r\n callee.type === 'MemberExpression' &&\r\n callee.object.type === 'Identifier' &&\r\n callee.object.name === 'window' &&\r\n callee.property.type === 'Identifier' &&\r\n callee.property.name === 'confirm'\r\n ) {\r\n context.report({ node, messageId: 'useMenuHandlerConfirm' });\r\n }\r\n },\r\n };\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: warn when a JSX `<select>` element is used. The framework ships\r\n//? `Dropdown` (src/_components/Dropdown.tsx) with search, keyboard nav,\r\n//? sizing variants, and consistent dark/light styling. Native `<select>`\r\n//? skips all of that.\r\n\r\nimport type { Rule } from 'eslint';\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\n//? JSX AST nodes are extended at runtime by eslint-plugin-react, but\r\n//? eslint's stock `Rule.RuleListener` type does not know about them. We\r\n//? describe the shapes we read inline.\r\ninterface JsxOpeningElementShape {\r\n name: { type: string; name?: string };\r\n}\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'suggestion',\r\n docs: {\r\n description: 'Prefer the framework `Dropdown` component over native `<select>` elements.',\r\n },\r\n messages: {\r\n useDropdown:\r\n 'Use `Dropdown` from `src/_components/Dropdown.tsx` (or `MultiSelectDropdown` for multi-select) instead of native `<select>`. The framework component handles keyboard nav, search, sizing, and dark/light theme.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n const listener: Rule.RuleListener = {\r\n JSXOpeningElement(rawNode: unknown): void {\r\n const node = rawNode as JsxOpeningElementShape & Rule.Node;\r\n if (node.name.type === 'JSXIdentifier' && node.name.name === 'select') {\r\n context.report({ node, messageId: 'useDropdown' });\r\n }\r\n },\r\n };\r\n return listener;\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: warn on `alert(...)` / `window.alert(...)`. The framework's\r\n//? `notify` helper (from @luckystack/core) renders themed toast\r\n//? notifications via the registered notifier (default sonner).\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'suggestion',\r\n docs: {\r\n description: 'Prefer `notify()` over the native `alert()` dialog.',\r\n },\r\n messages: {\r\n useNotify:\r\n 'Use `notify({ type, message })` from `@luckystack/core` instead of native `alert()`. Renders a themed toast via the registered notifier.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n return {\r\n CallExpression(node) {\r\n const callee = node.callee;\r\n if (callee.type === 'Identifier' && callee.name === 'alert') {\r\n context.report({ node, messageId: 'useNotify' });\r\n return;\r\n }\r\n if (\r\n callee.type === 'MemberExpression' &&\r\n callee.object.type === 'Identifier' &&\r\n callee.object.name === 'window' &&\r\n callee.property.type === 'Identifier' &&\r\n callee.property.name === 'alert'\r\n ) {\r\n context.report({ node, messageId: 'useNotify' });\r\n }\r\n },\r\n };\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Public entry for `@luckystack/core/eslint`. Composes the LuckyStack\r\n//? flat-config tier that the scaffolded `eslint.luckystack.config.js`\r\n//? consumes. Rules that target an optional `@luckystack/*` peer package\r\n//? are gated via `hasPackage(...)` so absent peers cause silent rule\r\n//? skips (NOT noisy \"rule not found\" errors).\r\n//?\r\n//? Override surface: consumers can spread this default export and append\r\n//? their own config blocks, or replace individual rule severities by\r\n//? re-stating them with `'off' | 'warn' | 'error'`.\r\n\r\nimport type { Linter } from 'eslint';\r\n\r\nimport { hasPackage } from './internal/hasPackage.js';\r\nimport type { EslintRule } from './internal/ruleTypes.js';\r\n\r\nimport noArbitraryTailwindColor from './rules/no-arbitrary-tailwind-color.js';\r\nimport noDirectPrismaImportInComponents from './rules/no-direct-prisma-import-in-components.js';\r\nimport noRawFetchInSrc from './rules/no-raw-fetch-in-src.js';\r\nimport noRawTryCatch from './rules/no-raw-try-catch.js';\r\nimport noUnsafeApiWrappers from './rules/no-unsafe-api-wrappers.js';\r\nimport noUnsafeSyncWrappers from './rules/no-unsafe-sync-wrappers.js';\r\nimport preferLuckystackConfirm from './rules/prefer-luckystack-confirm.js';\r\nimport preferLuckystackDropdown from './rules/prefer-luckystack-dropdown.js';\r\nimport preferLuckystackNotify from './rules/prefer-luckystack-notify.js';\r\n\r\nconst allRules: Record<string, EslintRule> = {\r\n 'no-raw-try-catch': noRawTryCatch,\r\n 'no-raw-fetch-in-src': noRawFetchInSrc,\r\n 'no-unsafe-api-wrappers': noUnsafeApiWrappers,\r\n 'no-unsafe-sync-wrappers': noUnsafeSyncWrappers,\r\n 'prefer-luckystack-dropdown': preferLuckystackDropdown,\r\n 'prefer-luckystack-confirm': preferLuckystackConfirm,\r\n 'prefer-luckystack-notify': preferLuckystackNotify,\r\n 'no-direct-prisma-import-in-components': noDirectPrismaImportInComponents,\r\n 'no-arbitrary-tailwind-color': noArbitraryTailwindColor,\r\n};\r\n\r\nconst hasApi = hasPackage('@luckystack/api');\r\nconst hasCore = hasPackage('@luckystack/core');\r\nconst hasSync = hasPackage('@luckystack/sync');\r\n\r\nconst ruleSeverities: Record<string, Linter.RuleSeverity> = {\r\n // Always-on errors.\r\n 'luckystack/no-raw-try-catch': 'error',\r\n\r\n // Package-gated errors. Disabled when the relevant peer is absent so\r\n // a consumer using only @luckystack/core sees no \"use apiRequest\" noise.\r\n 'luckystack/no-raw-fetch-in-src': hasApi || hasCore ? 'error' : 'off',\r\n 'luckystack/no-unsafe-api-wrappers': hasApi ? 'error' : 'off',\r\n 'luckystack/no-unsafe-sync-wrappers': hasSync ? 'error' : 'off',\r\n\r\n // Warnings — enabled by default per framework owner's preference.\r\n 'luckystack/prefer-luckystack-dropdown': 'warn',\r\n 'luckystack/prefer-luckystack-confirm': 'warn',\r\n 'luckystack/prefer-luckystack-notify': 'warn',\r\n 'luckystack/no-direct-prisma-import-in-components': 'warn',\r\n 'luckystack/no-arbitrary-tailwind-color': 'warn',\r\n};\r\n\r\nconst luckystackConfig: Linter.Config[] = [\r\n {\r\n files: ['**/*.{ts,tsx,js,jsx,mjs,cjs}'],\r\n plugins: {\r\n luckystack: { rules: allRules },\r\n },\r\n rules: ruleSeverities,\r\n },\r\n];\r\n\r\nexport default luckystackConfig;\r\n\r\n//? Named exports for advanced consumers who want to assemble their own\r\n//? config or selectively re-enable individual rules.\r\nexport { allRules as rules };\r\n\r\n\r\nexport {hasPackage} from './internal/hasPackage.js';"],"mappings":"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","names":["rule","rule","rule","rule","SUSPECT_PARAM_NAMES","SKIP_KEYS","rule","rule","rule","rule"]}
1
+ {"version":3,"sources":["../../src/eslint/internal/hasPackage.ts","../../src/eslint/rules/no-arbitrary-tailwind-color.ts","../../src/eslint/rules/no-direct-prisma-import-in-components.ts","../../src/eslint/rules/no-raw-fetch-in-src.ts","../../src/eslint/rules/no-raw-try-catch.ts","../../src/eslint/rules/no-unsafe-api-wrappers.ts","../../src/eslint/rules/no-unsafe-sync-wrappers.ts","../../src/eslint/rules/prefer-luckystack-confirm.ts","../../src/eslint/rules/prefer-luckystack-dropdown.ts","../../src/eslint/rules/prefer-luckystack-notify.ts","../../src/eslint/index.ts"],"sourcesContent":["//? Peer-dep presence probe used to gate package-dependent eslint rules.\n//? Resolves against `process.cwd()` so the CONSUMER's node_modules drives\n//? activation, not this package's own resolution graph.\n//?\n//? Implementation: tries `require.resolve` first (works for CJS-compatible\n//? packages), falls back to an fs-based `node_modules/<name>/package.json`\n//? check for pure-ESM packages whose `exports` map omits the `require`\n//? condition (which is the case for the @luckystack/* packages themselves).\n\nimport { existsSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\n\nconst localRequire = createRequire(import.meta.url);\n\nconst checkOnDisk = (name: string): boolean => {\n const segments = name.startsWith('@')\n ? name.split('/').slice(0, 2)\n : [name.split('/')[0] ?? name];\n return existsSync(path.join(process.cwd(), 'node_modules', ...segments, 'package.json'));\n};\n\nexport const hasPackage = (name: string): boolean => {\n try {\n localRequire.resolve(name, { paths: [process.cwd()] });\n return true;\n } catch {\n return checkOnDisk(name);\n }\n};\n","//? Rule: warn on arbitrary Tailwind color values (`text-[#fff]`,\n//? `bg-[#abc123]`, `border-[#000]`) inside className strings. The framework\n//? mandates colors from `src/index.css` `@theme` block (rule 14). Arbitrary\n//? colors break dark-mode auto-switching.\n\nimport type { Rule } from 'eslint';\n\nimport type { EslintRule } from '../internal/ruleTypes.js';\n\nconst ARBITRARY_COLOR_PATTERN = /\\b(?:text|bg|border|ring|fill|stroke|from|to|via|outline|decoration|accent|caret|placeholder|divide)-\\[#[0-9a-fA-F]{3,8}\\]/;\n\n//? This rule reads JSX AST nodes (`JSXAttribute`, `JSXExpressionContainer`,\n//? `TemplateLiteral` quasis) that eslint-plugin-react injects into the visitor\n//? map at runtime but that eslint's stock `Rule.Node` type doesn't model. The\n//? objects ARE real eslint nodes at runtime — `context.report({ node })` only\n//? needs `{ type, loc, range, ... }`, all present. This guard narrows an\n//? `unknown` to `Rule.Node` in one place so the call sites stay cast-free and\n//? the previous file-wide `as unknown as Rule.Node` double-casts are gone.\nconst asRuleNode = (node: object): Rule.Node => node as Rule.Node;\n\n//? JSX AST nodes (JSXAttribute, JSXExpressionContainer, …) are not part of\n//? eslint's stock estree AST. eslint-plugin-react extends the visitor map at\n//? runtime, but the stock `Rule.RuleListener` type does not know about them,\n//? so we describe the shapes we read inline. The actual eslint runtime gives\n//? us the right object; this is purely a TS-side annotation.\ntype ClassNameValueShape =\n | { type: 'Literal'; value: unknown }\n | { type: 'JSXExpressionContainer'; expression: ExpressionShape }\n | { type: string };\n\ntype ExpressionShape =\n | { type: 'Literal'; value: unknown }\n | { type: 'TemplateLiteral'; quasis: readonly { value: { cooked?: string; raw: string } }[] }\n | { type: string };\n\ninterface JsxAttributeShape {\n name: { type: string; name?: string };\n value?: ClassNameValueShape | null;\n}\n\nconst reportIfArbitrary = (\n context: Rule.RuleContext,\n node: Rule.Node,\n value: string,\n): void => {\n if (ARBITRARY_COLOR_PATTERN.test(value)) {\n context.report({ node, messageId: 'useThemeToken' });\n }\n};\n\nconst rule: EslintRule = {\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Disallow arbitrary Tailwind color values (`text-[#…]`, `bg-[#…]`, …). Use tokens from `src/index.css` `@theme` block.',\n },\n messages: {\n useThemeToken:\n 'Do not use arbitrary Tailwind color values like `text-[#…]`. Use a token from `src/index.css` `@theme` block (e.g. `bg-primary`, `text-title`, `border-divider`). Arbitrary colors break dark-mode auto-switching.',\n },\n schema: [],\n },\n create(context) {\n const listener: Rule.RuleListener = {\n JSXAttribute(rawNode: unknown): void {\n const node = rawNode as JsxAttributeShape & Rule.Node;\n if (node.name.type !== 'JSXIdentifier' || node.name.name !== 'className') return;\n const value = node.value;\n if (!value) return;\n if (value.type === 'Literal' && typeof (value as { value?: unknown }).value === 'string') {\n reportIfArbitrary(context, asRuleNode(value), (value as { value: string }).value);\n return;\n }\n if (value.type === 'JSXExpressionContainer') {\n const expression = (value as { expression: ExpressionShape }).expression;\n if (expression.type === 'TemplateLiteral') {\n const quasis = (expression as { quasis: readonly { value: { cooked?: string; raw: string } }[] }).quasis;\n for (const quasi of quasis) {\n reportIfArbitrary(\n context,\n asRuleNode(quasi),\n quasi.value.cooked ?? quasi.value.raw,\n );\n }\n } else if (expression.type === 'Literal' && typeof (expression as { value?: unknown }).value === 'string') {\n reportIfArbitrary(\n context,\n asRuleNode(expression),\n (expression as { value: string }).value,\n );\n }\n }\n },\n };\n return listener;\n },\n};\n\nexport default rule;\n","//? Rule: warn on `import … from '@prisma/client'` outside of allowed\n//? boundaries. Convention: app code re-exports Prisma model types through\n//? `src/_types/<ModelName>.ts` so swapping providers / extending types\n//? stays centralised. Direct imports leak Prisma details into UI code.\n//?\n//? Allowed paths: `src/_types/**`, `server/**`, and any file ending in\n//? `Adapter.ts` (legitimate adapter implementations).\n\nimport type { EslintRule } from '../internal/ruleTypes.js';\n\nconst isAllowedPath = (filename: string): boolean => {\n const normalised = filename.replaceAll('\\\\', '/');\n if (normalised.includes('/src/_types/')) return true;\n if (normalised.includes('/server/')) return true;\n if (normalised.endsWith('Adapter.ts') || normalised.endsWith('Adapter.tsx')) return true;\n if (normalised.includes('/packages/')) return true;\n //? Project-root config files (the LuckyStack `config.ts` convention) and\n //? any `*.config.ts` are framework boundaries — Prisma types there are\n //? expected and not a \"leaking into component code\" concern.\n if (normalised.endsWith('/config.ts') || normalised.endsWith('.config.ts')) return true;\n if (normalised.includes('/prisma/')) return true;\n return false;\n};\n\nconst rule: EslintRule = {\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Re-export Prisma model types through `src/_types/<Model>.ts` rather than importing `@prisma/client` directly in components.',\n },\n messages: {\n reExportThroughTypes:\n 'Do not import from `@prisma/client` here. Re-export the type through `src/_types/<ModelName>.ts` and import that instead — keeps Prisma details out of component code.',\n },\n schema: [],\n },\n create(context) {\n if (isAllowedPath(context.filename)) return {};\n return {\n ImportDeclaration(node) {\n if (node.source.value === '@prisma/client') {\n context.report({ node, messageId: 'reExportThroughTypes' });\n }\n },\n };\n },\n};\n\nexport default rule;\n","//? Rule: forbid direct `fetch(...)` calls to framework `/api/*` or\n//? `/sync/*` routes. The framework provides typed transport helpers\n//? `apiRequest` (for `_api/` routes) and `syncRequest` (for `_sync/`\n//? routes) which preserve route/version generics + auth/CSRF/validation.\n//?\n//? The rule is deliberately narrow:\n//? - Fires when the URL is a literal / template containing `/api/` or\n//? `/sync/` (framework route patterns).\n//? - Skips URLs whose PATH STARTS with `/auth/` — the framework's auth\n//? endpoints (`/auth/api/credentials`, OAuth callbacks) are HTTP-only\n//? and intentionally use raw fetch (cookies, headers, redirects). The\n//? start-of-path check (not `.includes`) means a consumer's typed\n//? route under an `auth/` page folder (URL `/api/auth/...`) still\n//? fires correctly.\n//? - Skips external URLs (starts with `http://`, `https://`, `//`) —\n//? consumers fetching third-party APIs are fine.\n//? - Skips dynamic URLs (variable, function call, etc.) — be permissive\n//? rather than flag-by-default; consumers can opt in via comments.\n//?\n//? Gated by hasPackage('@luckystack/api') OR hasPackage('@luckystack/core')\n//? at the config-composition layer.\n\nimport type { EslintRule } from '../internal/ruleTypes.js';\n\ninterface AstNodeShape {\n type?: string;\n value?: unknown;\n quasis?: { value?: { raw?: string; cooked?: string } }[];\n}\n\nconst extractStaticUrlText = (urlNode: unknown): string | null => {\n if (!urlNode || typeof urlNode !== 'object') return null;\n const n = urlNode as AstNodeShape;\n if (n.type === 'Literal' && typeof n.value === 'string') return n.value;\n if (n.type === 'TemplateLiteral' && Array.isArray(n.quasis)) {\n return n.quasis.map((q) => q.value?.cooked ?? q.value?.raw ?? '').join('|');\n }\n return null;\n};\n\nconst targetsFrameworkRoute = (urlNode: unknown): boolean => {\n const text = extractStaticUrlText(urlNode);\n if (text === null) return false;\n if (/^(https?:)?\\/\\//.test(text)) return false;\n //? Skip only when the path STARTS with `/auth/` (framework's special\n //? endpoints). The leading `|` accounts for `extractStaticUrlText`'s\n //? template-literal join when the first quasi is empty, e.g.\n //? `${backendUrl}/auth/api/credentials` joins to `|/auth/api/credentials`.\n if (/^(?:\\|)?\\/auth\\//.test(text)) return false;\n return /(?:^|[^A-Za-z])\\/(?:api|sync)\\//.test(text);\n};\n\nconst rule: EslintRule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Disallow raw `fetch(...)` to framework `/api/*` and `/sync/*` routes. Use `apiRequest` / `syncRequest` instead.',\n },\n messages: {\n useApiRequest:\n 'Do not call `fetch` directly for framework `/api/*` routes. Use `apiRequest({ name, version, data })` for typed inference, or `httpFetch(...)` from `@luckystack/core` if you need a raw same-origin request.',\n useSyncRequest:\n 'Do not call `fetch` directly for framework `/sync/*` routes. Use `syncRequest({ name, version, data, receiver })` instead.',\n },\n schema: [],\n },\n create(context) {\n return {\n CallExpression(node) {\n const callee = node.callee;\n const isFetchCall =\n (callee.type === 'Identifier' && callee.name === 'fetch') ||\n (callee.type === 'MemberExpression' &&\n callee.object.type === 'Identifier' &&\n callee.object.name === 'window' &&\n callee.property.type === 'Identifier' &&\n callee.property.name === 'fetch');\n if (!isFetchCall) return;\n const url = node.arguments[0];\n if (!targetsFrameworkRoute(url)) return;\n const text = extractStaticUrlText(url) ?? '';\n const messageId = text.includes('/sync/') ? 'useSyncRequest' : 'useApiRequest';\n context.report({ node, messageId });\n },\n };\n },\n};\n\nexport default rule;\n","//? Rule: forbid raw `try { … } catch` inside src/server/shared code.\n//? The framework provides `tryCatch` from @luckystack/core (and the API/sync\n//? handler `functions.tryCatch` injection) that handles Sentry capture +\n//? normalised tuple returns. Raw try/catch bypasses that.\n\nimport type { EslintRule } from '../internal/ruleTypes.js';\n\nconst rule: EslintRule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Disallow raw `try { … } catch` blocks — use the framework `tryCatch` helper instead.',\n },\n messages: {\n useTryCatch:\n 'Do not use raw try/catch. Import `tryCatch` from `@luckystack/core` (client) or `server/functions/tryCatch` (server), or use the injected `functions.tryCatch` in API / sync handlers.',\n },\n schema: [],\n },\n create(context) {\n return {\n TryStatement(node) {\n //? Only fire when an actual catch clause is present. `try { } finally { }`\n //? is a different construct (cleanup, not error handling) and the\n //? `tryCatch` helper is not a substitute.\n if (node.handler) {\n context.report({ node, messageId: 'useTryCatch' });\n }\n },\n };\n },\n};\n\nexport default rule;\n","//? Rule: forbid local wrappers around `apiRequest` whose parameter types\n//? erase the route/version generics. The framework's type system relies on\n//? literal `name`/`version` strings to infer `serverOutput` / `clientOutput`.\n//? A wrapper like:\n//?\n//? const unsafeApi = (name: string, version: string, data: unknown) =>\n//? apiRequest({ name: name as any, ... });\n//?\n//? destroys that inference. Always call `apiRequest` directly with route\n//? literals, or write a wrapper that preserves the generics.\n//?\n//? Gated by hasPackage('@luckystack/api') at the config-composition layer.\n\n//? Double-cast + any-spread disabled file-wide: bridges `Rule.Node` to specific\n//? AST shapes; the spread iterates over `Object.entries(node)` whose values are\n//? typed as `any` because eslint's AST shape varies by node kind.\n/* eslint-disable no-restricted-syntax, @typescript-eslint/no-unsafe-argument */\n\nimport type { EslintRule } from '../internal/ruleTypes.js';\n\nconst SUSPECT_PARAM_NAMES = new Set(['name', 'version', 'route', 'apiName']);\n\n//? AST keys that point to parents or non-AST metadata. Including them in\n//? a recursive descent causes infinite loops because eslint adds `parent`\n//? pointers during traversal.\nconst SKIP_KEYS = new Set(['parent', 'loc', 'range', 'tokens', 'comments']);\n\nconst containsApiRequestCall = (body: unknown): boolean => {\n if (!body || typeof body !== 'object') return false;\n const visited = new WeakSet<object>();\n const stack: unknown[] = [body];\n while (stack.length > 0) {\n const node = stack.pop() as Record<string, unknown> | null;\n if (!node || typeof node !== 'object') continue;\n if (visited.has(node)) continue;\n visited.add(node);\n const callee = (node as { type?: string; callee?: { type?: string; name?: string } }).callee;\n if (\n (node as { type?: string }).type === 'CallExpression' &&\n callee?.type === 'Identifier' &&\n (callee.name === 'apiRequest' || callee.name === 'syncRequest')\n ) {\n return true;\n }\n for (const [key, value] of Object.entries(node)) {\n if (SKIP_KEYS.has(key)) continue;\n if (Array.isArray(value)) stack.push(...value);\n else if (value && typeof value === 'object') stack.push(value);\n }\n }\n return false;\n};\n\nconst isSuspectFunction = (node: {\n params?: { type?: string; name?: string; typeAnnotation?: { typeAnnotation?: { type?: string } } }[];\n body?: unknown;\n}): boolean => {\n if (!node.params || node.params.length === 0) return false;\n const hasSuspectStringParam = node.params.some((p) => {\n if (p.type !== 'Identifier' || !p.name) return false;\n if (!SUSPECT_PARAM_NAMES.has(p.name)) return false;\n const annotation = p.typeAnnotation?.typeAnnotation?.type;\n return annotation === 'TSStringKeyword';\n });\n if (!hasSuspectStringParam) return false;\n return containsApiRequestCall(node.body);\n};\n\nconst rule: EslintRule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Disallow local wrappers around `apiRequest` / `syncRequest` whose `name`/`version` params are typed as plain `string` — this erases the generic route/version inference.',\n },\n messages: {\n unsafeWrapper:\n 'This wrapper around `apiRequest` / `syncRequest` accepts `{{paramName}}: string` and erases the route/version generic inference. Call the framework helper directly with literal route names, or type the parameter as a literal union (e.g. `name: \\'examples/getUserData\\'`).',\n },\n schema: [],\n },\n create(context) {\n return {\n FunctionDeclaration(node) {\n if (isSuspectFunction(node)) {\n const suspect = (node.params as { name?: string }[]).find((p) => p.name && SUSPECT_PARAM_NAMES.has(p.name));\n context.report({ node, messageId: 'unsafeWrapper', data: { paramName: suspect?.name ?? 'name' } });\n }\n },\n ArrowFunctionExpression(node) {\n if (isSuspectFunction(node)) {\n const suspect = (node.params as { name?: string }[]).find((p) => p.name && SUSPECT_PARAM_NAMES.has(p.name));\n context.report({ node, messageId: 'unsafeWrapper', data: { paramName: suspect?.name ?? 'name' } });\n }\n },\n };\n },\n};\n\nexport default rule;\n","//? Rule: same shape as no-unsafe-api-wrappers, but targeting wrappers\n//? around `syncRequest` and `upsertSyncEventCallback`. Gated by\n//? hasPackage('@luckystack/sync') at the config-composition layer.\n//?\n//? Note: the api-wrappers rule already covers the `syncRequest` call site;\n//? this rule additionally catches `upsertSyncEventCallback` wrappers and\n//? exists as a distinct identity so the sync-only rule can be disabled\n//? independently when a consumer uses api but not sync.\n\n//? Double-cast + any-spread disabled file-wide: bridges `Rule.Node` to specific\n//? AST shapes; the spread iterates over `Object.entries(node)` whose values are\n//? typed as `any` because eslint's AST shape varies by node kind.\n/* eslint-disable no-restricted-syntax, @typescript-eslint/no-unsafe-argument */\n\nimport type { EslintRule } from '../internal/ruleTypes.js';\n\nconst SUSPECT_PARAM_NAMES = new Set(['name', 'version', 'route', 'syncName']);\nconst SUSPECT_CALLEES = new Set(['syncRequest', 'upsertSyncEventCallback']);\n\n//? AST keys that point to parents or non-AST metadata. Skipped to avoid\n//? infinite loops when eslint adds `parent` pointers during traversal.\nconst SKIP_KEYS = new Set(['parent', 'loc', 'range', 'tokens', 'comments']);\n\nconst containsSuspectCall = (body: unknown): boolean => {\n if (!body || typeof body !== 'object') return false;\n const visited = new WeakSet<object>();\n const stack: unknown[] = [body];\n while (stack.length > 0) {\n const node = stack.pop() as Record<string, unknown> | null;\n if (!node || typeof node !== 'object') continue;\n if (visited.has(node)) continue;\n visited.add(node);\n const callee = (node as { type?: string; callee?: { type?: string; name?: string } }).callee;\n if (\n (node as { type?: string }).type === 'CallExpression' &&\n callee?.type === 'Identifier' &&\n SUSPECT_CALLEES.has(callee.name ?? '')\n ) {\n return true;\n }\n for (const [key, value] of Object.entries(node)) {\n if (SKIP_KEYS.has(key)) continue;\n if (Array.isArray(value)) stack.push(...value);\n else if (value && typeof value === 'object') stack.push(value);\n }\n }\n return false;\n};\n\nconst isSuspect = (node: {\n params?: { type?: string; name?: string; typeAnnotation?: { typeAnnotation?: { type?: string } } }[];\n body?: unknown;\n}): boolean => {\n if (!node.params || node.params.length === 0) return false;\n const hasSuspectStringParam = node.params.some((p) => {\n if (p.type !== 'Identifier' || !p.name) return false;\n if (!SUSPECT_PARAM_NAMES.has(p.name)) return false;\n return p.typeAnnotation?.typeAnnotation?.type === 'TSStringKeyword';\n });\n if (!hasSuspectStringParam) return false;\n return containsSuspectCall(node.body);\n};\n\nconst rule: EslintRule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Disallow local wrappers around `syncRequest` / `upsertSyncEventCallback` whose `name`/`version` params are typed as plain `string`.',\n },\n messages: {\n unsafeSyncWrapper:\n 'This wrapper around `syncRequest` / `upsertSyncEventCallback` accepts a `string` route param and erases the generic event-payload inference. Call the framework helper directly with literal route names.',\n },\n schema: [],\n },\n create(context) {\n return {\n FunctionDeclaration(node) {\n if (isSuspect(node)) {\n context.report({ node, messageId: 'unsafeSyncWrapper' });\n }\n },\n ArrowFunctionExpression(node) {\n if (isSuspect(node)) {\n context.report({ node, messageId: 'unsafeSyncWrapper' });\n }\n },\n };\n },\n};\n\nexport default rule;\n","//? Rule: warn on `confirm(...)` / `window.confirm(...)` calls. The framework\n//? provides `menuHandler.confirm({ title, content, input? })` from\n//? `src/_functions/menuHandler.ts` which renders a styled, theme-aware,\n//? Promise-returning confirm dialog and respects keyboard / accessibility.\n\nimport type { EslintRule } from '../internal/ruleTypes.js';\n\nconst rule: EslintRule = {\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Prefer `menuHandler.confirm({ title, content })` over the native `confirm()` dialog.',\n },\n messages: {\n useMenuHandlerConfirm:\n 'Use `menuHandler.confirm({ title, content })` from `src/_functions/menuHandler.ts` instead of native `confirm()`. Returns a `Promise<boolean>` with proper theming.',\n },\n schema: [],\n },\n create(context) {\n return {\n CallExpression(node) {\n const callee = node.callee;\n if (callee.type === 'Identifier' && callee.name === 'confirm') {\n context.report({ node, messageId: 'useMenuHandlerConfirm' });\n return;\n }\n if (\n callee.type === 'MemberExpression' &&\n callee.object.type === 'Identifier' &&\n callee.object.name === 'window' &&\n callee.property.type === 'Identifier' &&\n callee.property.name === 'confirm'\n ) {\n context.report({ node, messageId: 'useMenuHandlerConfirm' });\n }\n },\n };\n },\n};\n\nexport default rule;\n","//? Rule: warn when a JSX `<select>` element is used. The framework ships\n//? `Dropdown` (src/_components/Dropdown.tsx) with search, keyboard nav,\n//? sizing variants, and consistent dark/light styling. Native `<select>`\n//? skips all of that.\n\nimport type { Rule } from 'eslint';\n\nimport type { EslintRule } from '../internal/ruleTypes.js';\n\n//? JSX AST nodes are extended at runtime by eslint-plugin-react, but\n//? eslint's stock `Rule.RuleListener` type does not know about them. We\n//? describe the shapes we read inline.\ninterface JsxOpeningElementShape {\n name: { type: string; name?: string };\n}\n\nconst rule: EslintRule = {\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Prefer the framework `Dropdown` component over native `<select>` elements.',\n },\n messages: {\n useDropdown:\n 'Use `Dropdown` from `src/_components/Dropdown.tsx` (or `MultiSelectDropdown` for multi-select) instead of native `<select>`. The framework component handles keyboard nav, search, sizing, and dark/light theme.',\n },\n schema: [],\n },\n create(context) {\n const listener: Rule.RuleListener = {\n JSXOpeningElement(rawNode: unknown): void {\n const node = rawNode as JsxOpeningElementShape & Rule.Node;\n if (node.name.type === 'JSXIdentifier' && node.name.name === 'select') {\n context.report({ node, messageId: 'useDropdown' });\n }\n },\n };\n return listener;\n },\n};\n\nexport default rule;\n","//? Rule: warn on `alert(...)` / `window.alert(...)`. The framework's\n//? `notify` helper (from @luckystack/core) renders themed toast\n//? notifications via the registered notifier (default sonner).\n\nimport type { EslintRule } from '../internal/ruleTypes.js';\n\nconst rule: EslintRule = {\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Prefer `notify()` over the native `alert()` dialog.',\n },\n messages: {\n useNotify:\n 'Use `notify({ type, message })` from `@luckystack/core` instead of native `alert()`. Renders a themed toast via the registered notifier.',\n },\n schema: [],\n },\n create(context) {\n return {\n CallExpression(node) {\n const callee = node.callee;\n if (callee.type === 'Identifier' && callee.name === 'alert') {\n context.report({ node, messageId: 'useNotify' });\n return;\n }\n if (\n callee.type === 'MemberExpression' &&\n callee.object.type === 'Identifier' &&\n callee.object.name === 'window' &&\n callee.property.type === 'Identifier' &&\n callee.property.name === 'alert'\n ) {\n context.report({ node, messageId: 'useNotify' });\n }\n },\n };\n },\n};\n\nexport default rule;\n","//? Public entry for `@luckystack/core/eslint`. Composes the LuckyStack\n//? flat-config tier that the scaffolded `eslint.luckystack.config.js`\n//? consumes. Rules that target an optional `@luckystack/*` peer package\n//? are gated via `hasPackage(...)` so absent peers cause silent rule\n//? skips (NOT noisy \"rule not found\" errors).\n//?\n//? Override surface: consumers can spread this default export and append\n//? their own config blocks, or replace individual rule severities by\n//? re-stating them with `'off' | 'warn' | 'error'`.\n\nimport type { Linter } from 'eslint';\n\nimport { hasPackage } from './internal/hasPackage.js';\nimport type { EslintRule } from './internal/ruleTypes.js';\n\nimport noArbitraryTailwindColor from './rules/no-arbitrary-tailwind-color.js';\nimport noDirectPrismaImportInComponents from './rules/no-direct-prisma-import-in-components.js';\nimport noRawFetchInSrc from './rules/no-raw-fetch-in-src.js';\nimport noRawTryCatch from './rules/no-raw-try-catch.js';\nimport noUnsafeApiWrappers from './rules/no-unsafe-api-wrappers.js';\nimport noUnsafeSyncWrappers from './rules/no-unsafe-sync-wrappers.js';\nimport preferLuckystackConfirm from './rules/prefer-luckystack-confirm.js';\nimport preferLuckystackDropdown from './rules/prefer-luckystack-dropdown.js';\nimport preferLuckystackNotify from './rules/prefer-luckystack-notify.js';\n\nconst allRules: Record<string, EslintRule> = {\n 'no-raw-try-catch': noRawTryCatch,\n 'no-raw-fetch-in-src': noRawFetchInSrc,\n 'no-unsafe-api-wrappers': noUnsafeApiWrappers,\n 'no-unsafe-sync-wrappers': noUnsafeSyncWrappers,\n 'prefer-luckystack-dropdown': preferLuckystackDropdown,\n 'prefer-luckystack-confirm': preferLuckystackConfirm,\n 'prefer-luckystack-notify': preferLuckystackNotify,\n 'no-direct-prisma-import-in-components': noDirectPrismaImportInComponents,\n 'no-arbitrary-tailwind-color': noArbitraryTailwindColor,\n};\n\nconst hasApi = hasPackage('@luckystack/api');\nconst hasCore = hasPackage('@luckystack/core');\nconst hasSync = hasPackage('@luckystack/sync');\n\nconst ruleSeverities: Record<string, Linter.RuleSeverity> = {\n // Always-on errors.\n 'luckystack/no-raw-try-catch': 'error',\n\n // Package-gated errors. Disabled when the relevant peer is absent so\n // a consumer using only @luckystack/core sees no \"use apiRequest\" noise.\n 'luckystack/no-raw-fetch-in-src': hasApi || hasCore ? 'error' : 'off',\n 'luckystack/no-unsafe-api-wrappers': hasApi ? 'error' : 'off',\n 'luckystack/no-unsafe-sync-wrappers': hasSync ? 'error' : 'off',\n\n // Warnings — enabled by default per framework owner's preference.\n 'luckystack/prefer-luckystack-dropdown': 'warn',\n 'luckystack/prefer-luckystack-confirm': 'warn',\n 'luckystack/prefer-luckystack-notify': 'warn',\n 'luckystack/no-direct-prisma-import-in-components': 'warn',\n 'luckystack/no-arbitrary-tailwind-color': 'warn',\n};\n\nconst luckystackConfig: Linter.Config[] = [\n {\n files: ['**/*.{ts,tsx,js,jsx,mjs,cjs}'],\n plugins: {\n luckystack: { rules: allRules },\n },\n rules: ruleSeverities,\n },\n];\n\nexport default luckystackConfig;\n\n//? Named exports for advanced consumers who want to assemble their own\n//? config or selectively re-enable individual rules.\nexport { allRules as rules };\n\n\nexport {hasPackage} from './internal/hasPackage.js';"],"mappings":"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","names":["rule","rule","rule","rule","SUSPECT_PARAM_NAMES","SKIP_KEYS","rule","rule","rule","rule"]}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,10 @@
1
- import { a6 as ErrorParam, a7 as ErrorResponseInput, a8 as NormalizedErrorResponse, a9 as HealthHashConfig, aa as DeepPartial, B as BaseSessionLayout, b as AuthProps } from './pageRouteValidation-gqktrJci.js';
2
- export { ab as ApiConfig, A as ApiMethodMap, a as AppConfig, ac as AuthConfig, ad as AuthRateLimitConfig, ae as CorsConfig, D as DEFAULT_PAGE_ROUTE_RULES, af as DEFAULT_PROJECT_CONFIG, ag as DevConfig, ah as HttpConfig, H as HttpMethodLiteral, ai as HttpStreamConfig, aj as INVALID_ERROR_RESPONSE_CODE, L as Logger, c as LoggerContext, d as LoggingConfig, N as Notifier, e as NotifyInput, f as NotifyParam, ak as OfflineQueueConfig, P as PagePathValidationResult, g as PageRouteRules, al as PasswordPolicyConfig, am as PathsConfig, h as ProjectConfig, an as ProjectConfigInput, ao as QueueDropReason, ap as RateLimitIdentity, aq as RateLimitIdentityParams, R as RateLimitingConfig, S as SOCKETSTATUS, ar as SecurityHeadersConfig, as as ServiceRouteParseError, at as ServiceRouteParseResult, au as ServiceRouteParseSuccess, i as SessionConfig, j as SessionLocation, av as SocketConfig, aw as SyncConfig, ax as SyncFlushPressureConfig, ay as SyncStreamThrottleConfig, az as TransportRouteParseError, aA as TransportRouteParseResult, aB as TransportRouteParseSuccess, aC as ValidationConfig, k as buildApiResponseEventName, l as buildApiStreamEventName, m as buildGetJoinedRoomsResponseEventName, n as buildJoinRoomResponseEventName, o as buildLeaveRoomResponseEventName, p as buildSyncProgressEventName, q as buildSyncResponseEventName, r as clearCsrfToken, aD as createDevLogger, aE as deepMerge, aF as defaultHttpStatusForResponse, s as enqueueApiRequest, t as enqueueSyncRequest, u as flushApiQueue, v as flushSyncQueue, w as getApiQueueSize, x as getCsrfToken, y as getLogger, z as getNotifier, C as getProjectConfig, aG as getProjectName, E as getRegisteredApiMethod, F as getSyncQueueSize, G as httpFetch, I as incrementResponseIndex, J as isApiMethodMapRegistered, aH as isErrorParamArray, aI as isLoggerRegistered, K as isOnline, aJ as isPlainObject, M as isProjectConfigRegistered, O as normalizeErrorResponseCore, Q as notify, T as parseServiceRouteName, aK as parseTransportRouteName, U as registerApiMethodMap, V as registerLogger, W as registerNotifier, X as registerProjectConfig, Y as removeApiQueueItem, Z as removeApiQueueItemsByKey, _ as removeSyncQueueItem, aL as resetLoggerForTests, $ as setSocket, a0 as sleep, a1 as socket, a2 as socketEventNames, a3 as statusContent, a4 as validatePagePath, a5 as waitForSocket } from './pageRouteValidation-gqktrJci.js';
1
+ import { X as ErrorParam, Y as ErrorResponseInput, Z as NormalizedErrorResponse } from './pageRouteValidation-sJJCX-YV.js';
2
+ export { A as ApiMethodMap, D as DEFAULT_PAGE_ROUTE_RULES, H as HttpMethodLiteral, _ as INVALID_ERROR_RESPONSE_CODE, L as Logger, a as LoggerContext, N as Notifier, b as NotifyInput, c as NotifyParam, P as PagePathValidationResult, d as PageRouteRules, $ as QueueDropReason, S as SOCKETSTATUS, a0 as ServiceRouteParseError, a1 as ServiceRouteParseResult, a2 as ServiceRouteParseSuccess, a3 as TransportRouteParseError, a4 as TransportRouteParseResult, a5 as TransportRouteParseSuccess, e as buildApiResponseEventName, f as buildApiStreamEventName, g as buildGetJoinedRoomsResponseEventName, h as buildJoinRoomResponseEventName, i as buildLeaveRoomResponseEventName, j as buildSyncProgressEventName, k as buildSyncResponseEventName, l as clearCsrfToken, a6 as createDevLogger, a7 as defaultHttpStatusForResponse, m as enqueueApiRequest, n as enqueueSyncRequest, o as flushApiQueue, p as flushSyncQueue, q as getApiQueueSize, r as getCsrfToken, s as getLogger, t as getNotifier, u as getRegisteredApiMethod, v as getSyncQueueSize, w as httpFetch, x as incrementResponseIndex, y as isApiMethodMapRegistered, a8 as isErrorParamArray, a9 as isLoggerRegistered, z as isOnline, B as normalizeErrorResponseCore, C as notify, E as parseServiceRouteName, aa as parseTransportRouteName, F as registerApiMethodMap, G as registerLogger, I as registerNotifier, J as removeApiQueueItem, K as removeApiQueueItemsByKey, M as removeSyncQueueItem, ab as resetLoggerForTests, O as setSocket, Q as sleep, R as socket, T as socketEventNames, U as statusContent, V as validatePagePath, W as waitForSocket } from './pageRouteValidation-sJJCX-YV.js';
3
+ import { H as HealthHashConfig, D as DeepPartial, B as BaseSessionLayout, a as AuthProps } from './sessionTypes-Dzen_rPK.js';
4
+ export { c as ApiConfig, A as AppConfig, d as AuthConfig, e as AuthRateLimitConfig, C as CorsConfig, f as DEFAULT_PROJECT_CONFIG, h as DevConfig, j as HttpConfig, k as HttpStreamConfig, J as Jsonify, L as LoggingConfig, O as OfflineQueueConfig, l as PasswordPolicyConfig, m as PathsConfig, P as ProjectConfig, n as ProjectConfigInput, o as RateLimitIdentity, p as RateLimitIdentityParams, R as RateLimitingConfig, q as SecurityHeadersConfig, S as SessionConfig, b as SessionLocation, s as SocketConfig, t as SyncConfig, u as SyncFlushPressureConfig, v as SyncStreamThrottleConfig, V as ValidationConfig, w as deepMerge, g as getProjectConfig, x as getProjectName, y as isPlainObject, i as isProjectConfigRegistered, r as registerProjectConfig } from './sessionTypes-Dzen_rPK.js';
3
5
  export { ApiTypeMap, StreamPayload, SyncTypeMap } from './apiTypeStubs.js';
4
6
  import { Server, Socket } from 'socket.io';
7
+ export { D as DeployConfigShape, a as DeployDevelopmentShape, b as DeployEnvironmentShape, c as DeployResourceShape, d as DeployRoutingShape, P as PresetDefinition, S as SecretsResolvedListener, e as ServiceDefinition, f as ServicesConfigShape, g as getDeployConfig, h as getServicesConfig, i as isDeployConfigRegistered, j as isServicesConfigRegistered, n as notifySecretsResolved, r as registerDeployConfig, k as registerSecretsResolvedListener, l as registerServicesConfig } from './config-DZCzBNwP.js';
5
8
  import { z } from 'zod';
6
9
  import * as _prisma_client_runtime_library from '@prisma/client/runtime/library';
7
10
  import * as _prisma_client from '@prisma/client';
@@ -375,121 +378,6 @@ declare const getEmailSenderByName: (name: string) => EmailSender | null;
375
378
  declare const listEmailSenderNames: () => string[];
376
379
  declare const isEmailSenderRegistered: () => boolean;
377
380
 
378
- interface DeployResourceShape {
379
- type: 'redis' | 'mongo';
380
- urlEnvKey: string;
381
- synchronizedEnvKeys?: string[];
382
- }
383
- interface DeployEnvironmentShape {
384
- redis: string;
385
- mongo: string;
386
- fallback?: string;
387
- bindings: Record<string, string>;
388
- }
389
- interface DeployRoutingShape {
390
- onMissingService?: 'hard-error' | 'proxy-fallback';
391
- missingServiceErrorCode?: string;
392
- enableUnhealthyFallback?: boolean;
393
- strictBootHandshake?: boolean;
394
- /**
395
- * Opt INTO the boot-handshake's synchronized-env (cookie/session secret) drift
396
- * check. DEFAULT false — the router stays a dumb proxy that holds NO backend
397
- * secrets. Comparing synchronized-env hashes requires the router process to
398
- * carry the same SESSION_SECRET etc. as the backends, which most deployments
399
- * deliberately avoid; the always-on shared-Redis handshake is unaffected. Set
400
- * true only when you intentionally give the router the synchronized secrets.
401
- */
402
- verifySynchronizedEnv?: boolean;
403
- /** Default port the router listens on when ROUTER_PORT env var is unset (default 4000). */
404
- defaultRouterPort?: number;
405
- /** Default ms between health polls when not specified per-call (default 5000). */
406
- defaultHealthPollMs?: number;
407
- /** ms before the fallback `/_health` probe times out (default 3000). */
408
- healthProbeTimeoutMs?: number;
409
- /** Seconds the boot-UUID Redis key lives for (default 3600 = 1h). */
410
- bootKeyTtlSeconds?: number;
411
- /**
412
- * ms before the router gives up proxying to an upstream backend (SEC-30 /
413
- * router-DeployRoutingShape). Guards against slow-loris upstreams holding a
414
- * router worker open. The router reads this when building its proxy request.
415
- * DEFAULT undefined → router falls back to its own built-in default.
416
- */
417
- upstreamTimeoutMs?: number;
418
- /**
419
- * Name of the service that terminates websocket (Socket.io) traffic. The
420
- * router pins WS upgrade requests to this service (they cannot be load-balanced
421
- * round-robin without sticky sessions). DEFAULT undefined → router uses its
422
- * `system` convention.
423
- */
424
- websocketService?: string;
425
- /**
426
- * Path the router exposes for its OWN health/liveness (distinct from the
427
- * backend `/_health` boot-handshake endpoint). DEFAULT undefined → router
428
- * uses its built-in default.
429
- */
430
- routerHealthPath?: string;
431
- /**
432
- * Max request body size (bytes) the router will buffer/forward before
433
- * rejecting with 413. DEFAULT undefined → router uses its built-in default.
434
- */
435
- maxRequestBodyBytes?: number;
436
- /**
437
- * Max size (bytes) of the upgrade `head` buffer the WS proxy forwards to the
438
- * upstream during a WebSocket handshake. An over-cap head is rejected (the
439
- * client socket is destroyed) BEFORE the upstream leg opens, so a client
440
- * cannot push an unbounded pre-upgrade buffer through the router. DEFAULT
441
- * undefined → router uses its built-in default (64 KiB).
442
- */
443
- wsMaxHeadBytes?: number;
444
- /**
445
- * Idle-timeout (ms) for an UPGRADED WebSocket pipe: when no bytes flow in
446
- * either direction for this long, the router tears the proxied pair down.
447
- * Bounds an otherwise-unbounded pre/post-auth pipe a client could hold open
448
- * against the router. The timer resets on any activity. DEFAULT undefined →
449
- * router uses its built-in default (120000 ms = 2 min). Set `0` to disable.
450
- */
451
- wsIdleTimeoutMs?: number;
452
- /**
453
- * Per-connection byte budget for an UPGRADED WebSocket pipe: when the total
454
- * bytes piped across both legs exceed this cap, the router tears the proxied
455
- * pair down. Bounds how much a single connection can stream through the
456
- * router. DEFAULT undefined → router uses its built-in default (100 MiB). Set
457
- * `false` to disable the cap (unbounded).
458
- */
459
- wsMaxBytesPerConnection?: number | false;
460
- }
461
- interface DeployDevelopmentShape {
462
- enableFallbackRouting?: boolean;
463
- healthPollMs?: number;
464
- switchNewTrafficToLocalWhenHealthy?: boolean;
465
- }
466
- interface DeployConfigShape {
467
- resources: Record<string, DeployResourceShape>;
468
- environments?: Record<string, DeployEnvironmentShape>;
469
- routing?: DeployRoutingShape;
470
- development?: DeployDevelopmentShape;
471
- }
472
- declare const registerDeployConfig: (config: DeployConfigShape) => DeployConfigShape;
473
- declare const getDeployConfig: () => DeployConfigShape;
474
- declare const isDeployConfigRegistered: () => boolean;
475
-
476
- interface ServiceDefinition {
477
- /** 'root' -> reserved for the system service. Otherwise a folder name under srcDir. */
478
- source: 'root' | string;
479
- }
480
- interface PresetDefinition {
481
- description?: string;
482
- /** Services that are bundled together into one backend artifact. */
483
- services: string[];
484
- }
485
- interface ServicesConfigShape {
486
- services: Record<string, ServiceDefinition>;
487
- presets: Record<string, PresetDefinition>;
488
- }
489
- declare const registerServicesConfig: (config: ServicesConfigShape) => ServicesConfigShape;
490
- declare const getServicesConfig: () => ServicesConfigShape;
491
- declare const isServicesConfigRegistered: () => boolean;
492
-
493
381
  type LocaleReloader = () => void | Promise<void>;
494
382
  declare const registerLocaleReloader: (reloader: LocaleReloader) => LocaleReloader;
495
383
  declare const getLocaleReloader: () => LocaleReloader | null;
@@ -515,18 +403,27 @@ declare const setSentryUser: (user: {
515
403
  } | null) => void;
516
404
  declare const startSpan: (name: string, op: string) => unknown;
517
405
 
518
- type ErrorTrackerContext = Record<string, unknown>;
519
- declare const sanitizeErrorString: (value: string) => string;
520
- declare const sanitizeErrorStrings: (error: unknown) => {
521
- message: string;
522
- stack: string | undefined;
523
- } | null;
524
406
  interface ErrorTrackerUser {
525
407
  id?: string;
526
408
  email?: string;
527
409
  username?: string;
528
410
  [key: string]: unknown;
529
411
  }
412
+ /** Open an isolated request identity scope before the first async boundary. */
413
+ declare const runWithErrorTrackerIdentityScope: <T>(fn: () => T) => T;
414
+ /** Open an isolated scope with a user that is already known. */
415
+ declare const runWithErrorTrackerIdentity: <T>(user: ErrorTrackerUser | null, fn: () => T) => T;
416
+ /** Set the user inside the active request scope; no-op outside a scope. */
417
+ declare const setCurrentErrorTrackerIdentity: (user: ErrorTrackerUser | null) => void;
418
+ /** Read the current request identity, or null outside a scope. */
419
+ declare const getCurrentErrorTrackerIdentity: () => ErrorTrackerUser | null;
420
+
421
+ type ErrorTrackerContext = Record<string, unknown>;
422
+ declare const sanitizeErrorString: (value: string) => string;
423
+ declare const sanitizeErrorStrings: (error: unknown) => {
424
+ message: string;
425
+ stack: string | undefined;
426
+ } | null;
530
427
  interface ErrorTrackerEvent {
531
428
  /** When false, the adapter must not forward this event (beforeSend opt-out). */
532
429
  forwarded: boolean;
@@ -564,27 +461,6 @@ interface ErrorTracker {
564
461
  */
565
462
  flush?: () => Promise<void>;
566
463
  }
567
- /**
568
- * Open a per-request error-tracker identity scope and run `fn` inside it. Call at
569
- * request ENTRY (before any await that could interleave with another request); the
570
- * identity starts null and is filled in later via {@link setCurrentErrorTrackerIdentity}
571
- * once the session is known. Each invocation gets an isolated box (ET-02).
572
- */
573
- declare const runWithErrorTrackerIdentityScope: <T>(fn: () => T) => T;
574
- /**
575
- * Run `fn` with `user` bound as the ambient error-tracker identity (ET-02). Convenience
576
- * wrapper that opens a scope and immediately sets the identity — used where the user is
577
- * already known up front (and by the adapter regression tests).
578
- */
579
- declare const runWithErrorTrackerIdentity: <T>(user: ErrorTrackerUser | null, fn: () => T) => T;
580
- /**
581
- * Write `user` into the active identity box opened by {@link runWithErrorTrackerIdentityScope}
582
- * / {@link runWithErrorTrackerIdentity}. No-op when called outside any scope (a background /
583
- * non-request capture has no per-request box; adapters fall back to their own global).
584
- */
585
- declare const setCurrentErrorTrackerIdentity: (user: ErrorTrackerUser | null) => void;
586
- /** Read the ambient per-event identity for the active request scope, if any. */
587
- declare const getCurrentErrorTrackerIdentity: () => ErrorTrackerUser | null;
588
464
  type PreCaptureFilter = (event: ErrorTrackerEvent) => boolean;
589
465
  declare const registerPreCaptureFilter: (filter: PreCaptureFilter | null) => void;
590
466
  declare const registerErrorTracker: (tracker: ErrorTracker) => void;
@@ -690,10 +566,6 @@ declare const getRedisConnectionOptions: () => RedisConnectionOptions;
690
566
  declare const registerStrayPrefixCommand: (...commands: string[]) => void;
691
567
  declare const redis: Redis$1;
692
568
 
693
- type SecretsResolvedListener = (changedKeys: readonly string[] | undefined) => void;
694
- declare const registerSecretsResolvedListener: (listener: SecretsResolvedListener) => (() => void);
695
- declare const notifySecretsResolved: (changedKeys?: readonly string[]) => void;
696
-
697
569
  type RedisKeyFormatter = (namespace: string, suffix: string) => string;
698
570
  declare const defaultRedisKeyFormatter: RedisKeyFormatter;
699
571
  declare const registerRedisKeyFormatter: (fn: RedisKeyFormatter) => void;
@@ -1895,4 +1767,4 @@ declare const clearAllHooks: () => void;
1895
1767
  declare const registerSyncHook: <TName extends SyncHookName>(name: TName, handler: SyncHookHandler<SyncHookPayloads[TName]>) => (() => void);
1896
1768
  declare const dispatchSyncHook: <TName extends SyncHookName>(name: TName, payload: SyncHookPayloads[TName]) => void;
1897
1769
 
1898
- export { type ApiAuthRejectedPayload, type ApiErrorPayload, type ApiResponseEnvelope, AuthProps, type AvatarConfig, type AvatarConfigInput, BOOT_KEY_PREFIX, BaseSessionLayout, type CheckRateLimitParams, type CookiePrefixConstraints, type CorsRejectedPayload, type CreateLocalizedNormalizerInput, type CsrfConfig, type CsrfCookieOptions, type CsrfMismatchPayload, DEFAULT_AVATAR_CONFIG, DEFAULT_CLIENT_KEY, DEFAULT_CSRF_CONFIG, DEFAULT_ENV_FILES, DEFAULT_REDACTED_LOG_KEYS, DEPTH_TRUNCATED_PLACEHOLDER, type DbHealthCheck, type DbHealthResult, DeepPartial, type DeployConfigShape, type DeployDevelopmentShape, type DeployEnvironmentShape, type DeployResourceShape, type DeployRoutingShape, type DispatchResult, type EmailAttachment, type EmailMessage, type EmailResult, type EmailSender, type EmailSenderRegistry, type ErrorFormatter, type ErrorFormatterContext, ErrorParam, ErrorResponseInput, type ErrorTracker, type ErrorTrackerContext, type ErrorTrackerEvent, type ErrorTrackerUser, type FormatterEnvelope, GENERATED_API_DOCS_PATH, GENERATED_API_SCHEMAS_PATH, GENERATED_SOCKET_TYPES_PATH, HealthHashConfig, type HealthHashDescriptor, type HookHandler, type HookName, type HookPayloads, type HookResult, type HookSessionShape, type HookStopSignal, type HttpMethod, type LanguageCode, type LocaleReloader, type LocalizedNormalizer, type NormalizeErrorResponseInput, NormalizedErrorResponse, type OnUploadCompletePayload, type OnUploadStartPayload, type OneTimeTokenHandle, PUBLIC_DIR, type PeerRequire, type PostApiExecutePayload, type PostApiRespondPayload, type PostApiValidatePayload, type PostAvatarServePayload, type PostErrorNormalizePayload, type PostHttpRequestPayload, type PostSessionRefreshPayload, type PostSyncAuthorizePayload, type PostSyncExecutePayload, type PostSyncFanoutPayload, type PostSyncValidatePayload, type PreApiExecutePayload, type PreApiRespondPayload, type PreApiValidatePayload, type PreAvatarServePayload, type PreCaptureFilter, type PreErrorNormalizePayload, type PreHttpRequestPayload, type PreServerStopPayload, type PreSessionRefreshPayload, type PreSocketMessagePayload, type PreSyncAuthorizePayload, type PreSyncExecutePayload, type PreSyncFanoutPayload, type PreSyncRecipientPayload, type PreSyncValidatePayload, type PresetDefinition, type ProcessUploadInput, type ProcessUploadResult, REDACTED_PLACEHOLDER, ROOT_DIR, type RateLimitExceededPayload, type RateLimitResult, type RateLimitStrategy, type RedisConnectionOptions, type RedisKeyFormatter, type Registry, type RegistryOptions, type ResolveClientIpParams, type RoomNameFormatter, type RoomNameFormatterContext, type RuntimeApiMapsResult, type RuntimeEnv, type RuntimeMapsProvider, type RuntimeSyncMapsResult, SERVER_DIR, SERVER_FUNCTIONS_DIR, SHARED_DIR, SRC_DIR, type SecretsResolvedListener, type ServiceDefinition, type ServicesConfigShape, type SessionCreatedPayload, type SessionLogoutInput, type SessionProvider, type SessionRevokedPayload, type SessionSaveResult, type SocketMiddleware, type SpanHandle, type SpanResult, type SyncErrorPayload, type SyncHookHandler, type SyncHookName, type SyncHookPayloads, TSCONFIG_ALIAS_FILES, type TranslateFunction, type TranslateInput, UNKNOWN_CLIENT_IP, UPLOADS_DIR, type ValidationResult$1 as ValidationResult, abortAllForSocket, abortApiByResponseIndex, abortSyncByCb, acquireLease, allowedOrigin, type apiMessage, appendErrorTracker, applyCookiePrefixConstraints, applyErrorFormatter, applySocketMiddlewares, applyStrayKeyPrefix, attachSocketRedisAdapter, bootstrapEnv, captureException, captureExceptionAcrossTrackers, captureMessage, captureMessageAcrossTrackers, checkRateLimit, clearAllHooks, clearAllRateLimits, clearRateLimit, clearSocketMiddlewares, collectSynchronizedEnvKeys, computeSynchronizedEnvHashes, consumeOneTimeToken, consumeOneTimeTokenJson, createLocalizedNormalizer, createRegistry, defaultRateLimitStrategy, defaultRedisKeyFormatter, defaultRoomNameFormatter, deriveTokenBucketId, describeHealthHashConfig, dispatchHook, dispatchSyncHook, ensurePeerDepInstalled, env, escapeHtml, extractLanguageFromHeader, extractTokenFromRequest, extractTokenFromSocket, flushErrorTrackers, formatKey, formatRoomName, getActiveErrorTrackers, getAvatarConfig, getBindAddress, getCookieValue, getCsrfConfig, getCurrentErrorTrackerIdentity, getDbHealthCheck, getDeployConfig, getEffectiveHttpMethod, getEmailSender, getEmailSenderByName, getEnv, getEnvFiles, getErrorFormatter, getGeneratedApiDocsPath, getGeneratedApiSchemasPath, getGeneratedSocketTypesPath, getIoInstance, getLocaleReloader, getLocalizedNormalizer, getParams, getPrismaClient, getPrismaClientFor, getPrismaClientKeys, getPublicDir, getRateLimitStatus, getRateLimitStrategy, getRedactedLogKeys, getRedisClient, getRedisClientFor, getRedisClientKeys, getRedisConnectionOptions, getRedisKeyFormatter, getRegisteredSessionProvider, getRoomNameFormatter, getRuntimeApiMaps, getRuntimeSyncMaps, getServerDir, getServerFunctionDirs, getServerFunctionsDir, getServicesConfig, getSharedDir, getSocketMiddlewares, getSrcDir, getUploadsDir, hasCookie, hashSynchronizedValue, hashSynchronizedValueWith, inferHttpMethod, initConsolelog, initSharedSentry, isDbHealthCheckRegistered, isDeployConfigRegistered, isEmailSenderRegistered, isFalsy, isGetMethodName, isLocalizedNormalizerRegistered, isLoopbackIp, isMethodAllowed, isPrismaClientRegistered, isPrismaClientResolvable, isProduction, isRedactedLogKey, isRedisClientRegistered, isRuntimeMapsProviderRegistered, isServicesConfigRegistered, isSessionProviderRegistered, issueOneTimeToken, listEmailSenderNames, loadEnvFiles, loadPeer, normalizeErrorResponse, normalizeOrigin, notifySecretsResolved, oneTimeTokenKey, performLogout, prisma, processUpload, readBootUuid, readSession, rebuildDefaultRedisClient, recordMetricAcrossTrackers, redis, registerApiAbortController, registerAvatarConfig, registerBindAddress, registerCsrfConfig, registerDbHealthCheck, registerDeployConfig, registerEmailSender, registerEmailSenders, registerErrorFormatter, registerErrorTracker, registerErrorTrackers, registerHook, registerLocaleReloader, registerLocalizedNormalizer, registerPreCaptureFilter, registerPrismaClient, registerRateLimitStrategy, registerRedactedLogKeys, registerRedisClient, registerRedisKeyFormatter, registerRoomNameFormatter, registerRuntimeMapsProvider, registerSecretsResolvedListener, registerServicesConfig, registerSessionProvider, registerSocketMiddleware, registerStrayPrefixCommand, registerSyncAbortController, registerSyncHook, releaseLease, removeSession, renewLease, resetClientsForTests, resetCsrfConfigForTests, resetDbHealthCheckForTests, resetDefaultRedisClient, resetRedactedLogKeysForTests, resetRedisKeyFormatterForTests, resetSessionProviderForTests, resolveClientIp, resolveEnvKey, resolveErrorMessage, resolveFromRoot, resolveHealthHashConfig, resolveHealthHashConfigFromDescriptor, runWithErrorTrackerIdentity, runWithErrorTrackerIdentityScope, sanitizeErrorString, sanitizeErrorStrings, sanitizeForLog, serveAvatar, setCurrentErrorTrackerIdentity, setErrorTrackerUser, setIoInstance, setSentryUser, startSpan, startSpanAcrossTrackers, startSpanHandle, type syncMessage, tryCatch, tryCatchSync, unregisterApiAbortController, unregisterSyncAbortController, validateInputByType, validateRequest, writeBootUuid, writeSession };
1770
+ export { type ApiAuthRejectedPayload, type ApiErrorPayload, type ApiResponseEnvelope, AuthProps, type AvatarConfig, type AvatarConfigInput, BOOT_KEY_PREFIX, BaseSessionLayout, type CheckRateLimitParams, type CookiePrefixConstraints, type CorsRejectedPayload, type CreateLocalizedNormalizerInput, type CsrfConfig, type CsrfCookieOptions, type CsrfMismatchPayload, DEFAULT_AVATAR_CONFIG, DEFAULT_CLIENT_KEY, DEFAULT_CSRF_CONFIG, DEFAULT_ENV_FILES, DEFAULT_REDACTED_LOG_KEYS, DEPTH_TRUNCATED_PLACEHOLDER, type DbHealthCheck, type DbHealthResult, DeepPartial, type DispatchResult, type EmailAttachment, type EmailMessage, type EmailResult, type EmailSender, type EmailSenderRegistry, type ErrorFormatter, type ErrorFormatterContext, ErrorParam, ErrorResponseInput, type ErrorTracker, type ErrorTrackerContext, type ErrorTrackerEvent, type ErrorTrackerUser, type FormatterEnvelope, GENERATED_API_DOCS_PATH, GENERATED_API_SCHEMAS_PATH, GENERATED_SOCKET_TYPES_PATH, HealthHashConfig, type HealthHashDescriptor, type HookHandler, type HookName, type HookPayloads, type HookResult, type HookSessionShape, type HookStopSignal, type HttpMethod, type LanguageCode, type LocaleReloader, type LocalizedNormalizer, type NormalizeErrorResponseInput, NormalizedErrorResponse, type OnUploadCompletePayload, type OnUploadStartPayload, type OneTimeTokenHandle, PUBLIC_DIR, type PeerRequire, type PostApiExecutePayload, type PostApiRespondPayload, type PostApiValidatePayload, type PostAvatarServePayload, type PostErrorNormalizePayload, type PostHttpRequestPayload, type PostSessionRefreshPayload, type PostSyncAuthorizePayload, type PostSyncExecutePayload, type PostSyncFanoutPayload, type PostSyncValidatePayload, type PreApiExecutePayload, type PreApiRespondPayload, type PreApiValidatePayload, type PreAvatarServePayload, type PreCaptureFilter, type PreErrorNormalizePayload, type PreHttpRequestPayload, type PreServerStopPayload, type PreSessionRefreshPayload, type PreSocketMessagePayload, type PreSyncAuthorizePayload, type PreSyncExecutePayload, type PreSyncFanoutPayload, type PreSyncRecipientPayload, type PreSyncValidatePayload, type ProcessUploadInput, type ProcessUploadResult, REDACTED_PLACEHOLDER, ROOT_DIR, type RateLimitExceededPayload, type RateLimitResult, type RateLimitStrategy, type RedisConnectionOptions, type RedisKeyFormatter, type Registry, type RegistryOptions, type ResolveClientIpParams, type RoomNameFormatter, type RoomNameFormatterContext, type RuntimeApiMapsResult, type RuntimeEnv, type RuntimeMapsProvider, type RuntimeSyncMapsResult, SERVER_DIR, SERVER_FUNCTIONS_DIR, SHARED_DIR, SRC_DIR, type SessionCreatedPayload, type SessionLogoutInput, type SessionProvider, type SessionRevokedPayload, type SessionSaveResult, type SocketMiddleware, type SpanHandle, type SpanResult, type SyncErrorPayload, type SyncHookHandler, type SyncHookName, type SyncHookPayloads, TSCONFIG_ALIAS_FILES, type TranslateFunction, type TranslateInput, UNKNOWN_CLIENT_IP, UPLOADS_DIR, type ValidationResult$1 as ValidationResult, abortAllForSocket, abortApiByResponseIndex, abortSyncByCb, acquireLease, allowedOrigin, type apiMessage, appendErrorTracker, applyCookiePrefixConstraints, applyErrorFormatter, applySocketMiddlewares, applyStrayKeyPrefix, attachSocketRedisAdapter, bootstrapEnv, captureException, captureExceptionAcrossTrackers, captureMessage, captureMessageAcrossTrackers, checkRateLimit, clearAllHooks, clearAllRateLimits, clearRateLimit, clearSocketMiddlewares, collectSynchronizedEnvKeys, computeSynchronizedEnvHashes, consumeOneTimeToken, consumeOneTimeTokenJson, createLocalizedNormalizer, createRegistry, defaultRateLimitStrategy, defaultRedisKeyFormatter, defaultRoomNameFormatter, deriveTokenBucketId, describeHealthHashConfig, dispatchHook, dispatchSyncHook, ensurePeerDepInstalled, env, escapeHtml, extractLanguageFromHeader, extractTokenFromRequest, extractTokenFromSocket, flushErrorTrackers, formatKey, formatRoomName, getActiveErrorTrackers, getAvatarConfig, getBindAddress, getCookieValue, getCsrfConfig, getCurrentErrorTrackerIdentity, getDbHealthCheck, getEffectiveHttpMethod, getEmailSender, getEmailSenderByName, getEnv, getEnvFiles, getErrorFormatter, getGeneratedApiDocsPath, getGeneratedApiSchemasPath, getGeneratedSocketTypesPath, getIoInstance, getLocaleReloader, getLocalizedNormalizer, getParams, getPrismaClient, getPrismaClientFor, getPrismaClientKeys, getPublicDir, getRateLimitStatus, getRateLimitStrategy, getRedactedLogKeys, getRedisClient, getRedisClientFor, getRedisClientKeys, getRedisConnectionOptions, getRedisKeyFormatter, getRegisteredSessionProvider, getRoomNameFormatter, getRuntimeApiMaps, getRuntimeSyncMaps, getServerDir, getServerFunctionDirs, getServerFunctionsDir, getSharedDir, getSocketMiddlewares, getSrcDir, getUploadsDir, hasCookie, hashSynchronizedValue, hashSynchronizedValueWith, inferHttpMethod, initConsolelog, initSharedSentry, isDbHealthCheckRegistered, isEmailSenderRegistered, isFalsy, isGetMethodName, isLocalizedNormalizerRegistered, isLoopbackIp, isMethodAllowed, isPrismaClientRegistered, isPrismaClientResolvable, isProduction, isRedactedLogKey, isRedisClientRegistered, isRuntimeMapsProviderRegistered, isSessionProviderRegistered, issueOneTimeToken, listEmailSenderNames, loadEnvFiles, loadPeer, normalizeErrorResponse, normalizeOrigin, oneTimeTokenKey, performLogout, prisma, processUpload, readBootUuid, readSession, rebuildDefaultRedisClient, recordMetricAcrossTrackers, redis, registerApiAbortController, registerAvatarConfig, registerBindAddress, registerCsrfConfig, registerDbHealthCheck, registerEmailSender, registerEmailSenders, registerErrorFormatter, registerErrorTracker, registerErrorTrackers, registerHook, registerLocaleReloader, registerLocalizedNormalizer, registerPreCaptureFilter, registerPrismaClient, registerRateLimitStrategy, registerRedactedLogKeys, registerRedisClient, registerRedisKeyFormatter, registerRoomNameFormatter, registerRuntimeMapsProvider, registerSessionProvider, registerSocketMiddleware, registerStrayPrefixCommand, registerSyncAbortController, registerSyncHook, releaseLease, removeSession, renewLease, resetClientsForTests, resetCsrfConfigForTests, resetDbHealthCheckForTests, resetDefaultRedisClient, resetRedactedLogKeysForTests, resetRedisKeyFormatterForTests, resetSessionProviderForTests, resolveClientIp, resolveEnvKey, resolveErrorMessage, resolveFromRoot, resolveHealthHashConfig, resolveHealthHashConfigFromDescriptor, runWithErrorTrackerIdentity, runWithErrorTrackerIdentityScope, sanitizeErrorString, sanitizeErrorStrings, sanitizeForLog, serveAvatar, setCurrentErrorTrackerIdentity, setErrorTrackerUser, setIoInstance, setSentryUser, startSpan, startSpanAcrossTrackers, startSpanHandle, type syncMessage, tryCatch, tryCatchSync, unregisterApiAbortController, unregisterSyncAbortController, validateInputByType, validateRequest, writeBootUuid, writeSession };