@luckystack/core 0.11.0 → 0.12.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.
@@ -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-local-socket-enumeration.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 enumerating the Socket.io server's LOCAL socket maps.\n//? Three ways of reaching a room's sockets look identical in the editor:\n//? - `io.sockets.adapter.rooms.get(room)` / `io.sockets.adapter.sids`\n//? — only THIS instance.\n//? - enumerating `io.sockets.sockets` (`.values()`, `.keys()`,\n//? `.entries()`, `.forEach()`, `.size`, `for...of`, spread)\n//? — only THIS instance.\n//? - `await io.in(room).fetchSockets()` — ALL instances (Redis-adapter\n//? aware).\n//? The Redis adapter synchronises DELIVERY (`io.to(room).emit()`) but NOT\n//? those two local maps. A broadcast that enumerates a local map, or an\n//? emit gated on `adapter.rooms.has(room)`, works in dev (one instance)\n//? and silently goes dead on every other instance of a split deployment.\n//? A consumer project made this exact mistake three times independently.\n//?\n//? Good path: `getRoomSockets(room, { userId })` from `@luckystack/core`,\n//? or `io.in(room).fetchSockets()`. A deliberate per-instance use (e.g. a\n//? sweep cleaning up its own connections) opts out with\n//? `// eslint-disable-next-line luckystack/no-local-socket-enumeration -- <why>`\n//? and, at runtime, `getIoInstance({ raw: true })` — the dev-mode\n//? `getIoInstance()` proxy throws on these accesses.\n//?\n//? Deliberately NOT reported:\n//? - `io.sockets.sockets.get(id)` / `.has(id)` / `.delete(id)` — a\n//? keyed lookup from a local socket handler is per definition local\n//? and correct; only ENUMERATION is wrong.\n//? - `socket.rooms.has(room)` — the per-socket room set is fine.\n//? - Computed access (`io['sockets']['adapter']['rooms']`) — out of\n//? scope here; the runtime proxy catches it.\n//?\n//? Gated by hasPackage('@luckystack/core') OR hasPackage('@luckystack/sync')\n//? at the config-composition layer.\n\nimport type { Rule } from 'eslint';\nimport type * as ESTree from 'estree';\n\nimport type { EslintRule } from '../internal/ruleTypes.js';\n\nconst ADAPTER_LOCAL_MAPS = new Set(['rooms', 'sids']);\nconst ENUMERATING_MEMBERS = new Set(['values', 'keys', 'entries', 'forEach', 'size']);\n\n//? `<X>.<name>` — a non-computed member access whose property is `name`.\nconst isNamedMember = (\n node: ESTree.Node,\n name: string,\n): node is ESTree.MemberExpression & { property: ESTree.Identifier } =>\n node.type === 'MemberExpression' &&\n !node.computed &&\n node.property.type === 'Identifier' &&\n node.property.name === name;\n\n//? `<Y>.sockets.sockets` — the local socket map on a Socket.io server.\nconst isLocalSocketsMap = (node: ESTree.Node): boolean =>\n isNamedMember(node, 'sockets') && isNamedMember(node.object, 'sockets');\n\nconst rule: EslintRule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow enumerating the Socket.io server\\'s local socket maps (`.adapter.rooms`, `.adapter.sids`, iterating `io.sockets.sockets`). They only see THIS instance; use `getRoomSockets(...)` or `io.in(room).fetchSockets()`.',\n },\n messages: {\n localAdapterMap:\n '`.adapter.{{name}}` only sees sockets connected to THIS instance — on a multi-instance deployment every other instance is invisible here. Use `getRoomSockets(room, { userId })` from `@luckystack/core` or `await io.in(room).fetchSockets()`. For deliberate per-instance work use `getIoInstance({ raw: true })` and add `// eslint-disable-next-line luckystack/no-local-socket-enumeration -- <why>`.',\n localSocketEnumeration:\n 'Enumerating `io.sockets.sockets` (`.{{name}}`) only sees sockets connected to THIS instance — on a multi-instance deployment every other instance is invisible here. Use `getRoomSockets(room, { userId })` from `@luckystack/core` or `await io.in(room).fetchSockets()`. For deliberate per-instance work use `getIoInstance({ raw: true })` and add `// eslint-disable-next-line luckystack/no-local-socket-enumeration -- <why>`.',\n },\n schema: [],\n },\n create(context: Rule.RuleContext) {\n const reportEnumeration = (node: ESTree.Node, name: string): void => {\n context.report({ node, messageId: 'localSocketEnumeration', data: { name } });\n };\n return {\n MemberExpression(node) {\n if (node.computed || node.property.type !== 'Identifier') return;\n const name = node.property.name;\n //? (a) `<X>.adapter.rooms` / `<X>.adapter.sids`\n if (ADAPTER_LOCAL_MAPS.has(name) && isNamedMember(node.object, 'adapter')) {\n context.report({ node, messageId: 'localAdapterMap', data: { name } });\n return;\n }\n //? (b) `<Y>.sockets.sockets.values()` / `.keys()` / `.entries()` /\n //? `.forEach()` / `.size` — `.get()` / `.has()` / `.delete()` pass.\n if (ENUMERATING_MEMBERS.has(name) && isLocalSocketsMap(node.object)) {\n reportEnumeration(node, name);\n }\n },\n //? (c) `for (const s of <Y>.sockets.sockets)`\n ForOfStatement(node) {\n if (isLocalSocketsMap(node.right)) reportEnumeration(node.right, 'for...of');\n },\n //? (d) `[...<Y>.sockets.sockets]`\n SpreadElement(node) {\n if (isLocalSocketsMap(node.argument)) reportEnumeration(node.argument, '...spread');\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 noLocalSocketEnumeration from './rules/no-local-socket-enumeration.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 'no-local-socket-enumeration': noLocalSocketEnumeration,\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 // Local Socket.io maps (`.adapter.rooms`, iterating `io.sockets.sockets`) only see one instance.\n 'luckystack/no-local-socket-enumeration': hasCore || 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","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-local-socket-enumeration.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/no-untranslated-jsx-text.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 the JSX-aware parser produces at runtime\n//? 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. The parser supplies them at runtime, but the\n//? 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 enumerating the Socket.io server's LOCAL socket maps.\n//? Three ways of reaching a room's sockets look identical in the editor:\n//? - `io.sockets.adapter.rooms.get(room)` / `io.sockets.adapter.sids`\n//? — only THIS instance.\n//? - enumerating `io.sockets.sockets` (`.values()`, `.keys()`,\n//? `.entries()`, `.forEach()`, `.size`, `for...of`, spread)\n//? — only THIS instance.\n//? - `await io.in(room).fetchSockets()` — ALL instances (Redis-adapter\n//? aware).\n//? The Redis adapter synchronises DELIVERY (`io.to(room).emit()`) but NOT\n//? those two local maps. A broadcast that enumerates a local map, or an\n//? emit gated on `adapter.rooms.has(room)`, works in dev (one instance)\n//? and silently goes dead on every other instance of a split deployment.\n//? A consumer project made this exact mistake three times independently.\n//?\n//? Good path: `getRoomSockets(room, { userId })` from `@luckystack/core`,\n//? or `io.in(room).fetchSockets()`. A deliberate per-instance use (e.g. a\n//? sweep cleaning up its own connections) opts out with\n//? `// eslint-disable-next-line luckystack/no-local-socket-enumeration -- <why>`\n//? and, at runtime, `getIoInstance({ raw: true })` — the dev-mode\n//? `getIoInstance()` proxy throws on these accesses.\n//?\n//? Deliberately NOT reported:\n//? - `io.sockets.sockets.get(id)` / `.has(id)` / `.delete(id)` — a\n//? keyed lookup from a local socket handler is per definition local\n//? and correct; only ENUMERATION is wrong.\n//? - `socket.rooms.has(room)` — the per-socket room set is fine.\n//? - Computed access (`io['sockets']['adapter']['rooms']`) — out of\n//? scope here; the runtime proxy catches it.\n//?\n//? Gated by hasPackage('@luckystack/core') OR hasPackage('@luckystack/sync')\n//? at the config-composition layer.\n\nimport type { Rule } from 'eslint';\nimport type * as ESTree from 'estree';\n\nimport type { EslintRule } from '../internal/ruleTypes.js';\n\nconst ADAPTER_LOCAL_MAPS = new Set(['rooms', 'sids']);\nconst ENUMERATING_MEMBERS = new Set(['values', 'keys', 'entries', 'forEach', 'size']);\n\n//? `<X>.<name>` — a non-computed member access whose property is `name`.\nconst isNamedMember = (\n node: ESTree.Node,\n name: string,\n): node is ESTree.MemberExpression & { property: ESTree.Identifier } =>\n node.type === 'MemberExpression' &&\n !node.computed &&\n node.property.type === 'Identifier' &&\n node.property.name === name;\n\n//? `<Y>.sockets.sockets` — the local socket map on a Socket.io server.\nconst isLocalSocketsMap = (node: ESTree.Node): boolean =>\n isNamedMember(node, 'sockets') && isNamedMember(node.object, 'sockets');\n\nconst rule: EslintRule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow enumerating the Socket.io server\\'s local socket maps (`.adapter.rooms`, `.adapter.sids`, iterating `io.sockets.sockets`). They only see THIS instance; use `getRoomSockets(...)` or `io.in(room).fetchSockets()`.',\n },\n messages: {\n localAdapterMap:\n '`.adapter.{{name}}` only sees sockets connected to THIS instance — on a multi-instance deployment every other instance is invisible here. Use `getRoomSockets(room, { userId })` from `@luckystack/core` or `await io.in(room).fetchSockets()`. For deliberate per-instance work use `getIoInstance({ raw: true })` and add `// eslint-disable-next-line luckystack/no-local-socket-enumeration -- <why>`.',\n localSocketEnumeration:\n 'Enumerating `io.sockets.sockets` (`.{{name}}`) only sees sockets connected to THIS instance — on a multi-instance deployment every other instance is invisible here. Use `getRoomSockets(room, { userId })` from `@luckystack/core` or `await io.in(room).fetchSockets()`. For deliberate per-instance work use `getIoInstance({ raw: true })` and add `// eslint-disable-next-line luckystack/no-local-socket-enumeration -- <why>`.',\n },\n schema: [],\n },\n create(context: Rule.RuleContext) {\n const reportEnumeration = (node: ESTree.Node, name: string): void => {\n context.report({ node, messageId: 'localSocketEnumeration', data: { name } });\n };\n return {\n MemberExpression(node) {\n if (node.computed || node.property.type !== 'Identifier') return;\n const name = node.property.name;\n //? (a) `<X>.adapter.rooms` / `<X>.adapter.sids`\n if (ADAPTER_LOCAL_MAPS.has(name) && isNamedMember(node.object, 'adapter')) {\n context.report({ node, messageId: 'localAdapterMap', data: { name } });\n return;\n }\n //? (b) `<Y>.sockets.sockets.values()` / `.keys()` / `.entries()` /\n //? `.forEach()` / `.size` — `.get()` / `.has()` / `.delete()` pass.\n if (ENUMERATING_MEMBERS.has(name) && isLocalSocketsMap(node.object)) {\n reportEnumeration(node, name);\n }\n },\n //? (c) `for (const s of <Y>.sockets.sockets)`\n ForOfStatement(node) {\n if (isLocalSocketsMap(node.right)) reportEnumeration(node.right, 'for...of');\n },\n //? (d) `[...<Y>.sockets.sockets]`\n SpreadElement(node) {\n if (isLocalSocketsMap(node.argument)) reportEnumeration(node.argument, '...spread');\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 @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 @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: user-facing text in JSX goes through the project's translator\n//? (AGENTS.md rule 13). Replaces `react/jsx-no-literals` with the options the\n//? framework always ran it with (`noStrings`, `ignoreProps`, a punctuation\n//? allow-list): eslint-plugin-react stopped at ESLint 9 and was otherwise only\n//? kept for this one rule. Behaviour is a faithful port, so existing disables\n//? and expectations carry over unchanged:\n//? - JSX text children and string/template literals that are a child's\n//? `{…}` expression are reported; attribute values (props) are not.\n//? - A string concatenation (`{'a' + b}`) counts as the literal itself;\n//? ternaries and `&&` branches are not inspected.\n\nimport type { Rule } from 'eslint';\n\nimport type { EslintRule } from '../internal/ruleTypes.js';\n\n//? Characters and units that read the same in every language, so routing them\n//? through the translator only adds noise. Compared after trimming.\nexport const DEFAULT_ALLOWED_JSX_STRINGS: readonly string[] = [\n '!', '?', '-', '/', ':', ',', '(', ')', '%', '&',\n '@', '#', '$', '^', '*', '+', '=', '|', '.', '...',\n '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10',\n '•', '»', '«', '—', '–',\n 'x', 'px', 'rem', 'em', 'ms', 's', '°',\n];\n\nconst WHITESPACE_ONLY = /^\\s+$/;\nconst ELEMENT_TYPES = new Set(['JSXElement', 'JSXFragment']);\n\n//? JSX nodes are not part of eslint's estree typings; the parser supplies them\n//? at runtime. Describe only what this rule reads.\ninterface NodeShape {\n type: string;\n parent?: NodeShape | null;\n}\n\ninterface TextNodeShape extends NodeShape {\n value: unknown;\n raw?: string;\n}\n\nconst asRuleNode = (node: object): Rule.Node => node as Rule.Node;\n\n//? `'a' + b + 'c'` — climb out of the concatenation so its pieces are judged\n//? by where the whole expression sits.\nconst parentSkippingConcatenation = (node: NodeShape): NodeShape | null => {\n let current = node;\n while (current.parent?.type === 'BinaryExpression') current = current.parent;\n return current.parent ?? null;\n};\n\n//? A text child: either directly inside an element/fragment, or the\n//? expression of a `{…}` that is itself a child (not an attribute value).\nconst isChildPosition = (node: NodeShape): boolean => {\n const parent = parentSkippingConcatenation(node);\n if (!parent) return false;\n if (ELEMENT_TYPES.has(parent.type)) return true;\n return parent.type === 'JSXExpressionContainer' && ELEMENT_TYPES.has(parent.parent?.type ?? '');\n};\n\nconst rule: EslintRule = {\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Disallow untranslated text in JSX. User-facing text goes through the project translator.',\n },\n messages: {\n untranslated:\n 'Untranslated text in JSX: \"{{text}}\". Put user-facing text through the project translator (`useTranslator`) so every language gets it.',\n },\n schema: [\n {\n type: 'object',\n properties: {\n allowedStrings: { type: 'array', items: { type: 'string' }, uniqueItems: true },\n },\n additionalProperties: false,\n },\n ],\n },\n create(context) {\n const options = (context.options[0] ?? {}) as { allowedStrings?: readonly string[] };\n const allowed = new Set((options.allowedStrings ?? DEFAULT_ALLOWED_JSX_STRINGS).map((s) => s.trim()));\n\n const isAllowedText = (node: TextNodeShape): boolean => {\n if (typeof node.value !== 'string' || WHITESPACE_ONLY.test(node.value) || node.value === '') return true;\n return allowed.has(node.value.trim()) || (node.raw !== undefined && allowed.has(node.raw.trim()));\n };\n\n const report = (node: NodeShape): void => {\n const ruleNode = asRuleNode(node);\n context.report({\n node: ruleNode,\n messageId: 'untranslated',\n data: { text: context.sourceCode.getText(ruleNode).trim() },\n });\n };\n\n const listener: Rule.RuleListener = {\n JSXText(rawNode: unknown): void {\n const node = rawNode as TextNodeShape;\n if (!isAllowedText(node) && isChildPosition(node)) report(node);\n },\n Literal(rawNode: unknown): void {\n const node = rawNode as TextNodeShape;\n if (!isAllowedText(node) && isChildPosition(node)) report(node);\n },\n TemplateLiteral(rawNode: unknown): void {\n const node = rawNode as NodeShape;\n const parent = parentSkippingConcatenation(node);\n if (parent?.type === 'JSXExpressionContainer' && parent.parent?.type === 'JSXElement') report(node);\n },\n };\n return listener;\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 noLocalSocketEnumeration from './rules/no-local-socket-enumeration.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 noUntranslatedJsxText from './rules/no-untranslated-jsx-text.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 'no-local-socket-enumeration': noLocalSocketEnumeration,\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 'no-untranslated-jsx-text': noUntranslatedJsxText,\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 // Local Socket.io maps (`.adapter.rooms`, iterating `io.sockets.sockets`) only see one instance.\n 'luckystack/no-local-socket-enumeration': hasCore || 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 //? User-facing text goes through the translator (AGENTS.md rule 13).\n 'luckystack/no-untranslated-jsx-text': '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","rule","SUSPECT_PARAM_NAMES","SKIP_KEYS","rule","asRuleNode","rule","rule","rule","rule"]}
@@ -0,0 +1,4 @@
1
+ import type { EslintRule } from '../internal/ruleTypes.js';
2
+ export declare const DEFAULT_ALLOWED_JSX_STRINGS: readonly string[];
3
+ declare const rule: EslintRule;
4
+ export default rule;
package/dist/index.js CHANGED
@@ -51,7 +51,7 @@ import {
51
51
  tryCatchSync,
52
52
  validatePagePath,
53
53
  waitForSocket
54
- } from "./chunk-5FXBTGYL.js";
54
+ } from "./chunk-XDX5MV54.js";
55
55
  import {
56
56
  getDeployConfig,
57
57
  getPortOverride,
@@ -98,7 +98,7 @@ import {
98
98
  startSpan,
99
99
  startSpanAcrossTrackers,
100
100
  startSpanHandle
101
- } from "./chunk-IJYNVM2W.js";
101
+ } from "./chunk-P3SSLA3E.js";
102
102
  import {
103
103
  DEFAULT_PROJECT_CONFIG,
104
104
  createRegistry,