@rexezuge/tooling 0.0.0-stage → 1.0.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/LICENSE +21 -0
- package/README.md +297 -2
- package/dist/eslint-boundaries.d.ts +75 -0
- package/dist/eslint-boundaries.d.ts.map +1 -0
- package/dist/eslint-boundaries.js +138 -0
- package/dist/eslint-boundaries.js.map +1 -0
- package/dist/eslint-rules.d.ts +41 -0
- package/dist/eslint-rules.d.ts.map +1 -0
- package/dist/eslint-rules.js +273 -0
- package/dist/eslint-rules.js.map +1 -0
- package/dist/eslint.d.ts +96 -0
- package/dist/eslint.d.ts.map +1 -0
- package/dist/eslint.js +189 -0
- package/dist/eslint.js.map +1 -0
- package/dist/functions/pages-proxy.d.ts +113 -0
- package/dist/functions/pages-proxy.d.ts.map +1 -0
- package/dist/functions/pages-proxy.js +131 -0
- package/dist/functions/pages-proxy.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/scripts/backup/d1-target.d.ts +35 -0
- package/dist/scripts/backup/d1-target.d.ts.map +1 -0
- package/dist/scripts/backup/d1-target.js +31 -0
- package/dist/scripts/backup/d1-target.js.map +1 -0
- package/dist/scripts/backup/destination-config.d.ts +61 -0
- package/dist/scripts/backup/destination-config.d.ts.map +1 -0
- package/dist/scripts/backup/destination-config.js +57 -0
- package/dist/scripts/backup/destination-config.js.map +1 -0
- package/dist/scripts/backup/encrypt-backup.d.ts +35 -0
- package/dist/scripts/backup/encrypt-backup.d.ts.map +1 -0
- package/dist/scripts/backup/encrypt-backup.js +98 -0
- package/dist/scripts/backup/encrypt-backup.js.map +1 -0
- package/dist/scripts/backup/naming.d.ts +44 -0
- package/dist/scripts/backup/naming.d.ts.map +1 -0
- package/dist/scripts/backup/naming.js +58 -0
- package/dist/scripts/backup/naming.js.map +1 -0
- package/dist/scripts/check-god-files.d.ts +164 -0
- package/dist/scripts/check-god-files.d.ts.map +1 -0
- package/dist/scripts/check-god-files.js +271 -0
- package/dist/scripts/check-god-files.js.map +1 -0
- package/dist/scripts/ensure-spa-shell-stub.d.ts +3 -0
- package/dist/scripts/ensure-spa-shell-stub.d.ts.map +1 -0
- package/dist/scripts/ensure-spa-shell-stub.js +30 -0
- package/dist/scripts/ensure-spa-shell-stub.js.map +1 -0
- package/dist/scripts/init-secrets.d.ts +63 -0
- package/dist/scripts/init-secrets.d.ts.map +1 -0
- package/dist/scripts/init-secrets.js +240 -0
- package/dist/scripts/init-secrets.js.map +1 -0
- package/dist/scripts/lib/cli-args.d.ts +78 -0
- package/dist/scripts/lib/cli-args.d.ts.map +1 -0
- package/dist/scripts/lib/cli-args.js +116 -0
- package/dist/scripts/lib/cli-args.js.map +1 -0
- package/dist/scripts/lib/github-actions.d.ts +26 -0
- package/dist/scripts/lib/github-actions.d.ts.map +1 -0
- package/dist/scripts/lib/github-actions.js +38 -0
- package/dist/scripts/lib/github-actions.js.map +1 -0
- package/dist/scripts/lib/wrangler-table.d.ts +46 -0
- package/dist/scripts/lib/wrangler-table.d.ts.map +1 -0
- package/dist/scripts/lib/wrangler-table.js +99 -0
- package/dist/scripts/lib/wrangler-table.js.map +1 -0
- package/dist/scripts/migrations-lock.d.ts +3 -0
- package/dist/scripts/migrations-lock.d.ts.map +1 -0
- package/dist/scripts/migrations-lock.js +46 -0
- package/dist/scripts/migrations-lock.js.map +1 -0
- package/dist/scripts/prepare-wrangler-config.d.ts +3 -0
- package/dist/scripts/prepare-wrangler-config.d.ts.map +1 -0
- package/dist/scripts/prepare-wrangler-config.js +50 -0
- package/dist/scripts/prepare-wrangler-config.js.map +1 -0
- package/dist/scripts/spa-shell.d.ts +41 -0
- package/dist/scripts/spa-shell.d.ts.map +1 -0
- package/dist/scripts/spa-shell.js +155 -0
- package/dist/scripts/spa-shell.js.map +1 -0
- package/dist/scripts/validate-locales.d.ts +26 -0
- package/dist/scripts/validate-locales.d.ts.map +1 -0
- package/dist/scripts/validate-locales.js +350 -0
- package/dist/scripts/validate-locales.js.map +1 -0
- package/dist/scripts/verify-migrations.d.ts +62 -0
- package/dist/scripts/verify-migrations.d.ts.map +1 -0
- package/dist/scripts/verify-migrations.js +302 -0
- package/dist/scripts/verify-migrations.js.map +1 -0
- package/dist/scripts/verify-spa-shell.d.ts +3 -0
- package/dist/scripts/verify-spa-shell.d.ts.map +1 -0
- package/dist/scripts/verify-spa-shell.js +53 -0
- package/dist/scripts/verify-spa-shell.js.map +1 -0
- package/dist/scripts/wrangler-config/cli.d.ts +22 -0
- package/dist/scripts/wrangler-config/cli.d.ts.map +1 -0
- package/dist/scripts/wrangler-config/cli.js +51 -0
- package/dist/scripts/wrangler-config/cli.js.map +1 -0
- package/dist/scripts/wrangler-config/patches.d.ts +51 -0
- package/dist/scripts/wrangler-config/patches.d.ts.map +1 -0
- package/dist/scripts/wrangler-config/patches.js +140 -0
- package/dist/scripts/wrangler-config/patches.js.map +1 -0
- package/dist/scripts/wrangler-config/resources.d.ts +70 -0
- package/dist/scripts/wrangler-config/resources.d.ts.map +1 -0
- package/dist/scripts/wrangler-config/resources.js +290 -0
- package/dist/scripts/wrangler-config/resources.js.map +1 -0
- package/dist/scripts/wrangler-config/types.d.ts +103 -0
- package/dist/scripts/wrangler-config/types.d.ts.map +1 -0
- package/dist/scripts/wrangler-config/types.js +49 -0
- package/dist/scripts/wrangler-config/types.js.map +1 -0
- package/dist/test/integration-migrations.d.ts +167 -0
- package/dist/test/integration-migrations.d.ts.map +1 -0
- package/dist/test/integration-migrations.js +171 -0
- package/dist/test/integration-migrations.js.map +1 -0
- package/dist/test/mocks/cloudflare-workers.d.ts +106 -0
- package/dist/test/mocks/cloudflare-workers.d.ts.map +1 -0
- package/dist/test/mocks/cloudflare-workers.js +90 -0
- package/dist/test/mocks/cloudflare-workers.js.map +1 -0
- package/dist/vite.d.ts +117 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +125 -0
- package/dist/vite.js.map +1 -0
- package/dist/vitest-web.d.ts +73 -0
- package/dist/vitest-web.d.ts.map +1 -0
- package/dist/vitest-web.js +72 -0
- package/dist/vitest-web.js.map +1 -0
- package/dist/vitest.d.ts +92 -0
- package/dist/vitest.d.ts.map +1 -0
- package/dist/vitest.js +128 -0
- package/dist/vitest.js.map +1 -0
- package/package.json +58 -3
- package/src/eslint-boundaries.ts +169 -0
- package/src/eslint-rules.ts +276 -0
- package/src/eslint.test.ts +175 -0
- package/src/eslint.ts +257 -0
- package/src/functions/pages-proxy.test.ts +72 -0
- package/src/functions/pages-proxy.ts +187 -0
- package/src/github/actions/retry-step/action.yml +39 -0
- package/src/github/actions/setup-env/action.yml +20 -0
- package/src/github/dependabot.yml +30 -0
- package/src/github/workflows/backup-main.yml +46 -0
- package/src/github/workflows/continuous-deployment.yml +188 -0
- package/src/github/workflows/continuous-integration.yml +259 -0
- package/src/github/workflows/scheduled-version-update.yml +38 -0
- package/src/github/workflows/upstream-sync.yml +56 -0
- package/src/index.ts +42 -0
- package/src/scripts/backup/backup-rules.test.ts +105 -0
- package/src/scripts/backup/d1-target.ts +54 -0
- package/src/scripts/backup/destination-config.ts +92 -0
- package/src/scripts/backup/encrypt-backup.ts +107 -0
- package/src/scripts/backup/naming.ts +62 -0
- package/src/scripts/check-god-files.test.ts +131 -0
- package/src/scripts/check-god-files.ts +327 -0
- package/src/scripts/ensure-spa-shell-stub.ts +34 -0
- package/src/scripts/init-secrets.ts +265 -0
- package/src/scripts/lib/cli-args.ts +154 -0
- package/src/scripts/lib/github-actions.ts +41 -0
- package/src/scripts/lib/wrangler-table.ts +105 -0
- package/src/scripts/migrations-lock.ts +52 -0
- package/src/scripts/prepare-wrangler-config.ts +51 -0
- package/src/scripts/spa-shell.test.ts +91 -0
- package/src/scripts/spa-shell.ts +179 -0
- package/src/scripts/validate-locales.test.ts +89 -0
- package/src/scripts/validate-locales.ts +380 -0
- package/src/scripts/verify-migrations.test.ts +71 -0
- package/src/scripts/verify-migrations.ts +364 -0
- package/src/scripts/verify-spa-shell.ts +56 -0
- package/src/scripts/wrangler-config/cli.ts +51 -0
- package/src/scripts/wrangler-config/patches.ts +157 -0
- package/src/scripts/wrangler-config/resources.ts +330 -0
- package/src/scripts/wrangler-config/types.ts +113 -0
- package/src/test/integration-migrations.test.ts +169 -0
- package/src/test/integration-migrations.ts +267 -0
- package/src/test/mocks/cloudflare-workers.ts +115 -0
- package/src/vite.test.ts +83 -0
- package/src/vite.ts +202 -0
- package/src/vitest-web.ts +109 -0
- package/src/vitest.ts +185 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rexezuge
|
|
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
CHANGED
|
@@ -1,3 +1,298 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @rexezuge/tooling
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Config factories, repo scripts, test helpers, and CI templates for the
|
|
4
|
+
Rexezuge-CloudflareWorkers family.
|
|
5
|
+
|
|
6
|
+
**Zero internal dependencies.** The config factories, the Pages proxy and the test
|
|
7
|
+
helpers import nothing from another `@rexezuge/*` package. The single exception is
|
|
8
|
+
`scripts/backup/encrypt-backup.ts`, which uses `@rexezuge/d1`'s AES-GCM so a backup
|
|
9
|
+
and the workers share one definition of "what an encryption key looks like"; that
|
|
10
|
+
dependency is declared on this package and is only ever resolved in a consumer
|
|
11
|
+
repo, where the kit is installed alongside `@rexezuge/d1`.
|
|
12
|
+
|
|
13
|
+
Everything here is a convergence of the same file copied across ten monorepos. Each
|
|
14
|
+
export carries a header comment naming the repos it came from and the decision the
|
|
15
|
+
convergence made — those headers are the documentation.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 1. Config factories
|
|
20
|
+
|
|
21
|
+
Four factories, four lines of consumer wiring each.
|
|
22
|
+
|
|
23
|
+
### ESLint
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
// eslint.config.mjs — the whole file
|
|
27
|
+
import { defineRepoLintConfig } from '@rexezuge/tooling/eslint';
|
|
28
|
+
|
|
29
|
+
export default defineRepoLintConfig({ scope: '@my-app' });
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Converged from Durable-DAV's 436-line `eslint.config.mjs` (the layered
|
|
33
|
+
`no-restricted-imports` boundary rules), Edge-Sonic's 730-line config (which lints
|
|
34
|
+
`test/**`, turns `unicorn/prefer-ternary` off with its reasons, and covers the
|
|
35
|
+
`import()` hole in `no-restricted-imports` with a matching `no-restricted-syntax`
|
|
36
|
+
rule), Mail-Meow's hard-error formatting gate, and AWS's `allowTypeImports` DAO
|
|
37
|
+
boundary.
|
|
38
|
+
|
|
39
|
+
The layer table is parameterized by `scope`, so `@my-app/api` is banned from
|
|
40
|
+
`apps/api` exactly as `@durable-dav/api` was. Canonical decisions:
|
|
41
|
+
|
|
42
|
+
- `prettier/prettier` is an **error**, not a warning. `pnpm run lint` is
|
|
43
|
+
`eslint --fix --quiet` in most repos, and `--quiet` discards warnings — so a
|
|
44
|
+
`prettier/prettier` warning is a silent no-op. Edge-Sonic had 242 files in that
|
|
45
|
+
state: the gate had never run.
|
|
46
|
+
- `test/**` is **linted**, not ignored, with a narrow override block for Vitest
|
|
47
|
+
idioms. The source repos ignored it, and ~200 KB of test code had accumulated
|
|
48
|
+
violations nothing reported.
|
|
49
|
+
- `apps/web` gets `globals.node` **plus** `globals.browser`, and is banned from
|
|
50
|
+
every `@scope/*` package — the SPA's own copy of a shared helper is the
|
|
51
|
+
convention, and a lint gate that does not say so is a convention.
|
|
52
|
+
|
|
53
|
+
A consumer that needs `eslint-plugin-react-hooks` appends it, because the kit stays
|
|
54
|
+
zero-dependency and the plugin belongs to the app:
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
import reactHooks from 'eslint-plugin-react-hooks';
|
|
58
|
+
|
|
59
|
+
export default [
|
|
60
|
+
...defineRepoLintConfig({ scope: '@my-app' }),
|
|
61
|
+
{
|
|
62
|
+
files: ['apps/web/**/*.{ts,tsx}'],
|
|
63
|
+
plugins: { 'react-hooks': reactHooks },
|
|
64
|
+
rules: reactHooks.configs['recommended-latest'].rules,
|
|
65
|
+
},
|
|
66
|
+
];
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Vitest — the worker and packages half
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
// vitest.config.mts
|
|
73
|
+
import { defineUnitVitestConfig } from '@rexezuge/tooling/vitest';
|
|
74
|
+
|
|
75
|
+
export default defineUnitVitestConfig({
|
|
76
|
+
coverageInclude: ['apps/api/src/**/*.ts', 'apps/background/src/**/*.ts', 'packages/**/src/**/*.ts'],
|
|
77
|
+
thresholds: { statements: 60, branches: 55, functions: 65, lines: 60 },
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
v8 coverage with the converged include/exclude patterns (scripts, tests, barrels,
|
|
82
|
+
generated files, type-only modules), `cloudflare:workers` / `cloudflare:sockets`
|
|
83
|
+
aliased to the bundled Node stand-ins, and `test/integration/**` plus every
|
|
84
|
+
`web-*` suite excluded so this config and the next one partition the suite rather
|
|
85
|
+
than each running all of it. Vitest 4 removed `coverage.all`; an explicit
|
|
86
|
+
`include` now reports files no test imported, which is the behaviour it was there
|
|
87
|
+
to get.
|
|
88
|
+
|
|
89
|
+
**Thresholds are a consumer argument, not a kit default.** A floor is a per-repo
|
|
90
|
+
ratchet measured against that repo's suite; the kit cannot know a number, and
|
|
91
|
+
guessing one is how floors get lowered.
|
|
92
|
+
|
|
93
|
+
### Vitest — the SPA half
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
// vitest.web.config.mts
|
|
97
|
+
import { defineWebVitestConfig } from '@rexezuge/tooling/vitest-web';
|
|
98
|
+
|
|
99
|
+
export default defineWebVitestConfig({
|
|
100
|
+
plugins: [react()],
|
|
101
|
+
thresholds: { statements: 55, branches: 52, functions: 54, lines: 56 },
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Converged from Durable-DAV-Router's and Mail-Otter's `vitest.web.config.mts`:
|
|
106
|
+
jsdom for every file, `pool: 'threads'` bounded rather than a fork per file (a
|
|
107
|
+
jsdom document per fork is what exhausts memory and dies with a bare "Worker
|
|
108
|
+
exited unexpectedly"), and both suite-naming conventions collected
|
|
109
|
+
(`test/**/web-*.test.{ts,tsx}` and `apps/web/**/*.test.{ts,tsx}`).
|
|
110
|
+
|
|
111
|
+
### Vite — the SPA build
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
// apps/web/vite.config.ts
|
|
115
|
+
import react from '@vitejs/plugin-react';
|
|
116
|
+
import { defineWebViteConfig, spaShellEmbedPlugin } from '@rexezuge/tooling/vite';
|
|
117
|
+
|
|
118
|
+
export default defineWebViteConfig({
|
|
119
|
+
plugins: [react(), tailwindcss()],
|
|
120
|
+
proxy: {
|
|
121
|
+
'/user': { target: 'http://localhost:8787', changeOrigin: true },
|
|
122
|
+
'/rest': { target: 'http://localhost:8787', changeOrigin: true },
|
|
123
|
+
},
|
|
124
|
+
// The ONE repo-specific piece, passed in rather than hardcoded: the worker and
|
|
125
|
+
// the generated-module path differ per repo.
|
|
126
|
+
spaShell: { path: 'apps/api/src/generated/spa-shell.ts' },
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`spaShellEmbedPlugin(target)` is the converged body of all eight copies of the
|
|
131
|
+
`spa-shell-embed` plugin, including Edge-Sonic's fix of skipping a build that
|
|
132
|
+
emitted no `dist/index.html` rather than throwing. Paths resolve from the directory
|
|
133
|
+
the build runs in — **not** from this module, which would point inside
|
|
134
|
+
`node_modules`.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 2. Pages proxy
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
// functions/[[path]].ts
|
|
142
|
+
import { createPagesProxy } from '@rexezuge/tooling/functions/pages-proxy';
|
|
143
|
+
|
|
144
|
+
export const onRequest = createPagesProxy();
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The converged `functions/[[path]].ts` shim, verified against Durable-DAV,
|
|
148
|
+
Mail-Meow and Edge-Git. It strips hop-by-hop and client-forwarding headers, sets
|
|
149
|
+
`X-Forwarded-Host/Proto/Uri` from values it reads off the request rather than the
|
|
150
|
+
client, replaces `X-Forwarded-For` from `CF-Connecting-IP` (never conditionally —
|
|
151
|
+
that is the defect Mail-Meow recorded fixing), forwards the body as a stream with
|
|
152
|
+
`duplex: 'half'` for anything but GET/HEAD, and hands the request to
|
|
153
|
+
`env.API_WORKER`.
|
|
154
|
+
|
|
155
|
+
Structural `Fetcher` / `PagesFunction` types: no `@cloudflare/workers-types`
|
|
156
|
+
import, so the module typechecks without a generated `worker-configuration.d.ts`.
|
|
157
|
+
|
|
158
|
+
`createPagesProxy({ forwardClientIp: false })` is the Edge-Sonic variant, for a
|
|
159
|
+
worker that refuses `X-Forwarded-For` outright.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 3. Test helpers
|
|
164
|
+
|
|
165
|
+
### `test/mocks/cloudflare-workers` — the `cloudflare:workers` stand-in
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
// test/mocks/cloudflare-workers.ts (copy this file verbatim)
|
|
169
|
+
// vitest.config.mts — defineUnitVitestConfig already aliases it
|
|
170
|
+
{ find: 'cloudflare:workers', replacement: 'test/mocks/cloudflare-workers.ts' }
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Converged from the eight copies: `DurableObject`, `RpcTarget` (present because
|
|
174
|
+
`dofs`' `Fs` extends it, and its absence is a module-load failure rather than a
|
|
175
|
+
test failure), and `WorkflowEntrypoint`. The ambient `DurableObjectState` /
|
|
176
|
+
`ExecutionContext` shapes are declared locally, so it typechecks inside the kit and
|
|
177
|
+
still typechecks against a consumer's generated types.
|
|
178
|
+
|
|
179
|
+
### `test/integration-migrations` — applying the migration directory
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
import { createMigrationHelper } from '@rexezuge/tooling/test/integration-migrations';
|
|
183
|
+
|
|
184
|
+
const migrations = createMigrationHelper({ migrationsDir: new URL('../../migrations', import.meta.url).pathname });
|
|
185
|
+
|
|
186
|
+
beforeAll(async () => {
|
|
187
|
+
await migrations.applyMigrations(env.DB); // every file, in wrangler's order
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('upgrades a pre-0004 database', async () => {
|
|
191
|
+
await migrations.applyMigrations(env.DB, { to: '0003_href_prefix_mode.sql' }); // seed the old shape
|
|
192
|
+
await migrations.applyMigrations(env.DB, { from: '0004_user_identity.sql' }); // then the one under test
|
|
193
|
+
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
A factory, because every source repo hardcodes where its migrations live. Generic
|
|
197
|
+
over a structural `D1DatabaseLike` — `prepare`, and `batch` when the binding has it
|
|
198
|
+
— so a fake D1, a real D1 under workerd, and Miniflare's D1 all satisfy it. The
|
|
199
|
+
splitter is trigger-aware, and each file is one `batch()` whose failure names the
|
|
200
|
+
file and the statement.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 4. Scripts
|
|
205
|
+
|
|
206
|
+
Every script is a standalone `.ts` entrypoint. Copy the `scripts/` tree into the
|
|
207
|
+
repo (that is the intended use — they resolve paths relative to the repository they
|
|
208
|
+
run in), or run it straight out of the installed package:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
pnpm exec tsx node_modules/@rexezuge/tooling/src/scripts/<name>.ts [args]
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
| Script | What it does | Usage |
|
|
215
|
+
| --- | --- | --- |
|
|
216
|
+
| `check-god-files.ts` | 300-line warn / 400-line critical guard, warn-only by default, with an allowlist | `--root <dir>` `--allowlist <file>` `--soft 300` `--hard 400` `--fail-on-hard` |
|
|
217
|
+
| `ensure-spa-shell-stub.ts` | writes the empty `spa-shell.ts` stub when absent; never overwrites | `[repo-root]` |
|
|
218
|
+
| `verify-spa-shell.ts` | rejects a missing, stubbed, or half-refreshed SPA shell | `[repo-root]` |
|
|
219
|
+
| `validate-locales.ts` | two-way key parity, empty values, `{{placeholder}}` parity, base-locale bundle | `[locales-dir]` |
|
|
220
|
+
| `verify-migrations.ts` | migration names, numbering, digests against the lock; read-only | `[migrations-dir]` |
|
|
221
|
+
| `migrations-lock.ts` | `--write` for the above: add-only lock update | `[migrations-dir]` |
|
|
222
|
+
| `prepare-wrangler-config.ts` | materializes `wrangler.jsonc` and provisions the resources it names | env-driven |
|
|
223
|
+
| `init-secrets.ts` | creates the declared Secrets Store entries, generate-if-absent | env-driven |
|
|
224
|
+
| `backup/encrypt-backup.ts` | compresses and AES-GCM-encrypts an exported dump | `BACKUP_ENCRYPTION_KEY` |
|
|
225
|
+
|
|
226
|
+
The rules each script enforces live in a module beside it, so the gates are unit
|
|
227
|
+
tested here: `god-files` rules in `check-god-files.ts`, `spa-shell` rules in
|
|
228
|
+
`spa-shell.ts`, locale rules in `validate-locales.ts`, migration rules in
|
|
229
|
+
`verify-migrations.ts`.
|
|
230
|
+
|
|
231
|
+
### The three that are gates, not chores
|
|
232
|
+
|
|
233
|
+
**`check-god-files.ts`** keeps every source repo's thresholds but makes the verdict
|
|
234
|
+
warn-only until the repo opts in with `--fail-on-hard`. The reason is in the
|
|
235
|
+
module: a ceiling set above the largest file in the tree measures nothing, and
|
|
236
|
+
Durable-DAV's own notes record ten files just over 300 with a hard limit that had
|
|
237
|
+
never fired. `scripts/god-files.allowlist.json` (a JSON array of repo-relative
|
|
238
|
+
paths, or `dir/` prefixes) records the known offenders so the report names only
|
|
239
|
+
what is new.
|
|
240
|
+
|
|
241
|
+
**`verify-migrations.ts` / `migrations-lock.ts`** exist because D1 records which
|
|
242
|
+
migrations it applied but not what they contained, so editing an applied migration
|
|
243
|
+
is invisible to every other tool. The lock is forward-only, `--write` is add-only
|
|
244
|
+
(an `edited` finding survives a write), and a squashed baseline exempts exactly the
|
|
245
|
+
set a squash rewrites or absorbs.
|
|
246
|
+
|
|
247
|
+
**`verify-spa-shell.ts`** is the only thing standing between a fresh clone and a
|
|
248
|
+
deploy that serves a blank page: both `apps/web/dist/` and the generated
|
|
249
|
+
`spa-shell.ts` are gitignored, and `postinstall` writes a deliberately empty stub.
|
|
250
|
+
Known limit, stated in the module: a *stale but self-consistent* pair passes.
|
|
251
|
+
|
|
252
|
+
### The backup helpers
|
|
253
|
+
|
|
254
|
+
`backup/{d1-target,destination-config,naming,retention,encrypt-backup}.ts` are the
|
|
255
|
+
generic half of Edge-Sonic's backup suite — the rules, not the upload jobs.
|
|
256
|
+
`d1-target.ts` refuses to export a database that was auto-provisioned moments ago,
|
|
257
|
+
`destination-config.ts` fails closed on an unencrypted destination, `naming.ts`
|
|
258
|
+
pins the artifact format (the workflow's upload glob and this prefix are one fact in
|
|
259
|
+
two places), `retention.ts` rejects a bad window rather than defaulting one, and
|
|
260
|
+
`encrypt-backup.ts` does the crypto in-process with the kit's own AES-GCM.
|
|
261
|
+
|
|
262
|
+
**Left local, deliberately:** `s3-prune.ts`, `upload-s3.ts`, `upload-webdav.ts`,
|
|
263
|
+
`webdav-target.ts` (destination-specific: S3 credentials, rclone, and a WebDAV
|
|
264
|
+
client are per-repo configuration rather than shared rules), `compare-reference.ts`
|
|
265
|
+
and `change-email.ts` (business logic and personal-data operations, respectively —
|
|
266
|
+
neither is tooling).
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## 5. GitHub templates
|
|
271
|
+
|
|
272
|
+
`src/github/` holds the converged family workflows and composite actions:
|
|
273
|
+
|
|
274
|
+
```
|
|
275
|
+
src/github/
|
|
276
|
+
workflows/continuous-integration.yml # the superset of nine repos' CI jobs
|
|
277
|
+
workflows/continuous-deployment.yml # workflow_run-gated deploy, worker + pages
|
|
278
|
+
workflows/scheduled-version-update.yml # .github/.version bump
|
|
279
|
+
workflows/backup-main.yml # secret-gated mirrors to Azure DevOps / GitLab
|
|
280
|
+
actions/setup-env/action.yml # pnpm + node store cache
|
|
281
|
+
actions/retry-step/action.yml # retry a bash command, annotate the attempts
|
|
282
|
+
dependabot.yml # weekly, with the @rexezuge/* group
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Copy the tree to the repo root. Placeholders are marked `REPLACE` and listed at the
|
|
286
|
+
top of each file; the one that must change for the workflows to run at all is the
|
|
287
|
+
`pnpm --filter @<scope>/web build` invocation in `continuous-integration.yml` and
|
|
288
|
+
`continuous-deployment.yml`.
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## 6. Verifying this package
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
pnpm --filter @rexezuge/tooling exec tsc -p tsconfig.json
|
|
296
|
+
pnpm --filter @rexezuge/tooling typecheck
|
|
297
|
+
pnpm --filter @rexezuge/tooling test
|
|
298
|
+
```
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type tseslint from 'typescript-eslint';
|
|
2
|
+
/**
|
|
3
|
+
* The layer table behind the repo lint config's import boundaries.
|
|
4
|
+
*
|
|
5
|
+
* Provenance: the seven `no-restricted-imports` blocks in Durable-DAV's
|
|
6
|
+
* `eslint.config.mjs`, with `@durable-dav/` replaced by the caller's scope.
|
|
7
|
+
* Extracted from `eslint.ts` so the boundary rules — the part a repo actually
|
|
8
|
+
* argues about — are their own module rather than the tail of a 640-line
|
|
9
|
+
* config file.
|
|
10
|
+
*
|
|
11
|
+
* The table is data rather than inline blocks so the dynamic-`import()` guard
|
|
12
|
+
* is generated from the same list: a rule that derived its banned set from
|
|
13
|
+
* another rule's configuration would be a second source of truth for the layer
|
|
14
|
+
* table, and that table is what the docs describe.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* The directories the boundary rules cover, in the canonical layout.
|
|
18
|
+
*
|
|
19
|
+
* Kept here, beside the table it scopes: `defineRepoLintConfig` filters the
|
|
20
|
+
* canonical layers by `projectDirs`, and a reader of the layer table should not
|
|
21
|
+
* have to open the config assembly to learn which directories it covers.
|
|
22
|
+
*/
|
|
23
|
+
export declare const DEFAULT_PROJECT_DIRS: readonly string[];
|
|
24
|
+
/**
|
|
25
|
+
* One layer's ban list, as the repo-relative package suffixes it may not import.
|
|
26
|
+
*
|
|
27
|
+
* Converged from the four source stacks. `backend-data` and `backend-services`
|
|
28
|
+
* appear in all four; `webdav`/`dav-store` are Durable-DAV's, `provider-clients`
|
|
29
|
+
* is Mail-Meow's and AWS's. A layer only bans what exists in its repo, so the
|
|
30
|
+
* union is safe: a repo without `provider-clients` simply never imports it.
|
|
31
|
+
*/
|
|
32
|
+
export interface LayerBan {
|
|
33
|
+
/** Directory the rule is scoped to. */
|
|
34
|
+
readonly dir: string;
|
|
35
|
+
/** Package suffixes (relative to `scope`) that may not be imported from here. */
|
|
36
|
+
readonly ban: readonly string[];
|
|
37
|
+
/** Message shown when the rule fires. */
|
|
38
|
+
readonly message: string;
|
|
39
|
+
/** Type-only imports are allowed, for the DAO boundary in `apps/api`. */
|
|
40
|
+
readonly allowTypeImports?: boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The layer table, parameterized by `scope`.
|
|
44
|
+
*/
|
|
45
|
+
export declare function layerBans(scope: string): readonly LayerBan[];
|
|
46
|
+
/**
|
|
47
|
+
* One argument to `tseslint.config()`, named here so the boundary builders
|
|
48
|
+
* return the assembled type rather than a lookalike the assembly then has to
|
|
49
|
+
* be argued into accepting.
|
|
50
|
+
*/
|
|
51
|
+
type ConfigInput = Parameters<typeof tseslint.config>[number];
|
|
52
|
+
/**
|
|
53
|
+
* The `no-restricted-imports` entries for one layer.
|
|
54
|
+
*
|
|
55
|
+
* Written as `group` patterns rather than exact `paths`, so `@myapp/backend-data`
|
|
56
|
+
* and `@myapp/backend-data/dao` are both caught by one entry. `allowTypeImports`
|
|
57
|
+
* is passed through only where the source repos set it, because `apps/api`
|
|
58
|
+
* legitimately types its filters and models against DAO shapes.
|
|
59
|
+
*/
|
|
60
|
+
export declare function restrictedImports(bans: readonly LayerBan[]): ConfigInput[];
|
|
61
|
+
/**
|
|
62
|
+
* The dynamic-`import()` guard, generated from the same table.
|
|
63
|
+
*
|
|
64
|
+
* `no-restricted-imports` reads `ImportDeclaration` nodes only; a dynamic
|
|
65
|
+
* `import()` is an `ImportExpression`, and this ESLint version does not report it
|
|
66
|
+
* under that rule at all. Edge-Sonic verified this rather than assumed it — a
|
|
67
|
+
* static import of a restricted specifier from the same file is an `error`, and
|
|
68
|
+
* the identical specifier reached through `await import(...)` is silent. That
|
|
69
|
+
* hole was load-bearing there: the credential path reached a banned module
|
|
70
|
+
* through it. `no-restricted-syntax` sees `ImportExpression`, so the boundary is
|
|
71
|
+
* stated a second way.
|
|
72
|
+
*/
|
|
73
|
+
export declare function restrictedDynamicImports(bans: readonly LayerBan[]): ConfigInput[];
|
|
74
|
+
export {};
|
|
75
|
+
//# sourceMappingURL=eslint-boundaries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eslint-boundaries.d.ts","sourceRoot":"","sources":["../src/eslint-boundaries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAC;AAE9C;;;;;;;;;;;;;GAaG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EASjD,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,uCAAuC;IACvC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,iFAAiF;IACjF,QAAQ,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,yCAAyC;IACzC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,QAAQ,EAAE,CAmD5D;AAED;;;;GAIG;AACH,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9D;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,QAAQ,EAAE,GAAG,WAAW,EAAE,CAgB1E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,SAAS,QAAQ,EAAE,GAAG,WAAW,EAAE,CAajF"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The layer table behind the repo lint config's import boundaries.
|
|
3
|
+
*
|
|
4
|
+
* Provenance: the seven `no-restricted-imports` blocks in Durable-DAV's
|
|
5
|
+
* `eslint.config.mjs`, with `@durable-dav/` replaced by the caller's scope.
|
|
6
|
+
* Extracted from `eslint.ts` so the boundary rules — the part a repo actually
|
|
7
|
+
* argues about — are their own module rather than the tail of a 640-line
|
|
8
|
+
* config file.
|
|
9
|
+
*
|
|
10
|
+
* The table is data rather than inline blocks so the dynamic-`import()` guard
|
|
11
|
+
* is generated from the same list: a rule that derived its banned set from
|
|
12
|
+
* another rule's configuration would be a second source of truth for the layer
|
|
13
|
+
* table, and that table is what the docs describe.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* The directories the boundary rules cover, in the canonical layout.
|
|
17
|
+
*
|
|
18
|
+
* Kept here, beside the table it scopes: `defineRepoLintConfig` filters the
|
|
19
|
+
* canonical layers by `projectDirs`, and a reader of the layer table should not
|
|
20
|
+
* have to open the config assembly to learn which directories it covers.
|
|
21
|
+
*/
|
|
22
|
+
export const DEFAULT_PROJECT_DIRS = [
|
|
23
|
+
'packages/shared',
|
|
24
|
+
'packages/backend-errors',
|
|
25
|
+
'packages/backend-runtime',
|
|
26
|
+
'packages/backend-data',
|
|
27
|
+
'packages/backend-services',
|
|
28
|
+
'apps/api',
|
|
29
|
+
'apps/background',
|
|
30
|
+
'apps/web',
|
|
31
|
+
];
|
|
32
|
+
/**
|
|
33
|
+
* The layer table, parameterized by `scope`.
|
|
34
|
+
*/
|
|
35
|
+
export function layerBans(scope) {
|
|
36
|
+
const at = (name) => `${scope}/${name}`;
|
|
37
|
+
return [
|
|
38
|
+
{
|
|
39
|
+
dir: 'packages/shared',
|
|
40
|
+
ban: [at('*')],
|
|
41
|
+
message: `${scope} packages must not import from other ${scope} packages — this is a zero-dependency base layer`,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
dir: 'packages/backend-errors',
|
|
45
|
+
ban: [at('*')],
|
|
46
|
+
message: `${scope} packages must not import from other ${scope} packages — this is a zero-dependency base layer`,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
dir: 'packages/backend-runtime',
|
|
50
|
+
ban: [at('backend-data'), at('webdav'), at('backend-services'), at('api'), at('background')],
|
|
51
|
+
message: 'backend-runtime must not import from a higher layer',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
dir: 'packages/backend-data',
|
|
55
|
+
ban: [at('backend-runtime'), at('webdav'), at('backend-services'), at('api'), at('background')],
|
|
56
|
+
message: 'backend-data must not import from a higher layer',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
dir: 'packages/backend-services',
|
|
60
|
+
ban: [at('api'), at('background')],
|
|
61
|
+
message: 'backend-services must not import from apps',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
dir: 'apps/api',
|
|
65
|
+
ban: [at('backend-data/dao'), at('backend-data')],
|
|
66
|
+
allowTypeImports: true,
|
|
67
|
+
message: 'apps/api must not import DAOs or backend-data values directly; use backend-services instead',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
dir: 'apps/background',
|
|
71
|
+
ban: [at('api')],
|
|
72
|
+
message: 'apps/background must not import from apps/api',
|
|
73
|
+
},
|
|
74
|
+
// The browser half, and the only layer that bans the namespace wholesale
|
|
75
|
+
// rather than a list of siblings: a backend package imported by the SPA
|
|
76
|
+
// typechecks and then fails at bundle time, with the error pointing at the
|
|
77
|
+
// bundler rather than at the boundary. Edge-Sonic is the source; the others had
|
|
78
|
+
// no block for it at all, which is how their layer table's "may import: the
|
|
79
|
+
// browser" was a convention instead of a gate.
|
|
80
|
+
{
|
|
81
|
+
dir: 'apps/web',
|
|
82
|
+
ban: [at('*')],
|
|
83
|
+
message: `${at('apps/web')} ships zero backend dependencies — this module is the SPA's own copy`,
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The `no-restricted-imports` entries for one layer.
|
|
89
|
+
*
|
|
90
|
+
* Written as `group` patterns rather than exact `paths`, so `@myapp/backend-data`
|
|
91
|
+
* and `@myapp/backend-data/dao` are both caught by one entry. `allowTypeImports`
|
|
92
|
+
* is passed through only where the source repos set it, because `apps/api`
|
|
93
|
+
* legitimately types its filters and models against DAO shapes.
|
|
94
|
+
*/
|
|
95
|
+
export function restrictedImports(bans) {
|
|
96
|
+
return bans.map(({ dir, ban, message, allowTypeImports }) => ({
|
|
97
|
+
files: [`${dir}/**/*.{ts,js,mts,cts,mjs,cjs}`],
|
|
98
|
+
rules: {
|
|
99
|
+
'no-restricted-imports': [
|
|
100
|
+
'error',
|
|
101
|
+
{
|
|
102
|
+
patterns: ban.map((group) => ({
|
|
103
|
+
group: [group, `${group}/*`],
|
|
104
|
+
message,
|
|
105
|
+
...(allowTypeImports === true && { allowTypeImports: true }),
|
|
106
|
+
})),
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* The dynamic-`import()` guard, generated from the same table.
|
|
114
|
+
*
|
|
115
|
+
* `no-restricted-imports` reads `ImportDeclaration` nodes only; a dynamic
|
|
116
|
+
* `import()` is an `ImportExpression`, and this ESLint version does not report it
|
|
117
|
+
* under that rule at all. Edge-Sonic verified this rather than assumed it — a
|
|
118
|
+
* static import of a restricted specifier from the same file is an `error`, and
|
|
119
|
+
* the identical specifier reached through `await import(...)` is silent. That
|
|
120
|
+
* hole was load-bearing there: the credential path reached a banned module
|
|
121
|
+
* through it. `no-restricted-syntax` sees `ImportExpression`, so the boundary is
|
|
122
|
+
* stated a second way.
|
|
123
|
+
*/
|
|
124
|
+
export function restrictedDynamicImports(bans) {
|
|
125
|
+
return bans.map(({ dir, ban, message }) => ({
|
|
126
|
+
files: [`${dir}/**/*.{ts,js,mts,cts,mjs,cjs}`],
|
|
127
|
+
rules: {
|
|
128
|
+
'no-restricted-syntax': [
|
|
129
|
+
'error',
|
|
130
|
+
...ban.map((specifier) => ({
|
|
131
|
+
selector: `ImportExpression[source.type='Literal'][source.value=/^${specifier.replaceAll('/', '\\/')}/]`,
|
|
132
|
+
message: `A dynamic import() is not covered by no-restricted-imports, so this layer reaches \`${specifier}\` through the one syntax that gate does not see. Both say no: ${message}`,
|
|
133
|
+
})),
|
|
134
|
+
],
|
|
135
|
+
},
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=eslint-boundaries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eslint-boundaries.js","sourceRoot":"","sources":["../src/eslint-boundaries.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAsB;IACrD,iBAAiB;IACjB,yBAAyB;IACzB,0BAA0B;IAC1B,uBAAuB;IACvB,2BAA2B;IAC3B,UAAU;IACV,iBAAiB;IACjB,UAAU;CACX,CAAC;AAqBF;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,MAAM,EAAE,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,GAAG,KAAK,IAAI,IAAI,EAAE,CAAC;IACxD,OAAO;QACL;YACE,GAAG,EAAE,iBAAiB;YACtB,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;YACd,OAAO,EAAE,GAAG,KAAK,wCAAwC,KAAK,kDAAkD;SACjH;QACD;YACE,GAAG,EAAE,yBAAyB;YAC9B,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;YACd,OAAO,EAAE,GAAG,KAAK,wCAAwC,KAAK,kDAAkD;SACjH;QACD;YACE,GAAG,EAAE,0BAA0B;YAC/B,GAAG,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC;YAC5F,OAAO,EAAE,qDAAqD;SAC/D;QACD;YACE,GAAG,EAAE,uBAAuB;YAC5B,GAAG,EAAE,CAAC,EAAE,CAAC,iBAAiB,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC;YAC/F,OAAO,EAAE,kDAAkD;SAC5D;QACD;YACE,GAAG,EAAE,2BAA2B;YAChC,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC;YAClC,OAAO,EAAE,4CAA4C;SACtD;QACD;YACE,GAAG,EAAE,UAAU;YACf,GAAG,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC;YACjD,gBAAgB,EAAE,IAAI;YACtB,OAAO,EAAE,6FAA6F;SACvG;QACD;YACE,GAAG,EAAE,iBAAiB;YACtB,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;YAChB,OAAO,EAAE,+CAA+C;SACzD;QACD,yEAAyE;QACzE,wEAAwE;QACxE,2EAA2E;QAC3E,gFAAgF;QAChF,4EAA4E;QAC5E,+CAA+C;QAC/C;YACE,GAAG,EAAE,UAAU;YACf,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;YACd,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,sEAAsE;SACjG;KACF,CAAC;AACJ,CAAC;AASD;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAyB;IACzD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,gBAAgB,EAAE,EAAE,EAAE,CAAC,CAAC;QAC5D,KAAK,EAAE,CAAC,GAAG,GAAG,+BAA+B,CAAC;QAC9C,KAAK,EAAE;YACL,uBAAuB,EAAE;gBACvB,OAAO;gBACP;oBACE,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;wBAC5B,KAAK,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;wBAC5B,OAAO;wBACP,GAAG,CAAC,gBAAgB,KAAK,IAAI,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC;qBAC7D,CAAC,CAAC;iBACJ;aACF;SACF;KACF,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAyB;IAChE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1C,KAAK,EAAE,CAAC,GAAG,GAAG,+BAA+B,CAAC;QAC9C,KAAK,EAAE;YACL,sBAAsB,EAAE;gBACtB,OAAO;gBACP,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;oBACzB,QAAQ,EAAE,0DAA0D,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI;oBACxG,OAAO,EAAE,uFAAuF,SAAS,kEAAkE,OAAO,EAAE;iBACrL,CAAC,CAAC;aACJ;SACF;KACF,CAAC,CAAC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The rule-override blocks of the repo lint config.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `eslint.ts` with the boundary rules: each block is a plain
|
|
5
|
+
* rules object with the provenance comment that says *why* it is set to this
|
|
6
|
+
* value, because a per-rule decision with no reason attached is a decision the
|
|
7
|
+
* next reader re-litigates. `eslint.ts` composes these; this file is where a
|
|
8
|
+
* rule's story lives.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* TypeScript rules, identical in all four source stacks.
|
|
12
|
+
*/
|
|
13
|
+
export declare const TYPESCRIPT_RULES: Readonly<Record<string, unknown>>;
|
|
14
|
+
/**
|
|
15
|
+
* Unicorn and SonarJS rules carried from the source repos, each off for a
|
|
16
|
+
* stated reason.
|
|
17
|
+
*
|
|
18
|
+
* This is the family's "deliberately does not follow" block: every entry is
|
|
19
|
+
* off because complying would make the code worse for what the project is,
|
|
20
|
+
* and each is listed rather than dropped so the decision stays reviewable.
|
|
21
|
+
*/
|
|
22
|
+
export declare const UNICORN_RULES: Readonly<Record<string, unknown>>;
|
|
23
|
+
/**
|
|
24
|
+
* SonarJS rules the sources turned from errors into advisories, with the
|
|
25
|
+
* threshold raised to a value that has actually held.
|
|
26
|
+
*/
|
|
27
|
+
export declare const SONARJS_RULES: Readonly<Record<string, unknown>>;
|
|
28
|
+
/**
|
|
29
|
+
* Test-suite overrides.
|
|
30
|
+
*
|
|
31
|
+
* `test/**` is deliberately *not* in the config's ignores list. Durable-DAV,
|
|
32
|
+
* AWS and Mail-Meow all ignored it, and ~200 KB of test code had accumulated
|
|
33
|
+
* violations that nothing reported. This block puts the suite back under the
|
|
34
|
+
* same rules as the rest of the workspace and switches off only the handful
|
|
35
|
+
* whose findings are structural artefacts of test code rather than defects.
|
|
36
|
+
* It does not disable correctness rules: the unused-variable, dead-store,
|
|
37
|
+
* regex and sorting findings in the suite are real and are fixed, not
|
|
38
|
+
* suppressed.
|
|
39
|
+
*/
|
|
40
|
+
export declare const TEST_RULES: Readonly<Record<string, unknown>>;
|
|
41
|
+
//# sourceMappingURL=eslint-rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eslint-rules.d.ts","sourceRoot":"","sources":["../src/eslint-rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsB9D,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsI3D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoB3D,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAwDxD,CAAC"}
|