@pattern-stack/codegen 0.20.2 → 0.21.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 (57) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/dist/{chunk-3VEVGL74.js → chunk-3A34R6CI.js} +4 -4
  3. package/dist/{chunk-KK5A7B2T.js → chunk-524YKITE.js} +134 -20
  4. package/dist/chunk-524YKITE.js.map +1 -0
  5. package/dist/{chunk-VDL5CJ5C.js → chunk-6CJRZHV4.js} +4 -4
  6. package/dist/{chunk-COGHTKXY.js → chunk-7625PLY7.js} +4 -4
  7. package/dist/{chunk-QMN3LQR3.js → chunk-EEJC66ZF.js} +9 -9
  8. package/dist/{chunk-NR7QQ6ZI.js → chunk-G3IKPDTP.js} +2 -2
  9. package/dist/{chunk-BKP72EDW.js → chunk-GMRTI7AK.js} +12 -12
  10. package/dist/{chunk-E5FJWOMP.js → chunk-GV337QP3.js} +7 -7
  11. package/dist/{chunk-D44QFQJZ.js → chunk-MBFSG4KQ.js} +3 -3
  12. package/dist/{chunk-JGGZUP64.js → chunk-NXHL5YII.js} +7 -7
  13. package/dist/{chunk-E6PLM6QG.js → chunk-TKU6VYG3.js} +6 -6
  14. package/dist/{chunk-MVKW2BCR.js → chunk-YULGWXCY.js} +4 -4
  15. package/dist/{chunk-DB5UXJC3.js → chunk-YXI7K4MJ.js} +4 -4
  16. package/dist/runtime/base-classes/index.js +22 -22
  17. package/dist/runtime/shared/openapi/index.js +3 -3
  18. package/dist/runtime/subsystems/auth/auth.module.js +3 -3
  19. package/dist/runtime/subsystems/auth/index.js +15 -15
  20. package/dist/runtime/subsystems/bridge/bridge-delivery.drizzle-backend.js +3 -3
  21. package/dist/runtime/subsystems/bridge/bridge-outbox-drain-hook.js +4 -4
  22. package/dist/runtime/subsystems/bridge/bridge.module.js +15 -15
  23. package/dist/runtime/subsystems/bridge/index.js +24 -24
  24. package/dist/runtime/subsystems/cache/cache.module.js +2 -2
  25. package/dist/runtime/subsystems/cache/index.js +4 -4
  26. package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js +2 -2
  27. package/dist/runtime/subsystems/events/events.module.js +3 -3
  28. package/dist/runtime/subsystems/events/index.js +5 -5
  29. package/dist/runtime/subsystems/index.js +85 -85
  30. package/dist/runtime/subsystems/jobs/index.js +27 -27
  31. package/dist/runtime/subsystems/jobs/job-orchestrator.bullmq-backend.js +5 -5
  32. package/dist/runtime/subsystems/jobs/job-orchestrator.drizzle-backend.js +2 -2
  33. package/dist/runtime/subsystems/jobs/job-run-service.drizzle-backend.js +2 -2
  34. package/dist/runtime/subsystems/jobs/job-worker.bullmq-backend.js +3 -3
  35. package/dist/runtime/subsystems/jobs/job-worker.js +2 -2
  36. package/dist/runtime/subsystems/jobs/job-worker.module.js +9 -9
  37. package/dist/runtime/subsystems/jobs/jobs-domain.module.js +7 -7
  38. package/dist/runtime/subsystems/storage/index.js +1 -1
  39. package/dist/runtime/subsystems/storage/storage.module.js +1 -1
  40. package/dist/src/cli/index.js +80 -76
  41. package/dist/src/cli/index.js.map +1 -1
  42. package/dist/src/index.d.ts +111 -1
  43. package/dist/src/index.js +3 -1
  44. package/package.json +1 -1
  45. package/dist/chunk-KK5A7B2T.js.map +0 -1
  46. /package/dist/{chunk-3VEVGL74.js.map → chunk-3A34R6CI.js.map} +0 -0
  47. /package/dist/{chunk-VDL5CJ5C.js.map → chunk-6CJRZHV4.js.map} +0 -0
  48. /package/dist/{chunk-COGHTKXY.js.map → chunk-7625PLY7.js.map} +0 -0
  49. /package/dist/{chunk-QMN3LQR3.js.map → chunk-EEJC66ZF.js.map} +0 -0
  50. /package/dist/{chunk-NR7QQ6ZI.js.map → chunk-G3IKPDTP.js.map} +0 -0
  51. /package/dist/{chunk-BKP72EDW.js.map → chunk-GMRTI7AK.js.map} +0 -0
  52. /package/dist/{chunk-E5FJWOMP.js.map → chunk-GV337QP3.js.map} +0 -0
  53. /package/dist/{chunk-D44QFQJZ.js.map → chunk-MBFSG4KQ.js.map} +0 -0
  54. /package/dist/{chunk-JGGZUP64.js.map → chunk-NXHL5YII.js.map} +0 -0
  55. /package/dist/{chunk-E6PLM6QG.js.map → chunk-TKU6VYG3.js.map} +0 -0
  56. /package/dist/{chunk-MVKW2BCR.js.map → chunk-YULGWXCY.js.map} +0 -0
  57. /package/dist/{chunk-DB5UXJC3.js.map → chunk-YXI7K4MJ.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,54 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.21.0] — 2026-06-06
8
+
9
+ **FieldMeta enrichment (ADR-040, Phase A of type-aware rendering).** The
10
+ frontend emitter's per-entity field metadata now carries enough vocabulary for
11
+ consumers to build metadata-driven rendering (the swe-brain renderer kit
12
+ consumes this in its Phase B). All additive.
13
+
14
+ ### Added
15
+
16
+ - **Full `ui_*` hint passthrough.** `ui_group`, `ui_visible`, `ui_placeholder`,
17
+ `ui_help`, and `ui_format` were accepted by the schema but dropped before
18
+ emission. They now survive parser → derivation → emitted `FieldMeta`
19
+ (`group` / `visible` / `placeholder` / `help` / `format`). `format` was
20
+ previously only ever the hardcoded timestamp `{ dateFormat: 'relative' }`;
21
+ authored `ui_format` now passes through.
22
+ - **Key-field curation (qField parity).** New YAML keys `ui_key_field` +
23
+ `ui_key_field_order` surface as `isKeyField` / `keyFieldOrder` on the row
24
+ (the qField / EAV `field_definitions` names — one vocabulary, multiple
25
+ homes), and `<camel>Metadata` gains `keyFields`: the ordered curated
26
+ field-name list (sorted by `keyFieldOrder`, declaration order for ties) that
27
+ drives card/preview field selection.
28
+ - **Family/behavior common-field bundles** (timestamps precedent): the
29
+ `soft_delete` behavior now contributes a `deletedAt` row
30
+ (datetime / tertiary / relative); entities whose declared fields carry the
31
+ synced/integrated shape (both `external_id` AND `provider`) get
32
+ `group: 'external_sync'` defaulted onto those fields (plus
33
+ `provider_metadata` when present) — a derivation default only, authored
34
+ `ui_group` always wins. Behavior-contributed columns (not in the parsed
35
+ field map) still get no rows: the emitter never emits a row for a column it
36
+ cannot see.
37
+ - **EAV `data_type` → `FieldType` contract.** `EAV_DATA_TYPE_TO_FIELD_TYPE`
38
+ (`string→text, integer/decimal→number, boolean→boolean, date→date,
39
+ datetime→datetime, json→json, reference→reference, picklist→enum,
40
+ multipicklist→enum`; multi-select rendering is consumer-side) is exported
41
+ from the package root AND emitted into every generated
42
+ `fields/field-meta.ts`, rendered from the same source object so the copies
43
+ cannot drift. See ADR-040 for the convergence story
44
+ (qField/CatalogField ↔ codegen FieldMeta ↔ EAV `field_definitions`).
45
+
46
+ ### Tests
47
+
48
+ - emit-fields suite: hint passthrough (incl. author-override-beats-default and
49
+ string escaping), key-field curation + `keyFields` ordering, soft_delete /
50
+ external-sync bundles, EAV contract completeness vs the emitted copy.
51
+ - Frontend golden fixtures now exercise the new surface; the snapshot locks
52
+ curation ordering (`first_name` before `email` despite declaration order),
53
+ the `deletedAt` bundle, and the `external_sync` group default.
54
+
7
55
  ## [0.20.2] — 2026-06-06
8
56
 
9
57
  Two consumer-found fixes (dogfooding swe-brain on 0.20.1).
@@ -7,13 +7,13 @@ import {
7
7
  import {
8
8
  MissingTenantIdError
9
9
  } from "./chunk-T4BIIU5E.js";
10
+ import {
11
+ jobRuns
12
+ } from "./chunk-OKXZ63IA.js";
10
13
  import {
11
14
  JOBS_MULTI_TENANT,
12
15
  JOB_ORCHESTRATOR
13
16
  } from "./chunk-ZPL74UQN.js";
14
- import {
15
- jobRuns
16
- } from "./chunk-OKXZ63IA.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-3VEVGL74.js.map
201
+ //# sourceMappingURL=chunk-3A34R6CI.js.map
@@ -120,7 +120,12 @@ var UiMetadataSchema = z.object({
120
120
  ui_visible: z.boolean().optional(),
121
121
  ui_placeholder: z.string().optional(),
122
122
  ui_help: z.string().optional(),
123
- ui_format: z.record(z.unknown()).optional()
123
+ ui_format: z.record(z.unknown()).optional(),
124
+ // Key-field curation (ADR-040): curated/displayed fields that drive card &
125
+ // preview surfaces. Names mirror qField / EAV `field_definitions`
126
+ // (`isKeyField` / `keyFieldOrder`) — one metadata vocabulary, multiple homes.
127
+ ui_key_field: z.boolean().optional(),
128
+ ui_key_field_order: z.number().optional()
124
129
  });
125
130
  var BaseFieldSchema = z.object({
126
131
  type: FieldTypeSchema,
@@ -1371,6 +1376,22 @@ function detectYamlType(filePath) {
1371
1376
  }
1372
1377
 
1373
1378
  // src/parser/load-entities.ts
1379
+ function parseUiMetadata(fieldDef) {
1380
+ return {
1381
+ label: fieldDef.ui_label,
1382
+ type: fieldDef.ui_type,
1383
+ importance: fieldDef.ui_importance,
1384
+ group: fieldDef.ui_group,
1385
+ sortable: fieldDef.ui_sortable,
1386
+ filterable: fieldDef.ui_filterable,
1387
+ visible: fieldDef.ui_visible,
1388
+ placeholder: fieldDef.ui_placeholder,
1389
+ help: fieldDef.ui_help,
1390
+ format: fieldDef.ui_format,
1391
+ keyField: fieldDef.ui_key_field,
1392
+ keyFieldOrder: fieldDef.ui_key_field_order
1393
+ };
1394
+ }
1374
1395
  function transformToEntity(result) {
1375
1396
  const { definition, filePath } = result;
1376
1397
  const queries = definition.queries?.filter((q) => "by" in q).map((q) => ({
@@ -1413,15 +1434,7 @@ function transformToEntity(result) {
1413
1434
  min: fieldDef.min,
1414
1435
  max: fieldDef.max
1415
1436
  },
1416
- ui: {
1417
- label: fieldDef.ui_label,
1418
- type: fieldDef.ui_type,
1419
- importance: fieldDef.ui_importance,
1420
- group: fieldDef.ui_group,
1421
- sortable: fieldDef.ui_sortable,
1422
- filterable: fieldDef.ui_filterable,
1423
- visible: fieldDef.ui_visible
1424
- }
1437
+ ui: parseUiMetadata(fieldDef)
1425
1438
  };
1426
1439
  entity.fields.set(name, field);
1427
1440
  }
@@ -1614,15 +1627,7 @@ function transformToRelationshipDefinition(result) {
1614
1627
  min: fieldDef.min,
1615
1628
  max: fieldDef.max
1616
1629
  },
1617
- ui: {
1618
- label: fieldDef.ui_label,
1619
- type: fieldDef.ui_type,
1620
- importance: fieldDef.ui_importance,
1621
- group: fieldDef.ui_group,
1622
- sortable: fieldDef.ui_sortable,
1623
- filterable: fieldDef.ui_filterable,
1624
- visible: fieldDef.ui_visible
1625
- }
1630
+ ui: parseUiMetadata(fieldDef)
1626
1631
  };
1627
1632
  fields.set(name, field);
1628
1633
  }
@@ -4066,6 +4071,109 @@ registerLibraryPattern(KnowledgePattern);
4066
4071
  registerLibraryPattern(MetadataPattern);
4067
4072
  registerLibraryPattern(JunctionPattern);
4068
4073
 
4074
+ // src/emitters/frontend/field-meta.ts
4075
+ var CAMEL = (s) => s.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
4076
+ function formatLabel(fieldName) {
4077
+ return fieldName.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
4078
+ }
4079
+ function inferUiType(field) {
4080
+ if (field.ui.type) return field.ui.type;
4081
+ if (Array.isArray(field.choices) && field.choices.length > 0) return "enum";
4082
+ if (field.foreignKey) return "reference";
4083
+ const nameLower = field.name.toLowerCase();
4084
+ if (nameLower.includes("email")) return "email";
4085
+ if (nameLower.includes("url") || nameLower.includes("website")) return "url";
4086
+ if (nameLower.includes("password")) return "password";
4087
+ if (nameLower.includes("price") || nameLower.includes("amount") || nameLower.includes("cost") || nameLower.includes("value") || nameLower.includes("revenue")) {
4088
+ return "money";
4089
+ }
4090
+ if (nameLower.includes("percent") || nameLower.includes("rate")) {
4091
+ return "percentage";
4092
+ }
4093
+ switch (field.type) {
4094
+ case "string":
4095
+ return field.constraints.maxLength && field.constraints.maxLength > 500 ? "textarea" : "text";
4096
+ case "integer":
4097
+ case "decimal":
4098
+ return "number";
4099
+ case "boolean":
4100
+ return "boolean";
4101
+ case "uuid":
4102
+ return "text";
4103
+ case "date":
4104
+ return "date";
4105
+ case "datetime":
4106
+ return "datetime";
4107
+ case "json":
4108
+ return "json";
4109
+ default:
4110
+ return "text";
4111
+ }
4112
+ }
4113
+ function inferUiImportance(field) {
4114
+ if (field.ui.importance) return field.ui.importance;
4115
+ const nameLower = field.name.toLowerCase();
4116
+ if (["id", "created_at", "updated_at", "deleted_at"].includes(nameLower)) {
4117
+ return "tertiary";
4118
+ }
4119
+ if (field.foreignKey && nameLower.endsWith("_id")) return "secondary";
4120
+ if (field.required) return "primary";
4121
+ if (nameLower.includes("name") || nameLower.includes("title")) return "primary";
4122
+ return "secondary";
4123
+ }
4124
+ function isEntityRefField(field) {
4125
+ if (field.type === "entity_ref") return true;
4126
+ return field.name.endsWith("_entity_type") || field.name.endsWith("_entity_id");
4127
+ }
4128
+ function deriveFieldMeta(field, defaults = {}) {
4129
+ const hasChoices = Array.isArray(field.choices) && field.choices.length > 0;
4130
+ const meta = {
4131
+ field: CAMEL(field.name),
4132
+ label: field.ui.label ?? formatLabel(field.name),
4133
+ type: inferUiType(field),
4134
+ importance: inferUiImportance(field),
4135
+ sortable: field.ui.sortable ?? false,
4136
+ filterable: field.ui.filterable ?? false
4137
+ };
4138
+ const group = field.ui.group ?? defaults.group;
4139
+ if (group !== void 0) meta.group = group;
4140
+ if (field.ui.visible !== void 0) meta.visible = field.ui.visible;
4141
+ if (field.ui.placeholder !== void 0) meta.placeholder = field.ui.placeholder;
4142
+ if (field.ui.help !== void 0) meta.help = field.ui.help;
4143
+ if (field.ui.format !== void 0) meta.format = field.ui.format;
4144
+ if (hasChoices) meta.choices = field.choices;
4145
+ if (field.foreignKey) meta.reference = field.foreignKey.table;
4146
+ if (field.ui.keyField) {
4147
+ meta.isKeyField = true;
4148
+ if (field.ui.keyFieldOrder !== void 0) {
4149
+ meta.keyFieldOrder = field.ui.keyFieldOrder;
4150
+ }
4151
+ }
4152
+ return meta;
4153
+ }
4154
+ var EXTERNAL_SYNC_GROUP = "external_sync";
4155
+ var EXTERNAL_SYNC_FIELDS = /* @__PURE__ */ new Set([
4156
+ "external_id",
4157
+ "provider",
4158
+ "provider_metadata"
4159
+ ]);
4160
+ function hasExternalSyncShape(fieldNames) {
4161
+ const names = new Set(fieldNames);
4162
+ return names.has("external_id") && names.has("provider");
4163
+ }
4164
+ var EAV_DATA_TYPE_TO_FIELD_TYPE = {
4165
+ string: "text",
4166
+ integer: "number",
4167
+ decimal: "number",
4168
+ boolean: "boolean",
4169
+ date: "date",
4170
+ datetime: "datetime",
4171
+ json: "json",
4172
+ reference: "reference",
4173
+ picklist: "enum",
4174
+ multipicklist: "enum"
4175
+ };
4176
+
4069
4177
  // src/index.ts
4070
4178
  async function analyzeDomain(entitiesDir, relationshipsOrOptions) {
4071
4179
  const opts = typeof relationshipsOrOptions === "string" ? { relationshipsDir: relationshipsOrOptions } : relationshipsOrOptions ?? {};
@@ -4186,7 +4294,13 @@ export {
4186
4294
  KnowledgePattern,
4187
4295
  MetadataPattern,
4188
4296
  IntegratedPattern,
4297
+ isEntityRefField,
4298
+ deriveFieldMeta,
4299
+ EXTERNAL_SYNC_GROUP,
4300
+ EXTERNAL_SYNC_FIELDS,
4301
+ hasExternalSyncShape,
4302
+ EAV_DATA_TYPE_TO_FIELD_TYPE,
4189
4303
  analyzeDomain,
4190
4304
  validateEntities
4191
4305
  };
4192
- //# sourceMappingURL=chunk-KK5A7B2T.js.map
4306
+ //# sourceMappingURL=chunk-524YKITE.js.map