@starci/hfs 5.2.0 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/README.md +1 -1
- package/cache/hfs-family.d.mts +2 -3
- package/cache/hfs-family.mjs +4 -9
- package/cache/secret-records.d.mts +7 -0
- package/cache/secret-records.mjs +12 -0
- package/cache/session.mjs +4 -2
- package/codemod/account-doors.d.mts +36 -0
- package/codemod/account-doors.mjs +128 -0
- package/codemod/main.mjs +31 -1
- package/codemod/module-definition.d.mts +52 -0
- package/codemod/module-definition.mjs +242 -0
- package/codemod/quality-binding.d.mts +33 -0
- package/codemod/quality-binding.mjs +38 -0
- package/codemod/secrets-cache.d.mts +35 -0
- package/codemod/secrets-cache.mjs +70 -0
- package/codemod/sops-rules.d.mts +34 -0
- package/codemod/sops-rules.mjs +69 -0
- package/codemod/theme-tokens.mjs +48 -2
- package/lint/run.d.mts +6 -0
- package/lint/run.mjs +63 -10
- package/package.json +1 -1
- package/runtime/knowledge/hfs/canon-pins.yaml +43 -10
- package/runtime/knowledge/hfs/fe-stack.yaml +3 -3
- package/runtime/knowledge/hfs/rules.yaml +13 -9
- package/runtime/knowledge/hfs/slots.yaml +105 -12
- package/runtime/modules/kernel/failure-codes.yaml +5 -4
- package/runtime/scripts/hfs/architecture/config.d.mts +4 -0
- package/runtime/scripts/hfs/architecture/config.mjs +25 -1
- package/runtime/scripts/hfs/architecture/module-per-transport.d.mts +1 -1
- package/runtime/scripts/hfs/architecture/module-per-transport.mjs +6 -1
- package/runtime/scripts/hfs/architecture/root-packages.d.mts +26 -0
- package/runtime/scripts/hfs/architecture/root-packages.mjs +78 -0
- package/runtime/scripts/hfs/architecture/type-context.d.mts +4 -1
- package/runtime/scripts/hfs/architecture/type-context.mjs +30 -0
- package/runtime/scripts/hfs/architecture/typescript.d.mts +7 -1
- package/runtime/scripts/hfs/architecture/typescript.mjs +21 -1
- package/runtime/scripts/hfs/explicit-surface-rule.mjs +1 -1
- package/runtime/scripts/hfs/rules/database-access.mjs +39 -1
- package/runtime/scripts/hfs/rules/monorepo.d.mts +4 -0
- package/runtime/scripts/hfs/rules/monorepo.mjs +10 -5
- package/runtime/scripts/hfs/rules/secrets.mjs +11 -0
- package/runtime/scripts/hfs/secret-errors.d.mts +3 -0
- package/runtime/scripts/hfs/secret-errors.mjs +8 -0
- package/runtime/scripts/hfs/secret-init.d.mts +6 -0
- package/runtime/scripts/hfs/secret-init.mjs +23 -0
- package/runtime/scripts/hfs/secret-sops.mjs +9 -1
- package/runtime/scripts/hfs/secret-standard.d.mts +20 -0
- package/runtime/scripts/hfs/secret-standard.mjs +106 -0
- package/runtime/scripts/hfs/secret.mjs +5 -1
- package/runtime/scripts/hfs/view.d.mts +23 -0
- package/runtime/scripts/hfs/view.mjs +68 -0
- package/runtime/scripts/lib/declaration-surface.d.mts +4 -0
- package/runtime/scripts/lib/declaration-surface.mjs +55 -1
- package/runtime/scripts/lib/secret-records.d.mts +13 -0
- package/runtime/scripts/lib/secret-records.mjs +83 -0
- package/scaffold/add-inbox-lite.mjs +2 -2
- package/scaffold/add-queue-lite.mjs +1 -3
- package/scaffold/app.d.mts +2 -2
- package/scaffold/app.mjs +10 -12
- package/scaffold/lite-exports.mjs +1 -15
- package/scripts/sync-bundles.d.mts +8 -0
- package/stack/images/openclaw-runtime/Dockerfile +18 -0
- package/stack/images/openclaw-runtime/entrypoint.sh +23 -0
- package/stack/images/openclaw-runtime/openclaw-init.mjs +101 -0
- package/stack/images/openclaw-runtime/openclaw-relay.mjs +25 -0
- package/stack/local-up.mjs +3 -0
- package/stack/runtime-layers.d.mts +21 -0
- package/stack/runtime-layers.mjs +67 -0
- package/sync/hygiene.mjs +3 -1
- package/sync/index.d.mts +2 -0
- package/sync/index.mjs +33 -2
- package/templates/app/auth-doors.sql.partial +115 -0
- package/templates/app/ci-workflows/github/workflows/ci.yml +1 -1
- package/templates/app/ci-workflows-lite/github/workflows/ci.yml +1 -1
- package/templates/app/package-scripts/core.json +1 -1
- package/templates/app/package-scripts/package.json +1 -1
- package/templates/app/package-scripts-lite/package.json +1 -1
- package/templates/app/skeleton-lite/.starcistacks/application-stacks.yaml +9 -0
- package/templates/app/skeleton-lite/.starcistacks/dev/README.md +3 -1
- package/templates/app/skeleton-lite/.starcistacks/dev/infra/compose/compose.yaml +19 -1
- package/templates/app/skeleton-lite/.starcistacks/dev/runtime/env/KEYS.md +3 -0
- package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/stack.yaml +5 -0
- package/templates/app/skeleton-lite/.starcistacks/production/runtime/env/KEYS.md +4 -0
- package/templates/app/skeleton-lite/db/migrations/__timestamp___baseline.sql +24 -4
- package/templates/be/auth-lite/src/features/api/auth/application/auth.contracts.ts +33 -0
- package/templates/be/auth-lite/src/features/api/auth/application/confirm.command.ts +11 -0
- package/templates/be/auth-lite/src/features/api/auth/application/confirm.handler.ts +22 -0
- package/templates/be/auth-lite/src/features/api/auth/application/forgot.command.ts +11 -0
- package/templates/be/auth-lite/src/features/api/auth/application/forgot.handler.ts +22 -0
- package/templates/be/auth-lite/src/features/api/auth/application/resend.command.ts +11 -0
- package/templates/be/auth-lite/src/features/api/auth/application/resend.handler.ts +22 -0
- package/templates/be/auth-lite/src/features/api/auth/application/reset.command.ts +11 -0
- package/templates/be/auth-lite/src/features/api/auth/application/reset.handler.ts +22 -0
- package/templates/be/auth-lite/src/features/api/auth/application/signup.command.ts +11 -0
- package/templates/be/auth-lite/src/features/api/auth/application/signup.handler.ts +22 -0
- package/templates/be/auth-lite/src/features/api/auth/auth.module-definition.ts +3 -10
- package/templates/be/auth-lite/src/features/api/auth/auth.module.ts +6 -1
- package/templates/be/auth-lite/src/features/api/auth/transport/http/auth-http.module-definition.ts +3 -10
- package/templates/be/auth-lite/src/features/api/auth/transport/http/auth.controller.ts +56 -1
- package/templates/be/auth-lite/src/features/api/auth/transport/http/dto/forgot.request.ts +16 -0
- package/templates/be/auth-lite/src/features/api/auth/transport/http/dto/resend.request.ts +16 -0
- package/templates/be/auth-lite/src/features/api/auth/transport/http/dto/reset.request.ts +18 -0
- package/templates/be/auth-lite/src/features/api/auth/transport/http/dto/signup.request.ts +22 -0
- package/templates/be/auth-lite/src/features/api/auth/transport/http/dto/token.request.ts +11 -0
- package/templates/be/auth-lite/src/modules/domain/identity/account-directory.service.spec.ts +30 -30
- package/templates/be/auth-lite/src/modules/domain/identity/account-directory.service.ts +7 -16
- package/templates/be/auth-lite/src/modules/domain/identity/authenticator.service.spec.ts +113 -49
- package/templates/be/auth-lite/src/modules/domain/identity/authenticator.service.ts +42 -53
- package/templates/be/auth-lite/src/modules/domain/identity/identity-email.log-events.ts +6 -0
- package/templates/be/auth-lite/src/modules/domain/identity/identity-email.service.spec.ts +233 -0
- package/templates/be/auth-lite/src/modules/domain/identity/identity-email.service.ts +176 -0
- package/templates/be/auth-lite/src/modules/domain/identity/identity-sign-in.log-events.ts +6 -0
- package/templates/be/auth-lite/src/modules/domain/identity/persistence/account-doors.port.ts +98 -0
- package/templates/be/auth-lite/src/modules/domain/identity/persistence/entities/identity-email-token.entity.ts +34 -0
- package/templates/be/auth-lite/src/modules/domain/identity/persistence/entities/index.ts +3 -10
- package/templates/be/auth-lite/src/modules/domain/identity/sign-in.service.spec.ts +17 -0
- package/templates/be/auth-lite/src/modules/domain/identity/sign-in.service.ts +6 -0
- package/templates/be/auth-lite/src/tests/fixtures/builders/identity.builder.ts +29 -33
- package/templates/be/inbox/module-definition.ts.tpl +2 -9
- package/templates/be/inbox/platform/event-bus/event-bus.module-definition.ts.tpl +2 -11
- package/templates/be/inbox/platform/inbox/inbox.module-definition.ts.tpl +2 -9
- package/templates/be/patterns/api/feature.module-definition.ts.tpl +3 -9
- package/templates/be/patterns/api/graphql.module-definition.ts.tpl +3 -9
- package/templates/be/patterns/cli/group.module-definition.ts.tpl +2 -9
- package/templates/be/patterns/event-bus/platform/event-bus.module-definition.ts.tpl +3 -10
- package/templates/be/patterns/idempotency/platform/inbox/inbox.module-definition.ts.tpl +2 -9
- package/templates/be/patterns/jobs/job.module-definition.ts.tpl +2 -9
- package/templates/be/patterns/jobs/job.queue.module-definition.ts.tpl +3 -9
- package/templates/be/patterns/jobs/platform/jobs.module-definition.ts.tpl +3 -10
- package/templates/be/patterns/projections/projection.module-definition.ts.tpl +2 -9
- package/templates/be/patterns/queues/platform/queue.module-definition.ts.tpl +3 -10
- package/templates/be/patterns/queues/queue.module-definition.ts.tpl +2 -9
- package/templates/be/patterns/reactors/message.module-definition.ts.tpl +3 -9
- package/templates/be/patterns/reactors/reactor.module-definition.ts.tpl +2 -9
- package/templates/be/patterns/realtime/channel.graphql.module-definition.ts.tpl +3 -9
- package/templates/be/patterns/realtime/channel.sse.module-definition.ts.tpl +3 -9
- package/templates/be/patterns/realtime/channel.websocket.module-definition.ts.tpl +3 -9
- package/templates/be/patterns/saga/saga.message.module-definition.ts.tpl +3 -9
- package/templates/be/patterns/saga/saga.module-definition.ts.tpl +2 -9
- package/templates/be/patterns/webhooks/webhook.http.module-definition.ts.tpl +3 -9
- package/templates/be/platform/graphql/graphql.module-definition.ts +2 -9
- package/templates/be/skeleton/src/features/api/system-health/system-health.module-definition.ts +3 -9
- package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.module-definition.ts +3 -9
- package/templates/be/skeleton/src/features/cli/cli.module-definition.ts +2 -9
- package/templates/be/skeleton/src/features/cli/migrate/migrate.module-definition.ts +3 -9
- package/templates/be/skeleton/src/features/cli/seed/seed.module-definition.ts +2 -9
- package/templates/be/skeleton/src/modules/domain/identity/identity.module-definition.ts +2 -9
- package/templates/be/skeleton/src/modules/domain/liveness/liveness.module-definition.ts +2 -9
- package/templates/be/skeleton/src/modules/domain/note/note.module-definition.ts +2 -9
- package/templates/be/skeleton/src/modules/platform/clock/clock.module-definition.ts +2 -9
- package/templates/be/skeleton/src/modules/platform/cqrs/cqrs.contracts.ts +2 -0
- package/templates/be/skeleton/src/modules/platform/cqrs/cqrs.module-definition.ts +2 -9
- package/templates/be/skeleton/src/modules/platform/database/database.module-definition.ts +3 -13
- package/templates/be/skeleton/src/modules/platform/errors/errors.module-definition.ts +4 -11
- package/templates/be/skeleton/src/modules/platform/http/http.module-definition.ts +4 -9
- package/templates/be/skeleton/src/modules/platform/http-security/http-security.module-definition.ts +5 -11
- package/templates/be/skeleton/src/modules/platform/i18n/i18n.module-definition.ts +4 -11
- package/templates/be/skeleton/src/modules/platform/ids/ids.module-definition.ts +2 -9
- package/templates/be/skeleton/src/modules/platform/logging/logging.module-definition.ts +2 -9
- package/templates/be/skeleton/src/modules/platform/retry/retry.module-definition.ts +2 -9
- package/templates/be/skeleton-lite/apps/api/src/api.env.ts +4 -0
- package/templates/be/skeleton-lite/apps/api/src/api.options.ts +3 -0
- package/templates/be/skeleton-lite/apps/api/src/compose/integrations.ts +3 -1
- package/templates/be/skeleton-lite/src/modules/domain/identity/errors/identity.error.ts +6 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/identity.module.ts +3 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/index.ts +1 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/messages/identity-mail.messages.ts +65 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/messages/identity.messages.ts +4 -0
- package/templates/be/skeleton-lite/src/modules/integrations/mail/index.ts +6 -0
- package/templates/be/skeleton-lite/src/modules/integrations/mail/mail.config.ts +33 -0
- package/templates/be/skeleton-lite/src/modules/integrations/mail/mail.decorators.ts +14 -0
- package/templates/be/skeleton-lite/src/modules/integrations/mail/mail.module-definition.ts +12 -0
- package/templates/be/skeleton-lite/src/modules/integrations/mail/mail.module.ts +27 -0
- package/templates/be/skeleton-lite/src/modules/integrations/mail/mail.options.ts +22 -0
- package/templates/be/skeleton-lite/src/modules/integrations/object-storage/object-storage.module-definition.ts +2 -9
- package/templates/be/skeleton-lite/src/modules/integrations/passport/index.ts +1 -1
- package/templates/be/skeleton-lite/src/modules/platform/database/index.ts +1 -0
- package/templates/be/skeleton-lite/src/modules/platform/http-security/rate-limit.guard.spec.ts +11 -0
- package/templates/be/skeleton-lite/src/tests/fixtures/builders/api.builder.ts +11 -0
- package/templates/be/table/api/feature.module-definition.ts.tpl +3 -9
- package/templates/be/table/api/graphql.module-definition.ts.tpl +3 -9
- package/templates/be/table/module-definition.ts.tpl +2 -9
- package/templates/fe/auth-lite/apps/web/src/modules/auth/email-doors.ts +16 -0
- package/templates/fe/auth-lite/apps/web/src/modules/auth/index.ts +5 -0
- package/templates/fe/skeleton/packages/__project__-i18n/src/index.ts +30 -67
- package/templates/fe/skeleton/packages/__project__-i18n/src/proxy.ts +6 -21
- package/templates/fe/skeleton/packages/__project__-i18n/src/routing.ts +10 -16
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/auth/confirm/page.tsx +9 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/auth/forgot/page.tsx +9 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/auth/resend/page.tsx +9 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/auth/reset/page.tsx +9 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/auth/signup/page.tsx +9 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/layout.tsx +5 -9
- package/templates/fe/skeleton-lite/apps/web/src/components/blocks/EmailDoorForm/component.tsx +51 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/blocks/EmailDoorForm/index.tsx +84 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppConfirmPage/index.tsx +25 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppForgotPage/index.tsx +21 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/component.tsx +11 -3
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/index.tsx +4 -1
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppResendPage/index.tsx +21 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppResetPage/index.tsx +25 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppSignupPage/index.tsx +21 -0
- package/templates/fe/skeleton-lite/apps/web/src/hooks/emailAuth/emailAuth.shared.ts +12 -0
- package/templates/fe/skeleton-lite/apps/web/src/hooks/emailAuth/index.ts +2 -0
- package/templates/fe/skeleton-lite/apps/web/src/hooks/emailAuth/useEmailDoor.ts +32 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/index.ts +2 -2
- package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/en.json +50 -1
- package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/vi.json +50 -1
- package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/request.ts +7 -30
- package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/routing.ts +13 -14
- package/templates/fe/skeleton-lite/apps/web/src/modules/routes/index.ts +5 -0
- package/templates/fe/skeleton-lite/apps/web/src/proxy.ts +4 -17
- package/templates/be/auth-lite/src/modules/domain/identity/persistence/entities/auth-identity.entity.ts +0 -38
- package/templates/be/auth-lite/src/modules/domain/identity/persistence/entities/auth-user.entity.ts +0 -54
package/lint/run.mjs
CHANGED
|
@@ -6,11 +6,13 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
|
|
|
6
6
|
}
|
|
7
7
|
return path;
|
|
8
8
|
};
|
|
9
|
-
// The linters of `starci app check --gate lint`: ESLint once per side and stylelint over the fe stylesheets, through the app's own install.
|
|
9
|
+
// The linters of `starci app check --gate lint`: ESLint once per side (and once for the root workspace packages) and stylelint over the fe stylesheets, through the app's own install.
|
|
10
10
|
//
|
|
11
11
|
// 1. ESLint runs from the side folder with that side's eslint.config.mjs (be/ the be canon, fe/ the fe canon: the per-file rules and the
|
|
12
12
|
// project-graph rules of the architecture machine, findings on the line of the offending TypeScript file); each side lints only its own
|
|
13
13
|
// files, so the be rules never see fe/ and the fe rules never see be/;
|
|
14
|
+
// 1b. the root workspace packages (packages/<pkg>/src/**) are a third scope: ESLint runs from the app root with the managed root eslint.config.mjs (sync renders it), the files
|
|
15
|
+
// app-relative, whole on every run (no result records), the project graph left to the sides;
|
|
14
16
|
// 2. stylelint judges the fe side's stylesheets (sync STYLE_GLOB) from fe/ with its stylelint.config.mjs.
|
|
15
17
|
// `cachedLinters` is the one entry of `app check`: per side it judges only what the records of `.starcistacks/cache/lint/<side>/` cannot
|
|
16
18
|
// vouch for (cache/lint-family.mjs, contexts/project/check-cache.md), and `eslintRepository` is the launcher it and the cacheless run share.
|
|
@@ -114,6 +116,41 @@ const eslintFindings = (results, appRoot) => results.flatMap((result) => (result
|
|
|
114
116
|
})));
|
|
115
117
|
/** The files of `changed` (app-relative) below `side`/, relative to the side folder. */
|
|
116
118
|
const onSide = (changed, side) => changed.filter((file) => file.startsWith(`${side}/`)).map((file) => file.slice(side.length + 1));
|
|
119
|
+
/**
|
|
120
|
+
* The root workspace packages of an app (`packages/<pkg>/src/**`) are linted by the managed `eslint.config.mjs` of the app root, as a third scope beside
|
|
121
|
+
* the two sides: its files are app-relative and its working directory is the app root. It has a scope only while the config is there.
|
|
122
|
+
*/
|
|
123
|
+
export const PACKAGES = 'packages';
|
|
124
|
+
export const PACKAGES_CONFIG = 'eslint.config.mjs';
|
|
125
|
+
const hasPackagesLint = (repoRoot) => fs.existsSync(path.join(repoRoot, PACKAGES_CONFIG)) && fs.existsSync(path.join(repoRoot, PACKAGES));
|
|
126
|
+
/** The root config of the app, its default export awaited: the flat config the packages are linted by. */
|
|
127
|
+
async function packagesConfig(repoRoot) {
|
|
128
|
+
const loaded = await import(__rewriteRelativeImportExtension(`${pathToFileURL(path.join(repoRoot, PACKAGES_CONFIG)).href}?scope=${Date.now()}`));
|
|
129
|
+
const config = await loaded.default;
|
|
130
|
+
if (!Array.isArray(config))
|
|
131
|
+
throw new Error(`${PACKAGES_CONFIG} did not export a flat config`);
|
|
132
|
+
return config;
|
|
133
|
+
}
|
|
134
|
+
/** The package sources the root config selects, app-relative: the walk stays below `packages/`, where the config's selectors point. */
|
|
135
|
+
async function packageSources(repoRoot) {
|
|
136
|
+
const scope = canonScope(await packagesConfig(repoRoot));
|
|
137
|
+
const files = [];
|
|
138
|
+
const visit = (folder) => {
|
|
139
|
+
for (const child of fs.readdirSync(path.join(repoRoot, folder), { withFileTypes: true })) {
|
|
140
|
+
const file = posix(path.join(folder, child.name));
|
|
141
|
+
if (scope.ignored(file) || scope.ignored(`${file}/__starci_scope_probe__`))
|
|
142
|
+
continue;
|
|
143
|
+
if (child.isSymbolicLink())
|
|
144
|
+
throw new Error(`cannot enumerate symlink ${file}`);
|
|
145
|
+
if (child.isDirectory())
|
|
146
|
+
visit(file);
|
|
147
|
+
else if (child.isFile() && scope.source(file))
|
|
148
|
+
files.push(file);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
visit(PACKAGES);
|
|
152
|
+
return files.sort(byCodeUnit);
|
|
153
|
+
}
|
|
117
154
|
const fileKey = (file) => process.platform === 'win32' ? path.resolve(file).toLowerCase() : path.resolve(file);
|
|
118
155
|
const inside = (root, file) => { const rel = path.relative(root, file); return rel !== '..' && !rel.startsWith(`..${path.sep}`) && !path.isAbsolute(rel); };
|
|
119
156
|
/**
|
|
@@ -300,29 +337,36 @@ function graphCanonsOf(repoRoot, cwd, side) {
|
|
|
300
337
|
/** Starts the ESLint child of every side that has work and returns one record per side: skipped, a scope error, or the running child. */
|
|
301
338
|
async function launchEslint({ app, repoRoot, opts, changed, existing, run = runLinter, scopes = {}, handOutGraph = false }) {
|
|
302
339
|
const launches = [];
|
|
303
|
-
|
|
304
|
-
|
|
340
|
+
const scopesToLint = app ? [...SIDES, ...(hasPackagesLint(repoRoot) ? [PACKAGES] : [])].filter((candidate) => opts.side === undefined || opts.side === candidate) : [];
|
|
341
|
+
for (const side of scopesToLint) {
|
|
342
|
+
const packages = side === PACKAGES;
|
|
343
|
+
const sources = (packages ? existing.filter((file) => file.startsWith(`${PACKAGES}/`)) : onSide(existing, side)).filter((file) => /\.(?:[cm]?[jt]sx?)$/.test(file));
|
|
305
344
|
if (changed !== null && !sources.length) {
|
|
306
345
|
launches.push({ side, skipped: 'no changed source file' });
|
|
307
346
|
continue;
|
|
308
347
|
}
|
|
309
|
-
const cwd = path.join(repoRoot, side);
|
|
348
|
+
const cwd = packages ? repoRoot : path.join(repoRoot, side);
|
|
310
349
|
let expected;
|
|
311
350
|
// a caller that enumerated the side's scope already (the cache) hands it over: the canon config is loaded and the folders walked once per run
|
|
312
351
|
const known = scopes[side];
|
|
313
352
|
try {
|
|
314
|
-
expected = changed ? sources : known !== undefined ? [...known] : await sourceFiles({ repoRoot, cwd, side });
|
|
353
|
+
expected = changed ? sources : known !== undefined ? [...known] : packages ? await packageSources(repoRoot) : await sourceFiles({ repoRoot, cwd, side });
|
|
315
354
|
}
|
|
316
355
|
catch (error) {
|
|
317
|
-
launches.push({ side, scopeError: `eslint source scope is unavailable in ${side}
|
|
356
|
+
launches.push({ side, scopeError: `eslint source scope is unavailable in ${packages ? `${PACKAGES}/` : `${side}/`}: ${String(error?.message ?? error)}` });
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
// nothing the root config selects below packages/ is a scope with no file, not a run
|
|
360
|
+
if (packages && !expected.length) {
|
|
361
|
+
launches.push({ side, skipped: 'no package source' });
|
|
318
362
|
continue;
|
|
319
363
|
}
|
|
320
364
|
const head = ['--format', 'json', ...(opts.fix ? ['--fix'] : [])];
|
|
321
|
-
// the child that builds the canon's project graph for its rules hands the snapshot out when the caller keeps the graph findings (the cache)
|
|
322
|
-
const graph = handOutGraph ? graphCanonsOf(repoRoot, cwd, side) : undefined;
|
|
365
|
+
// the child that builds the canon's project graph for its rules hands the snapshot out when the caller keeps the graph findings (the cache); the packages are no side folder and have no graph
|
|
366
|
+
const graph = handOutGraph && !packages ? graphCanonsOf(repoRoot, cwd, side) : undefined;
|
|
323
367
|
// The files of a diff go to ONE child through a file (a diff of hundreds of long paths outgrows the Windows command line, and each extra
|
|
324
368
|
// child would build the whole TypeScript program again); the whole side is a single directory argument.
|
|
325
|
-
const launch = Promise.resolve().then(() => run(changed ? { cwd, pkg: 'eslint', bin: 'eslint', args: head, list: sources, bound: repoRoot, ...(graph === undefined ? {} : { graph }) } : { cwd, pkg: 'eslint', bin: 'eslint', args: [...head, '.'], files: expected.length, bound: repoRoot, ...(graph === undefined ? {} : { graph }) }));
|
|
369
|
+
const launch = Promise.resolve().then(() => run(changed ? { cwd, pkg: 'eslint', bin: 'eslint', args: head, list: sources, bound: repoRoot, ...(graph === undefined ? {} : { graph }) } : { cwd, pkg: 'eslint', bin: 'eslint', args: [...head, packages ? PACKAGES : '.'], files: expected.length, bound: repoRoot, ...(graph === undefined ? {} : { graph }) }));
|
|
326
370
|
launches.push({ side, cwd, expected, run: launch.catch(spawnFailure) });
|
|
327
371
|
}
|
|
328
372
|
return launches;
|
|
@@ -358,7 +402,8 @@ export async function eslintRepository({ repoRoot, app = readRepoDeclaration(loa
|
|
|
358
402
|
const checked = checkedEslintResults({ results: linted.results, expected: launch.expected, cwd: launch.cwd, changed: changed !== null });
|
|
359
403
|
errors.push(...checked.errors);
|
|
360
404
|
linted.results = checked.results;
|
|
361
|
-
|
|
405
|
+
// the paths of a side's messages are side-relative and become app-relative; the packages' are app-relative already
|
|
406
|
+
const appRelative = side === PACKAGES ? ((message) => message) : appRelativeMessages(side, path.join(repoRoot, side));
|
|
362
407
|
for (const result of linted.results)
|
|
363
408
|
for (const message of result.messages ?? [])
|
|
364
409
|
message.message = appRelative(message.message);
|
|
@@ -497,6 +542,14 @@ export async function cachedLinters({ repoRoot, app, side: only, run, session })
|
|
|
497
542
|
style.ran = true;
|
|
498
543
|
}
|
|
499
544
|
}
|
|
545
|
+
// The root packages are small and have no result records: they are linted whole on every run, through the same launcher.
|
|
546
|
+
if ((only === undefined || only === PACKAGES) && hasPackagesLint(repoRoot)) {
|
|
547
|
+
const linted = await eslintRepository({ repoRoot, app, opts: { side: PACKAGES }, run });
|
|
548
|
+
eslint.errors.push(...linted.errors);
|
|
549
|
+
eslint.raw.push(...linted.raw);
|
|
550
|
+
eslint.findings.push(...linted.findings);
|
|
551
|
+
eslint.engine.sides[PACKAGES] = linted.engine.sides[PACKAGES] ?? { files: 0 };
|
|
552
|
+
}
|
|
500
553
|
session.report(lintFamilyReport(sides));
|
|
501
554
|
return { eslint, stylelint: style, sides };
|
|
502
555
|
}
|
package/package.json
CHANGED
|
@@ -38,42 +38,49 @@ pins:
|
|
|
38
38
|
source: packages/next-data/package.json
|
|
39
39
|
why: 'the SWR data helpers of every front end (fe-stack data, owner:next-data-package): pollingRestart, the viewer and tenant key helpers, viewerSwrConfig and the viewer cache; each operation hook stays in the app and the package holds no component.'
|
|
40
40
|
'@starci/grammar':
|
|
41
|
-
version: 0.21.
|
|
41
|
+
version: 0.21.15
|
|
42
42
|
group: starci
|
|
43
43
|
install: registry
|
|
44
44
|
side: fe
|
|
45
45
|
source: packages/grammar/package.json
|
|
46
46
|
why: 'the grammar front ends read: the brand layer sets `--font-sans` and `--font-mono` and the grammar reads them; it carries the Input tel kind, the copyable and read-only Input, the IconButton disclosure props and count badge, ChatBubble, FillViewport, Textarea mentions and Enter-to-send, the leading PrimaryRailLayout rail, the plate-less Image, ListRow, the soft Alert, Progress steps, the floating primary IconButton, FlowGraph, the STATE-8 loading views and the bordered selectable TagGroup chips. The runtime source version wins for a @starci package.'
|
|
47
|
+
'@starci/next-i18n':
|
|
48
|
+
version: 0.1.0
|
|
49
|
+
group: starci
|
|
50
|
+
install: registry
|
|
51
|
+
side: fe
|
|
52
|
+
source: packages/next-i18n/package.json
|
|
53
|
+
why: 'the next-intl stack of every front end (fe-stack i18n, owner:next-i18n-package): defineI18n over the locales of the app, the locale-negotiating proxy, the locale-aware navigation, the request config that loads the catalogs of the app and the locale read of the [locale] layout; the app keeps its message catalogs and writes none of the stack.'
|
|
47
54
|
'@starci/eslint-canon-be':
|
|
48
|
-
version: 3.
|
|
55
|
+
version: 3.14.0
|
|
49
56
|
group: starci
|
|
50
57
|
install: registry
|
|
51
58
|
side: be
|
|
52
59
|
source: packages/eslint-canon-be/package.json
|
|
53
60
|
why: 'the back-end ESLint canon: `loadHfs(import.meta.url)` of be/eslint.config.mjs finds the app-root hfs.json (kind app) and gives every linted file the view of the be side, and the project graph is built per side; its bundled runtime copies (slots, canon-pins, failure codes, the architecture machine) put .starcistacks and .sops.yaml at the app root; `starciBeConfig({ hfs: loadHfs(import.meta.url) })` is the typed factory and the BE-CONVENTION laws are its rules.'
|
|
54
61
|
'@starci/eslint-canon-fe':
|
|
55
|
-
version: 9.
|
|
62
|
+
version: 9.12.0
|
|
56
63
|
group: starci
|
|
57
64
|
install: registry
|
|
58
65
|
side: fe
|
|
59
66
|
source: packages/eslint-canon-fe/package.json
|
|
60
67
|
why: 'the front-end ESLint canon: `loadHfs(import.meta.url)` of fe/eslint.config.mjs finds the app-root hfs.json (kind app) and gives every linted file the view of the fe side, and the project graph is built per side; its bundled runtime copies (slots, canon-pins, failure codes, the architecture machine) put .starcistacks and .sops.yaml at the app root; the front end has no tests (FE_NO_TESTS R97 in hfs) and no-vietnamese-in-source (R91) applies.'
|
|
61
68
|
'@starci/eslint-grammar-core':
|
|
62
|
-
version: 0.21.
|
|
69
|
+
version: 0.21.15
|
|
63
70
|
group: starci
|
|
64
71
|
install: registry
|
|
65
72
|
side: fe
|
|
66
73
|
source: packages/eslint-grammar-core/package.json
|
|
67
74
|
why: 'the StarCi Grammar component API lint, versioned with @starci/grammar; front ends compose this family package with the universal FE canon.'
|
|
68
75
|
'@starci/eslint-grammar-offset-pop':
|
|
69
|
-
version: 0.21.
|
|
76
|
+
version: 0.21.15
|
|
70
77
|
group: starci
|
|
71
78
|
install: registry
|
|
72
79
|
side: fe
|
|
73
80
|
source: packages/eslint-grammar-offset-pop/package.json
|
|
74
81
|
why: 'the Offset Pop Grammar component API lint, versioned with @starci/grammar; its shared component contract comes from the StarCi family lint without copying rules.'
|
|
75
82
|
'@starci/stylelint-canon':
|
|
76
|
-
version: 2.
|
|
83
|
+
version: 2.6.0
|
|
77
84
|
group: starci
|
|
78
85
|
install: registry
|
|
79
86
|
side: fe
|
|
@@ -92,7 +99,7 @@ pins:
|
|
|
92
99
|
side: both
|
|
93
100
|
source: packages/prettier-config/package.json
|
|
94
101
|
'@starci/jest-preset':
|
|
95
|
-
version: 2.6.
|
|
102
|
+
version: 2.6.2
|
|
96
103
|
group: starci
|
|
97
104
|
install: registry
|
|
98
105
|
side: be
|
|
@@ -112,13 +119,27 @@ pins:
|
|
|
112
119
|
side: be
|
|
113
120
|
source: packages/ai-router/package.json
|
|
114
121
|
why: 'the AI pool router of a back end: a NestJS module that routes OpenAI-compatible chat, stream and embeddings calls across keys, models and providers, with @starci/ai-router/testing for its specs; @starci/jest-preset compiles it as an ESM-only dependency.'
|
|
115
|
-
'@starci/
|
|
122
|
+
'@starci/nest-kit':
|
|
116
123
|
version: 0.1.0
|
|
117
124
|
group: starci
|
|
118
125
|
install: registry
|
|
126
|
+
side: be
|
|
127
|
+
source: packages/nest-kit/package.json
|
|
128
|
+
why: 'the module definition of every back-end module: defineConfigurableModule and defineCapabilityModule return the module base class, the options token and the options types with their types stated, so a <x>.module-definition.ts is one call that the lint on stated export types (R368) and the duplicate-code check (R21) both accept; @starci/jest-preset compiles it as an ESM-only dependency.'
|
|
129
|
+
'@starci/auth':
|
|
130
|
+
version: 0.2.0
|
|
131
|
+
group: starci
|
|
132
|
+
install: registry
|
|
119
133
|
side: both
|
|
120
134
|
source: packages/auth/package.json
|
|
121
135
|
why: 'the lite sign-in: the NestJS module (EdDSA access tokens with a multi-key JWKS, passwords, Google OAuth with state and PKCE, rotating refresh sessions, the sign-in budget, the refresh cookie), the front-end client and its React bindings, the door contracts and test doubles; the one importer of the identity libraries, reached by a back end only through integrations/passport; @starci/jest-preset compiles it as an ESM-only dependency.'
|
|
136
|
+
'@starci/auth-oidc':
|
|
137
|
+
version: 0.1.0
|
|
138
|
+
group: starci
|
|
139
|
+
install: registry
|
|
140
|
+
side: both
|
|
141
|
+
source: packages/auth-oidc/package.json
|
|
142
|
+
why: 'the full sign-in: the OIDC client of the identity provider (Keycloak) behind the PrincipalVerifier of @starci/auth, so guards do not change between editions: the NestJS module (issuer discovery, the JWKS with caching and rotation, algorithm-pinned token checks, role mapping, the authorization code flow with PKCE and nonce), the front-end client (PKCE redirect, one shared refresh, tokens in memory) and the fake issuer for tests; the one importer of jose in a full app, reached by a back end only through integrations/keycloak; @starci/jest-preset compiles it as an ESM-only dependency.'
|
|
122
143
|
'@starci/object-storage':
|
|
123
144
|
version: 0.1.0
|
|
124
145
|
group: starci
|
|
@@ -126,8 +147,15 @@ pins:
|
|
|
126
147
|
side: be
|
|
127
148
|
source: packages/object-storage/package.json
|
|
128
149
|
why: 'object storage of a back end: a NestJS module and the ObjectStorage port over S3-compatible storage (presigned PUT and GET that sign the content type and size, head, get, put, list, delete, bucket setup, size and content-type limits, coded errors), with @starci/object-storage/testing for its specs; the only importer of @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner (R331).'
|
|
150
|
+
'@starci/mail':
|
|
151
|
+
version: 0.1.0
|
|
152
|
+
group: starci
|
|
153
|
+
install: registry
|
|
154
|
+
side: be
|
|
155
|
+
source: packages/mail/package.json
|
|
156
|
+
why: 'outgoing mail of a back end: a NestJS module and the Mailer port over SMTP (connect, greeting, socket and total timeouts, STARTTLS required by default, recipient, message and attachment checks, a shared SMTP target policy, coded errors, typed escaping render helpers returning { subject, text, html }), with @starci/mail/testing for its specs; the only importer of nodemailer (R90).'
|
|
129
157
|
'@starci/hfs':
|
|
130
|
-
version: 5.
|
|
158
|
+
version: 5.3.0
|
|
131
159
|
group: starci
|
|
132
160
|
install: registry
|
|
133
161
|
side: both
|
|
@@ -570,6 +598,11 @@ pins:
|
|
|
570
598
|
group: framework
|
|
571
599
|
side: be
|
|
572
600
|
why: 'signs the presigned PUT and GET inside @starci/object-storage locally, the same release as client-s3; no app file imports it.'
|
|
601
|
+
nodemailer:
|
|
602
|
+
version: 10.1.7
|
|
603
|
+
group: framework
|
|
604
|
+
side: be
|
|
605
|
+
why: 'the SMTP client inside @starci/mail, which depends on it at exactly this version and which no app file imports; 10.1.7 is the release of 2026-10-18, chosen over newer ones that had not aged two weeks.'
|
|
573
606
|
'@apollo/server':
|
|
574
607
|
version: 5.5.1
|
|
575
608
|
group: framework
|
|
@@ -670,7 +703,7 @@ pins:
|
|
|
670
703
|
version: 6.2.12
|
|
671
704
|
group: framework
|
|
672
705
|
side: be
|
|
673
|
-
why: signs the app's own
|
|
706
|
+
why: signs the app's own access tokens and verifies them against its own key set inside @starci/auth, and verifies the identity provider's tokens against its JWKS inside @starci/auth-oidc; no app file imports it.
|
|
674
707
|
class-transformer:
|
|
675
708
|
version: 0.5.1
|
|
676
709
|
group: framework
|
|
@@ -96,18 +96,18 @@ concerns:
|
|
|
96
96
|
hand-written reader (read-event-stream.ts) and no second SSE library is installed.
|
|
97
97
|
- id: auth
|
|
98
98
|
tier: core
|
|
99
|
-
packages: ['@starci/auth']
|
|
99
|
+
packages: ['@starci/auth', '@starci/auth-oidc']
|
|
100
100
|
home: [fe.modules.auth]
|
|
101
101
|
pattern: FE-AUTH
|
|
102
102
|
forbids: ['@supabase/supabase-js', '@supabase/ssr', '@supabase/auth-js', jose, jwt-decode, next-auth, '@auth/core', keycloak-js, oidc-client-ts]
|
|
103
103
|
why: modules/auth is the session issuer's client (one @starci/auth client instance over the app's own back-end auth doors, the access token in its memory; full - the app's IdP client); it yields the session and the access token for the Apollo link and never reads data.
|
|
104
104
|
- id: i18n
|
|
105
105
|
tier: core
|
|
106
|
-
packages: [next-intl]
|
|
106
|
+
packages: [next-intl, '@starci/next-i18n']
|
|
107
107
|
home: [fe.modules.i18n]
|
|
108
108
|
pattern: FE-I18N
|
|
109
109
|
forbids: [i18next, react-i18next, next-i18next, react-intl, '@lingui/react']
|
|
110
|
-
why: useTranslations for copy and the next-intl formatter for numbers, fixed dates and currency; FE-DATE owns live time display.
|
|
110
|
+
why: useTranslations for copy and the next-intl formatter for numbers, fixed dates and currency; FE-DATE owns live time display. The routing, the proxy, the navigation, the request config and the locale read of the layout are @starci/next-i18n's (owner next-i18n-package); an app calls no defineRouting, createNavigation, getRequestConfig or createMiddleware.
|
|
111
111
|
- id: ui
|
|
112
112
|
tier: core
|
|
113
113
|
packages: ['@heroui/react', '@heroui/styles', tailwindcss, '@starci/grammar', react-aria-components]
|
|
@@ -133,8 +133,8 @@ rules:
|
|
|
133
133
|
- {path: packages/hfs/src/hfs-managed-file-drift.spec.mjs, edition: full, codes: [HFS_MANAGED_FILE_DRIFT]}
|
|
134
134
|
- id: R06
|
|
135
135
|
code: "HFS_PLAINTEXT_SECRET"
|
|
136
|
-
law: "Secrets exist only as `.starcistacks/<env>/secrets/<slug>.enc`."
|
|
137
|
-
kinds: [check, design]
|
|
136
|
+
law: "Secrets exist only as `.starcistacks/<env>/secrets/<slug>.enc`; the committed check cache (`.starcistacks/cache/check/secrets/`) holds codes, paths, positions and digests only, and is judged by what it holds."
|
|
137
|
+
kinds: [check, design, codemod]
|
|
138
138
|
gates: [pre-commit, land, ci]
|
|
139
139
|
failureCodes: ["HFS_PLAINTEXT_SECRET"]
|
|
140
140
|
enforcers:
|
|
@@ -143,7 +143,7 @@ rules:
|
|
|
143
143
|
editions: [lite, full]
|
|
144
144
|
docs: [docs/legacy-managed-rule-coverage.md#r06-plaintext-secrets]
|
|
145
145
|
templateNa: "Encrypted secrets are supplied by the app secret command; plaintext secret files are forbidden and are never scaffolded."
|
|
146
|
-
proves: [packages/hfs/src/hfs-plaintext-secret.spec.mjs]
|
|
146
|
+
proves: [packages/hfs/src/hfs-plaintext-secret.spec.mjs, packages/hfs/src/check-cache-secret-records.spec.mjs]
|
|
147
147
|
exemplifiedBy:
|
|
148
148
|
- {path: packages/hfs/src/hfs-plaintext-secret.spec.mjs, editions: [lite, full]}
|
|
149
149
|
witness:
|
|
@@ -1216,7 +1216,7 @@ rules:
|
|
|
1216
1216
|
code: "FE_I18N_PLACEMENT"
|
|
1217
1217
|
editions: [lite, full]
|
|
1218
1218
|
docs: [docs/architecture.md#r59]
|
|
1219
|
-
law: "`next-intl` with `[locale]`;
|
|
1219
|
+
law: "`next-intl` with `[locale]`; the stack (routing, proxy, navigation, request config, the layout's locale read) is built by `@starci/next-i18n` over the app's `defineI18n` description and by no product source. A single app keeps the description and its request config in `modules/i18n` and builds its navigation with `createI18nNavigation` in the `modules/routes` public entry; apps that share a product share one `fe/packages/<family>-i18n` workspace package that holds the description and composes the package's factories through `createAppI18n`. The proxy is `createProxy` of `@starci/next-i18n/proxy` and never evaluates navigation runtime."
|
|
1220
1220
|
kinds: [check, codemod, lint]
|
|
1221
1221
|
gates: [settle, land, ci]
|
|
1222
1222
|
failureCodes: ["FE_I18N_PLACEMENT", "FE_I18N_NAVIGATION", "FE_I18N_FORMATTER"]
|
|
@@ -1269,6 +1269,7 @@ rules:
|
|
|
1269
1269
|
- {kind: stylelint, id: raw-brand-value}
|
|
1270
1270
|
- {kind: stylelint, id: no-apply-raw}
|
|
1271
1271
|
- {kind: stylelint, id: no-important}
|
|
1272
|
+
- {kind: stylelint, id: no-self-reference}
|
|
1272
1273
|
- {kind: stylelint, id: globals-shape}
|
|
1273
1274
|
- {kind: stylelint, id: globals-import-order}
|
|
1274
1275
|
- {kind: stylelint, id: no-token-redefinition}
|
|
@@ -4263,7 +4264,7 @@ rules:
|
|
|
4263
4264
|
editionWhy: "owner:lite-backing-services makes the db service lite's database; application-role and forced-RLS requirements apply to that backing."
|
|
4264
4265
|
docs: [docs/microservices.md#r255]
|
|
4265
4266
|
templateNa: "Application roles and table ownership are product-authored db migration content, rather than a scaffolded SQL surface."
|
|
4266
|
-
law: "The declared back-end database role (app_be by default) has only the privileges it needs: role declarations refuse superuser and bypassrls, require noinherit and nobypassrls,
|
|
4267
|
+
law: "The declared back-end database role (app_be by default) has only the privileges it needs: role declarations refuse superuser and bypassrls, require noinherit and nobypassrls, never grant all schema or table privileges, and leave it with no grant after the last migration on schema auth, on a table or sequence in it, or by default privilege for it (accounts are reached through SECURITY DEFINER doors; a later migration that revokes a grant clears it). Tables owned by that role enable and force row level security by default; a forceRls exemption identifies the table and carries a nonempty reason. This applies to every edition that declares Supabase."
|
|
4267
4268
|
kinds: [check]
|
|
4268
4269
|
gates: [settle, land, ci]
|
|
4269
4270
|
failureCodes: ["DB_APP_ROLE", "DB_FORCE_RLS_DEFAULT"]
|
|
@@ -4773,7 +4774,7 @@ rules:
|
|
|
4773
4774
|
|
|
4774
4775
|
- id: R279
|
|
4775
4776
|
code: "BE_THIRD_PARTY_OWNER"
|
|
4776
|
-
law: "Third-party SDK ownership is derived from the app's package.json dependencies rather than a finite SDK table. A dependency outside the pure-library and framework allowlists is imported only by one integrations/<provider> capability; domain services call that integration's public API. Existing infrastructure owner restrictions remain in force."
|
|
4777
|
+
law: "Third-party SDK ownership is derived from the app's package.json dependencies rather than a finite SDK table. A dependency outside the pure-library and framework allowlists is imported only by one integrations/<provider> capability; domain services call that integration's public API. A workspace package of the app itself (a folder the root workspaces of package.json name) is first-party source and no SDK; what it imports is judged over its own files. Existing infrastructure owner restrictions remain in force."
|
|
4777
4778
|
kinds: [lint]
|
|
4778
4779
|
gates: [pre-commit, settle, land, ci]
|
|
4779
4780
|
failureCodes: ["BE_THIRD_PARTY_OWNER"]
|
|
@@ -5083,7 +5084,7 @@ rules:
|
|
|
5083
5084
|
- {path: packages/hfs/src/hfs-stacks-deploy.spec.mjs, editions: [lite, full]}
|
|
5084
5085
|
- id: R295
|
|
5085
5086
|
code: "BE_MODULE_DEFINITION_MISSING"
|
|
5086
|
-
law: "Every NestJS module of the product has a module definition (owner ruling 2026-10-15, owner:module-definition-everywhere): capability modules, sub-modules, features, transport modules and cli groups alike. For a module `<x>` the folder holds `<x>.module-definition.ts` (`export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
|
|
5087
|
+
law: "Every NestJS module of the product has a module definition (owner ruling 2026-10-15, owner:module-definition-everywhere): capability modules, sub-modules, features, transport modules and cli groups alike. For a module `<x>` the folder holds `<x>.module-definition.ts` (`export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE, ASYNC_OPTIONS_TYPE } = defineConfigurableModule<XOptions>()` of `@starci/nest-kit`, which states the exported types so the file is neither an inferred surface (R368) nor a clone of its neighbour (R21); the representative module of a capability calls `defineCapabilityModule<XOptions>()`, which adds the `isGlobal` extra defaulting to `false`; `starci app codemod module-definition` rewrites a definition written with `ConfigurableModuleBuilder`), `<x>.options.ts` (`export type XOptions`, `Record<string, never>` with a one-line doc when it takes nothing yet) and `<x>.module.ts` (`@Module({...}) export class XModule extends ConfigurableModuleClass {}`, no `register` override except the capability representative's). A module appears in an `imports` array or in an app composition group only as `XModule.register({...})`, never as a bare class. The `AppModule` of an app root and the test world are composition roots and are not judged."
|
|
5087
5088
|
kinds: [lint, codemod]
|
|
5088
5089
|
gates: [pre-commit, settle, land, ci]
|
|
5089
5090
|
failureCodes: ["BE_MODULE_DEFINITION_MISSING"]
|
|
@@ -5697,20 +5698,23 @@ rules:
|
|
|
5697
5698
|
ruling: "A model call made straight from code uses LangChain with retrieved context, through the ai-router gateway (owner ruling be-ai-langchain-gateway): the LangChain clients point at the gateway's base URL with its virtual key."
|
|
5698
5699
|
- id: R328
|
|
5699
5700
|
code: "BE_AUTH_PASSPORT_OWNER"
|
|
5700
|
-
law: "The identity libraries (@nestjs/passport, passport, passport-google-oauth20, passport-local, @nestjs/jwt, jose and bcryptjs) are the dependencies of @starci/auth and are imported by no app file; @starci/auth/server is imported only by integrations/passport,
|
|
5701
|
+
law: "The identity libraries (@nestjs/passport, passport, passport-google-oauth20, passport-local, @nestjs/jwt, jose and bcryptjs) are the dependencies of @starci/auth (lite) and of @starci/auth-oidc (full, which owns jose for its provider tokens) and are imported by no app file; @starci/auth/server is imported only by integrations/passport and @starci/auth-oidc/server only by integrations/keycloak, each package's one glue. bcrypt and every Supabase client are owned nowhere."
|
|
5701
5702
|
kinds: [lint]
|
|
5702
5703
|
gates: [pre-commit, settle, land, ci]
|
|
5703
5704
|
failureCodes: ["BE_AUTH_PASSPORT_OWNER"]
|
|
5704
5705
|
enforcers:
|
|
5705
5706
|
- {kind: eslint-be, id: infra-import-owner}
|
|
5706
|
-
editions: [lite]
|
|
5707
|
+
editions: [lite, full]
|
|
5707
5708
|
docs: [contexts/code/be/api-auth.md]
|
|
5708
5709
|
proves:
|
|
5709
5710
|
- packages/eslint-canon-be/src/auth-passport.spec.ts
|
|
5711
|
+
- packages/eslint-canon-be/src/auth-oidc-package.spec.ts
|
|
5710
5712
|
exemplifiedBy:
|
|
5711
5713
|
- {path: packages/hfs/templates/be/skeleton-lite/src/modules/integrations/passport/passport.tokens.ts, edition: lite}
|
|
5714
|
+
- {path: packages/auth-oidc/src/server/index.ts, edition: full}
|
|
5712
5715
|
witness:
|
|
5713
5716
|
- {path: packages/eslint-canon-be/src/auth-passport.spec.ts, edition: lite, codes: [BE_AUTH_PASSPORT_OWNER]}
|
|
5717
|
+
- {path: packages/eslint-canon-be/src/auth-oidc-package.spec.ts, edition: full, codes: [BE_AUTH_PASSPORT_OWNER]}
|
|
5714
5718
|
cases:
|
|
5715
5719
|
- id: case-1
|
|
5716
5720
|
date: "2026-10-29"
|