@starci/hfs 4.11.16 → 4.11.17

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.11.17 - 2026-10-30
4
+
5
+ - Fixed: `stemOfEvent` (the event class file name of R151) maps underscores to dashes as well as dots, matching eslint-canon-be's `event-consumer-shape` and the kebab case of `source-suffix`.
6
+ - Fixed: `starci app emit`'s write pass (outDir is the app root) no longer calls `appHasDbTypes`/`writeDbTypes`, whose module (`emit/db-types.mjs`) left with the lite Supabase types in 4.10.0: every write pass aborted after `events.json` and wrote no `schema.graphql` or `openapi.json`. `emitContracts` answers `{ written, skipped, standIns }`; spec: the write pass in `src/input-bounds-emit.spec.mjs`.
7
+ - Changed: the bundled canon pins name ai-router 0.4.0 (mounted keys), hfs 4.11.17, eslint-canon-be 3.8.16, eslint-canon-fe 9.5.18 and the Grammar family 0.15.29. No rule or template changed.
8
+
3
9
  ## 4.11.16 - 2026-10-30
4
10
 
5
11
  - Fixed: the back-end skeleton's `OriginGuard` (`platform/http-security`, BE-AUTH-5) requires an actual allowed `Origin` header on a cookie-bearing mutation (`POST`, `PUT`, `PATCH`, `DELETE` with a `Cookie` header) and on a door or handler marked with the new `RequireOrigin()` (`http-security.decorators.ts`, metadata `REQUIRE_ORIGIN_KEY`), which covers the start of a cookie-authenticated flow before the first cookie exists. A missing, empty, opaque (`null`) or foreign `Origin` is refused with `HTTP_SECURITY_ORIGIN_REJECTED` (403), and an allowed `Referer` no longer stands in for it there; `ServerToServer` does not exempt such a request. Safe methods, and mutations without a cookie on unmarked doors, keep their rules (Referer fallback when Origin is absent, the `ServerToServer` exemption). Spec `origin.guard.spec.ts`: class and handler markers, the first sign-in, cookie-bearing requests and the preserved admission paths, split into describe groups within the function budget.
@@ -27,7 +27,6 @@ import { fileURLToPath } from 'node:url';
27
27
  import { emitEvents, eventServices, eventsSnapshotPath } from './events.mjs';
28
28
  import { openapiPath } from './operations.mjs';
29
29
  import { readEnv } from '../runtime/scripts/lib/env.mjs';
30
- import { createSlotResolver, loadSlotManifest, locateDeclaration, readRepoDeclaration } from '../runtime/scripts/hfs/slots.mjs';
31
30
 
32
31
  /** The stderr prefix of a dependency the worker could not load and stood in for. */
33
32
  const STAND_IN = 'stand-in ';
@@ -75,37 +74,16 @@ function emitApp(repoRoot, app) {
75
74
  return { graphql: graphql.text, openapi: operations.text, standIns: [...graphql.lines, ...operations.lines] };
76
75
  }
77
76
 
78
- /**
79
- * The app-scope slot view of the repository `repoRoot` belongs to: `{ appRoot, resolver }`, or null when no app declaration
80
- * resolves there (a bare folder is not an app and emits no types). `repoRoot` is the be side folder, so `locateDeclaration`
81
- * answers the app root above it.
82
- */
83
- function appDbScope(repoRoot) {
84
- try {
85
- const { appRoot } = locateDeclaration(repoRoot);
86
- const manifest = loadSlotManifest();
87
- return { appRoot, resolver: createSlotResolver(manifest, readRepoDeclaration(manifest, appRoot)) };
88
- } catch {
89
- return null;
90
- }
91
- }
92
-
93
77
  /**
94
78
  * Writes the snapshots of every api app: `contracts/<app>/schema.graphql` when it serves GraphQL and `contracts/<app>/openapi.json`
95
- * when it has an operation table. Answers `{ written: [paths], skipped: [apps], standIns: { app: [lines] }, types }`, `skipped`
79
+ * when it has an operation table. Answers `{ written: [paths], skipped: [apps], standIns: { app: [lines] } }`, `skipped`
96
80
  * being the apps with neither. `declaration` is the parsed hfs.json. `outDir` (absolute) redirects the snapshots to another
97
81
  * root, keeping their relative paths.
98
- *
99
- * On the real write pass (`outDir` is `repoRoot`) the app's database types are written too when the slot `app.db.types`
100
- * is enabled: `resolver` is the app-scope slot view (built from the declaration at the app root when not passed), `appRoot`
101
- * overrides where the types land, and `run` is the command runner `writeDbTypes` spawns `psql` with. `types` in the answer
102
- * is `writeDbTypes`'s `{ path, changed }`, or null for an app without the slot or a redirected pass.
103
82
  */
104
- export function emitContracts({ repoRoot, declaration, outDir = repoRoot, resolver, appRoot, run } = {}) {
83
+ export function emitContracts({ repoRoot, declaration, outDir = repoRoot } = {}) {
105
84
  const written = [];
106
85
  const skipped = [];
107
86
  const standIns = {};
108
- let types = null;
109
87
  for (const app of apiApps(declaration)) {
110
88
  const emitted = emitApp(repoRoot, app);
111
89
  if (emitted.graphql === null && emitted.openapi === null) {
@@ -130,12 +108,5 @@ export function emitContracts({ repoRoot, declaration, outDir = repoRoot, resolv
130
108
  fs.writeFileSync(target, events);
131
109
  written.push(relative);
132
110
  }
133
- // The generated Database types are an app-level artifact of the write pass only: a redirected outDir is the R23 check
134
- // mode, and L09 judges drift on the same emitted text through the injected emitTypes (emit/db-types.mjs dbTypesEmitter).
135
- if (outDir === repoRoot) {
136
- const scope = resolver === undefined ? appDbScope(repoRoot) : { appRoot: locateDeclaration(repoRoot).appRoot, resolver };
137
- const target = appRoot ?? scope?.appRoot;
138
- if (target !== null && target !== undefined && scope?.resolver != null && appHasDbTypes(scope.resolver)) types = writeDbTypes({ root: target, run });
139
- }
140
- return { written, skipped, standIns, types };
111
+ return { written, skipped, standIns };
141
112
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@starci/hfs",
3
- "version": "4.11.16",
3
+ "version": "4.11.17",
4
4
  "description": "The StarCi app command implementation for scaffolding, linting, checking and synchronizing one product repository.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -31,35 +31,35 @@ pins:
31
31
  source: packages/event-stream/package.json
32
32
  why: 'the one server-sent-events client of every front end (fe-stack event-stream, owner:event-stream-package): the transport client layer (modules/api/sse/clients) creates one instance for the app with the bearer token source and the stream operations follow on it; it carries Last-Event-ID resume, the capped doubling backoff, the heartbeat timeout, the single 401 renewal and the useSWRSubscription adapter, so no app keeps a hand-written reader.'
33
33
  '@starci/grammar':
34
- version: 0.15.28
34
+ version: 0.15.29
35
35
  group: starci
36
36
  install: registry
37
37
  side: fe
38
38
  source: packages/grammar/package.json
39
39
  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.'
40
40
  '@starci/eslint-canon-be':
41
- version: 3.8.15
41
+ version: 3.8.16
42
42
  group: starci
43
43
  install: registry
44
44
  side: be
45
45
  source: packages/eslint-canon-be/package.json
46
46
  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.'
47
47
  '@starci/eslint-canon-fe':
48
- version: 9.5.17
48
+ version: 9.5.18
49
49
  group: starci
50
50
  install: registry
51
51
  side: fe
52
52
  source: packages/eslint-canon-fe/package.json
53
53
  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.'
54
54
  '@starci/eslint-grammar-core':
55
- version: 0.15.28
55
+ version: 0.15.29
56
56
  group: starci
57
57
  install: registry
58
58
  side: fe
59
59
  source: packages/eslint-grammar-core/package.json
60
60
  why: 'the StarCi Grammar component API lint, versioned with @starci/grammar; front ends compose this family package with the universal FE canon.'
61
61
  '@starci/eslint-grammar-offset-pop':
62
- version: 0.15.28
62
+ version: 0.15.29
63
63
  group: starci
64
64
  install: registry
65
65
  side: fe
@@ -99,14 +99,14 @@ pins:
99
99
  source: packages/test-world/package.json
100
100
  why: 'the shared e2e library of every back end (R47, R48), a devDependency of every back end: the warm stack behind toxiproxy, the network-edge fakes, the Nest boot, the typed useTestWorld handle, useSandbox for contract specs and the outage lock. A fake declared https (defineHttpFake) serves TLS with the run''s ephemeral in-memory fake CA and publishes its PEM as w.fake.<name>.ca for the app''s own client to trust; verification is never turned off. Kafka is real own infra (the one digest-pinned apache/kafka KRaft image, a broker listener and proxy per slot, slot-prefixed topics, consumer groups and client ids) and Postgres is schema-per-context (a schema and a login role per context in a shared database). Each worker has its own data slot (<ns>_w<k>) with its own databases, Keycloak realm, leased Redis DB, bucket/collection/topic prefixes, fakes host, toxiproxy proxies and outage lock; a run provisions min(jest workers, workers cap, default 2) slots, and state file protocol 2 pairs exactly with @starci/jest-preset (TEST_WORLD_PAIR_MISMATCH otherwise). A modules world boots real peer apps beside its modules, world.apps.<name>.during(fn) is the outage of a peer app, w.keycloak.clientSecret(client) answers the run-generated secret of a confidential realm client, world.keycloak.events/sessions read the realm user events and live sessions, world.infra.postgresql.connection(name) takes one database connection down while the others serve, and world.resolve and scope.resolve take any Nest token. Every path a declaration names (`stack`, seeds, the realm, Dockerfiles) resolves from the app root (the directory of hfs.json); the globalSetup registers the path aliases as TypeScript resolves them. Its CLI main is exported at ./cli for starci app stack.'
101
101
  '@starci/ai-router':
102
- version: 0.3.0
102
+ version: 0.4.0
103
103
  group: starci
104
104
  install: registry
105
105
  side: be
106
106
  source: packages/ai-router/package.json
107
107
  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.'
108
108
  '@starci/hfs':
109
- version: 4.11.16
109
+ version: 4.11.17
110
110
  group: starci
111
111
  install: registry
112
112
  side: both
@@ -28,8 +28,9 @@ const TEST_CALLEES = new Set(['it', 'test']);
28
28
  /** The TypeScript compiler of the app (else of the runtime), or null. */
29
29
  const typescriptFor = (repoRoot) => loadTypescript(repoRoot, HERE);
30
30
 
31
- /** The event-bus pattern file name of an event name: dots become dashes (`order.placed` -> `order-placed`). */
32
- export const stemOfEvent = (name) => name.replaceAll('.', '-');
31
+ /** The event-bus pattern file name of an event name: dots and underscores become dashes (`order.placed` -> `order-placed`,
32
+ * `installation_changed` -> `installation-changed`), the kebab case source-suffix gives every file. */
33
+ export const stemOfEvent = (name) => name.replaceAll(/[._]/gu, '-');
33
34
 
34
35
  /** The initializer of a `static` property member with an identifier name, parentheses and `as` casts stripped, else null. */
35
36
  function staticMemberValue(ts, member) {