@hyperfixation/eslint-config 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Graham Lutz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,31 @@
1
+ import type { Linter } from "eslint";
2
+ /**
3
+ * The four bans follow from the run model: a run crosses a deploy by restarting, never by
4
+ * carrying a workflow across an `applicationVersion` boundary. `patch`/`deprecatePatch` would
5
+ * run new code against another version's checkpoints; `recv`/`send`/`getEvent`/`setEvent` park
6
+ * a workflow in a wait no drain can bound; `sendInTransaction` writes to a DBOS row that may
7
+ * have been garbage-collected, discarding a committed decision.
8
+ */
9
+ export declare const BANNED_DBOS_PROPERTIES: readonly ["patch", "deprecatePatch", "recv", "send", "getEvent", "setEvent"];
10
+ /** Matched on the member name, so an instance `dbosClient.sendInTransaction(…)` is caught too. */
11
+ export declare const BANNED_MEMBER = "sendInTransaction";
12
+ /**
13
+ * A package's `exports` map already makes these a resolver error; the lint rule is what names
14
+ * the reason at the point of the import instead of in a `tsc` stack. The plan writes the
15
+ * patterns as `src/*` and `dist/*`; they are `**` here so a nested path cannot slip through.
16
+ */
17
+ export declare const DEEP_IMPORT_PATTERNS: readonly ["@hyperfixation/*/src", "@hyperfixation/*/src/**", "@hyperfixation/*/dist", "@hyperfixation/*/dist/**"];
18
+ /**
19
+ * A hint that fails fast in the editor, **not** the enforcement: round-3 finding 3 established
20
+ * that `no-restricted-imports` only constrains the importing file, so a helper in `src/lib/`
21
+ * that imports `@/db` and is imported by a flow is lint-legal. The step pool refuses the write
22
+ * whatever file issued it; this rule just shortens the loop for the common case.
23
+ */
24
+ export declare const FLOW_RAW_HANDLE_PATHS: readonly ["@/db", "@hyperfixation/db/client", "@hyperfixation/core/records"];
25
+ /**
26
+ * The plan scopes the hint to `src/flows/**`; the glob is unanchored so it holds for an app's
27
+ * `src/flows/` and for a fixture that is not under a `src/` at all.
28
+ */
29
+ export declare const FLOW_FILES: readonly ["**/flows/**/*.ts", "**/flows/**/*.tsx"];
30
+ export declare const hyperfixation: Linter.Config[];
31
+ export default hyperfixation;
package/dist/index.js ADDED
@@ -0,0 +1,108 @@
1
+ import tseslint from "typescript-eslint";
2
+ /**
3
+ * The four bans follow from the run model: a run crosses a deploy by restarting, never by
4
+ * carrying a workflow across an `applicationVersion` boundary. `patch`/`deprecatePatch` would
5
+ * run new code against another version's checkpoints; `recv`/`send`/`getEvent`/`setEvent` park
6
+ * a workflow in a wait no drain can bound; `sendInTransaction` writes to a DBOS row that may
7
+ * have been garbage-collected, discarding a committed decision.
8
+ */
9
+ export const BANNED_DBOS_PROPERTIES = [
10
+ "patch",
11
+ "deprecatePatch",
12
+ "recv",
13
+ "send",
14
+ "getEvent",
15
+ "setEvent",
16
+ ];
17
+ /** Matched on the member name, so an instance `dbosClient.sendInTransaction(…)` is caught too. */
18
+ export const BANNED_MEMBER = "sendInTransaction";
19
+ /**
20
+ * A package's `exports` map already makes these a resolver error; the lint rule is what names
21
+ * the reason at the point of the import instead of in a `tsc` stack. The plan writes the
22
+ * patterns as `src/*` and `dist/*`; they are `**` here so a nested path cannot slip through.
23
+ */
24
+ export const DEEP_IMPORT_PATTERNS = [
25
+ "@hyperfixation/*/src",
26
+ "@hyperfixation/*/src/**",
27
+ "@hyperfixation/*/dist",
28
+ "@hyperfixation/*/dist/**",
29
+ ];
30
+ /**
31
+ * A hint that fails fast in the editor, **not** the enforcement: round-3 finding 3 established
32
+ * that `no-restricted-imports` only constrains the importing file, so a helper in `src/lib/`
33
+ * that imports `@/db` and is imported by a flow is lint-legal. The step pool refuses the write
34
+ * whatever file issued it; this rule just shortens the loop for the common case.
35
+ */
36
+ export const FLOW_RAW_HANDLE_PATHS = [
37
+ "@/db",
38
+ "@hyperfixation/db/client",
39
+ "@hyperfixation/core/records",
40
+ ];
41
+ /**
42
+ * The plan scopes the hint to `src/flows/**`; the glob is unanchored so it holds for an app's
43
+ * `src/flows/` and for a fixture that is not under a `src/` at all.
44
+ */
45
+ export const FLOW_FILES = ["**/flows/**/*.ts", "**/flows/**/*.tsx"];
46
+ const TS_FILES = ["**/*.ts", "**/*.tsx"];
47
+ const RAW_HANDLE_MESSAGE = "Flows reach the database through ctx.tx only. The step pool refuses an unfenced write anyway; this is the fast hint.";
48
+ const bans = {
49
+ name: "hyperfixation/bans",
50
+ files: TS_FILES,
51
+ languageOptions: {
52
+ parser: tseslint.parser,
53
+ parserOptions: { ecmaVersion: "latest", sourceType: "module" },
54
+ },
55
+ rules: {
56
+ "no-restricted-properties": [
57
+ "error",
58
+ ...BANNED_DBOS_PROPERTIES.map((property) => ({
59
+ object: "DBOS",
60
+ property,
61
+ message: `DBOS.${property} is banned: a run crosses a deploy by restarting, not by carrying a workflow across an applicationVersion boundary.`,
62
+ })),
63
+ ],
64
+ "no-restricted-syntax": [
65
+ "error",
66
+ {
67
+ selector: `MemberExpression[property.name="${BANNED_MEMBER}"]`,
68
+ message: `${BANNED_MEMBER} is banned: no core table has an FK to a DBOS row, and a collected workflow row would silently discard the committed decision.`,
69
+ },
70
+ ],
71
+ "no-restricted-imports": [
72
+ "error",
73
+ {
74
+ patterns: [
75
+ {
76
+ group: [...DEEP_IMPORT_PATTERNS],
77
+ message: "Import the package's public entry. A deep import reaches past the exports map, which is the contract.",
78
+ },
79
+ ],
80
+ },
81
+ ],
82
+ },
83
+ };
84
+ const flowHints = {
85
+ name: "hyperfixation/flow-raw-handle-hint",
86
+ files: [...FLOW_FILES],
87
+ rules: {
88
+ "no-restricted-imports": [
89
+ "error",
90
+ {
91
+ paths: FLOW_RAW_HANDLE_PATHS.map((name) => ({ name, message: RAW_HANDLE_MESSAGE })),
92
+ patterns: [
93
+ {
94
+ group: [...DEEP_IMPORT_PATTERNS],
95
+ message: "Import the package's public entry. A deep import reaches past the exports map, which is the contract.",
96
+ },
97
+ ],
98
+ },
99
+ ],
100
+ },
101
+ };
102
+ /** Build output is never linted; it is not source anyone can fix. */
103
+ const ignores = {
104
+ name: "hyperfixation/ignores",
105
+ ignores: ["**/dist/**", "**/node_modules/**", "**/.turbo/**"],
106
+ };
107
+ export const hyperfixation = [ignores, bans, flowHints];
108
+ export default hyperfixation;
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@hyperfixation/eslint-config",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "description": "The shared flat ESLint config: the DBOS primitive ban, the deep-import ban, and the raw-handle hint in flows",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/grahamlutz/hyperfixation-core.git",
9
+ "directory": "packages/eslint-config"
10
+ },
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "type": "module",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "!dist/**/*.test.*"
25
+ ],
26
+ "dependencies": {
27
+ "typescript-eslint": "^8.46.0"
28
+ },
29
+ "devDependencies": {
30
+ "eslint": "^10.10.0"
31
+ },
32
+ "peerDependencies": {
33
+ "eslint": "^9.0.0 || ^10.0.0"
34
+ },
35
+ "scripts": {
36
+ "build": "tsc -p tsconfig.json",
37
+ "typecheck": "tsc -p tsconfig.json --noEmit",
38
+ "lint": "eslint src",
39
+ "test": "vitest run --passWithNoTests"
40
+ }
41
+ }