eslint-plugin-supabase-services-layer 1.0.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 Stephentraiforos
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.
package/README.md ADDED
@@ -0,0 +1,316 @@
1
+ # eslint-plugin-supabase-services-layer
2
+
3
+ ESLint plugin to enforce services layer architecture pattern in Supabase projects by restricting direct Supabase client imports to configured service directories.
4
+
5
+ ## Why This Plugin?
6
+
7
+ In Supabase projects using Next.js (or other frameworks), it's a best practice to encapsulate database access and business logic in a services layer. This plugin enforces that pattern by preventing direct imports of Supabase clients outside of designated service directories.
8
+
9
+ **Benefits:**
10
+ - Centralized business logic
11
+ - Easier testing and mocking
12
+ - Consistent error handling
13
+ - Clear separation of concerns
14
+ - Better code organization
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install eslint-plugin-supabase-services-layer --save-dev
20
+ # or
21
+ pnpm add -D eslint-plugin-supabase-services-layer
22
+ # or
23
+ yarn add -D eslint-plugin-supabase-services-layer
24
+ ```
25
+
26
+ ## Configuration
27
+
28
+ Add the plugin to your ESLint configuration:
29
+
30
+ ### Flat Config (eslint.config.js)
31
+
32
+ ```javascript
33
+ import supabaseServicesLayer from 'eslint-plugin-supabase-services-layer';
34
+
35
+ export default [
36
+ {
37
+ plugins: {
38
+ 'supabase-services-layer': supabaseServicesLayer,
39
+ },
40
+ rules: {
41
+ 'supabase-services-layer/no-direct-supabase-import': [
42
+ 'error',
43
+ {
44
+ allowedPaths: ['lib/services/**', 'supabase/functions/_shared/**'],
45
+ restrictedImports: ['@/lib/supabase/*', '**/supabase-client'],
46
+ },
47
+ ],
48
+ },
49
+ },
50
+ ];
51
+ ```
52
+
53
+ ### Legacy Config (.eslintrc.js)
54
+
55
+ ```javascript
56
+ module.exports = {
57
+ plugins: ['supabase-services-layer'],
58
+ rules: {
59
+ 'supabase-services-layer/no-direct-supabase-import': [
60
+ 'error',
61
+ {
62
+ allowedPaths: ['lib/services/**', 'supabase/functions/_shared/**'],
63
+ restrictedImports: ['@/lib/supabase/*', '**/supabase-client'],
64
+ },
65
+ ],
66
+ },
67
+ };
68
+ ```
69
+
70
+ ## Rule Options
71
+
72
+ ### `allowedPaths` (array of glob patterns)
73
+
74
+ Default: `['lib/services/**', 'src/services/**', 'supabase/functions/_shared/**']`
75
+
76
+ Glob patterns for directories where Supabase client imports are allowed.
77
+
78
+ **Examples:**
79
+ ```javascript
80
+ allowedPaths: [
81
+ 'lib/services/**', // Allow in lib/services/ and subdirectories
82
+ 'src/db/**', // Allow in src/db/ and subdirectories
83
+ 'supabase/functions/_shared/**', // Allow edge function services
84
+ ]
85
+ ```
86
+
87
+ ### `restrictedImports` (array of glob patterns)
88
+
89
+ Default: `['@/lib/supabase/*', '**/supabase-client']`
90
+
91
+ Import patterns to restrict. Supports glob patterns.
92
+
93
+ **Examples:**
94
+ ```javascript
95
+ restrictedImports: [
96
+ '@/lib/supabase/*', // Restricts @/lib/supabase/server, client, middleware
97
+ '**/supabase-client', // Restricts relative imports to supabase-client files
98
+ '@supabase/supabase-js', // Restricts direct @supabase/supabase-js imports
99
+ ]
100
+ ```
101
+
102
+ ### `errorMessage` (string)
103
+
104
+ Default: `"Supabase client imports are only allowed in services layer. Use service classes instead."`
105
+
106
+ Custom error message to display when violations are found.
107
+
108
+ ## Examples
109
+
110
+ ### ❌ Incorrect - Direct Import in API Route
111
+
112
+ ```typescript
113
+ // app/api/assessments/route.ts
114
+ import { createClient } from '@/lib/supabase/server'; // ❌ ESLint Error
115
+
116
+ export async function GET() {
117
+ const supabase = await createClient();
118
+ const { data } = await supabase.from('assessments').select('*');
119
+ return Response.json(data);
120
+ }
121
+ ```
122
+
123
+ ### ✅ Correct - Using Service Factory
124
+
125
+ ```typescript
126
+ // app/api/assessments/route.ts
127
+ import { createAssessmentService } from '@/lib/services/server'; // ✅ OK
128
+
129
+ export async function GET() {
130
+ const assessmentService = await createAssessmentService();
131
+ const assessments = await assessmentService.listAssessments();
132
+ return Response.json(assessments);
133
+ }
134
+ ```
135
+
136
+ ### ❌ Incorrect - Direct Import in Edge Function
137
+
138
+ ```typescript
139
+ // supabase/functions/worker/index.ts
140
+ import { createClient } from '../_shared/supabase-client'; // ❌ ESLint Error
141
+
142
+ Deno.serve(async (req) => {
143
+ const supabase = createClient();
144
+ const { data } = await supabase.from('queue').select('*');
145
+ // ...
146
+ });
147
+ ```
148
+
149
+ ### ✅ Correct - Using Edge Function Service
150
+
151
+ ```typescript
152
+ // supabase/functions/worker/index.ts
153
+ import { QueueService } from '../_shared/queue-service'; // ✅ OK
154
+
155
+ Deno.serve(async (req) => {
156
+ const queueService = new QueueService(this.supabaseFactory);
157
+ const jobs = await queueService.getPendingJobs();
158
+ // ...
159
+ });
160
+ ```
161
+
162
+ ### ✅ Allowed - Import in Service File
163
+
164
+ ```typescript
165
+ // lib/services/server/assessment-service.ts
166
+ import { createClient } from '@/lib/supabase/server'; // ✅ OK - in allowed path
167
+
168
+ export async function createAssessmentService() {
169
+ const supabase = await createClient();
170
+ return {
171
+ async listAssessments() {
172
+ const { data } = await supabase.from('assessments').select('*');
173
+ return data;
174
+ },
175
+ };
176
+ }
177
+ ```
178
+
179
+ ## Common Project Structures
180
+
181
+ ### Next.js with App Router
182
+
183
+ ```javascript
184
+ // eslint.config.js
185
+ export default [
186
+ {
187
+ rules: {
188
+ 'supabase-services-layer/no-direct-supabase-import': [
189
+ 'error',
190
+ {
191
+ allowedPaths: [
192
+ 'lib/services/**',
193
+ 'supabase/functions/_shared/**',
194
+ ],
195
+ restrictedImports: [
196
+ '@/lib/supabase/*',
197
+ '**/supabase-client',
198
+ ],
199
+ },
200
+ ],
201
+ },
202
+ },
203
+ ];
204
+ ```
205
+
206
+ ### Monorepo with Multiple Packages
207
+
208
+ ```javascript
209
+ // eslint.config.js
210
+ export default [
211
+ {
212
+ rules: {
213
+ 'supabase-services-layer/no-direct-supabase-import': [
214
+ 'error',
215
+ {
216
+ allowedPaths: [
217
+ 'packages/api/src/services/**',
218
+ 'packages/shared/src/db/**',
219
+ ],
220
+ restrictedImports: [
221
+ '@my-org/supabase/*',
222
+ '~/lib/supabase/*',
223
+ ],
224
+ },
225
+ ],
226
+ },
227
+ },
228
+ ];
229
+ ```
230
+
231
+ ### Custom Services Directory
232
+
233
+ ```javascript
234
+ // eslint.config.js
235
+ export default [
236
+ {
237
+ rules: {
238
+ 'supabase-services-layer/no-direct-supabase-import': [
239
+ 'error',
240
+ {
241
+ allowedPaths: ['src/data-access/**', 'src/api/services/**'],
242
+ restrictedImports: ['~/supabase-clients/*'],
243
+ },
244
+ ],
245
+ },
246
+ },
247
+ ];
248
+ ```
249
+
250
+ ## Troubleshooting
251
+
252
+ ### False Positives in Allowed Paths
253
+
254
+ If you're getting errors in files that should be allowed:
255
+
256
+ 1. Check your glob patterns match the file path
257
+ 2. Use `**` to match subdirectories: `lib/services/**`
258
+ 3. Verify the path separator matches your OS (use `/` for cross-platform)
259
+
260
+ ```javascript
261
+ // ❌ Wrong - won't match subdirectories
262
+ allowedPaths: ['lib/services']
263
+
264
+ // ✅ Correct - matches all subdirectories
265
+ allowedPaths: ['lib/services/**']
266
+ ```
267
+
268
+ ### Need to Temporarily Disable
269
+
270
+ If you need to temporarily allow a violation (not recommended):
271
+
272
+ ```typescript
273
+ // eslint-disable-next-line supabase-services-layer/no-direct-supabase-import
274
+ import { createClient } from '@/lib/supabase/server';
275
+ ```
276
+
277
+ Better approach: Create a service method instead!
278
+
279
+ ### Pattern Not Matching
280
+
281
+ If your custom patterns aren't working:
282
+
283
+ 1. Ensure patterns use forward slashes: `src/services/**`
284
+ 2. Use `*` for single-level matching: `*.ts`
285
+ 3. Use `**` for multi-level matching: `lib/**`
286
+ 4. Test patterns with [minimatch](https://github.com/isaacs/minimatch#testing)
287
+
288
+ ## Migration Guide
289
+
290
+ If you're adding this plugin to an existing codebase:
291
+
292
+ 1. Install the plugin
293
+ 2. Run ESLint to find all violations
294
+ 3. Create service classes for common operations
295
+ 4. Refactor code to use services
296
+ 5. Re-run ESLint to verify
297
+
298
+ **Common refactoring patterns:**
299
+
300
+ - API Routes → Use factory functions from `lib/services/server`
301
+ - Edge Functions → Use service classes with `ISupabaseClientFactory`
302
+ - Components → Use client services from `lib/services/client`
303
+
304
+ ## License
305
+
306
+ MIT
307
+
308
+ ## Contributing
309
+
310
+ Contributions welcome! Please open an issue or PR.
311
+
312
+ ## Related
313
+
314
+ - [Supabase Documentation](https://supabase.com/docs)
315
+ - [Next.js App Router](https://nextjs.org/docs/app)
316
+ - [ESLint Plugin Documentation](https://eslint.org/docs/latest/extend/plugins)
@@ -0,0 +1,23 @@
1
+ /**
2
+ * ESLint plugin to enforce services layer architecture in Supabase projects
3
+ */
4
+ declare const plugin: {
5
+ meta: {
6
+ name: string;
7
+ version: string;
8
+ };
9
+ rules: {
10
+ 'no-direct-supabase-import': import("eslint").Rule.RuleModule;
11
+ };
12
+ configs: {
13
+ recommended: {
14
+ plugins: string[];
15
+ rules: {
16
+ 'supabase-services-layer/no-direct-supabase-import': string;
17
+ };
18
+ };
19
+ };
20
+ };
21
+ export default plugin;
22
+ export type { RuleOptions } from './rules/no-direct-supabase-import';
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;CAgBX,CAAC;AAEF,eAAe,MAAM,CAAC;AAGtB,YAAY,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const no_direct_supabase_import_1 = __importDefault(require("./rules/no-direct-supabase-import"));
7
+ /**
8
+ * ESLint plugin to enforce services layer architecture in Supabase projects
9
+ */
10
+ const plugin = {
11
+ meta: {
12
+ name: 'eslint-plugin-supabase-services-layer',
13
+ version: '1.0.0',
14
+ },
15
+ rules: {
16
+ 'no-direct-supabase-import': no_direct_supabase_import_1.default,
17
+ },
18
+ configs: {
19
+ recommended: {
20
+ plugins: ['supabase-services-layer'],
21
+ rules: {
22
+ 'supabase-services-layer/no-direct-supabase-import': 'error',
23
+ },
24
+ },
25
+ },
26
+ };
27
+ exports.default = plugin;
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAAA,kGAAuE;AAEvE;;GAEG;AACH,MAAM,MAAM,GAAG;IACb,IAAI,EAAE;QACJ,IAAI,EAAE,uCAAuC;QAC7C,OAAO,EAAE,OAAO;KACjB;IACD,KAAK,EAAE;QACL,2BAA2B,EAAE,mCAAsB;KACpD;IACD,OAAO,EAAE;QACP,WAAW,EAAE;YACX,OAAO,EAAE,CAAC,yBAAyB,CAAC;YACpC,KAAK,EAAE;gBACL,mDAAmD,EAAE,OAAO;aAC7D;SACF;KACF;CACF,CAAC;AAEF,kBAAe,MAAM,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { Rule } from 'eslint';
2
+ /**
3
+ * Rule configuration options
4
+ */
5
+ export interface RuleOptions {
6
+ /**
7
+ * Glob patterns for paths where Supabase client imports are allowed
8
+ * @default ["lib/services/**", "src/services/**", "supabase/functions/_shared/**"]
9
+ */
10
+ allowedPaths?: string[];
11
+ /**
12
+ * Import patterns to restrict (supports glob patterns)
13
+ * @default - See DEFAULT_RESTRICTED_PATTERNS in source
14
+ */
15
+ restrictedImports?: string[];
16
+ /**
17
+ * Custom error message
18
+ * @default "Supabase client imports are only allowed in services layer. Use service classes instead."
19
+ */
20
+ errorMessage?: string;
21
+ }
22
+ /**
23
+ * ESLint rule to enforce services layer architecture
24
+ * Prevents direct Supabase client imports outside configured service directories
25
+ */
26
+ declare const rule: Rule.RuleModule;
27
+ export default rule;
28
+ //# sourceMappingURL=no-direct-supabase-import.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-direct-supabase-import.d.ts","sourceRoot":"","sources":["../../src/rules/no-direct-supabase-import.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAG9B;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAExB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE7B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAgBD;;;GAGG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UAuFhB,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const minimatch_1 = require("minimatch");
4
+ const DEFAULT_ALLOWED_PATTERNS = [
5
+ 'lib/services/**',
6
+ 'src/services/**',
7
+ 'supabase/functions/_shared/**',
8
+ ];
9
+ const DEFAULT_RESTRICTED_PATTERNS = [
10
+ '@/lib/supabase/*',
11
+ '**/supabase-client',
12
+ ];
13
+ const DEFAULT_ERROR_MESSAGE = 'Supabase client imports are only allowed in services layer. Use service classes instead.';
14
+ /**
15
+ * ESLint rule to enforce services layer architecture
16
+ * Prevents direct Supabase client imports outside configured service directories
17
+ */
18
+ const rule = {
19
+ meta: {
20
+ type: 'problem',
21
+ docs: {
22
+ description: 'Restrict Supabase client imports to services layer only to enforce layered architecture',
23
+ recommended: true,
24
+ },
25
+ messages: {
26
+ restrictedImport: '{{errorMessage}}',
27
+ },
28
+ schema: [
29
+ {
30
+ type: 'object',
31
+ properties: {
32
+ allowedPaths: {
33
+ type: 'array',
34
+ items: {
35
+ type: 'string',
36
+ },
37
+ },
38
+ restrictedImports: {
39
+ type: 'array',
40
+ items: {
41
+ type: 'string',
42
+ },
43
+ },
44
+ errorMessage: {
45
+ type: 'string',
46
+ },
47
+ },
48
+ additionalProperties: false,
49
+ },
50
+ ],
51
+ },
52
+ create(context) {
53
+ const options = context.options[0] || {};
54
+ const ruleOptions = {
55
+ allowedPaths: options.allowedPaths || DEFAULT_ALLOWED_PATTERNS,
56
+ restrictedImports: options.restrictedImports || DEFAULT_RESTRICTED_PATTERNS,
57
+ errorMessage: options.errorMessage || DEFAULT_ERROR_MESSAGE,
58
+ };
59
+ const filename = context.filename;
60
+ // If no filename provided (e.g., in RuleTester), check if test case
61
+ // RuleTester passes test cases with filename in the test object
62
+ if (!filename) {
63
+ // For RuleTester without explicit filename, allow the check
64
+ // This handles edge cases in testing
65
+ return {};
66
+ }
67
+ // Check if current file is in an allowed path
68
+ const isAllowedPath = ruleOptions.allowedPaths.some((pattern) => {
69
+ const matcher = new minimatch_1.Minimatch(pattern, { dot: true });
70
+ return matcher.match(filename);
71
+ });
72
+ // Skip checking if file is in allowed path
73
+ if (isAllowedPath) {
74
+ return {};
75
+ }
76
+ return {
77
+ ImportDeclaration(node) {
78
+ const importPath = String(node.source.value);
79
+ // Check if import matches any restricted pattern
80
+ const isRestricted = ruleOptions.restrictedImports.some((pattern) => {
81
+ const matcher = new minimatch_1.Minimatch(pattern);
82
+ return matcher.match(importPath);
83
+ });
84
+ if (isRestricted) {
85
+ context.report({
86
+ node,
87
+ messageId: 'restrictedImport',
88
+ data: {
89
+ errorMessage: ruleOptions.errorMessage,
90
+ },
91
+ });
92
+ }
93
+ },
94
+ };
95
+ },
96
+ };
97
+ exports.default = rule;
98
+ //# sourceMappingURL=no-direct-supabase-import.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-direct-supabase-import.js","sourceRoot":"","sources":["../../src/rules/no-direct-supabase-import.ts"],"names":[],"mappings":";;AACA,yCAAsC;AAyBtC,MAAM,wBAAwB,GAAG;IAC/B,iBAAiB;IACjB,iBAAiB;IACjB,+BAA+B;CAChC,CAAC;AAEF,MAAM,2BAA2B,GAAG;IAClC,kBAAkB;IAClB,oBAAoB;CACrB,CAAC;AAEF,MAAM,qBAAqB,GACzB,0FAA0F,CAAC;AAE7F;;;GAGG;AACH,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,yFAAyF;YAC3F,WAAW,EAAE,IAAI;SAClB;QACD,QAAQ,EAAE;YACR,gBAAgB,EAAE,kBAAkB;SACrC;QACD,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,YAAY,EAAE;wBACZ,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE;4BACL,IAAI,EAAE,QAAQ;yBACf;qBACF;oBACD,iBAAiB,EAAE;wBACjB,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE;4BACL,IAAI,EAAE,QAAQ;yBACf;qBACF;oBACD,YAAY,EAAE;wBACZ,IAAI,EAAE,QAAQ;qBACf;iBACF;gBACD,oBAAoB,EAAE,KAAK;aAC5B;SACF;KACF;IAED,MAAM,CAAC,OAAO;QACZ,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACzC,MAAM,WAAW,GAAgB;YAC/B,YAAY,EAAE,OAAO,CAAC,YAAY,IAAI,wBAAwB;YAC9D,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,IAAI,2BAA2B;YAC3E,YAAY,EAAE,OAAO,CAAC,YAAY,IAAI,qBAAqB;SAC5D,CAAC;QAEF,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QAElC,oEAAoE;QACpE,gEAAgE;QAChE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,4DAA4D;YAC5D,qCAAqC;YACrC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,8CAA8C;QAC9C,MAAM,aAAa,GAAG,WAAW,CAAC,YAAa,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;YAC/D,MAAM,OAAO,GAAG,IAAI,qBAAS,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;YACtD,OAAO,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,2CAA2C;QAC3C,IAAI,aAAa,EAAE,CAAC;YAClB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,OAAO;YACL,iBAAiB,CAAC,IAAI;gBACpB,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAE7C,iDAAiD;gBACjD,MAAM,YAAY,GAAG,WAAW,CAAC,iBAAkB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;oBACnE,MAAM,OAAO,GAAG,IAAI,qBAAS,CAAC,OAAO,CAAC,CAAC;oBACvC,OAAO,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;gBACnC,CAAC,CAAC,CAAC;gBAEH,IAAI,YAAY,EAAE,CAAC;oBACjB,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI;wBACJ,SAAS,EAAE,kBAAkB;wBAC7B,IAAI,EAAE;4BACJ,YAAY,EAAE,WAAW,CAAC,YAAY;yBACvC;qBACF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,kBAAe,IAAI,CAAC"}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "eslint-plugin-supabase-services-layer",
3
+ "version": "1.0.0",
4
+ "description": "ESLint plugin to enforce services layer architecture pattern in Supabase projects by restricting direct Supabase client imports to configured service directories",
5
+ "keywords": [
6
+ "eslint",
7
+ "eslint-plugin",
8
+ "supabase",
9
+ "services-layer",
10
+ "architecture",
11
+ "layered-architecture",
12
+ "code-organization",
13
+ "database",
14
+ "react",
15
+ "nextjs"
16
+ ],
17
+ "homepage": "https://github.com/itz4blitz/mimir#readme",
18
+ "bugs": {
19
+ "url": "https://github.com/itz4blitz/mimir/issues"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/itz4blitz/mimir.git",
24
+ "directory": "packages/eslint-plugin-supabase-services-layer"
25
+ },
26
+ "license": "MIT",
27
+ "author": "Stephentraiforos",
28
+ "main": "dist/index.js",
29
+ "types": "dist/index.d.ts",
30
+ "files": [
31
+ "dist",
32
+ "README.md",
33
+ "LICENSE"
34
+ ],
35
+ "peerDependencies": {
36
+ "eslint": ">=9"
37
+ },
38
+ "dependencies": {
39
+ "minimatch": "^10.0.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/minimatch": "^5.1.2",
43
+ "@typescript-eslint/parser": "^8.55.0",
44
+ "@typescript-eslint/rule-tester": "^8.55.0",
45
+ "typescript": "^5",
46
+ "vitest": "^4.0.14"
47
+ },
48
+ "engines": {
49
+ "node": ">=18.0.0"
50
+ },
51
+ "scripts": {
52
+ "build": "tsc",
53
+ "dev": "tsc --watch",
54
+ "test": "vitest run",
55
+ "test:watch": "vitest",
56
+ "test:coverage": "vitest run --coverage",
57
+ "lint": "eslint . --config ../../eslint.config.cjs"
58
+ }
59
+ }