@akanjs/cli 3.0.0-alpha.92 → 3.0.0-alpha.94

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/.build-stamp CHANGED
@@ -1 +1 @@
1
- 5d5ad210e5a6f57f93e8d14285cd21a0f6dc7e7b413bbc7b337f9c2554d37ac5
1
+ 9e1fb3c80249688a2b66d9624a455a30e358f4181e7d6ef9ca10d1b23148433e
@@ -555,6 +555,7 @@ Full contract — relevance ordering, `columns` / `weights`: `get_guideline` wit
555
555
  - Injected dependencies resolve by field-name convention: a field named `<refName>Service` resolves to the service registered under `<refName>`, and `<refName>Signal` likewise (`pkgs/akanjs/service/injectInfo.ts`).
556
556
  - The `Service`/`Signal` suffix is required — the injector strips it to derive the registry lookup key. Name the field after the target refName plus the suffix, not arbitrarily.
557
557
  - Preference order inside a service: `service<srv.XService>()` for another module's service · `plug(AdapterClass)` or `plug(StorageAdaptorRole)` for an adapter · `use<T>()` only to reach an `option.ts`-registered legacy singleton · `env(...)` for config.
558
+ - **`memory(...)` takes a scalar or model class, not only a primitive** — `memory(Map, { of: CallStateInput })` serializes through the constant and travels as JSON text, so the Redis and sqlite-backed caches round-trip the same declaration. Never hand-encode JSON into a `String` memory.
558
559
 
559
560
  ### Adapters — `adapt()` And `plug()`
560
561
 
@@ -736,7 +737,11 @@ shape, so `cascade` never means "related" — it means one of exactly these:
736
737
  its owner, so the owner never learns about its children and a lib model can be extended by an app's. Three
737
738
  forms: a relation, an id with `ref`, or a polymorphic id with `refPath`. An array, a Map, `ref` together with
738
739
  `refPath`, and a field naming no owner each fail the class build.
739
- - **A `refPath` must name an `enumOf` field** — a free-form owner type is unknowable at build time.
740
+ - **A `refPath` must name an `enumOf` field** — a free-form owner type is unknowable at build time. The one
741
+ exception is opt-in and priced: `polymorphic: "any"` alongside `cascade: "removeWith"` takes a free-form
742
+ `String` type field holding the owner's refName, and sweeps for children on **every** model's removal. The
743
+ sweep is one indexed probe, but a single wildcard edge turns every cascade in the app back to one document at
744
+ a time; the boot log names the edges in one `info` line.
740
745
  - **A cascade goes through the target's service, never its model** — that path is what runs the target's
741
746
  `_postRemove`, where a module puts the side effect the removal has to carry.
742
747
  - **Nothing checks whether another document still references the same target.** `File` in particular is deduped by
@@ -121,6 +121,26 @@ shape, so `cascade` never means "related" — it means one of exactly these:
121
121
  `refPath`. An array, a Map, `ref` together with `refPath`, and a field naming no owner each fail the class build.
122
122
  - **A `refPath` must name an `enumOf` field** — a free-form owner type is unknowable at build time, so every
123
123
  model's removal would have to sweep the polymorphic table on the chance it is the owner.
124
+ - **`polymorphic: "any"` buys that sweep on purpose**, for the one shape an enum cannot express: a child whose
125
+ owner is any model in the app, named by a free-form `String` holding the owner's refName.
126
+
127
+ ```ts
128
+ parent: field(ID, { refPath: "parentType", cascade: "removeWith", polymorphic: "any" }),
129
+ parentType: field(String), // holds the owner's refName
130
+ ```
131
+
132
+ The lookup itself is cheap — the declaration auto-creates the same `{ removedAt, typeKey, fk }` index, so a
133
+ removal that owns nothing is one index probe returning zero rows, not a scan. **The price is bulk: one wildcard
134
+ edge anywhere turns every cascade in the app back to one document at a time**, because a query-level removal of
135
+ *any* model would be a removal whose wildcard children were never looked for. The boot log says so in one
136
+ `info` line naming the edges — that line is the answer to "why does this app remove everything per document".
137
+ The opt-in is what keeps an app that declared none on the fast path.
138
+
139
+ Refused at the class build: `polymorphic: "any"` on a `refPath` that already names an `enumOf` (the enum names
140
+ the candidates and indexes better — keep one), a `typeKey` that is not a `String` (the sweep matches a refName
141
+ against that column, and a column that cannot hold one silently finds nothing), and the option anywhere other
142
+ than a `cascade: "removeWith"` field with a `refPath`. A wildcard owner is also exempt from the mount check
143
+ that a monomorphic owner fails at boot — it names no module to mount.
124
144
  - **A cascade goes through the target's service, never its model** — that path is what runs the target's
125
145
  `_postRemove`, where a module puts the side effect the removal has to carry.
126
146
  - **Bulk is decided at boot, per target model, for both directions.** A target with no `remove` schema hook, no
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akanjs/cli",
3
- "version": "3.0.0-alpha.92",
3
+ "version": "3.0.0-alpha.94",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -33,7 +33,7 @@
33
33
  "@langchain/openai": "^1.4.6",
34
34
  "@tailwindcss/node": "^4.3.0",
35
35
  "@trapezedev/project": "^7.1.4",
36
- "akanjs": "3.0.0-alpha.92",
36
+ "akanjs": "3.0.0-alpha.94",
37
37
  "chalk": "^5.6.2",
38
38
  "commander": "^14.0.3",
39
39
  "dayjs": "^1.11.20",