@sidebase/base-config 0.3.2 → 0.3.4
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/README.md +4 -4
- package/dist/config.d.mts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/eslint/index.d.mts +6 -1
- package/dist/eslint/index.d.ts +6 -1
- package/dist/eslint/index.mjs +40 -27
- package/docs/migration.md +27 -25
- package/package.json +1 -1
- package/presets/base/preset.json +2 -2
- package/presets/nuxt-app/preset.json +4 -4
- /package/presets/base/github/workflows/{streamctl-upgrade.yml → streamctl-upgrade.yaml} +0 -0
- /package/presets/base/templates/pnpm/{only-built-dependency.yml → only-built-dependency.yaml} +0 -0
- /package/presets/nuxt-app/github/workflows/{ci.yml → ci.yaml} +0 -0
- /package/presets/nuxt-app/github/workflows/{pr-preview-cleanup.yml → pr-preview-cleanup.yaml} +0 -0
- /package/presets/nuxt-app/templates/ci/{e2e-job.yml → e2e-job.yaml} +0 -0
- /package/presets/nuxt-app/templates/ci/{test-job.yml → test-job.yaml} +0 -0
package/README.md
CHANGED
|
@@ -23,9 +23,9 @@ instead.
|
|
|
23
23
|
|
|
24
24
|
| File | Managed as | What it is |
|
|
25
25
|
| ---- | ---------- | ---------- |
|
|
26
|
-
| `.github/workflows/ci.
|
|
27
|
-
| `.github/workflows/pr-preview-cleanup.
|
|
28
|
-
| `.github/workflows/streamctl-upgrade.
|
|
26
|
+
| `.github/workflows/ci.yaml` | owned | Lint, typecheck and build, plus optional test and e2e jobs |
|
|
27
|
+
| `.github/workflows/pr-preview-cleanup.yaml` | owned | Removes the `preview-deployed` label when `preview` is removed |
|
|
28
|
+
| `.github/workflows/streamctl-upgrade.yaml` | owned, opt-in | Weekly upgrade PRs (see [Upgrades](#upgrades)) |
|
|
29
29
|
| `Dockerfile` | owned | Production image, runs `prisma migrate deploy` and then the server |
|
|
30
30
|
| `tsconfig.json` | owned | Extends the shared strict base and Nuxt's generated config |
|
|
31
31
|
| `pnpm-workspace.yaml` | owned | 7-day release cooldown and the install-script allowlist |
|
|
@@ -176,7 +176,7 @@ TypeScript config file) in your devDependencies; `sync` adds both.
|
|
|
176
176
|
| `trpcGuard` | `false` | Ban `publicProcedure` in `server/trpc/routers/**` |
|
|
177
177
|
| `prismaImportGuard` | `false` | Ban `~~/prisma/` client imports outside server code |
|
|
178
178
|
| `typeDefStyle` | `"interface"` | Prefer `interface` or `type` |
|
|
179
|
-
| `autoImportPaths` | `["utils/", "composables/", "~~/shared/types/"]` | Paths Nuxt auto-imports, so direct imports are banned |
|
|
179
|
+
| `autoImportPaths` | `["utils/", "composables/", "~~/shared/types/"]` | Paths Nuxt auto-imports, so direct imports are banned in app code. The defaults cover `app/utils`, `shared/utils`, `app/composables` and `shared/types` under every Nuxt alias. Files in the root (or `layers/*`) `server/` and `shared/` dirs and relative imports are never matched |
|
|
180
180
|
| `autoImportTypeOnly` | `[]` | Of those, paths where `import type` stays allowed |
|
|
181
181
|
| `ignoresTypeAware` | config files | Files excluded from type-aware linting |
|
|
182
182
|
| `testFilePattern` | `*.test`, `*.spec`, `*.stories` | Files where the `process.env` and auto-import bans are off |
|
package/dist/config.d.mts
CHANGED
|
@@ -25,7 +25,7 @@ interface NuxtBaseCiConfig {
|
|
|
25
25
|
aptPackages?: string[];
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
|
-
* Runtime version pins (`config.versions.*`). `node` feeds every render (`ci.
|
|
28
|
+
* Runtime version pins (`config.versions.*`). `node` feeds every render (`ci.yaml`,
|
|
29
29
|
* the Dockerfile, the upgrade workflow); `pnpm` feeds the Dockerfile only, because CI
|
|
30
30
|
* takes pnpm from `package.json#packageManager`. Defaults come from the version
|
|
31
31
|
* baseline (node 24.21.0, pnpm 10.34.5).
|
package/dist/config.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ interface NuxtBaseCiConfig {
|
|
|
25
25
|
aptPackages?: string[];
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
|
-
* Runtime version pins (`config.versions.*`). `node` feeds every render (`ci.
|
|
28
|
+
* Runtime version pins (`config.versions.*`). `node` feeds every render (`ci.yaml`,
|
|
29
29
|
* the Dockerfile, the upgrade workflow); `pnpm` feeds the Dockerfile only, because CI
|
|
30
30
|
* takes pnpm from `package.json#packageManager`. Defaults come from the version
|
|
31
31
|
* baseline (node 24.21.0, pnpm 10.34.5).
|
package/dist/eslint/index.d.mts
CHANGED
|
@@ -12,7 +12,12 @@ interface CreateSidebaseEslintOptions {
|
|
|
12
12
|
prismaImportGuard?: boolean;
|
|
13
13
|
/** `ts/consistent-type-definitions`. Default `"interface"`. */
|
|
14
14
|
typeDefStyle?: "interface" | "type";
|
|
15
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Paths banned from direct import (Nuxt auto-import). Default `["utils/", "composables/", "~~/shared/types/"]`.
|
|
17
|
+
* The defaults expand to the Nuxt 4 app-side dirs (`app/` and `shared/` utils) under every
|
|
18
|
+
* default alias. Paths starting with `~`, `@`, `#`, `/`, `./` or `../` are used as-is.
|
|
19
|
+
* Not applied to files in the root (or `layers/*`) `server/` and `shared/` dirs.
|
|
20
|
+
*/
|
|
16
21
|
autoImportPaths?: string[];
|
|
17
22
|
/**
|
|
18
23
|
* Subset of {@link autoImportPaths} where `import type { ... }` is still allowed
|
package/dist/eslint/index.d.ts
CHANGED
|
@@ -12,7 +12,12 @@ interface CreateSidebaseEslintOptions {
|
|
|
12
12
|
prismaImportGuard?: boolean;
|
|
13
13
|
/** `ts/consistent-type-definitions`. Default `"interface"`. */
|
|
14
14
|
typeDefStyle?: "interface" | "type";
|
|
15
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Paths banned from direct import (Nuxt auto-import). Default `["utils/", "composables/", "~~/shared/types/"]`.
|
|
17
|
+
* The defaults expand to the Nuxt 4 app-side dirs (`app/` and `shared/` utils) under every
|
|
18
|
+
* default alias. Paths starting with `~`, `@`, `#`, `/`, `./` or `../` are used as-is.
|
|
19
|
+
* Not applied to files in the root (or `layers/*`) `server/` and `shared/` dirs.
|
|
20
|
+
*/
|
|
16
21
|
autoImportPaths?: string[];
|
|
17
22
|
/**
|
|
18
23
|
* Subset of {@link autoImportPaths} where `import type { ... }` is still allowed
|
package/dist/eslint/index.mjs
CHANGED
|
@@ -35,6 +35,8 @@ const TRPC_ROUTERS_GLOB = "**/server/trpc/routers/**/*.{ts,js}";
|
|
|
35
35
|
const ZOD_DEPRECATED_METHODS = ["extend", "merge", "passthrough"];
|
|
36
36
|
const APP_FILES = ["**/*.{ts,vue}"];
|
|
37
37
|
const APP_IGNORES = ["**/*.d.ts"];
|
|
38
|
+
const SHARED_FILES = ["shared/**/*.{ts,vue}", "layers/*/shared/**/*.{ts,vue}"];
|
|
39
|
+
const SERVER_FILES = ["server/**/*.{ts,vue}", "layers/*/server/**/*.{ts,vue}"];
|
|
38
40
|
const PROCESS_ENV_PROPERTY = {
|
|
39
41
|
object: "process",
|
|
40
42
|
property: "env",
|
|
@@ -71,12 +73,26 @@ function zodImportStyleBans(options) {
|
|
|
71
73
|
{ selector: `ExportNamedDeclaration[source.value=${ZOD_SOURCE}][exportKind!='type'] ExportSpecifier[local.name='z'][exportKind!='type']`, message: ZOD_IMPORT_STYLE_MESSAGE }
|
|
72
74
|
];
|
|
73
75
|
}
|
|
76
|
+
const NUXT_AUTO_IMPORT_GLOBS = /* @__PURE__ */ new Map([
|
|
77
|
+
["utils", [
|
|
78
|
+
"~/utils/**",
|
|
79
|
+
"@/utils/**",
|
|
80
|
+
"~~/app/utils/**",
|
|
81
|
+
"@@/app/utils/**",
|
|
82
|
+
"~~/shared/utils/**",
|
|
83
|
+
"@@/shared/utils/**",
|
|
84
|
+
"#shared/utils/**"
|
|
85
|
+
]],
|
|
86
|
+
["composables", ["~/composables/**", "@/composables/**", "~~/app/composables/**", "@@/app/composables/**"]],
|
|
87
|
+
["~~/shared/types", ["~~/shared/types/**", "@@/shared/types/**", "#shared/types/**"]]
|
|
88
|
+
]);
|
|
89
|
+
function escapeGlob(glob) {
|
|
90
|
+
return glob.replace(/^#/, "\\#");
|
|
91
|
+
}
|
|
74
92
|
function anchoredGlobs(rawPath) {
|
|
75
93
|
const path = rawPath.replace(/\/+$/, "");
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
return [`~/${path}/**`, `~~/${path}/**`, `@/${path}/**`];
|
|
94
|
+
const [first, ...rest] = NUXT_AUTO_IMPORT_GLOBS.get(path) ?? (/^(?:[~@#/]|\.{1,2}\/)/.test(path) ? [`${path}/**`] : [`~/${path}/**`, `~~/${path}/**`, `@/${path}/**`]);
|
|
95
|
+
return [escapeGlob(first), ...rest.map(escapeGlob)];
|
|
80
96
|
}
|
|
81
97
|
function importRestrictions(options) {
|
|
82
98
|
const paths = [
|
|
@@ -150,18 +166,27 @@ function buildEslintLayers(options) {
|
|
|
150
166
|
}
|
|
151
167
|
});
|
|
152
168
|
const { paths, patterns } = importRestrictions(options);
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
169
|
+
const prismaPatterns = options.prismaImportGuard ? [{
|
|
170
|
+
group: ["~~/prisma/*", "~~/prisma/**"],
|
|
171
|
+
message: "Do not import the Prisma client on the app side. Use a server-only module."
|
|
172
|
+
}] : [];
|
|
173
|
+
const scopes = [
|
|
174
|
+
["sidebase/restricted-app", APP_FILES, [...patterns, ...prismaPatterns]],
|
|
175
|
+
["sidebase/restricted-shared", SHARED_FILES, prismaPatterns],
|
|
176
|
+
// Server code legitimately imports the Prisma client.
|
|
177
|
+
["sidebase/restricted-server", SERVER_FILES, []]
|
|
178
|
+
];
|
|
179
|
+
for (const [name, files, scopePatterns] of scopes) {
|
|
180
|
+
configs.push({
|
|
181
|
+
name,
|
|
182
|
+
files,
|
|
183
|
+
ignores: APP_IGNORES,
|
|
184
|
+
rules: {
|
|
185
|
+
"no-restricted-properties": ["error", PROCESS_ENV_PROPERTY],
|
|
186
|
+
"ts/no-restricted-imports": ["error", scopePatterns.length > 0 ? { paths, patterns: scopePatterns } : { paths }]
|
|
187
|
+
}
|
|
188
|
+
});
|
|
158
189
|
}
|
|
159
|
-
configs.push({
|
|
160
|
-
name: "sidebase/restricted-app",
|
|
161
|
-
files: APP_FILES,
|
|
162
|
-
ignores: APP_IGNORES,
|
|
163
|
-
rules: appRules
|
|
164
|
-
});
|
|
165
190
|
const zodSyntax = [...zodImportStyleBans(options), ...zodMethodBans(options)];
|
|
166
191
|
if (zodSyntax.length > 0) {
|
|
167
192
|
configs.push({
|
|
@@ -180,18 +205,6 @@ function buildEslintLayers(options) {
|
|
|
180
205
|
rules: { "no-restricted-syntax": ["error", ...zodSyntax, PUBLIC_PROCEDURE_SELECTOR] }
|
|
181
206
|
});
|
|
182
207
|
}
|
|
183
|
-
if (options.prismaImportGuard) {
|
|
184
|
-
const prismaPattern = {
|
|
185
|
-
group: ["~~/prisma/*", "~~/prisma/**"],
|
|
186
|
-
message: "Do not import the Prisma client on the app side. Use a server-only module."
|
|
187
|
-
};
|
|
188
|
-
configs.push({
|
|
189
|
-
name: "sidebase/prisma-import-guard",
|
|
190
|
-
files: APP_FILES,
|
|
191
|
-
ignores: [...APP_IGNORES, "**/server/**"],
|
|
192
|
-
rules: { "ts/no-restricted-imports": ["error", { paths, patterns: [...patterns, prismaPattern] }] }
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
208
|
if (options.testFilePattern.length > 0) {
|
|
196
209
|
configs.push({
|
|
197
210
|
name: "sidebase/test-overrides",
|
package/docs/migration.md
CHANGED
|
@@ -607,38 +607,40 @@ anything it managed under an old path or an old payload is simply dropped from t
|
|
|
607
607
|
managed set rather than removed. `check` reports clean either way, because it only
|
|
608
608
|
inspects paths that are currently managed. Nothing will ever tell you these are there.
|
|
609
609
|
|
|
610
|
-
#### 9a. The
|
|
610
|
+
#### 9a. The orphaned `.yml` workflow files
|
|
611
611
|
|
|
612
|
-
Do this only if your repository synced
|
|
613
|
-
|
|
612
|
+
Do this only if your repository synced a payload that still shipped `.yml` workflows,
|
|
613
|
+
which is the case for every adoption branch cut before this release. Check:
|
|
614
614
|
|
|
615
615
|
```sh
|
|
616
616
|
ls .github/workflows/
|
|
617
617
|
```
|
|
618
618
|
|
|
619
|
-
If you see `ci.
|
|
620
|
-
`
|
|
619
|
+
If you see `ci.yml`, `pr-preview-cleanup.yml` or `streamctl-upgrade.yml` sitting next to
|
|
620
|
+
its `.yaml` counterpart, remove the `.yml` copies:
|
|
621
621
|
|
|
622
622
|
```sh
|
|
623
|
-
git rm --ignore-unmatch .github/workflows/ci.
|
|
624
|
-
```
|
|
625
|
-
|
|
626
|
-
`--ignore-unmatch` matters: the condition above is "
|
|
627
|
-
naming a path that does not exist aborts with `fatal: pathspec ... did not match
|
|
628
|
-
and removes
|
|
629
|
-
cleanup, would skim that error and keep running both copies of the
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
copies
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
623
|
+
git rm --ignore-unmatch .github/workflows/ci.yml .github/workflows/pr-preview-cleanup.yml .github/workflows/streamctl-upgrade.yml
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
`--ignore-unmatch` matters: the condition above is "any of these files", but `git rm` is
|
|
627
|
+
atomic, so naming a path that does not exist aborts with `fatal: pathspec ... did not match
|
|
628
|
+
any files` and removes NONE. A repository that opted one workflow out, or never enabled
|
|
629
|
+
preview cleanup or upgrade PRs, would skim that error and keep running both copies of the
|
|
630
|
+
others.
|
|
631
|
+
|
|
632
|
+
This is required, not tidying. The payload renamed those managed files from `.yml` to
|
|
633
|
+
`.yaml`, so every YAML file it ships uses the same extension as `pnpm-workspace.yaml`.
|
|
634
|
+
streamctl manages files by path, so the sync in step 7 wrote the new `.yaml` files but did
|
|
635
|
+
NOT delete the old `.yml` ones: they are simply no longer in the managed set. GitHub
|
|
636
|
+
Actions runs every file in `.github/workflows/`, so if you leave them the repository runs
|
|
637
|
+
BOTH copies. That means duplicate CI on every push, two `pr-preview-cleanup` jobs racing to
|
|
638
|
+
tear down the same preview environment, and two weekly upgrade PRs. The leftover copies
|
|
639
|
+
are also frozen forever, so they never receive later fixes, including security updates to
|
|
640
|
+
pinned action SHAs.
|
|
641
|
+
|
|
642
|
+
While you are here, if your config opts out of any of these workflows by its old path, for
|
|
643
|
+
example `files: { ".github/workflows/ci.yml": "off" }`, re-key it to the `.yaml` path.
|
|
642
644
|
An opt-out naming a path that is no longer managed does nothing, so the file you meant to
|
|
643
645
|
suppress would start arriving on the next sync.
|
|
644
646
|
|
|
@@ -646,7 +648,7 @@ suppress would start arriving on the next sync.
|
|
|
646
648
|
|
|
647
649
|
The same problem in a harder-to-see form. A `block` file keeps its markers after the
|
|
648
650
|
payload stops managing that path, so the block sits there forever: never updated, never
|
|
649
|
-
reported, and indistinguishable from a block that is still live. The
|
|
651
|
+
reported, and indistinguishable from a block that is still live. The `.yml`
|
|
650
652
|
workflows above are the known orphaned FILES for this release; orphaned blocks are not
|
|
651
653
|
enumerable in advance, because they depend on which payload version your repository
|
|
652
654
|
adopted first.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sidebase/base-config",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "Shared @sidebase base configuration for Nuxt repos: ESLint / Prisma / tsconfig factories on npm, plus the streamctl file-sync preset payload",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sidebase",
|
package/presets/base/preset.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
{ "path": ".vscode/settings.json", "strategy": "merge", "source": "base/vscode/settings.json", "render": "editor", "projectFields": ["editor.fontSize", "editor.rulers", "editor.formatOnSave", "files.exclude", "search.exclude", "files.watcherExclude"] },
|
|
11
11
|
{ "path": ".vscode/extensions.json", "strategy": "merge", "source": "base/vscode/extensions.json", "projectFields": ["unwantedRecommendations"] },
|
|
12
12
|
{ "path": "AGENTS.md", "strategy": "full", "source": "base/AGENTS.md", "adoption": "expected" },
|
|
13
|
-
{ "path": ".github/workflows/streamctl-upgrade.
|
|
13
|
+
{ "path": ".github/workflows/streamctl-upgrade.yaml", "strategy": "full", "source": "base/github/workflows/streamctl-upgrade.yaml", "render": "automation-upgrade", "enabledBy": "automation.upgradePr", "adoption": "unexpected" }
|
|
14
14
|
],
|
|
15
15
|
"renders": {
|
|
16
16
|
"automation-upgrade": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"MIN_RELEASE_AGE": { "configPath": "security.minimumReleaseAge", "default": "10080", "pattern": "^\\d+$" }
|
|
33
33
|
},
|
|
34
34
|
"fragments": [
|
|
35
|
-
{ "forEach": "pnpm.onlyBuiltDependencies", "source": "base/templates/pnpm/only-built-dependency.
|
|
35
|
+
{ "forEach": "pnpm.onlyBuiltDependencies", "source": "base/templates/pnpm/only-built-dependency.yaml" }
|
|
36
36
|
]
|
|
37
37
|
}
|
|
38
38
|
},
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
{ "path": "eslint.config.ts", "strategy": "scaffold", "source": "nuxt-app/eslint.config.ts", "shadowedBy": ["eslint.config.mjs", "eslint.config.js", "eslint.config.cjs"] },
|
|
7
7
|
{ "path": "prisma.config.ts", "strategy": "scaffold", "source": "nuxt-app/prisma.config.ts" },
|
|
8
8
|
{ "path": "Dockerfile", "strategy": "full", "source": "nuxt-app/Dockerfile", "render": "dockerfile", "adoption": "expected" },
|
|
9
|
-
{ "path": ".github/workflows/pr-preview-cleanup.
|
|
10
|
-
{ "path": ".github/workflows/ci.
|
|
9
|
+
{ "path": ".github/workflows/pr-preview-cleanup.yaml", "strategy": "full", "source": "nuxt-app/github/workflows/pr-preview-cleanup.yaml", "adoption": "expected" },
|
|
10
|
+
{ "path": ".github/workflows/ci.yaml", "strategy": "full", "source": "nuxt-app/github/workflows/ci.yaml", "render": "ci" }
|
|
11
11
|
],
|
|
12
12
|
"renders": {
|
|
13
13
|
"ci": {
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
"NODE_VERSION": { "configPath": "versions.node", "default": "24.21.0", "pattern": "^[\\w.+-]+$" }
|
|
17
17
|
},
|
|
18
18
|
"fragments": [
|
|
19
|
-
{ "toggle": "ci.unitTests", "source": "nuxt-app/templates/ci/test-job.
|
|
20
|
-
{ "toggle": "ci.e2e", "source": "nuxt-app/templates/ci/e2e-job.
|
|
19
|
+
{ "toggle": "ci.unitTests", "source": "nuxt-app/templates/ci/test-job.yaml" },
|
|
20
|
+
{ "toggle": "ci.e2e", "source": "nuxt-app/templates/ci/e2e-job.yaml" }
|
|
21
21
|
]
|
|
22
22
|
},
|
|
23
23
|
"dockerfile": {
|
|
File without changes
|
/package/presets/base/templates/pnpm/{only-built-dependency.yml → only-built-dependency.yaml}
RENAMED
|
File without changes
|
|
File without changes
|
/package/presets/nuxt-app/github/workflows/{pr-preview-cleanup.yml → pr-preview-cleanup.yaml}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|