@pattern-stack/codegen 0.17.2 → 0.18.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.
Files changed (118) hide show
  1. package/README.md +106 -2
  2. package/dist/{chunk-65MO75WM.js → chunk-2VGVSL2D.js} +8 -8
  3. package/dist/{chunk-VNBC3VXM.js → chunk-3A34R6CI.js} +7 -7
  4. package/dist/{chunk-I6UXRJ3Q.js → chunk-43SBT72G.js} +4 -4
  5. package/dist/{chunk-7OVCARTQ.js → chunk-5RT7JGKT.js} +4 -4
  6. package/dist/{chunk-E6PLM6QG.js → chunk-7MMS36AN.js} +9 -9
  7. package/dist/{chunk-4MVGAMUA.js → chunk-BK5ICA2F.js} +4 -4
  8. package/dist/{chunk-VDL5CJ5C.js → chunk-C5E7H553.js} +7 -7
  9. package/dist/{chunk-IOQMMH6C.js → chunk-CFFTPWHM.js} +79 -4
  10. package/dist/chunk-CFFTPWHM.js.map +1 -0
  11. package/dist/{chunk-XKWOJZZ4.js → chunk-E45CSC33.js} +2 -2
  12. package/dist/{chunk-AZLUWG5S.js → chunk-EWYI5GGJ.js} +13 -13
  13. package/dist/{chunk-BHZP6LOV.js → chunk-IN3EWFB4.js} +4 -4
  14. package/dist/{chunk-CZQUOIDY.js → chunk-J7JMVS2B.js} +4 -4
  15. package/dist/{chunk-KSTZIULO.js → chunk-K2I6XIK5.js} +4 -4
  16. package/dist/{chunk-Z7PQCAVK.js → chunk-LQ6PYFU6.js} +4 -4
  17. package/dist/{chunk-T6SCOJF4.js → chunk-NXHL5YII.js} +4 -4
  18. package/dist/{chunk-ATVGYF3D.js → chunk-PKDS6QIJ.js} +7 -7
  19. package/dist/{chunk-OZEPJGMA.js → chunk-R4BPUUB5.js} +4 -4
  20. package/dist/{chunk-B34G6PHD.js → chunk-RKNW56RU.js} +8 -8
  21. package/dist/{chunk-R6F6KFIL.js → chunk-TBGTMALE.js} +4 -4
  22. package/dist/{chunk-GM3RMJIJ.js → chunk-VHAR2BGH.js} +4 -4
  23. package/dist/{chunk-CLWBNXKF.js → chunk-W2UIDI3R.js} +4 -4
  24. package/dist/{chunk-235ZMMJR.js → chunk-X6BP6LI5.js} +3 -3
  25. package/dist/{chunk-KZDHMZ45.js → chunk-YZLBU6O2.js} +10 -10
  26. package/dist/runtime/base-classes/index.js +24 -24
  27. package/dist/runtime/subsystems/analytics/analytics.module.js +2 -2
  28. package/dist/runtime/subsystems/analytics/index.js +4 -4
  29. package/dist/runtime/subsystems/auth/auth.module.js +2 -2
  30. package/dist/runtime/subsystems/auth/index.js +12 -12
  31. package/dist/runtime/subsystems/bridge/bridge-delivery-handler.js +2 -2
  32. package/dist/runtime/subsystems/bridge/bridge-delivery.drizzle-backend.js +3 -3
  33. package/dist/runtime/subsystems/bridge/bridge-outbox-drain-hook.js +6 -6
  34. package/dist/runtime/subsystems/bridge/bridge.module.js +17 -17
  35. package/dist/runtime/subsystems/bridge/event-flow.service.js +2 -2
  36. package/dist/runtime/subsystems/bridge/index.js +24 -24
  37. package/dist/runtime/subsystems/cache/cache.module.js +1 -1
  38. package/dist/runtime/subsystems/cache/index.js +3 -3
  39. package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js +3 -3
  40. package/dist/runtime/subsystems/events/event-bus.memory-backend.js +2 -2
  41. package/dist/runtime/subsystems/events/events.module.js +7 -7
  42. package/dist/runtime/subsystems/events/generated/bus.js +2 -2
  43. package/dist/runtime/subsystems/events/generated/index.js +2 -2
  44. package/dist/runtime/subsystems/events/index.js +10 -10
  45. package/dist/runtime/subsystems/index.js +90 -90
  46. package/dist/runtime/subsystems/integration/build-change-source.js +2 -2
  47. package/dist/runtime/subsystems/integration/index.js +36 -36
  48. package/dist/runtime/subsystems/integration/integration.module.js +4 -4
  49. package/dist/runtime/subsystems/jobs/index.js +29 -29
  50. package/dist/runtime/subsystems/jobs/job-orchestrator.bullmq-backend.js +5 -5
  51. package/dist/runtime/subsystems/jobs/job-orchestrator.drizzle-backend.js +3 -3
  52. package/dist/runtime/subsystems/jobs/job-run-service.drizzle-backend.js +3 -3
  53. package/dist/runtime/subsystems/jobs/job-run-service.memory-backend.js +2 -2
  54. package/dist/runtime/subsystems/jobs/job-worker.js +3 -3
  55. package/dist/runtime/subsystems/jobs/job-worker.module.js +10 -10
  56. package/dist/runtime/subsystems/jobs/jobs-domain.module.js +8 -8
  57. package/dist/runtime/subsystems/observability/index.js +3 -3
  58. package/dist/runtime/subsystems/observability/observability.module.js +3 -3
  59. package/dist/runtime/subsystems/observability/observability.service.js +2 -2
  60. package/dist/runtime/subsystems/storage/index.js +4 -4
  61. package/dist/runtime/subsystems/storage/storage.module.js +2 -2
  62. package/dist/src/cli/index.js +1415 -252
  63. package/dist/src/cli/index.js.map +1 -1
  64. package/dist/src/index.d.ts +18 -0
  65. package/dist/src/index.js +12 -12
  66. package/package.json +1 -1
  67. package/src/config/locations.mjs +0 -6
  68. package/src/config/paths.mjs +0 -13
  69. package/templates/entity/new/prompt.js +12 -88
  70. package/dist/chunk-IOQMMH6C.js.map +0 -1
  71. package/templates/entity/new/frontend/_inject-entities-entry.ejs.t +0 -7
  72. package/templates/entity/new/frontend/_inject-entities-import.ejs.t +0 -7
  73. package/templates/entity/new/frontend/collections/_ensure-anchor-collections.ejs.t +0 -10
  74. package/templates/entity/new/frontend/collections/_inject-index.ejs.t +0 -9
  75. package/templates/entity/new/frontend/collections/_inject-schema-import.ejs.t +0 -9
  76. package/templates/entity/new/frontend/collections/collection.ejs.t +0 -86
  77. package/templates/entity/new/frontend/collections/collections-base.ejs.t +0 -35
  78. package/templates/entity/new/frontend/entity/collection.ejs.t +0 -173
  79. package/templates/entity/new/frontend/entity/combined.ejs.t +0 -505
  80. package/templates/entity/new/frontend/entity/fields.ejs.t +0 -105
  81. package/templates/entity/new/frontend/entity/hooks.ejs.t +0 -74
  82. package/templates/entity/new/frontend/entity/index.ejs.t +0 -22
  83. package/templates/entity/new/frontend/entity/mutation-hooks.ejs.t +0 -85
  84. package/templates/entity/new/frontend/entity/mutations.ejs.t +0 -39
  85. package/templates/entity/new/frontend/entity/types.ejs.t +0 -60
  86. package/templates/entity/new/frontend/generated/_inject-index-export.ejs.t +0 -7
  87. package/templates/entity/new/frontend/generated/_inject-index-import.ejs.t +0 -7
  88. package/templates/entity/new/frontend/generated/_inject-index-registry.ejs.t +0 -7
  89. package/templates/entity/new/frontend/store/_inject-collection-import.ejs.t +0 -9
  90. package/templates/entity/new/frontend/store/_inject-collections.ejs.t +0 -9
  91. package/templates/entity/new/frontend/store/_inject-entity.ejs.t +0 -9
  92. package/templates/entity/new/frontend/store/_inject-import.ejs.t +0 -9
  93. package/templates/entity/new/frontend/store/_inject-lookups.ejs.t +0 -9
  94. package/templates/entity/new/frontend/store/_inject-resolve.ejs.t +0 -10
  95. package/templates/entity/new/frontend/store/hooks.ejs.t +0 -73
  96. package/templates/entity/new/frontend/unified-entity.ejs.t +0 -29
  97. /package/dist/{chunk-65MO75WM.js.map → chunk-2VGVSL2D.js.map} +0 -0
  98. /package/dist/{chunk-VNBC3VXM.js.map → chunk-3A34R6CI.js.map} +0 -0
  99. /package/dist/{chunk-I6UXRJ3Q.js.map → chunk-43SBT72G.js.map} +0 -0
  100. /package/dist/{chunk-7OVCARTQ.js.map → chunk-5RT7JGKT.js.map} +0 -0
  101. /package/dist/{chunk-E6PLM6QG.js.map → chunk-7MMS36AN.js.map} +0 -0
  102. /package/dist/{chunk-4MVGAMUA.js.map → chunk-BK5ICA2F.js.map} +0 -0
  103. /package/dist/{chunk-VDL5CJ5C.js.map → chunk-C5E7H553.js.map} +0 -0
  104. /package/dist/{chunk-XKWOJZZ4.js.map → chunk-E45CSC33.js.map} +0 -0
  105. /package/dist/{chunk-AZLUWG5S.js.map → chunk-EWYI5GGJ.js.map} +0 -0
  106. /package/dist/{chunk-BHZP6LOV.js.map → chunk-IN3EWFB4.js.map} +0 -0
  107. /package/dist/{chunk-CZQUOIDY.js.map → chunk-J7JMVS2B.js.map} +0 -0
  108. /package/dist/{chunk-KSTZIULO.js.map → chunk-K2I6XIK5.js.map} +0 -0
  109. /package/dist/{chunk-Z7PQCAVK.js.map → chunk-LQ6PYFU6.js.map} +0 -0
  110. /package/dist/{chunk-T6SCOJF4.js.map → chunk-NXHL5YII.js.map} +0 -0
  111. /package/dist/{chunk-ATVGYF3D.js.map → chunk-PKDS6QIJ.js.map} +0 -0
  112. /package/dist/{chunk-OZEPJGMA.js.map → chunk-R4BPUUB5.js.map} +0 -0
  113. /package/dist/{chunk-B34G6PHD.js.map → chunk-RKNW56RU.js.map} +0 -0
  114. /package/dist/{chunk-R6F6KFIL.js.map → chunk-TBGTMALE.js.map} +0 -0
  115. /package/dist/{chunk-GM3RMJIJ.js.map → chunk-VHAR2BGH.js.map} +0 -0
  116. /package/dist/{chunk-CLWBNXKF.js.map → chunk-W2UIDI3R.js.map} +0 -0
  117. /package/dist/{chunk-235ZMMJR.js.map → chunk-X6BP6LI5.js.map} +0 -0
  118. /package/dist/{chunk-KZDHMZ45.js.map → chunk-YZLBU6O2.js.map} +0 -0
package/README.md CHANGED
@@ -138,6 +138,104 @@ modules/{plural}/
138
138
  use-cases/ FindById, List, declarative queries
139
139
  ```
140
140
 
141
+ **Frontend** (`generate.frontend: true`) — see [Frontend generation](#frontend-generation) below.
142
+
143
+ ## Frontend generation
144
+
145
+ Gated entirely by `generate.frontend` (default `false`; the scanner sets it
146
+ `true` when it finds an `apps/frontend/` directory). When on, the `entity new`
147
+ post-step (and therefore `gen-all`) renders the **complete frontend tree from the
148
+ full entity set in one pass** — a TypeScript emitter (`src/emitters/frontend/`),
149
+ not hygen templates. Re-running is idempotent: every file is a complete-file
150
+ write with a `@generated` banner, no inject/anchor machinery, no overwrite
151
+ prompts (ADR-038).
152
+
153
+ Output lands under `locations.frontendGenerated` (default
154
+ `apps/frontend/src/generated/`):
155
+
156
+ ```
157
+ generated/
158
+ index.ts whole-set barrel (+ version-pairing comment)
159
+ config.ts per-entity sync modes + runtime overrides
160
+ query-client.ts shared TanStack QueryClient
161
+ api/<entity>.ts REST client → the generated NestJS controllers
162
+ collections/<entity>.ts createCollection, branched on the entity's sync mode
163
+ entities/<entity>.ts createEntityHooks({ collection, api }) wiring
164
+ store/index.ts createStore over the full set (+ resolvers, lookups)
165
+ fields/<entity>.ts field metadata (FieldMeta, <entity>Fields)
166
+ ```
167
+
168
+ Entity types and Zod schemas are **imported** from `locations.dbEntities`
169
+ (default `@repo/db/entities`), not re-emitted. The emitter imports the plain
170
+ class name — `import type { <Class> } from '<dbEntities>/<name>'` — so
171
+ `dbEntities` is the contract: it MUST export the entity type under its plain
172
+ `<Class>` name (e.g. `Contact`, not `ContactEntity`). If your db package only
173
+ exports `<Class>Entity`, that is the one knob to change in the emitter.
174
+
175
+ The hook/mutation/store/provider logic is consumed from
176
+ `@pattern-stack/frontend-patterns` (`createEntityHooks`, `createStore`) — the
177
+ generated files are thin wiring. **The consumer's frontend installs that package
178
+ plus the paired TanStack libraries.** `project init` adds the version-pairing
179
+ deps to `apps/frontend/package.json` when `generate.frontend: true` (idempotent
180
+ merge — only missing keys added, existing version ranges preserved); when no
181
+ frontend package.json exists it prints the list to install. `@pattern-stack/codegen`
182
+ itself gains no runtime dependency.
183
+
184
+ | Package | Range |
185
+ |---|---|
186
+ | `@pattern-stack/frontend-patterns` | `^0.2.0-alpha.18` |
187
+ | `@tanstack/react-db` | `^0.1.55` |
188
+ | `@tanstack/electric-db-collection` | `^0.2.11` |
189
+ | `@tanstack/query-db-collection` | `^1.0.6` |
190
+ | `@tanstack/react-query` | `^5.0.0` |
191
+
192
+ ### `frontend:` config block
193
+
194
+ All knobs are inert unless `generate.frontend: true`. Defaults shown; the block
195
+ is optional (fully defaulted when absent):
196
+
197
+ ```yaml
198
+ frontend:
199
+ auth:
200
+ function: getAuthorizationHeader # auth-header fn; null DISABLES the header
201
+ parsers: # Electric column-type → parser fn source
202
+ timestamptz: '(date: string) => new Date(date)'
203
+ sync:
204
+ mode: electric # global default sync mode (api | electric)
205
+ shapeUrl: /v1/shape # Electric shape base path
206
+ useTableParam: true # emit `params: { table }` shape-URL form
207
+ columnMapper: snakeCamelMapper # Electric column mapper fn; null to omit
208
+ columnMapperNeedsCall: true # call the mapper (fn()) vs reference (fn)
209
+ apiBaseUrlImport: null # when set, import API_BASE_URL from it as baseURL
210
+ apiUrl: /api # REST base path when no apiBaseUrlImport
211
+ ```
212
+
213
+ `null`-disables convention: an **absent** `auth.function` defaults to
214
+ `getAuthorizationHeader`; an **explicit `null`** disables it entirely (no header
215
+ lines emitted). Likewise `sync.columnMapper: null` omits the Electric mapper.
216
+
217
+ ### Per-entity sync mode (`entity.sync`)
218
+
219
+ Each entity may override the global `frontend.sync.mode` inside its `entity:`
220
+ block (sibling to `surface:`/`context:`):
221
+
222
+ ```yaml
223
+ entity:
224
+ name: contact
225
+ plural: contacts
226
+ table: contacts
227
+ sync: api # api | electric — overrides frontend.sync.mode for this entity
228
+ ```
229
+
230
+ `api` wires `queryCollectionOptions` (REST via TanStack Query); `electric` wires
231
+ `electricCollectionOptions` (real-time shape sync). Absent → the global default.
232
+ `offline` (Electric + Dexie) is deferred — the schema rejects it.
233
+
234
+ Cross-entity FK names (file, plural, class, collection var) are resolved against
235
+ the **target entity's own YAML** via the registry — never re-pluralized from a
236
+ string at emit time (so an explicit `plural:` like `person`→`persons` is honored
237
+ by every consumer).
238
+
141
239
  ## Integration Codegen (provider/adapter + assembly + read primitive)
142
240
 
143
241
  When an entity carries a `surface:` tag and `definitions/providers/*.yaml` exist,
@@ -261,9 +359,14 @@ naming:
261
359
  terminology:
262
360
  command: use-case
263
361
  query: use-case
362
+
363
+ # frontend: # inert unless generate.frontend: true
364
+ # ... # see "Frontend generation" above for the full block
264
365
  ```
265
366
 
266
- Auto-detect your project's conventions with `codegen project scan`.
367
+ The `frontend:` block (auth, parsers, sync) is documented under
368
+ [Frontend generation](#frontend-generation). Auto-detect your project's
369
+ conventions with `codegen project scan`.
267
370
 
268
371
  ## Using in Your Project
269
372
 
@@ -276,6 +379,7 @@ See [docs/GETTING-STARTED.md](docs/GETTING-STARTED.md) for a walkthrough of enti
276
379
  ```
277
380
  src/ Generator source code
278
381
  cli/ Clipanion CLI (noun-verb architecture)
382
+ emitters/ TypeScript emitters (integration, frontend — ADR-038)
279
383
  analyzer/ Graph building, consistency checking
280
384
  parser/ YAML loading, cross-reference resolution
281
385
  scanner/ Project pattern detection
@@ -287,7 +391,7 @@ src/ Generator source code
287
391
  runtime/ Code shipped into consumer projects
288
392
  base-classes/ BaseRepository, BaseService, pattern bases
289
393
  subsystems/ Events, Jobs, Cache, Storage
290
- templates/ Hygen EJS templates
394
+ templates/ Hygen EJS templates (backend pipelines)
291
395
  test/ Baseline snapshots, scaffold integration, smoke test
292
396
  docs/ ADRs, consumer setup, getting started
293
397
  ```
@@ -1,22 +1,22 @@
1
1
  import {
2
2
  BRIDGE_DELIVERY_JOB_TYPE
3
- } from "./chunk-R6F6KFIL.js";
3
+ } from "./chunk-TBGTMALE.js";
4
4
  import {
5
5
  bridgeDelivery
6
6
  } from "./chunk-2TVVBC53.js";
7
7
  import {
8
- JOBS_WAKE_CHANNEL,
9
- pgNotify
10
- } from "./chunk-Q6LRJ4VI.js";
8
+ jobRuns
9
+ } from "./chunk-OKXZ63IA.js";
11
10
  import {
12
11
  JOBS_LISTEN_NOTIFY
13
12
  } from "./chunk-ZPL74UQN.js";
13
+ import {
14
+ JOBS_WAKE_CHANNEL,
15
+ pgNotify
16
+ } from "./chunk-Q6LRJ4VI.js";
14
17
  import {
15
18
  BRIDGE_REGISTRY
16
19
  } from "./chunk-4LH67P4U.js";
17
- import {
18
- jobRuns
19
- } from "./chunk-OKXZ63IA.js";
20
20
  import {
21
21
  __decorateClass,
22
22
  __decorateParam
@@ -151,4 +151,4 @@ BridgeOutboxDrainHook = __decorateClass([
151
151
  export {
152
152
  BridgeOutboxDrainHook
153
153
  };
154
- //# sourceMappingURL=chunk-65MO75WM.js.map
154
+ //# sourceMappingURL=chunk-2VGVSL2D.js.map
@@ -1,6 +1,3 @@
1
- import {
2
- MissingTenantIdError
3
- } from "./chunk-T4BIIU5E.js";
4
1
  import {
5
2
  clampLimit,
6
3
  decodeKeysetCursor,
@@ -8,12 +5,15 @@ import {
8
5
  toJobRunSummary
9
6
  } from "./chunk-L3LZWWSX.js";
10
7
  import {
11
- JOBS_MULTI_TENANT,
12
- JOB_ORCHESTRATOR
13
- } from "./chunk-ZPL74UQN.js";
8
+ MissingTenantIdError
9
+ } from "./chunk-T4BIIU5E.js";
14
10
  import {
15
11
  jobRuns
16
12
  } from "./chunk-OKXZ63IA.js";
13
+ import {
14
+ JOBS_MULTI_TENANT,
15
+ JOB_ORCHESTRATOR
16
+ } from "./chunk-ZPL74UQN.js";
17
17
  import {
18
18
  DRIZZLE
19
19
  } from "./chunk-U64T4YZE.js";
@@ -198,4 +198,4 @@ DrizzleJobRunService = __decorateClass([
198
198
  export {
199
199
  DrizzleJobRunService
200
200
  };
201
- //# sourceMappingURL=chunk-VNBC3VXM.js.map
201
+ //# sourceMappingURL=chunk-3A34R6CI.js.map
@@ -1,9 +1,9 @@
1
- import {
2
- WebhookChangeSource
3
- } from "./chunk-TIZXQU26.js";
4
1
  import {
5
2
  PollChangeSource
6
3
  } from "./chunk-4MF3HKJA.js";
4
+ import {
5
+ WebhookChangeSource
6
+ } from "./chunk-TIZXQU26.js";
7
7
 
8
8
  // runtime/subsystems/integration/build-change-source.ts
9
9
  function buildChangeSource(cfg, fetch, middlewares = []) {
@@ -26,4 +26,4 @@ function buildChangeSource(cfg, fetch, middlewares = []) {
26
26
  export {
27
27
  buildChangeSource
28
28
  };
29
- //# sourceMappingURL=chunk-I6UXRJ3Q.js.map
29
+ //# sourceMappingURL=chunk-43SBT72G.js.map
@@ -4,14 +4,14 @@ import {
4
4
  import {
5
5
  JOB_ORCHESTRATOR
6
6
  } from "./chunk-ZPL74UQN.js";
7
- import {
8
- EVENT_BUS
9
- } from "./chunk-H5NH7KPE.js";
10
7
  import {
11
8
  BRIDGE_DELIVERY_REPO,
12
9
  BRIDGE_MULTI_TENANT,
13
10
  BRIDGE_REGISTRY
14
11
  } from "./chunk-4LH67P4U.js";
12
+ import {
13
+ EVENT_BUS
14
+ } from "./chunk-H5NH7KPE.js";
15
15
  import {
16
16
  DRIZZLE
17
17
  } from "./chunk-U64T4YZE.js";
@@ -106,4 +106,4 @@ EventFlowService = __decorateClass([
106
106
  export {
107
107
  EventFlowService
108
108
  };
109
- //# sourceMappingURL=chunk-7OVCARTQ.js.map
109
+ //# sourceMappingURL=chunk-5RT7JGKT.js.map
@@ -5,23 +5,23 @@ import {
5
5
  JobTypeNotFoundError,
6
6
  MissingTenantIdError
7
7
  } from "./chunk-T4BIIU5E.js";
8
- import {
9
- JOBS_WAKE_CHANNEL,
10
- pgNotify
11
- } from "./chunk-Q6LRJ4VI.js";
12
8
  import {
13
9
  keySelectorToTemplate,
14
10
  resolveJobKey
15
11
  } from "./chunk-7P5ODGLA.js";
16
- import {
17
- JOBS_LISTEN_NOTIFY,
18
- JOBS_MULTI_TENANT
19
- } from "./chunk-ZPL74UQN.js";
20
12
  import {
21
13
  jobRuns,
22
14
  jobSteps,
23
15
  jobs
24
16
  } from "./chunk-OKXZ63IA.js";
17
+ import {
18
+ JOBS_LISTEN_NOTIFY,
19
+ JOBS_MULTI_TENANT
20
+ } from "./chunk-ZPL74UQN.js";
21
+ import {
22
+ JOBS_WAKE_CHANNEL,
23
+ pgNotify
24
+ } from "./chunk-Q6LRJ4VI.js";
25
25
  import {
26
26
  DRIZZLE
27
27
  } from "./chunk-U64T4YZE.js";
@@ -393,4 +393,4 @@ export {
393
393
  evaluateKeyTemplate,
394
394
  DrizzleJobOrchestrator
395
395
  };
396
- //# sourceMappingURL=chunk-E6PLM6QG.js.map
396
+ //# sourceMappingURL=chunk-7MMS36AN.js.map
@@ -1,12 +1,12 @@
1
+ import {
2
+ STORAGE
3
+ } from "./chunk-NYBCQZC7.js";
1
4
  import {
2
5
  LocalStorageBackend
3
6
  } from "./chunk-JWNHNUYL.js";
4
7
  import {
5
8
  MemoryStorageBackend
6
9
  } from "./chunk-3SZFUTXE.js";
7
- import {
8
- STORAGE
9
- } from "./chunk-NYBCQZC7.js";
10
10
  import {
11
11
  __decorateClass
12
12
  } from "./chunk-2E224ZSN.js";
@@ -37,4 +37,4 @@ StorageModule = __decorateClass([
37
37
  export {
38
38
  StorageModule
39
39
  };
40
- //# sourceMappingURL=chunk-4MVGAMUA.js.map
40
+ //# sourceMappingURL=chunk-BK5ICA2F.js.map
@@ -1,18 +1,18 @@
1
- import {
2
- JOBS_WAKE_CHANNEL,
3
- PgNotifyListener
4
- } from "./chunk-Q6LRJ4VI.js";
5
1
  import {
6
2
  JOB_HANDLER_REGISTRY
7
3
  } from "./chunk-7P5ODGLA.js";
4
+ import {
5
+ jobRuns
6
+ } from "./chunk-OKXZ63IA.js";
8
7
  import {
9
8
  JOB_ORCHESTRATOR,
10
9
  JOB_RUN_SERVICE,
11
10
  JOB_STEP_SERVICE
12
11
  } from "./chunk-ZPL74UQN.js";
13
12
  import {
14
- jobRuns
15
- } from "./chunk-OKXZ63IA.js";
13
+ JOBS_WAKE_CHANNEL,
14
+ PgNotifyListener
15
+ } from "./chunk-Q6LRJ4VI.js";
16
16
  import {
17
17
  tokenKey
18
18
  } from "./chunk-GYGNEQSC.js";
@@ -528,4 +528,4 @@ export {
528
528
  buildStaleSweepQuery,
529
529
  JobWorker
530
530
  };
531
- //# sourceMappingURL=chunk-VDL5CJ5C.js.map
531
+ //# sourceMappingURL=chunk-C5E7H553.js.map
@@ -349,7 +349,14 @@ var EntityConfigSchema = z.object({
349
349
  context: z.string().regex(
350
350
  /^[a-z][a-z0-9_]*$/,
351
351
  "context must be lowercase snake_case (e.g. 'integration')"
352
- ).optional()
352
+ ).optional(),
353
+ // ADR-038: per-entity frontend sync mode. Overrides global frontend.sync.mode.
354
+ // 'api' → queryCollectionOptions (REST via TanStack Query)
355
+ // 'electric' → electricCollectionOptions (real-time shape sync)
356
+ // 'offline' (Electric + Dexie) is deferred — see
357
+ // docs/specs/2026-06-04-frontend-pipeline-rebuild.md OQ-6.
358
+ // Sibling to `surface:`/`context:`; lives inside the `entity:` block.
359
+ sync: z.enum(["api", "electric"]).optional()
353
360
  }).strict().refine((d) => !(d.pattern && d.patterns), {
354
361
  message: "'pattern' and 'patterns' are mutually exclusive"
355
362
  });
@@ -1320,6 +1327,7 @@ function transformToEntity(result) {
1320
1327
  patterns: definition.entity.patterns,
1321
1328
  patternConfig: definition.entity.config,
1322
1329
  scopeable: definition.entity.scopeable ?? false,
1330
+ expose: definition.entity.expose ?? ["repository", "rest", "trpc"],
1323
1331
  folderStructure: definition.entity.folder_structure ?? "nested",
1324
1332
  fields: /* @__PURE__ */ new Map(),
1325
1333
  relationships: /* @__PURE__ */ new Map(),
@@ -1664,9 +1672,75 @@ function resolveRelationshipReferences(relationshipDefs, entities) {
1664
1672
  return issues;
1665
1673
  }
1666
1674
 
1675
+ // src/parser/entity-registry.ts
1676
+ import { resolve as resolve3 } from "path";
1677
+ var camelCase = (s) => s.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
1678
+ var pascalCase = (s) => {
1679
+ const camel = camelCase(s);
1680
+ return camel.charAt(0).toUpperCase() + camel.slice(1);
1681
+ };
1682
+ function loadErrorToIssue2(error) {
1683
+ const issues = [
1684
+ {
1685
+ severity: "error",
1686
+ type: "parse_error",
1687
+ message: error.error,
1688
+ path: error.filePath
1689
+ }
1690
+ ];
1691
+ if (error.details) {
1692
+ for (const detail of error.details) {
1693
+ issues.push({
1694
+ severity: "error",
1695
+ type: "schema_error",
1696
+ message: detail,
1697
+ path: error.filePath
1698
+ });
1699
+ }
1700
+ }
1701
+ return issues;
1702
+ }
1703
+ function loadEntityRegistry(entitiesDir) {
1704
+ const registry = /* @__PURE__ */ new Map();
1705
+ const issues = [];
1706
+ const resolvedDir = resolve3(entitiesDir);
1707
+ let files;
1708
+ try {
1709
+ files = findYamlFiles(resolvedDir);
1710
+ } catch {
1711
+ issues.push({
1712
+ severity: "error",
1713
+ type: "parse_error",
1714
+ message: `Failed to read directory: ${resolvedDir}`,
1715
+ path: resolvedDir
1716
+ });
1717
+ return { registry, issues };
1718
+ }
1719
+ for (const filePath of files) {
1720
+ const result = loadEntityFromYaml(filePath);
1721
+ if (!result.success) {
1722
+ issues.push(...loadErrorToIssue2(result));
1723
+ continue;
1724
+ }
1725
+ const { entity } = result.definition;
1726
+ registry.set(entity.name, {
1727
+ name: entity.name,
1728
+ plural: entity.plural,
1729
+ // authoritative — never derived
1730
+ table: entity.table,
1731
+ className: pascalCase(entity.name),
1732
+ classNamePlural: pascalCase(entity.plural),
1733
+ camelName: camelCase(entity.name),
1734
+ pluralCamelName: camelCase(entity.plural),
1735
+ sync: entity.sync ?? null
1736
+ });
1737
+ }
1738
+ return { registry, issues };
1739
+ }
1740
+
1667
1741
  // src/parser/validate-providers.ts
1668
1742
  import { existsSync as existsSync2, readFileSync as readFileSync2, statSync } from "fs";
1669
- import { isAbsolute, join as join2, resolve as resolve3 } from "path";
1743
+ import { isAbsolute, join as join2, resolve as resolve4 } from "path";
1670
1744
  import ts from "typescript";
1671
1745
  function collectEntitySurfaces(entities) {
1672
1746
  const surfaces = /* @__PURE__ */ new Set();
@@ -1698,7 +1772,7 @@ function resolveModuleFile(importPath, opts) {
1698
1772
  }
1699
1773
  }
1700
1774
  if (base === null) {
1701
- base = isAbsolute(importPath) ? importPath : resolve3(opts.sourceRoot, importPath);
1775
+ base = isAbsolute(importPath) ? importPath : resolve4(opts.sourceRoot, importPath);
1702
1776
  }
1703
1777
  const candidates = [
1704
1778
  base,
@@ -3999,6 +4073,7 @@ export {
3999
4073
  detectYamlType,
4000
4074
  loadEntities,
4001
4075
  loadRelationships,
4076
+ loadEntityRegistry,
4002
4077
  collectEntitySurfaces,
4003
4078
  validateProviders,
4004
4079
  buildDomainGraph,
@@ -4049,4 +4124,4 @@ export {
4049
4124
  analyzeDomain,
4050
4125
  validateEntities
4051
4126
  };
4052
- //# sourceMappingURL=chunk-IOQMMH6C.js.map
4127
+ //# sourceMappingURL=chunk-CFFTPWHM.js.map