@zeyolabs/kit 2026.11.8 → 2026.11.9
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/eslint-config.js +68 -0
- package/package.json +1 -1
package/eslint-config.js
CHANGED
|
@@ -113,3 +113,71 @@ export const drizzleRules = {
|
|
|
113
113
|
'drizzle/enforce-update-with-where': ['error', { drizzleObjectName }],
|
|
114
114
|
},
|
|
115
115
|
};
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Layer boundaries (see `standards/codex`): edges (remote functions, endpoints, hooks) reach the db
|
|
119
|
+
* only through managers; services never import managers; clients and libraries import nothing
|
|
120
|
+
* above them. Files are matched by name, so features keep `manager.server.ts`,
|
|
121
|
+
* `service.server.ts` and `client.server.ts` (or a `clients/` folder) and libraries live in `utils/`.
|
|
122
|
+
*
|
|
123
|
+
* - Starts as a warning so existing code can migrate; pass `severity: 'error'` once it is clean.
|
|
124
|
+
* - A file belongs to the first group it matches, in the order edge, service, client, library, so
|
|
125
|
+
* `utils/clients/x.ts` is a client and gets only the client rules.
|
|
126
|
+
* - Flat config does not merge `no-restricted-imports` across entries. Put these rules LAST, and
|
|
127
|
+
* pass your own restricted-import patterns as `extraPatterns` (added to every group).
|
|
128
|
+
* - Matching is by import specifier, so a barrel re-export bypasses it. An app with another layout
|
|
129
|
+
* (e.g. `services/*.ts`) passes its own `globs` (which files are which layer) and `imports`
|
|
130
|
+
* (which specifiers each layer is imported by). A green lint is not proof the boundaries hold.
|
|
131
|
+
* @param {{
|
|
132
|
+
* severity?: 'error' | 'warn',
|
|
133
|
+
* globs?: { client?: string[], edge?: string[], library?: string[], service?: string[] },
|
|
134
|
+
* imports?: { client?: string[], manager?: string[], service?: string[] },
|
|
135
|
+
* extraPatterns?: { group: string[], message?: string }[],
|
|
136
|
+
* }} [options]
|
|
137
|
+
*/
|
|
138
|
+
export function layerBoundaryRules(options = {}) {
|
|
139
|
+
const severity = options.severity ?? 'warn';
|
|
140
|
+
const extra = options.extraPatterns ?? [];
|
|
141
|
+
const globs = {
|
|
142
|
+
client: ['**/client.server.ts', '**/clients/**/*.ts'],
|
|
143
|
+
edge: ['**/*.remote.ts', '**/+server.ts', '**/+page.server.ts', '**/hooks.server.ts'],
|
|
144
|
+
library: ['**/utils/**/*.ts'],
|
|
145
|
+
service: ['**/service.server.ts'],
|
|
146
|
+
...options.globs,
|
|
147
|
+
};
|
|
148
|
+
const imports = {
|
|
149
|
+
client: ['**/client.server', '**/client.server.ts', '**/clients/**'],
|
|
150
|
+
manager: ['**/manager.server', '**/manager.server.ts'],
|
|
151
|
+
service: ['**/service.server', '**/service.server.ts'],
|
|
152
|
+
...options.imports,
|
|
153
|
+
};
|
|
154
|
+
const forbid = (group, message) => ({ group, message });
|
|
155
|
+
// First match wins: each group ignores the files of the groups before it.
|
|
156
|
+
const groups = [
|
|
157
|
+
[globs.edge, [forbid(imports.service, 'Edges call managers, not services (layer boundary).')]],
|
|
158
|
+
[
|
|
159
|
+
globs.service,
|
|
160
|
+
[forbid(imports.manager, 'Services must not import managers (layer boundary).')],
|
|
161
|
+
],
|
|
162
|
+
[
|
|
163
|
+
globs.client,
|
|
164
|
+
[
|
|
165
|
+
forbid(imports.manager, 'Clients must not import managers (layer boundary).'),
|
|
166
|
+
forbid(imports.service, 'Clients must not import services (layer boundary).'),
|
|
167
|
+
],
|
|
168
|
+
],
|
|
169
|
+
[
|
|
170
|
+
globs.library,
|
|
171
|
+
[
|
|
172
|
+
forbid(imports.manager, 'Libraries must not import managers (layer boundary).'),
|
|
173
|
+
forbid(imports.service, 'Libraries must not import services (layer boundary).'),
|
|
174
|
+
forbid(imports.client, 'Libraries must not import clients (layer boundary).'),
|
|
175
|
+
],
|
|
176
|
+
],
|
|
177
|
+
];
|
|
178
|
+
return groups.map(([files, patterns], index) => ({
|
|
179
|
+
files,
|
|
180
|
+
ignores: groups.slice(0, index).flatMap(([earlier]) => earlier),
|
|
181
|
+
rules: { 'no-restricted-imports': [severity, { patterns: [...patterns, ...extra] }] },
|
|
182
|
+
}));
|
|
183
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeyolabs/kit",
|
|
3
|
-
"version": "2026.11.
|
|
3
|
+
"version": "2026.11.9",
|
|
4
4
|
"description": "Shared SvelteKit-on-Cloudflare server toolkit: remote-function wrappers, passwordless auth (magic link + passkeys), email over a send_email binding or SMTP, Cloudflare context, monitoring, storage clients, utils and the ESLint config.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|