@luckystack/core 0.4.1 → 0.5.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.
- package/CHANGELOG.md +23 -0
- package/CLAUDE.md +245 -243
- package/LICENSE +21 -21
- package/README.md +93 -93
- package/dist/{chunk-H64EC7Q6.js → chunk-A3VMC576.js} +3 -3
- package/dist/chunk-A3VMC576.js.map +1 -0
- package/dist/{chunk-6BBJ2Q6I.js → chunk-ECWDUWBG.js} +1 -1
- package/dist/chunk-ECWDUWBG.js.map +1 -0
- package/dist/{chunk-TGYBUT4N.js → chunk-ELHTLIEX.js} +1 -1
- package/dist/chunk-ELHTLIEX.js.map +1 -0
- package/dist/client.js +4 -4
- package/dist/client.js.map +1 -1
- package/dist/eslint/index.js.map +1 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +38 -6
- package/dist/index.js.map +1 -1
- package/dist/{projectConfig-FITPOAMC.js → projectConfig-P2AHHQVW.js} +2 -2
- package/dist/{sentrySetup-MHAHHITT.js → sentrySetup-552JVLHJ.js} +2 -2
- package/docs/app-bootstrap.md +418 -418
- package/docs/config-registry.md +348 -348
- package/docs/csrf-config.md +88 -88
- package/docs/error-tracker-registry.md +174 -174
- package/docs/hooks.md +298 -298
- package/docs/rate-limit-strategy.md +170 -170
- package/docs/redis-adapter.md +111 -111
- package/docs/session-types.md +180 -180
- package/docs/socket-bootstrap.md +366 -366
- package/package.json +4 -1
- package/dist/chunk-6BBJ2Q6I.js.map +0 -1
- package/dist/chunk-H64EC7Q6.js.map +0 -1
- package/dist/chunk-TGYBUT4N.js.map +0 -1
- /package/dist/{projectConfig-FITPOAMC.js.map → projectConfig-P2AHHQVW.js.map} +0 -0
- /package/dist/{sentrySetup-MHAHHITT.js.map → sentrySetup-552JVLHJ.js.map} +0 -0
package/dist/eslint/index.js.map
CHANGED
|
@@ -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.\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":";AASA,SAAS,kBAAkB;AAC3B,SAAS,qBAAqB;AAC9B,OAAO,UAAU;AAEjB,IAAM,eAAe,cAAc,YAAY,GAAG;AAElD,IAAM,cAAc,CAAC,SAA0B;AAC7C,QAAM,WAAW,KAAK,WAAW,GAAG,IAChC,KAAK,MAAM,GAAG,EAAE,MAAM,GAAG,CAAC,IAC1B,CAAC,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,IAAI;AAC/B,SAAO,WAAW,KAAK,KAAK,QAAQ,IAAI,GAAG,gBAAgB,GAAG,UAAU,cAAc,CAAC;AACzF;AAEO,IAAM,aAAa,CAAC,SAA0B;AACnD,MAAI;AACF,iBAAa,QAAQ,MAAM,EAAE,OAAO,CAAC,QAAQ,IAAI,CAAC,EAAE,CAAC;AACrD,WAAO;AAAA,EACT,QAAQ;AACN,WAAO,YAAY,IAAI;AAAA,EACzB;AACF;;;ACpBA,IAAM,0BAA0B;AAShC,IAAM,aAAa,CAAC,SAA4B;AAsBhD,IAAM,oBAAoB,CACxB,SACA,MACA,UACS;AACT,MAAI,wBAAwB,KAAK,KAAK,GAAG;AACvC,YAAQ,OAAO,EAAE,MAAM,WAAW,gBAAgB,CAAC;AAAA,EACrD;AACF;AAEA,IAAM,OAAmB;AAAA,EACvB,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,eACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,EACX;AAAA,EACA,OAAO,SAAS;AACd,UAAM,WAA8B;AAAA,MAClC,aAAa,SAAwB;AACnC,cAAM,OAAO;AACb,YAAI,KAAK,KAAK,SAAS,mBAAmB,KAAK,KAAK,SAAS,YAAa;AAC1E,cAAM,QAAQ,KAAK;AACnB,YAAI,CAAC,MAAO;AACZ,YAAI,MAAM,SAAS,aAAa,OAAQ,MAA8B,UAAU,UAAU;AACxF,4BAAkB,SAAS,WAAW,KAAK,GAAI,MAA4B,KAAK;AAChF;AAAA,QACF;AACA,YAAI,MAAM,SAAS,0BAA0B;AAC3C,gBAAM,aAAc,MAA0C;AAC9D,cAAI,WAAW,SAAS,mBAAmB;AACzC,kBAAM,SAAU,WAAkF;AAClG,uBAAW,SAAS,QAAQ;AAC1B;AAAA,gBACE;AAAA,gBACA,WAAW,KAAK;AAAA,gBAChB,MAAM,MAAM,UAAU,MAAM,MAAM;AAAA,cACpC;AAAA,YACF;AAAA,UACF,WAAW,WAAW,SAAS,aAAa,OAAQ,WAAmC,UAAU,UAAU;AACzG;AAAA,cACE;AAAA,cACA,WAAW,UAAU;AAAA,cACpB,WAAiC;AAAA,YACpC;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAEA,IAAO,sCAAQ;;;ACxFf,IAAM,gBAAgB,CAAC,aAA8B;AACnD,QAAM,aAAa,SAAS,WAAW,MAAM,GAAG;AAChD,MAAI,WAAW,SAAS,cAAc,EAAG,QAAO;AAChD,MAAI,WAAW,SAAS,UAAU,EAAG,QAAO;AAC5C,MAAI,WAAW,SAAS,YAAY,KAAK,WAAW,SAAS,aAAa,EAAG,QAAO;AACpF,MAAI,WAAW,SAAS,YAAY,EAAG,QAAO;AAI9C,MAAI,WAAW,SAAS,YAAY,KAAK,WAAW,SAAS,YAAY,EAAG,QAAO;AACnF,MAAI,WAAW,SAAS,UAAU,EAAG,QAAO;AAC5C,SAAO;AACT;AAEA,IAAMA,QAAmB;AAAA,EACvB,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,sBACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,EACX;AAAA,EACA,OAAO,SAAS;AACd,QAAI,cAAc,QAAQ,QAAQ,EAAG,QAAO,CAAC;AAC7C,WAAO;AAAA,MACL,kBAAkB,MAAM;AACtB,YAAI,KAAK,OAAO,UAAU,kBAAkB;AAC1C,kBAAQ,OAAO,EAAE,MAAM,WAAW,uBAAuB,CAAC;AAAA,QAC5D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,gDAAQA;;;AClBf,IAAM,uBAAuB,CAAC,YAAoC;AAChE,MAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;AACpD,QAAM,IAAI;AACV,MAAI,EAAE,SAAS,aAAa,OAAO,EAAE,UAAU,SAAU,QAAO,EAAE;AAClE,MAAI,EAAE,SAAS,qBAAqB,MAAM,QAAQ,EAAE,MAAM,GAAG;AAC3D,WAAO,EAAE,OAAO,IAAI,CAAC,MAAM,EAAE,OAAO,UAAU,EAAE,OAAO,OAAO,EAAE,EAAE,KAAK,GAAG;AAAA,EAC5E;AACA,SAAO;AACT;AAEA,IAAM,wBAAwB,CAAC,YAA8B;AAC3D,QAAM,OAAO,qBAAqB,OAAO;AACzC,MAAI,SAAS,KAAM,QAAO;AAC1B,MAAI,kBAAkB,KAAK,IAAI,EAAG,QAAO;AAKzC,MAAI,mBAAmB,KAAK,IAAI,EAAG,QAAO;AAC1C,SAAO,kCAAkC,KAAK,IAAI;AACpD;AAEA,IAAMC,QAAmB;AAAA,EACvB,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,eACE;AAAA,MACF,gBACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,EACX;AAAA,EACA,OAAO,SAAS;AACd,WAAO;AAAA,MACL,eAAe,MAAM;AACnB,cAAM,SAAS,KAAK;AACpB,cAAM,cACH,OAAO,SAAS,gBAAgB,OAAO,SAAS,WAChD,OAAO,SAAS,sBACf,OAAO,OAAO,SAAS,gBACvB,OAAO,OAAO,SAAS,YACvB,OAAO,SAAS,SAAS,gBACzB,OAAO,SAAS,SAAS;AAC7B,YAAI,CAAC,YAAa;AAClB,cAAM,MAAM,KAAK,UAAU,CAAC;AAC5B,YAAI,CAAC,sBAAsB,GAAG,EAAG;AACjC,cAAM,OAAO,qBAAqB,GAAG,KAAK;AAC1C,cAAM,YAAY,KAAK,SAAS,QAAQ,IAAI,mBAAmB;AAC/D,gBAAQ,OAAO,EAAE,MAAM,UAAU,CAAC;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,8BAAQA;;;ACjFf,IAAMC,QAAmB;AAAA,EACvB,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,EACX;AAAA,EACA,OAAO,SAAS;AACd,WAAO;AAAA,MACL,aAAa,MAAM;AAIjB,YAAI,KAAK,SAAS;AAChB,kBAAQ,OAAO,EAAE,MAAM,WAAW,cAAc,CAAC;AAAA,QACnD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,2BAAQA;;;ACbf,IAAM,sBAAsB,oBAAI,IAAI,CAAC,QAAQ,WAAW,SAAS,SAAS,CAAC;AAK3E,IAAM,YAAY,oBAAI,IAAI,CAAC,UAAU,OAAO,SAAS,UAAU,UAAU,CAAC;AAE1E,IAAM,yBAAyB,CAAC,SAA2B;AACzD,MAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;AAC9C,QAAM,UAAU,oBAAI,QAAgB;AACpC,QAAM,QAAmB,CAAC,IAAI;AAC9B,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,OAAO,MAAM,IAAI;AACvB,QAAI,CAAC,QAAQ,OAAO,SAAS,SAAU;AACvC,QAAI,QAAQ,IAAI,IAAI,EAAG;AACvB,YAAQ,IAAI,IAAI;AAChB,UAAM,SAAU,KAAsE;AACtF,QACG,KAA2B,SAAS,oBACrC,QAAQ,SAAS,iBAChB,OAAO,SAAS,gBAAgB,OAAO,SAAS,gBACjD;AACA,aAAO;AAAA,IACT;AACA,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC/C,UAAI,UAAU,IAAI,GAAG,EAAG;AACxB,UAAI,MAAM,QAAQ,KAAK,EAAG,OAAM,KAAK,GAAG,KAAK;AAAA,eACpC,SAAS,OAAO,UAAU,SAAU,OAAM,KAAK,KAAK;AAAA,IAC/D;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAM,oBAAoB,CAAC,SAGZ;AACb,MAAI,CAAC,KAAK,UAAU,KAAK,OAAO,WAAW,EAAG,QAAO;AACrD,QAAM,wBAAwB,KAAK,OAAO,KAAK,CAAC,MAAM;AACpD,QAAI,EAAE,SAAS,gBAAgB,CAAC,EAAE,KAAM,QAAO;AAC/C,QAAI,CAAC,oBAAoB,IAAI,EAAE,IAAI,EAAG,QAAO;AAC7C,UAAM,aAAa,EAAE,gBAAgB,gBAAgB;AACrD,WAAO,eAAe;AAAA,EACxB,CAAC;AACD,MAAI,CAAC,sBAAuB,QAAO;AACnC,SAAO,uBAAuB,KAAK,IAAI;AACzC;AAEA,IAAMC,QAAmB;AAAA,EACvB,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,eACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,EACX;AAAA,EACA,OAAO,SAAS;AACd,WAAO;AAAA,MACL,oBAAoB,MAAM;AACxB,YAAI,kBAAkB,IAAI,GAAG;AAC3B,gBAAM,UAAW,KAAK,OAA+B,KAAK,CAAC,MAAM,EAAE,QAAQ,oBAAoB,IAAI,EAAE,IAAI,CAAC;AAC1G,kBAAQ,OAAO,EAAE,MAAM,WAAW,iBAAiB,MAAM,EAAE,WAAW,SAAS,QAAQ,OAAO,EAAE,CAAC;AAAA,QACnG;AAAA,MACF;AAAA,MACA,wBAAwB,MAAM;AAC5B,YAAI,kBAAkB,IAAI,GAAG;AAC3B,gBAAM,UAAW,KAAK,OAA+B,KAAK,CAAC,MAAM,EAAE,QAAQ,oBAAoB,IAAI,EAAE,IAAI,CAAC;AAC1G,kBAAQ,OAAO,EAAE,MAAM,WAAW,iBAAiB,MAAM,EAAE,WAAW,SAAS,QAAQ,OAAO,EAAE,CAAC;AAAA,QACnG;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,iCAAQA;;;AClFf,IAAMC,uBAAsB,oBAAI,IAAI,CAAC,QAAQ,WAAW,SAAS,UAAU,CAAC;AAC5E,IAAM,kBAAkB,oBAAI,IAAI,CAAC,eAAe,yBAAyB,CAAC;AAI1E,IAAMC,aAAY,oBAAI,IAAI,CAAC,UAAU,OAAO,SAAS,UAAU,UAAU,CAAC;AAE1E,IAAM,sBAAsB,CAAC,SAA2B;AACtD,MAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;AAC9C,QAAM,UAAU,oBAAI,QAAgB;AACpC,QAAM,QAAmB,CAAC,IAAI;AAC9B,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,OAAO,MAAM,IAAI;AACvB,QAAI,CAAC,QAAQ,OAAO,SAAS,SAAU;AACvC,QAAI,QAAQ,IAAI,IAAI,EAAG;AACvB,YAAQ,IAAI,IAAI;AAChB,UAAM,SAAU,KAAsE;AACtF,QACG,KAA2B,SAAS,oBACrC,QAAQ,SAAS,gBACjB,gBAAgB,IAAI,OAAO,QAAQ,EAAE,GACrC;AACA,aAAO;AAAA,IACT;AACA,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC/C,UAAIA,WAAU,IAAI,GAAG,EAAG;AACxB,UAAI,MAAM,QAAQ,KAAK,EAAG,OAAM,KAAK,GAAG,KAAK;AAAA,eACpC,SAAS,OAAO,UAAU,SAAU,OAAM,KAAK,KAAK;AAAA,IAC/D;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAM,YAAY,CAAC,SAGJ;AACb,MAAI,CAAC,KAAK,UAAU,KAAK,OAAO,WAAW,EAAG,QAAO;AACrD,QAAM,wBAAwB,KAAK,OAAO,KAAK,CAAC,MAAM;AACpD,QAAI,EAAE,SAAS,gBAAgB,CAAC,EAAE,KAAM,QAAO;AAC/C,QAAI,CAACD,qBAAoB,IAAI,EAAE,IAAI,EAAG,QAAO;AAC7C,WAAO,EAAE,gBAAgB,gBAAgB,SAAS;AAAA,EACpD,CAAC;AACD,MAAI,CAAC,sBAAuB,QAAO;AACnC,SAAO,oBAAoB,KAAK,IAAI;AACtC;AAEA,IAAME,QAAmB;AAAA,EACvB,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,mBACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,EACX;AAAA,EACA,OAAO,SAAS;AACd,WAAO;AAAA,MACL,oBAAoB,MAAM;AACxB,YAAI,UAAU,IAAI,GAAG;AACnB,kBAAQ,OAAO,EAAE,MAAM,WAAW,oBAAoB,CAAC;AAAA,QACzD;AAAA,MACF;AAAA,MACA,wBAAwB,MAAM;AAC5B,YAAI,UAAU,IAAI,GAAG;AACnB,kBAAQ,OAAO,EAAE,MAAM,WAAW,oBAAoB,CAAC;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,kCAAQA;;;ACpFf,IAAMC,QAAmB;AAAA,EACvB,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,uBACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,EACX;AAAA,EACA,OAAO,SAAS;AACd,WAAO;AAAA,MACL,eAAe,MAAM;AACnB,cAAM,SAAS,KAAK;AACpB,YAAI,OAAO,SAAS,gBAAgB,OAAO,SAAS,WAAW;AAC7D,kBAAQ,OAAO,EAAE,MAAM,WAAW,wBAAwB,CAAC;AAC3D;AAAA,QACF;AACA,YACE,OAAO,SAAS,sBAChB,OAAO,OAAO,SAAS,gBACvB,OAAO,OAAO,SAAS,YACvB,OAAO,SAAS,SAAS,gBACzB,OAAO,SAAS,SAAS,WACzB;AACA,kBAAQ,OAAO,EAAE,MAAM,WAAW,wBAAwB,CAAC;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,oCAAQA;;;ACzBf,IAAMC,QAAmB;AAAA,EACvB,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,EACX;AAAA,EACA,OAAO,SAAS;AACd,UAAM,WAA8B;AAAA,MAClC,kBAAkB,SAAwB;AACxC,cAAM,OAAO;AACb,YAAI,KAAK,KAAK,SAAS,mBAAmB,KAAK,KAAK,SAAS,UAAU;AACrE,kBAAQ,OAAO,EAAE,MAAM,WAAW,cAAc,CAAC;AAAA,QACnD;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAEA,IAAO,qCAAQA;;;ACnCf,IAAMC,QAAmB;AAAA,EACvB,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,WACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,EACX;AAAA,EACA,OAAO,SAAS;AACd,WAAO;AAAA,MACL,eAAe,MAAM;AACnB,cAAM,SAAS,KAAK;AACpB,YAAI,OAAO,SAAS,gBAAgB,OAAO,SAAS,SAAS;AAC3D,kBAAQ,OAAO,EAAE,MAAM,WAAW,YAAY,CAAC;AAC/C;AAAA,QACF;AACA,YACE,OAAO,SAAS,sBAChB,OAAO,OAAO,SAAS,gBACvB,OAAO,OAAO,SAAS,YACvB,OAAO,SAAS,SAAS,gBACzB,OAAO,SAAS,SAAS,SACzB;AACA,kBAAQ,OAAO,EAAE,MAAM,WAAW,YAAY,CAAC;AAAA,QACjD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,mCAAQA;;;ACff,IAAM,WAAuC;AAAA,EAC3C,oBAAoB;AAAA,EACpB,uBAAuB;AAAA,EACvB,0BAA0B;AAAA,EAC1B,2BAA2B;AAAA,EAC3B,8BAA8B;AAAA,EAC9B,6BAA6B;AAAA,EAC7B,4BAA4B;AAAA,EAC5B,yCAAyC;AAAA,EACzC,+BAA+B;AACjC;AAEA,IAAM,SAAS,WAAW,iBAAiB;AAC3C,IAAM,UAAU,WAAW,kBAAkB;AAC7C,IAAM,UAAU,WAAW,kBAAkB;AAE7C,IAAM,iBAAsD;AAAA;AAAA,EAE1D,+BAA+B;AAAA;AAAA;AAAA,EAI/B,kCAAkC,UAAU,UAAU,UAAU;AAAA,EAChE,qCAAqC,SAAS,UAAU;AAAA,EACxD,sCAAsC,UAAU,UAAU;AAAA;AAAA,EAG1D,yCAAyC;AAAA,EACzC,wCAAwC;AAAA,EACxC,uCAAuC;AAAA,EACvC,oDAAoD;AAAA,EACpD,0CAA0C;AAC5C;AAEA,IAAM,mBAAoC;AAAA,EACxC;AAAA,IACE,OAAO,CAAC,8BAA8B;AAAA,IACtC,SAAS;AAAA,MACP,YAAY,EAAE,OAAO,SAAS;AAAA,IAChC;AAAA,IACA,OAAO;AAAA,EACT;AACF;AAEA,IAAO,iBAAQ;","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.\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"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -663,8 +663,21 @@ declare const getEnv: () => RuntimeEnv;
|
|
|
663
663
|
declare global {
|
|
664
664
|
var __luckystackPrisma: PrismaClient | undefined;
|
|
665
665
|
}
|
|
666
|
+
/**
|
|
667
|
+
* Is a generated `@prisma/client` present in this install? Used by the
|
|
668
|
+
* default resolver's error path and by `/readyz` to decide whether a missing
|
|
669
|
+
* DB ping means "broken" or "this project has no Prisma by design".
|
|
670
|
+
*/
|
|
671
|
+
declare const isPrismaClientResolvable: () => boolean;
|
|
666
672
|
declare const prisma: PrismaClient<_prisma_client.Prisma.PrismaClientOptions, never, _prisma_client_runtime_library.DefaultArgs>;
|
|
667
673
|
|
|
674
|
+
type DbHealthResult = boolean | 'skipped';
|
|
675
|
+
type DbHealthCheck = () => Promise<DbHealthResult> | DbHealthResult;
|
|
676
|
+
declare const registerDbHealthCheck: (check: DbHealthCheck) => void;
|
|
677
|
+
declare const getDbHealthCheck: () => DbHealthCheck | null;
|
|
678
|
+
declare const isDbHealthCheckRegistered: () => boolean;
|
|
679
|
+
declare const resetDbHealthCheckForTests: () => void;
|
|
680
|
+
|
|
668
681
|
interface RedisConnectionOptions {
|
|
669
682
|
host: string;
|
|
670
683
|
port: number;
|
|
@@ -1876,4 +1889,4 @@ declare const clearAllHooks: () => void;
|
|
|
1876
1889
|
declare const registerSyncHook: <TName extends SyncHookName>(name: TName, handler: SyncHookHandler<SyncHookPayloads[TName]>) => (() => void);
|
|
1877
1890
|
declare const dispatchSyncHook: <TName extends SyncHookName>(name: TName, payload: SyncHookPayloads[TName]) => void;
|
|
1878
1891
|
|
|
1879
|
-
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, 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 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, 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, isDeployConfigRegistered, isEmailSenderRegistered, isFalsy, isGetMethodName, isLocalizedNormalizerRegistered, isLoopbackIp, isMethodAllowed, isPrismaClientRegistered, isProduction, isRedactedLogKey, isRedisClientRegistered, isRuntimeMapsProviderRegistered, isServicesConfigRegistered, isSessionProviderRegistered, issueOneTimeToken, listEmailSenderNames, loadEnvFiles, loadPeer, normalizeErrorResponse, normalizeOrigin, oneTimeTokenKey, performLogout, prisma, processUpload, readBootUuid, readSession, recordMetricAcrossTrackers, redis, registerApiAbortController, registerAvatarConfig, registerBindAddress, registerCsrfConfig, registerDeployConfig, registerEmailSender, registerEmailSenders, registerErrorFormatter, registerErrorTracker, registerErrorTrackers, registerHook, registerLocaleReloader, registerLocalizedNormalizer, registerPreCaptureFilter, registerPrismaClient, registerRateLimitStrategy, registerRedactedLogKeys, registerRedisClient, registerRedisKeyFormatter, registerRoomNameFormatter, registerRuntimeMapsProvider, registerServicesConfig, registerSessionProvider, registerSocketMiddleware, registerStrayPrefixCommand, registerSyncAbortController, registerSyncHook, releaseLease, removeSession, renewLease, resetClientsForTests, resetCsrfConfigForTests, 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 };
|
|
1892
|
+
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 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, oneTimeTokenKey, performLogout, prisma, processUpload, readBootUuid, readSession, recordMetricAcrossTrackers, redis, registerApiAbortController, registerAvatarConfig, registerBindAddress, registerCsrfConfig, registerDbHealthCheck, registerDeployConfig, registerEmailSender, registerEmailSenders, registerErrorFormatter, registerErrorTracker, registerErrorTrackers, registerHook, registerLocaleReloader, registerLocalizedNormalizer, registerPreCaptureFilter, registerPrismaClient, registerRateLimitStrategy, registerRedactedLogKeys, registerRedisClient, registerRedisKeyFormatter, registerRoomNameFormatter, registerRuntimeMapsProvider, registerServicesConfig, registerSessionProvider, registerSocketMiddleware, registerStrayPrefixCommand, registerSyncAbortController, registerSyncHook, releaseLease, removeSession, renewLease, resetClientsForTests, resetCsrfConfigForTests, resetDbHealthCheckForTests, 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 };
|
package/dist/index.js
CHANGED
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
tryCatchSync,
|
|
50
50
|
validatePagePath,
|
|
51
51
|
waitForSocket
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-A3VMC576.js";
|
|
53
53
|
import {
|
|
54
54
|
DEFAULT_PROJECT_CONFIG,
|
|
55
55
|
deepMerge,
|
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
isPlainObject,
|
|
59
59
|
isProjectConfigRegistered,
|
|
60
60
|
registerProjectConfig
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-ECWDUWBG.js";
|
|
62
62
|
import {
|
|
63
63
|
DEFAULT_REDACTED_LOG_KEYS,
|
|
64
64
|
DEPTH_TRUNCATED_PLACEHOLDER,
|
|
@@ -96,7 +96,7 @@ import {
|
|
|
96
96
|
startSpan,
|
|
97
97
|
startSpanAcrossTrackers,
|
|
98
98
|
startSpanHandle
|
|
99
|
-
} from "./chunk-
|
|
99
|
+
} from "./chunk-ELHTLIEX.js";
|
|
100
100
|
import {
|
|
101
101
|
createRegistry
|
|
102
102
|
} from "./chunk-USQA6QTX.js";
|
|
@@ -476,7 +476,7 @@ var isProduction = env.NODE_ENV === "production";
|
|
|
476
476
|
var getEnv = () => bootstrapEnv();
|
|
477
477
|
|
|
478
478
|
// src/db.ts
|
|
479
|
-
import {
|
|
479
|
+
import { createRequire as createRequire2 } from "module";
|
|
480
480
|
|
|
481
481
|
// src/clients.ts
|
|
482
482
|
var DEFAULT_CLIENT_KEY = "default";
|
|
@@ -526,8 +526,24 @@ var resetClientsForTests = () => {
|
|
|
526
526
|
};
|
|
527
527
|
|
|
528
528
|
// src/db.ts
|
|
529
|
+
var requireFromCore = createRequire2(import.meta.url);
|
|
530
|
+
var isPrismaClientResolvable = () => {
|
|
531
|
+
const [error] = tryCatchSync(() => requireFromCore.resolve("@prisma/client"));
|
|
532
|
+
return !error;
|
|
533
|
+
};
|
|
529
534
|
var buildDefaultPrismaClient = () => {
|
|
530
|
-
globalThis.__luckystackPrisma
|
|
535
|
+
if (!globalThis.__luckystackPrisma) {
|
|
536
|
+
const [loadError, loaded] = tryCatchSync(
|
|
537
|
+
() => requireFromCore("@prisma/client")
|
|
538
|
+
);
|
|
539
|
+
const PrismaClientCtor = loaded?.PrismaClient;
|
|
540
|
+
if (loadError || typeof PrismaClientCtor !== "function") {
|
|
541
|
+
throw new Error(
|
|
542
|
+
"[luckystack] no database client is available: '@prisma/client' is not installed/generated and no client was registered. Register your own database client in `luckystack/core/clients.ts` via registerPrismaClient(...) (any client whose surface your handlers use) \u2014 and swap the login UserAdapter via registerUserAdapter(...) if auth is on \u2014 or install Prisma: `npm i @prisma/client prisma` + `npx prisma generate`. Projects scaffolded with orm: 'none' are expected to fill in that file."
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
globalThis.__luckystackPrisma = new PrismaClientCtor();
|
|
546
|
+
}
|
|
531
547
|
return globalThis.__luckystackPrisma;
|
|
532
548
|
};
|
|
533
549
|
setDefaultPrismaResolver(buildDefaultPrismaClient);
|
|
@@ -553,6 +569,17 @@ var prisma = new Proxy({}, {
|
|
|
553
569
|
getOwnPropertyDescriptor: (_target, prop) => Reflect.getOwnPropertyDescriptor(getPrismaClient(), prop)
|
|
554
570
|
});
|
|
555
571
|
|
|
572
|
+
// src/dbHealthCheck.ts
|
|
573
|
+
var activeCheck = null;
|
|
574
|
+
var registerDbHealthCheck = (check) => {
|
|
575
|
+
activeCheck = check;
|
|
576
|
+
};
|
|
577
|
+
var getDbHealthCheck = () => activeCheck;
|
|
578
|
+
var isDbHealthCheckRegistered = () => activeCheck !== null;
|
|
579
|
+
var resetDbHealthCheckForTests = () => {
|
|
580
|
+
activeCheck = null;
|
|
581
|
+
};
|
|
582
|
+
|
|
556
583
|
// src/redis.ts
|
|
557
584
|
import Redis from "ioredis";
|
|
558
585
|
|
|
@@ -1887,7 +1914,7 @@ var validateInputByType = async ({
|
|
|
1887
1914
|
return { status: "success" };
|
|
1888
1915
|
}
|
|
1889
1916
|
if (resolveEnvKey() === "production") {
|
|
1890
|
-
const { getProjectConfig: getProjectConfig2 } = await import("./projectConfig-
|
|
1917
|
+
const { getProjectConfig: getProjectConfig2 } = await import("./projectConfig-P2AHHQVW.js");
|
|
1891
1918
|
if (getProjectConfig2().validation.runtimeMode === "off") {
|
|
1892
1919
|
return { status: "success" };
|
|
1893
1920
|
}
|
|
@@ -2138,6 +2165,7 @@ export {
|
|
|
2138
2165
|
getCsrfConfig,
|
|
2139
2166
|
getCsrfToken,
|
|
2140
2167
|
getCurrentErrorTrackerIdentity,
|
|
2168
|
+
getDbHealthCheck,
|
|
2141
2169
|
getDeployConfig,
|
|
2142
2170
|
getEffectiveHttpMethod,
|
|
2143
2171
|
getEmailSender,
|
|
@@ -2191,6 +2219,7 @@ export {
|
|
|
2191
2219
|
initConsolelog,
|
|
2192
2220
|
initSharedSentry,
|
|
2193
2221
|
isApiMethodMapRegistered,
|
|
2222
|
+
isDbHealthCheckRegistered,
|
|
2194
2223
|
isDeployConfigRegistered,
|
|
2195
2224
|
isEmailSenderRegistered,
|
|
2196
2225
|
isErrorParamArray,
|
|
@@ -2203,6 +2232,7 @@ export {
|
|
|
2203
2232
|
isOnline,
|
|
2204
2233
|
isPlainObject,
|
|
2205
2234
|
isPrismaClientRegistered,
|
|
2235
|
+
isPrismaClientResolvable,
|
|
2206
2236
|
isProduction,
|
|
2207
2237
|
isProjectConfigRegistered,
|
|
2208
2238
|
isRedactedLogKey,
|
|
@@ -2233,6 +2263,7 @@ export {
|
|
|
2233
2263
|
registerAvatarConfig,
|
|
2234
2264
|
registerBindAddress,
|
|
2235
2265
|
registerCsrfConfig,
|
|
2266
|
+
registerDbHealthCheck,
|
|
2236
2267
|
registerDeployConfig,
|
|
2237
2268
|
registerEmailSender,
|
|
2238
2269
|
registerEmailSenders,
|
|
@@ -2267,6 +2298,7 @@ export {
|
|
|
2267
2298
|
renewLease,
|
|
2268
2299
|
resetClientsForTests,
|
|
2269
2300
|
resetCsrfConfigForTests,
|
|
2301
|
+
resetDbHealthCheckForTests,
|
|
2270
2302
|
resetLoggerForTests,
|
|
2271
2303
|
resetRedactedLogKeysForTests,
|
|
2272
2304
|
resetRedisKeyFormatterForTests,
|