@sidebase/base-config 0.1.0 → 0.2.1
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 +106 -22
- package/dist/config.d.mts +70 -55
- package/dist/config.d.ts +70 -55
- package/dist/config.mjs +8 -2
- package/dist/eslint/index.d.mts +3 -6
- package/dist/eslint/index.d.ts +3 -6
- package/dist/eslint/index.mjs +25 -56
- package/dist/prisma/index.d.mts +12 -32
- package/dist/prisma/index.d.ts +12 -32
- package/dist/shared/{base-config.CuUhyvQo.d.mts → base-config.BoberVUk.d.mts} +4 -8
- package/dist/shared/{base-config.CuUhyvQo.d.ts → base-config.BoberVUk.d.ts} +4 -8
- package/docs/migration.md +76 -15
- package/package.json +13 -11
- package/presets/base/AGENTS.md +9 -0
- package/presets/base/dockerignore +11 -3
- package/presets/base/github/workflows/streamctl-upgrade.yml +13 -23
- package/presets/base/gitignore +6 -5
- package/presets/base/oxlintrc.json +4 -2
- package/presets/base/pnpm-workspace.yaml +9 -16
- package/presets/base/preset.json +8 -2
- package/presets/base/vscode/settings.json +7 -1
- package/presets/config.template.ts +4 -3
- package/presets/manifest.json +1 -1
- package/presets/nuxt-app/Dockerfile +16 -21
- package/presets/nuxt-app/github/workflows/ci.yml +8 -6
- package/presets/nuxt-app/github/workflows/pr-preview-cleanup.yml +12 -12
- package/presets/nuxt-app/preset.json +5 -1
- package/presets/nuxt-app/templates/ci/e2e-job.yml +5 -5
- package/presets/nuxt-app/templates/ci/test-job.yml +3 -0
package/dist/config.mjs
CHANGED
|
@@ -6,7 +6,8 @@ function knobKeys(shape) {
|
|
|
6
6
|
}
|
|
7
7
|
const NUXT_BASE_CI_KEYS = knobKeys({
|
|
8
8
|
unitTests: 0,
|
|
9
|
-
e2e: 0
|
|
9
|
+
e2e: 0,
|
|
10
|
+
aptPackages: 0
|
|
10
11
|
});
|
|
11
12
|
const NUXT_BASE_VERSIONS_KEYS = knobKeys({
|
|
12
13
|
node: 0,
|
|
@@ -19,6 +20,7 @@ const NUXT_BASE_DOCKER_KEYS = knobKeys({
|
|
|
19
20
|
buildSteps: 0,
|
|
20
21
|
finalStage: 0,
|
|
21
22
|
prismaRuntime: 0,
|
|
23
|
+
prismaVersion: 0,
|
|
22
24
|
startCommand: 0
|
|
23
25
|
});
|
|
24
26
|
const NUXT_BASE_AUTOMATION_KEYS = knobKeys({
|
|
@@ -30,6 +32,9 @@ const NUXT_BASE_SECURITY_KEYS = knobKeys({
|
|
|
30
32
|
const NUXT_BASE_PNPM_KEYS = knobKeys({
|
|
31
33
|
onlyBuiltDependencies: 0
|
|
32
34
|
});
|
|
35
|
+
const NUXT_BASE_EDITOR_KEYS = knobKeys({
|
|
36
|
+
i18nSourceLanguage: 0
|
|
37
|
+
});
|
|
33
38
|
const NUXT_BASE_TOP_LEVEL_KNOBS = knobKeys({
|
|
34
39
|
eslint: 0
|
|
35
40
|
});
|
|
@@ -40,7 +45,8 @@ const NUXT_BASE_CONFIG_KEYS = [
|
|
|
40
45
|
...NUXT_BASE_AUTOMATION_KEYS.map((key) => `automation.${key}`),
|
|
41
46
|
...NUXT_BASE_SECURITY_KEYS.map((key) => `security.${key}`),
|
|
42
47
|
...NUXT_BASE_PNPM_KEYS.map((key) => `pnpm.${key}`),
|
|
48
|
+
...NUXT_BASE_EDITOR_KEYS.map((key) => `editor.${key}`),
|
|
43
49
|
...NUXT_BASE_TOP_LEVEL_KNOBS
|
|
44
50
|
];
|
|
45
51
|
|
|
46
|
-
export { NUXT_BASE_AUTOMATION_KEYS, NUXT_BASE_CI_KEYS, NUXT_BASE_CONFIG_KEYS, NUXT_BASE_DOCKER_KEYS, NUXT_BASE_PNPM_KEYS, NUXT_BASE_SECURITY_KEYS, NUXT_BASE_VERSIONS_KEYS, defineNuxtBaseConfig };
|
|
52
|
+
export { NUXT_BASE_AUTOMATION_KEYS, NUXT_BASE_CI_KEYS, NUXT_BASE_CONFIG_KEYS, NUXT_BASE_DOCKER_KEYS, NUXT_BASE_EDITOR_KEYS, NUXT_BASE_PNPM_KEYS, NUXT_BASE_SECURITY_KEYS, NUXT_BASE_VERSIONS_KEYS, defineNuxtBaseConfig };
|
package/dist/eslint/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as CreateSidebaseEslintOptions } from '../shared/base-config.
|
|
2
|
-
export { E as ESLINT_OPTION_KEYS } from '../shared/base-config.
|
|
1
|
+
import { C as CreateSidebaseEslintOptions } from '../shared/base-config.BoberVUk.mjs';
|
|
2
|
+
export { E as ESLINT_OPTION_KEYS } from '../shared/base-config.BoberVUk.mjs';
|
|
3
3
|
import antfu, { TypedFlatConfigItem } from '@antfu/eslint-config';
|
|
4
4
|
|
|
5
5
|
/** {@link CreateSidebaseEslintOptions} with all defaults applied + the computed type-aware gate. */
|
|
@@ -20,10 +20,7 @@ interface ResolvedEslintOptions {
|
|
|
20
20
|
testFilePattern: string[];
|
|
21
21
|
typeAware: boolean;
|
|
22
22
|
}
|
|
23
|
-
/**
|
|
24
|
-
* Whether type-aware linting is on: gated behind `LINT_TYPEAWARE=true` so the
|
|
25
|
-
* slower type-aware pass stays opt-in (CI/local override).
|
|
26
|
-
*/
|
|
23
|
+
/** Type-aware linting is gated behind `LINT_TYPEAWARE=true` because it is slow. */
|
|
27
24
|
declare function isTypeAware(): boolean;
|
|
28
25
|
/** Apply the documented option defaults and resolve the type-aware gate. */
|
|
29
26
|
declare function resolveEslintOptions(options?: CreateSidebaseEslintOptions): ResolvedEslintOptions;
|
package/dist/eslint/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as CreateSidebaseEslintOptions } from '../shared/base-config.
|
|
2
|
-
export { E as ESLINT_OPTION_KEYS } from '../shared/base-config.
|
|
1
|
+
import { C as CreateSidebaseEslintOptions } from '../shared/base-config.BoberVUk.js';
|
|
2
|
+
export { E as ESLINT_OPTION_KEYS } from '../shared/base-config.BoberVUk.js';
|
|
3
3
|
import antfu, { TypedFlatConfigItem } from '@antfu/eslint-config';
|
|
4
4
|
|
|
5
5
|
/** {@link CreateSidebaseEslintOptions} with all defaults applied + the computed type-aware gate. */
|
|
@@ -20,10 +20,7 @@ interface ResolvedEslintOptions {
|
|
|
20
20
|
testFilePattern: string[];
|
|
21
21
|
typeAware: boolean;
|
|
22
22
|
}
|
|
23
|
-
/**
|
|
24
|
-
* Whether type-aware linting is on: gated behind `LINT_TYPEAWARE=true` so the
|
|
25
|
-
* slower type-aware pass stays opt-in (CI/local override).
|
|
26
|
-
*/
|
|
23
|
+
/** Type-aware linting is gated behind `LINT_TYPEAWARE=true` because it is slow. */
|
|
27
24
|
declare function isTypeAware(): boolean;
|
|
28
25
|
/** Apply the documented option defaults and resolve the type-aware gate. */
|
|
29
26
|
declare function resolveEslintOptions(options?: CreateSidebaseEslintOptions): ResolvedEslintOptions;
|
package/dist/eslint/index.mjs
CHANGED
|
@@ -107,30 +107,27 @@ function buildEslintLayers(options) {
|
|
|
107
107
|
imports: "always-multiline"
|
|
108
108
|
}],
|
|
109
109
|
"space-infix-ops": ["error"],
|
|
110
|
-
// `node/prefer-global/process` is
|
|
111
|
-
// eslint-plugin-n
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
// `
|
|
115
|
-
// is registered (see the comment there). The `no-restricted-properties`
|
|
116
|
-
// process.env ban below carries the real guard.
|
|
110
|
+
// `node/prefer-global/process` is deliberately not set here: antfu registers
|
|
111
|
+
// eslint-plugin-n only inside its own files-scoped object, so setting the rule in
|
|
112
|
+
// this plugin-less layer makes ESLint 10 abort. It is neutralized via
|
|
113
|
+
// `.override("antfu/node/rules")` in `createSidebaseEslint` instead. The
|
|
114
|
+
// `no-restricted-properties` process.env ban below carries the real guard.
|
|
117
115
|
"no-unused-expressions": ["error"],
|
|
118
116
|
"no-param-reassign": ["error"],
|
|
119
117
|
"no-fallthrough": ["error"],
|
|
120
118
|
"require-await": ["error"],
|
|
121
119
|
"ts/no-non-null-assertion": ["error"],
|
|
122
|
-
// antfu leaves `ts/no-explicit-any` off
|
|
123
|
-
// shipped `AGENTS.md` ban on `any`. Breaking for consumers
|
|
120
|
+
// antfu leaves `ts/no-explicit-any` off. This baseline enforces it, matching the
|
|
121
|
+
// shipped `AGENTS.md` ban on `any`. Breaking for consumers on adoption.
|
|
124
122
|
"ts/no-explicit-any": "error",
|
|
125
123
|
// Type-aware rules antfu enables that this baseline turns off.
|
|
126
124
|
"ts/no-misused-promises": "off",
|
|
127
125
|
"ts/no-unsafe-call": "off",
|
|
128
126
|
"ts/strict-boolean-expressions": "off",
|
|
129
127
|
"ts/promise-function-async": "off",
|
|
130
|
-
// Newer antfu rules outside the
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
// default; a repo can opt back in via `.append()`.
|
|
128
|
+
// Newer antfu rules outside the house baseline. `prefer-static-regex` is a perf
|
|
129
|
+
// nudge the apps never adopted, and `custom-event-name-casing` is wrong for
|
|
130
|
+
// naive-ui's kebab `update:*` v-model events. Opt back in via `.append()`.
|
|
134
131
|
"e18e/prefer-static-regex": "off",
|
|
135
132
|
"vue/custom-event-name-casing": "off"
|
|
136
133
|
}
|
|
@@ -141,17 +138,14 @@ function buildEslintLayers(options) {
|
|
|
141
138
|
});
|
|
142
139
|
configs.push({
|
|
143
140
|
name: "sidebase/console",
|
|
144
|
-
// Source files only
|
|
145
|
-
//
|
|
146
|
-
// README/doc examples. This carve-out leaves real `.ts`/`.vue`/... enforcement intact.
|
|
141
|
+
// Source files only. antfu's markdown processor lints fenced code blocks as virtual
|
|
142
|
+
// `*.md/*` files, so an un-scoped `no-console` fires inside doc examples.
|
|
147
143
|
ignores: ["**/*.md/**"],
|
|
148
144
|
rules: {
|
|
149
|
-
// Always pass an explicit options object
|
|
150
|
-
//
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
// allow-list was normalized to `"error"` in resolveEslintOptions, so the
|
|
154
|
-
// array branch here is always a non-empty allow-list (no cast needed).
|
|
145
|
+
// Always pass an explicit options object, or a severity-only override retains
|
|
146
|
+
// antfu's `{ allow: ["warn", "error"] }`. A hard ban emits `{}`, since no-console
|
|
147
|
+
// rejects an empty `allow` array. `resolveEslintOptions` already normalized an
|
|
148
|
+
// empty allow-list to `"error"`, so the array branch is always non-empty.
|
|
155
149
|
"no-console": options.console === "error" ? ["error", {}] : ["error", { allow: options.console }]
|
|
156
150
|
}
|
|
157
151
|
});
|
|
@@ -229,48 +223,23 @@ function createSidebaseEslint(options = {}) {
|
|
|
229
223
|
return antfu(
|
|
230
224
|
{
|
|
231
225
|
type: "app",
|
|
232
|
-
//
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
// Org house style: 2-space indent, single quotes, Vue on,
|
|
236
|
-
// JSON/YAML linting off (handled elsewhere).
|
|
226
|
+
// Personal scratch space. Root-anchored so `src/path/local.ts` stays linted.
|
|
227
|
+
ignores: ["local.*", "local.*/**", "prisma/local.*", "prisma/local.*/**"],
|
|
228
|
+
// House style. JSON and YAML linting are handled elsewhere.
|
|
237
229
|
stylistic: { indent: 2, quotes: "single" },
|
|
238
230
|
vue: true,
|
|
239
231
|
jsonc: false,
|
|
240
232
|
yaml: false,
|
|
241
|
-
//
|
|
242
|
-
//
|
|
233
|
+
// Gated behind `LINT_TYPEAWARE`. When on, point at the repo tsconfig and
|
|
234
|
+
// exclude the configured paths from the type-aware program.
|
|
243
235
|
typescript: resolved.typeAware ? { tsconfigPath: "tsconfig.json", ignoresTypeAware: resolved.ignoresTypeAware } : true
|
|
244
236
|
},
|
|
245
237
|
...buildEslintLayers(resolved)
|
|
246
238
|
).override("antfu/node/rules", {
|
|
247
|
-
// antfu
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
//
|
|
251
|
-
// resolution. Neutralize it HERE, inside antfu's own node-scoped config where the
|
|
252
|
-
// `node` plugin IS registered; setting it in a plugin-less object makes ESLint 10
|
|
253
|
-
// abort. `"off"`, not `["error", "always"]`, because `"always"` would wrongly flag
|
|
254
|
-
// the generated Prisma client's `import * as process from 'node:process'`.
|
|
255
|
-
//
|
|
256
|
-
// Note what this does NOT mean. prefer-global is not merely redundant here:
|
|
257
|
-
// `["error", "always"]` would also close a real hole, because
|
|
258
|
-
// `no-restricted-properties` keys on the `process.env` MEMBER EXPRESSION, and any
|
|
259
|
-
// import that renames the binding erases the shape it matches. Measured against
|
|
260
|
-
// this factory, the property ban alone catches `process.env.X`,
|
|
261
|
-
// `const { env } = process`, and a default import still named `process`, but NOT
|
|
262
|
-
// `import { env }`, `import { env as e }`, `import * as proc`, or
|
|
263
|
-
// `import proc from "node:process"`. Those are closed at the import site instead,
|
|
264
|
-
// by the `node:process` / `process` entries in `paths` (see `importRestrictions` in
|
|
265
|
-
// rules.ts): narrower than flipping prefer-global, and free of the Prisma-client
|
|
266
|
-
// false positive.
|
|
267
|
-
//
|
|
268
|
-
// With `importNames: ["env", "default"]` that is now the COMPLETE set, not a sample.
|
|
269
|
-
// Every way to reach `process.env` is covered by one rule or the other: the member
|
|
270
|
-
// expression and an un-renamed default import at the USAGE site, and the named,
|
|
271
|
-
// renamed-named, namespace and renamed-default imports at the IMPORT site. The
|
|
272
|
-
// un-renamed default being caught at the usage site rather than by the import ban is
|
|
273
|
-
// the asymmetry that hid the renamed-default hole for two rounds of review.
|
|
239
|
+
// antfu's `"never"` default flags every legitimate global `process` use. Neutralize
|
|
240
|
+
// it here, inside antfu's node-scoped config: a plugin-less object aborts ESLint 10.
|
|
241
|
+
// `"off"` and not `"always"`, which would flag the generated Prisma client. The
|
|
242
|
+
// `process.env` hole is covered at the import site by `importRestrictions`.
|
|
274
243
|
rules: { "node/prefer-global/process": "off" }
|
|
275
244
|
});
|
|
276
245
|
}
|
package/dist/prisma/index.d.mts
CHANGED
|
@@ -6,27 +6,12 @@ interface SchemaEngineDatasource {
|
|
|
6
6
|
shadowDatabaseUrl?: string;
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
|
-
* Seed the
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* reads `env("DATABASE_URL")` / `env("DIRECT_DATABASE_URL")` would fail at rest.
|
|
9
|
+
* Seed the Prisma connection env vars with localhost dev defaults when unset.
|
|
10
|
+
* Deliberately mutates `env`: once a `prisma.config.ts` exists Prisma stops auto-loading
|
|
11
|
+
* `.env`, so a schema reading `env("DATABASE_URL")` would fail at rest.
|
|
13
12
|
*
|
|
14
|
-
* Call it
|
|
15
|
-
*
|
|
16
|
-
* the seeded env and derives its direct-connection + shadow datasource.
|
|
17
|
-
*
|
|
18
|
-
* TWO paths, not one:
|
|
19
|
-
* - **Bare, or an explicit `DIRECT_DATABASE_URL`.** Seeds all three. Defaults:
|
|
20
|
-
* direct = local postgres, pooled = direct + `pgbouncer=1`, shadow = direct with a
|
|
21
|
-
* `/prisma-shadow` database.
|
|
22
|
-
* - **A real `DATABASE_URL` and no direct URL.** Seeds ONLY `DIRECT_DATABASE_URL`,
|
|
23
|
-
* derived from the pooled URL, and returns early. No shadow is seeded on purpose:
|
|
24
|
-
* deriving one would name a `/prisma-shadow` database on the production host, which
|
|
25
|
-
* Prisma CREATEs and DROPs.
|
|
26
|
-
*
|
|
27
|
-
* An empty-string value counts as unset throughout; `docker-compose` produces `""` for an
|
|
28
|
-
* undefined variable, and treating it as present is how the localhost default used to
|
|
29
|
-
* reach production.
|
|
13
|
+
* Call it after `import "dotenv/config"`. A real value always wins, and an empty string
|
|
14
|
+
* counts as unset.
|
|
30
15
|
*/
|
|
31
16
|
declare function applyPrismaDevEnv(env?: Record<string, string | undefined>): void;
|
|
32
17
|
/**
|
|
@@ -35,13 +20,12 @@ declare function applyPrismaDevEnv(env?: Record<string, string | undefined>): vo
|
|
|
35
20
|
*/
|
|
36
21
|
declare function stripPgbouncerParams(url: string): string;
|
|
37
22
|
/**
|
|
38
|
-
* Resolve the schema engine's datasource
|
|
39
|
-
* - direct URL = `DIRECT_DATABASE_URL`, else `DATABASE_URL` with
|
|
40
|
-
* - shadow DB = `SHADOW_DATABASE_URL` when present
|
|
23
|
+
* Resolve the schema engine's datasource:
|
|
24
|
+
* - direct URL = `DIRECT_DATABASE_URL`, else `DATABASE_URL` with pooler params stripped
|
|
25
|
+
* - shadow DB = `SHADOW_DATABASE_URL` when present
|
|
41
26
|
*
|
|
42
|
-
* Returns `undefined` when neither
|
|
43
|
-
*
|
|
44
|
-
* `prisma generate` without a database).
|
|
27
|
+
* Returns `undefined` when neither is set, so the config falls back to the schema's own
|
|
28
|
+
* `datasource` block, e.g. during `prisma generate` without a database.
|
|
45
29
|
*/
|
|
46
30
|
declare function resolveSchemaEngineDatasource(env: Record<string, string | undefined>): SchemaEngineDatasource | undefined;
|
|
47
31
|
|
|
@@ -54,8 +38,8 @@ interface BuildPrismaConfigOptions {
|
|
|
54
38
|
typedSql?: boolean;
|
|
55
39
|
}
|
|
56
40
|
/**
|
|
57
|
-
* Build the shared `@sidebase` Prisma config
|
|
58
|
-
*
|
|
41
|
+
* Build the shared `@sidebase` Prisma config. Gives the schema engine a pooler-free
|
|
42
|
+
* direct connection. Prisma 7's config shape is not covered.
|
|
59
43
|
*
|
|
60
44
|
* ```ts
|
|
61
45
|
* // prisma.config.ts
|
|
@@ -63,10 +47,6 @@ interface BuildPrismaConfigOptions {
|
|
|
63
47
|
* import { buildPrismaConfig } from "@sidebase/base-config/prisma";
|
|
64
48
|
* export default defineConfig(buildPrismaConfig({ views: true, typedSql: true }));
|
|
65
49
|
* ```
|
|
66
|
-
*
|
|
67
|
-
* Reads `DATABASE_URL` / `DIRECT_DATABASE_URL` / `SHADOW_DATABASE_URL` (the
|
|
68
|
-
* schema engine gets a pgbouncer-free direct connection). Prisma 7's changed
|
|
69
|
-
* config shape is out of scope for v1.
|
|
70
50
|
*/
|
|
71
51
|
declare function buildPrismaConfig(options?: BuildPrismaConfigOptions, env?: Record<string, string | undefined>): PrismaConfig;
|
|
72
52
|
|
package/dist/prisma/index.d.ts
CHANGED
|
@@ -6,27 +6,12 @@ interface SchemaEngineDatasource {
|
|
|
6
6
|
shadowDatabaseUrl?: string;
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
|
-
* Seed the
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* reads `env("DATABASE_URL")` / `env("DIRECT_DATABASE_URL")` would fail at rest.
|
|
9
|
+
* Seed the Prisma connection env vars with localhost dev defaults when unset.
|
|
10
|
+
* Deliberately mutates `env`: once a `prisma.config.ts` exists Prisma stops auto-loading
|
|
11
|
+
* `.env`, so a schema reading `env("DATABASE_URL")` would fail at rest.
|
|
13
12
|
*
|
|
14
|
-
* Call it
|
|
15
|
-
*
|
|
16
|
-
* the seeded env and derives its direct-connection + shadow datasource.
|
|
17
|
-
*
|
|
18
|
-
* TWO paths, not one:
|
|
19
|
-
* - **Bare, or an explicit `DIRECT_DATABASE_URL`.** Seeds all three. Defaults:
|
|
20
|
-
* direct = local postgres, pooled = direct + `pgbouncer=1`, shadow = direct with a
|
|
21
|
-
* `/prisma-shadow` database.
|
|
22
|
-
* - **A real `DATABASE_URL` and no direct URL.** Seeds ONLY `DIRECT_DATABASE_URL`,
|
|
23
|
-
* derived from the pooled URL, and returns early. No shadow is seeded on purpose:
|
|
24
|
-
* deriving one would name a `/prisma-shadow` database on the production host, which
|
|
25
|
-
* Prisma CREATEs and DROPs.
|
|
26
|
-
*
|
|
27
|
-
* An empty-string value counts as unset throughout; `docker-compose` produces `""` for an
|
|
28
|
-
* undefined variable, and treating it as present is how the localhost default used to
|
|
29
|
-
* reach production.
|
|
13
|
+
* Call it after `import "dotenv/config"`. A real value always wins, and an empty string
|
|
14
|
+
* counts as unset.
|
|
30
15
|
*/
|
|
31
16
|
declare function applyPrismaDevEnv(env?: Record<string, string | undefined>): void;
|
|
32
17
|
/**
|
|
@@ -35,13 +20,12 @@ declare function applyPrismaDevEnv(env?: Record<string, string | undefined>): vo
|
|
|
35
20
|
*/
|
|
36
21
|
declare function stripPgbouncerParams(url: string): string;
|
|
37
22
|
/**
|
|
38
|
-
* Resolve the schema engine's datasource
|
|
39
|
-
* - direct URL = `DIRECT_DATABASE_URL`, else `DATABASE_URL` with
|
|
40
|
-
* - shadow DB = `SHADOW_DATABASE_URL` when present
|
|
23
|
+
* Resolve the schema engine's datasource:
|
|
24
|
+
* - direct URL = `DIRECT_DATABASE_URL`, else `DATABASE_URL` with pooler params stripped
|
|
25
|
+
* - shadow DB = `SHADOW_DATABASE_URL` when present
|
|
41
26
|
*
|
|
42
|
-
* Returns `undefined` when neither
|
|
43
|
-
*
|
|
44
|
-
* `prisma generate` without a database).
|
|
27
|
+
* Returns `undefined` when neither is set, so the config falls back to the schema's own
|
|
28
|
+
* `datasource` block, e.g. during `prisma generate` without a database.
|
|
45
29
|
*/
|
|
46
30
|
declare function resolveSchemaEngineDatasource(env: Record<string, string | undefined>): SchemaEngineDatasource | undefined;
|
|
47
31
|
|
|
@@ -54,8 +38,8 @@ interface BuildPrismaConfigOptions {
|
|
|
54
38
|
typedSql?: boolean;
|
|
55
39
|
}
|
|
56
40
|
/**
|
|
57
|
-
* Build the shared `@sidebase` Prisma config
|
|
58
|
-
*
|
|
41
|
+
* Build the shared `@sidebase` Prisma config. Gives the schema engine a pooler-free
|
|
42
|
+
* direct connection. Prisma 7's config shape is not covered.
|
|
59
43
|
*
|
|
60
44
|
* ```ts
|
|
61
45
|
* // prisma.config.ts
|
|
@@ -63,10 +47,6 @@ interface BuildPrismaConfigOptions {
|
|
|
63
47
|
* import { buildPrismaConfig } from "@sidebase/base-config/prisma";
|
|
64
48
|
* export default defineConfig(buildPrismaConfig({ views: true, typedSql: true }));
|
|
65
49
|
* ```
|
|
66
|
-
*
|
|
67
|
-
* Reads `DATABASE_URL` / `DIRECT_DATABASE_URL` / `SHADOW_DATABASE_URL` (the
|
|
68
|
-
* schema engine gets a pgbouncer-free direct connection). Prisma 7's changed
|
|
69
|
-
* config shape is out of scope for v1.
|
|
70
50
|
*/
|
|
71
51
|
declare function buildPrismaConfig(options?: BuildPrismaConfigOptions, env?: Record<string, string | undefined>): PrismaConfig;
|
|
72
52
|
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Options for the published ESLint factory (`@sidebase/base-config/eslint`).
|
|
3
|
-
* Covers the per-repo variance found across the consuming repos.
|
|
4
|
-
*/
|
|
1
|
+
/** Options for the published ESLint factory (`@sidebase/base-config/eslint`). */
|
|
5
2
|
interface CreateSidebaseEslintOptions {
|
|
6
3
|
/** Zod `.extend()/.merge()/.passthrough()` bans and/or `import * as z` enforcement. Default `"none"` (opt-in). */
|
|
7
4
|
zod?: "full" | "import-style" | "none";
|
|
@@ -36,10 +33,9 @@ interface CreateSidebaseEslintOptions {
|
|
|
36
33
|
testFilePattern?: string[];
|
|
37
34
|
}
|
|
38
35
|
/**
|
|
39
|
-
* Runtime list of every {@link CreateSidebaseEslintOptions} key
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* the key is listed here too, so the validator allow-list can never drift.
|
|
36
|
+
* Runtime list of every {@link CreateSidebaseEslintOptions} key. The `satisfies` map
|
|
37
|
+
* keeps it exhaustive: a new option fails to compile until it is listed here, so the
|
|
38
|
+
* validator allow-list cannot drift.
|
|
43
39
|
*/
|
|
44
40
|
declare const ESLINT_OPTION_KEYS: string[];
|
|
45
41
|
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Options for the published ESLint factory (`@sidebase/base-config/eslint`).
|
|
3
|
-
* Covers the per-repo variance found across the consuming repos.
|
|
4
|
-
*/
|
|
1
|
+
/** Options for the published ESLint factory (`@sidebase/base-config/eslint`). */
|
|
5
2
|
interface CreateSidebaseEslintOptions {
|
|
6
3
|
/** Zod `.extend()/.merge()/.passthrough()` bans and/or `import * as z` enforcement. Default `"none"` (opt-in). */
|
|
7
4
|
zod?: "full" | "import-style" | "none";
|
|
@@ -36,10 +33,9 @@ interface CreateSidebaseEslintOptions {
|
|
|
36
33
|
testFilePattern?: string[];
|
|
37
34
|
}
|
|
38
35
|
/**
|
|
39
|
-
* Runtime list of every {@link CreateSidebaseEslintOptions} key
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* the key is listed here too, so the validator allow-list can never drift.
|
|
36
|
+
* Runtime list of every {@link CreateSidebaseEslintOptions} key. The `satisfies` map
|
|
37
|
+
* keeps it exhaustive: a new option fails to compile until it is listed here, so the
|
|
38
|
+
* validator allow-list cannot drift.
|
|
43
39
|
*/
|
|
44
40
|
declare const ESLINT_OPTION_KEYS: string[];
|
|
45
41
|
|
package/docs/migration.md
CHANGED
|
@@ -35,11 +35,12 @@ order, so the second one is the binding constraint:
|
|
|
35
35
|
The widening came after the guard, so **a build containing the widening also contains the
|
|
36
36
|
guard, and the widening is the effective minimum.** Requiring it is sufficient.
|
|
37
37
|
|
|
38
|
-
> **Minimum version: `0.
|
|
39
|
-
>
|
|
40
|
-
> `
|
|
41
|
-
>
|
|
42
|
-
>
|
|
38
|
+
> **Minimum version: `0.3.0`.**
|
|
39
|
+
> The binding constraint is the payload manifest's `schemaVersion: 3` (the
|
|
40
|
+
> `PRISMA_VERSION_DEFAULT` placeholder uses `fromDependency`, a schema-3 feature): a 0.2.x
|
|
41
|
+
> CLI rejects the whole payload with `SCHEMA_UNSUPPORTED` ("Upgrade the CLI or the
|
|
42
|
+
> payload"). 0.2.0's own prerequisites (both above, plus reading `streamctl.config.ts`
|
|
43
|
+
> from the repo root) are of course included.
|
|
43
44
|
|
|
44
45
|
### Verify your CLI has both, without needing the version number
|
|
45
46
|
|
|
@@ -170,7 +171,7 @@ harder to tell which change caused what.
|
|
|
170
171
|
Do this BEFORE touching the config.
|
|
171
172
|
|
|
172
173
|
```sh
|
|
173
|
-
pnpm add -D @sidebase/streamctl@^0.
|
|
174
|
+
pnpm add -D @sidebase/streamctl@^0.3.0
|
|
174
175
|
```
|
|
175
176
|
|
|
176
177
|
### 3. Swap the payload package
|
|
@@ -333,10 +334,10 @@ the managed file and is reverted on the next sync.
|
|
|
333
334
|
warns you. `streamctl check` stays green, the file looks deliberate, and a package whose
|
|
334
335
|
install scripts are blocked still installs.
|
|
335
336
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
337
|
+
The consequence is narrower than it first appears. The usual suspects (`sharp`,
|
|
338
|
+
`@tailwindcss/oxide`, `unrs-resolver`, `@parcel/watcher`) ship their native binary as a
|
|
339
|
+
prebuilt optional dependency, so on a platform with a prebuild they keep working whether or
|
|
340
|
+
not they are approved, cold install included. Verified across pnpm
|
|
340
341
|
10.28.1, 10.29.1 and 10.29.3. Where the loss is real:
|
|
341
342
|
|
|
342
343
|
- architectures with no prebuild, where the binary genuinely has to be compiled
|
|
@@ -356,14 +357,13 @@ pnpm install
|
|
|
356
357
|
migrating from `@sidestream-tech/nuxt-config` it reports something like:
|
|
357
358
|
|
|
358
359
|
```
|
|
359
|
-
[!] adoption (
|
|
360
|
+
[!] adoption (3) pre-existing file(s) streamctl now manages
|
|
360
361
|
tsconfig.json - pre-existing file streamctl now manages; adopting is expected
|
|
361
|
-
.dockerignore - pre-existing file streamctl now manages; adopting is expected
|
|
362
362
|
pnpm-workspace.yaml - pre-existing file streamctl now manages; adopting is expected
|
|
363
363
|
Dockerfile - pre-existing file streamctl now manages; adopting is expected
|
|
364
364
|
-> `sync --interactive` to adopt per file, `sync --force` to take ownership, or `--only <glob>` to scope
|
|
365
365
|
|
|
366
|
-
|
|
366
|
+
3 conflict(s) pending; see the per-kind guidance above.
|
|
367
367
|
```
|
|
368
368
|
|
|
369
369
|
This is not a failure and it is not something to route around. A fully-managed file whose
|
|
@@ -539,6 +539,67 @@ strategy only inspects its own markers, and the block is present and correct; an
|
|
|
539
539
|
outside it is invisible to the check. That is why this is a manual step rather than
|
|
540
540
|
something drift detection reports.
|
|
541
541
|
|
|
542
|
+
### 8b. Reconcile `.dockerignore` by hand
|
|
543
|
+
|
|
544
|
+
**Same cause as step 8, and equally not migration-specific.** `.dockerignore` is block-managed
|
|
545
|
+
too, so on first sync the payload appends its block to whatever your repository already had.
|
|
546
|
+
Your existing lines stay above it. Nothing is overwritten and nothing is reported.
|
|
547
|
+
|
|
548
|
+
Most of the leftovers are harmless. Ignore patterns are additive, so a duplicated `node_modules`
|
|
549
|
+
or `.env` above the block is inert; it changes nothing about what the build context carries.
|
|
550
|
+
Delete them anyway, and not for tidiness. The detector below is the only thing that will ever
|
|
551
|
+
tell you a payload entry has started shadowing something of yours, and it is not a one-shot
|
|
552
|
+
check. A future payload version can add an entry that collides with a line you kept above the
|
|
553
|
+
block. A file with leftover duplicates reads `AFFECTED` forever, so it can no longer distinguish
|
|
554
|
+
that from the noise. Clearing them keeps the check able to answer next time.
|
|
555
|
+
|
|
556
|
+
**The case that bites is a negation.** `.dockerignore` is last-match-wins, and the managed block
|
|
557
|
+
is appended at the BOTTOM, so every payload entry beats anything you wrote above it. A repository
|
|
558
|
+
that deliberately un-ignored something now silently loses that:
|
|
559
|
+
|
|
560
|
+
```
|
|
561
|
+
!tests <- yours, above the block. Now dead.
|
|
562
|
+
|
|
563
|
+
# BEGIN streamctl MANAGED BLOCK dockerignore
|
|
564
|
+
...
|
|
565
|
+
tests <- payload's, below yours. Wins.
|
|
566
|
+
# END streamctl MANAGED BLOCK dockerignore
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
The build context stops carrying `tests/`, and the failure surfaces later and somewhere else --
|
|
570
|
+
as a `COPY` that lands nothing, or an in-image test run that cannot find its fixtures. The build
|
|
571
|
+
itself succeeds.
|
|
572
|
+
|
|
573
|
+
Check what sits above the block:
|
|
574
|
+
|
|
575
|
+
```sh
|
|
576
|
+
awk '/# BEGIN streamctl MANAGED BLOCK dockerignore/{exit} {print}' .dockerignore \
|
|
577
|
+
| command grep -qv '^[[:space:]]*\(#.*\)\?$' && echo AFFECTED || echo clean
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
As in step 8, use `command grep` -- the detector reads its exit code as its entire answer, and a
|
|
581
|
+
wrapped `grep` can report `clean` on an affected file.
|
|
582
|
+
|
|
583
|
+
`AFFECTED` does not mean something broke; it means read those lines and decide. Anything you
|
|
584
|
+
actually need, and every negation without exception, moves **below** the `# END` marker, which is
|
|
585
|
+
the supported extension point:
|
|
586
|
+
|
|
587
|
+
```
|
|
588
|
+
# END streamctl MANAGED BLOCK dockerignore
|
|
589
|
+
|
|
590
|
+
!tests
|
|
591
|
+
my-project-specific-dir
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
Finish by re-running the `AFFECTED`/`clean` detector above; it only says `clean` once nothing but
|
|
595
|
+
comments and blank lines is left above the block, so clear the harmless duplicates out too rather
|
|
596
|
+
than keeping a detector that can never go green.
|
|
597
|
+
|
|
598
|
+
**`streamctl check` will never flag any of this.** Block drift detection inspects only the marker
|
|
599
|
+
region, so the block is present and correct and the check exits 0 while your dead negation sits
|
|
600
|
+
three lines above it, permanently. This is the one step here that no tooling will ever remind you
|
|
601
|
+
to do.
|
|
602
|
+
|
|
542
603
|
### 9. Clean up what the payload no longer manages
|
|
543
604
|
|
|
544
605
|
Two different kinds of leftover, with the same cause: streamctl manages by path, so
|
|
@@ -760,5 +821,5 @@ keeps its own command this way.
|
|
|
760
821
|
|
|
761
822
|
Nothing here is destructive if you work on a branch. `sync` rewrites tracked files, so
|
|
762
823
|
`git diff` shows everything it did and `git restore` undoes it. Keep the migration on its
|
|
763
|
-
own branch and its own commit so that if the sync diff turns out to be larger than
|
|
764
|
-
expected, reverting it is one operation
|
|
824
|
+
own branch and its own commit, so that if the sync diff turns out to be larger than
|
|
825
|
+
expected, reverting it is one operation.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sidebase/base-config",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
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",
|
|
@@ -52,6 +52,16 @@
|
|
|
52
52
|
"engines": {
|
|
53
53
|
"node": ">=22"
|
|
54
54
|
},
|
|
55
|
+
"packageManager": "pnpm@10.29.1",
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "unbuild",
|
|
58
|
+
"typecheck": "tsc --noEmit -p tsconfig.json && tsc -p tsconfig.test.json",
|
|
59
|
+
"test": "vitest run",
|
|
60
|
+
"lint": "eslint .",
|
|
61
|
+
"validate:presets": "node scripts/validate-presets.mjs",
|
|
62
|
+
"e2e:dry-run": "pnpm build && node scripts/e2e-dry-run.mjs",
|
|
63
|
+
"prepack": "pnpm build"
|
|
64
|
+
},
|
|
55
65
|
"dependencies": {
|
|
56
66
|
"@antfu/eslint-config": "^7.4",
|
|
57
67
|
"ufo": "^1.6.4"
|
|
@@ -72,7 +82,7 @@
|
|
|
72
82
|
"devDependencies": {
|
|
73
83
|
"@arethetypeswrong/cli": "^0.18.5",
|
|
74
84
|
"@prisma/client": "^6.19.3",
|
|
75
|
-
"@sidebase/streamctl": "^0.
|
|
85
|
+
"@sidebase/streamctl": "^0.3.0",
|
|
76
86
|
"@types/node": "^24.0.0",
|
|
77
87
|
"eslint": "^10.5.0",
|
|
78
88
|
"jiti": "^2.7.0",
|
|
@@ -82,13 +92,5 @@
|
|
|
82
92
|
"unbuild": "^3.5.0",
|
|
83
93
|
"vitest": "^3.0.0",
|
|
84
94
|
"yaml": "^2.9.0"
|
|
85
|
-
},
|
|
86
|
-
"scripts": {
|
|
87
|
-
"build": "unbuild",
|
|
88
|
-
"typecheck": "tsc --noEmit -p tsconfig.json && tsc -p tsconfig.test.json",
|
|
89
|
-
"test": "vitest run",
|
|
90
|
-
"lint": "eslint .",
|
|
91
|
-
"validate:presets": "node scripts/validate-presets.mjs",
|
|
92
|
-
"e2e:dry-run": "pnpm build && node scripts/e2e-dry-run.mjs"
|
|
93
95
|
}
|
|
94
|
-
}
|
|
96
|
+
}
|
package/presets/base/AGENTS.md
CHANGED
|
@@ -10,6 +10,15 @@ follow. They are the same across every repo in the fleet.
|
|
|
10
10
|
- Never commit secrets, credentials, or generated build artifacts.
|
|
11
11
|
- Keep all code, comments and identifiers in English.
|
|
12
12
|
|
|
13
|
+
## Comments & wording
|
|
14
|
+
|
|
15
|
+
- Keep comments short. Say WHY the code is the way it is, not what it plainly does.
|
|
16
|
+
- ASCII only: no em dash, en dash, arrow, ellipsis, curly quote, or emoji.
|
|
17
|
+
- One idea per sentence. Cut filler openers ("It is worth noting") and inflated words
|
|
18
|
+
("leverage", "utilize", "robust", "seamless").
|
|
19
|
+
- Do not leave a comment describing an alternative you rejected, or internal ticket
|
|
20
|
+
shorthand a reader cannot resolve.
|
|
21
|
+
|
|
13
22
|
## Types & correctness
|
|
14
23
|
|
|
15
24
|
- Use precise types; avoid `any` and unchecked casts. Parse and validate external input at the boundary instead of trusting it downstream.
|
|
@@ -6,13 +6,21 @@ npm-debug*
|
|
|
6
6
|
.output
|
|
7
7
|
.data
|
|
8
8
|
dist
|
|
9
|
+
test
|
|
9
10
|
tests
|
|
10
11
|
*.log
|
|
11
12
|
.env
|
|
12
13
|
.env.*
|
|
13
14
|
!.env.example
|
|
14
|
-
# The build
|
|
15
|
-
#
|
|
16
|
-
# is intentionally allowed through.
|
|
15
|
+
# The build stage globs `.npmrc*`, so keep token-bearing backups like
|
|
16
|
+
# `.npmrc.local` out of the build context. `.npmrc` itself is allowed through.
|
|
17
17
|
.npmrc.*
|
|
18
18
|
.DS_Store
|
|
19
|
+
# Local dev state from `pnpm db` or `docker compose up`. `prisma/pglite-data` is
|
|
20
|
+
# tens of MB, and root-owned `prisma/local.postgres_data` fails a rootless build.
|
|
21
|
+
# Root-anchored so `src/path/local.ts` still reaches the build context.
|
|
22
|
+
prisma/client
|
|
23
|
+
prisma/pglite-data
|
|
24
|
+
pgliteHealthz
|
|
25
|
+
local.*
|
|
26
|
+
prisma/local.*
|