@pattern-stack/codegen 0.20.2 → 0.22.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 (34) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +5 -1
  3. package/dist/{chunk-BKP72EDW.js → chunk-6DQEIXYU.js} +10 -10
  4. package/dist/{chunk-KK5A7B2T.js → chunk-6ECCJVYW.js} +136 -20
  5. package/dist/chunk-6ECCJVYW.js.map +1 -0
  6. package/dist/{chunk-QMN3LQR3.js → chunk-FNHNSFIJ.js} +9 -9
  7. package/dist/{chunk-JGGZUP64.js → chunk-NXHL5YII.js} +7 -7
  8. package/dist/{chunk-D44QFQJZ.js → chunk-QXVCRA23.js} +2 -2
  9. package/dist/{chunk-MVKW2BCR.js → chunk-YULGWXCY.js} +4 -4
  10. package/dist/runtime/base-classes/index.js +20 -20
  11. package/dist/runtime/shared/openapi/index.js +3 -3
  12. package/dist/runtime/subsystems/auth/auth.module.js +3 -3
  13. package/dist/runtime/subsystems/auth/index.js +15 -15
  14. package/dist/runtime/subsystems/bridge/bridge-delivery.drizzle-backend.js +2 -2
  15. package/dist/runtime/subsystems/bridge/bridge-outbox-drain-hook.js +1 -1
  16. package/dist/runtime/subsystems/bridge/bridge.module.js +10 -10
  17. package/dist/runtime/subsystems/bridge/index.js +18 -18
  18. package/dist/runtime/subsystems/cache/cache.module.js +1 -1
  19. package/dist/runtime/subsystems/cache/index.js +3 -3
  20. package/dist/runtime/subsystems/index.js +66 -66
  21. package/dist/runtime/subsystems/jobs/index.js +11 -11
  22. package/dist/runtime/subsystems/jobs/job-worker.module.js +5 -5
  23. package/dist/runtime/subsystems/jobs/jobs-domain.module.js +4 -4
  24. package/dist/src/cli/index.js +94 -80
  25. package/dist/src/cli/index.js.map +1 -1
  26. package/dist/src/index.d.ts +111 -1
  27. package/dist/src/index.js +3 -1
  28. package/package.json +1 -1
  29. package/dist/chunk-KK5A7B2T.js.map +0 -1
  30. /package/dist/{chunk-BKP72EDW.js.map → chunk-6DQEIXYU.js.map} +0 -0
  31. /package/dist/{chunk-QMN3LQR3.js.map → chunk-FNHNSFIJ.js.map} +0 -0
  32. /package/dist/{chunk-JGGZUP64.js.map → chunk-NXHL5YII.js.map} +0 -0
  33. /package/dist/{chunk-D44QFQJZ.js.map → chunk-QXVCRA23.js.map} +0 -0
  34. /package/dist/{chunk-MVKW2BCR.js.map → chunk-YULGWXCY.js.map} +0 -0
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  JobsDomainModule
3
- } from "../../../chunk-BKP72EDW.js";
3
+ } from "../../../chunk-6DQEIXYU.js";
4
+ import "../../../chunk-VQOAATIG.js";
4
5
  import "../../../chunk-3VEVGL74.js";
5
6
  import "../../../chunk-CDLWYZVQ.js";
6
7
  import "../../../chunk-L3LZWWSX.js";
7
8
  import "../../../chunk-DV4RV2DC.js";
9
+ import "../../../chunk-PNZSGAB2.js";
10
+ import "../../../chunk-SNQ3TOWP.js";
8
11
  import "../../../chunk-I6MVCB5A.js";
9
12
  import "../../../chunk-RHVN6NA7.js";
10
13
  import "../../../chunk-E6PLM6QG.js";
11
- import "../../../chunk-VQOAATIG.js";
12
- import "../../../chunk-PNZSGAB2.js";
13
- import "../../../chunk-SNQ3TOWP.js";
14
14
  import "../../../chunk-T4BIIU5E.js";
15
15
  import "../../../chunk-Q6LRJ4VI.js";
16
16
  import "../../../chunk-7P5ODGLA.js";
@@ -1,11 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  DIRECTION_TO_POOL,
4
+ EAV_DATA_TYPE_TO_FIELD_TYPE,
4
5
  EVENT_FIELD_TYPES,
6
+ EXTERNAL_SYNC_FIELDS,
7
+ EXTERNAL_SYNC_GROUP,
5
8
  _resetRegistryForTests,
6
9
  analyzeDomain,
7
10
  buildManifest,
8
11
  collectEntitySurfaces,
12
+ deriveFieldMeta,
9
13
  detectYamlType,
10
14
  findYamlFiles,
11
15
  formatConsole,
@@ -17,7 +21,9 @@ import {
17
21
  getManifestDir,
18
22
  getOrchestrationPatternNames,
19
23
  getPendingSuggestions,
24
+ hasExternalSyncShape,
20
25
  isActiveProvider,
26
+ isEntityRefField,
21
27
  isManifestStale,
22
28
  loadAppPatterns,
23
29
  loadEntities,
@@ -38,7 +44,7 @@ import {
38
44
  validateOrchestrationProject,
39
45
  validateProviders,
40
46
  writeManifest
41
- } from "../../chunk-KK5A7B2T.js";
47
+ } from "../../chunk-6ECCJVYW.js";
42
48
  import "../../chunk-KVOWSC5S.js";
43
49
  import "../../chunk-QFUIE37H.js";
44
50
  import "../../chunk-FFUDEIFF.js";
@@ -5494,79 +5500,11 @@ function emitStore(ctx, outDir) {
5494
5500
 
5495
5501
  // src/emitters/frontend/emit-fields.ts
5496
5502
  import { join as join15 } from "path";
5497
-
5498
- // src/emitters/frontend/field-meta.ts
5499
- var CAMEL2 = (s) => s.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
5500
- function formatLabel(fieldName) {
5501
- return fieldName.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
5502
- }
5503
- function inferUiType(field) {
5504
- if (field.ui.type) return field.ui.type;
5505
- if (Array.isArray(field.choices) && field.choices.length > 0) return "enum";
5506
- if (field.foreignKey) return "reference";
5507
- const nameLower = field.name.toLowerCase();
5508
- if (nameLower.includes("email")) return "email";
5509
- if (nameLower.includes("url") || nameLower.includes("website")) return "url";
5510
- if (nameLower.includes("password")) return "password";
5511
- if (nameLower.includes("price") || nameLower.includes("amount") || nameLower.includes("cost") || nameLower.includes("value") || nameLower.includes("revenue")) {
5512
- return "money";
5513
- }
5514
- if (nameLower.includes("percent") || nameLower.includes("rate")) {
5515
- return "percentage";
5516
- }
5517
- switch (field.type) {
5518
- case "string":
5519
- return field.constraints.maxLength && field.constraints.maxLength > 500 ? "textarea" : "text";
5520
- case "integer":
5521
- case "decimal":
5522
- return "number";
5523
- case "boolean":
5524
- return "boolean";
5525
- case "uuid":
5526
- return "text";
5527
- case "date":
5528
- return "date";
5529
- case "datetime":
5530
- return "datetime";
5531
- case "json":
5532
- return "json";
5533
- default:
5534
- return "text";
5535
- }
5536
- }
5537
- function inferUiImportance(field) {
5538
- if (field.ui.importance) return field.ui.importance;
5539
- const nameLower = field.name.toLowerCase();
5540
- if (["id", "created_at", "updated_at", "deleted_at"].includes(nameLower)) {
5541
- return "tertiary";
5542
- }
5543
- if (field.foreignKey && nameLower.endsWith("_id")) return "secondary";
5544
- if (field.required) return "primary";
5545
- if (nameLower.includes("name") || nameLower.includes("title")) return "primary";
5546
- return "secondary";
5547
- }
5548
- function isEntityRefField(field) {
5549
- if (field.type === "entity_ref") return true;
5550
- return field.name.endsWith("_entity_type") || field.name.endsWith("_entity_id");
5551
- }
5552
- function deriveFieldMeta(field) {
5553
- const hasChoices = Array.isArray(field.choices) && field.choices.length > 0;
5554
- const meta = {
5555
- field: CAMEL2(field.name),
5556
- label: field.ui.label ?? formatLabel(field.name),
5557
- type: inferUiType(field),
5558
- importance: inferUiImportance(field),
5559
- sortable: field.ui.sortable ?? false,
5560
- filterable: field.ui.filterable ?? false
5561
- };
5562
- if (hasChoices) meta.choices = field.choices;
5563
- if (field.foreignKey) meta.reference = field.foreignKey.table;
5564
- return meta;
5565
- }
5566
-
5567
- // src/emitters/frontend/emit-fields.ts
5568
5503
  var SOURCE_DESC_SET5 = "the entity set";
5569
5504
  function buildFieldMetaTypeFile() {
5505
+ const eavKeys = Object.keys(EAV_DATA_TYPE_TO_FIELD_TYPE);
5506
+ const eavUnion = eavKeys.map((k) => ` | '${k}'`).join("\n");
5507
+ const eavEntries = Object.entries(EAV_DATA_TYPE_TO_FIELD_TYPE).map(([k, v]) => ` ${k}: '${v}',`).join("\n");
5570
5508
  const body = `/**
5571
5509
  * Field metadata types for DataGrid, forms, and admin surfaces.
5572
5510
  */
@@ -5598,37 +5536,85 @@ export interface FieldMeta<T = unknown> {
5598
5536
  importance: FieldImportance;
5599
5537
  sortable?: boolean;
5600
5538
  filterable?: boolean;
5539
+ /** Layout grouping (e.g. 'external_sync'). */
5540
+ group?: string;
5541
+ /** \`false\` \u21D2 hidden by default. Absent means visible. */
5542
+ visible?: boolean;
5543
+ placeholder?: string;
5544
+ /** Help/description text shown alongside the field. */
5545
+ help?: string;
5601
5546
  format?: Record<string, unknown>;
5602
5547
  choices?: string[];
5603
5548
  reference?: string;
5549
+ /** Curated/displayed field \u2014 drives card & preview field selection. */
5550
+ isKeyField?: boolean;
5551
+ /** Sort position within the key-field set. */
5552
+ keyFieldOrder?: number;
5604
5553
  }
5554
+
5555
+ /** EAV \`field_definitions.data_type\` vocabulary. */
5556
+ export type EavDataType =
5557
+ ${eavUnion};
5558
+
5559
+ /**
5560
+ * EAV \`field_definitions.data_type\` \u2192 \`FieldType\` rendering contract: an EAV
5561
+ * field renders through the same vocabulary as a native column. Note both
5562
+ * \`picklist\` and \`multipicklist\` map to \`enum\` \u2014 multi-select rendering is a
5563
+ * consumer-side concern (check the EAV row's cardinality, not the FieldType).
5564
+ */
5565
+ export const EAV_DATA_TYPE_TO_FIELD_TYPE: Record<EavDataType, FieldType> = {
5566
+ ${eavEntries}
5567
+ };
5605
5568
  `;
5606
5569
  return withBanner(SOURCE_DESC_SET5, body);
5607
5570
  }
5608
5571
  function hasTimestamps(parsed) {
5609
5572
  return parsed?.behaviors.includes("timestamps") ?? false;
5610
5573
  }
5611
- function displayFields(parsed) {
5574
+ function hasSoftDelete(parsed) {
5575
+ return parsed?.behaviors.includes("soft_delete") ?? false;
5576
+ }
5577
+ function displayFields(parsed, opts = {}) {
5612
5578
  if (!parsed) return [];
5579
+ const syncShape = hasExternalSyncShape(parsed.fields.keys());
5613
5580
  const out = [];
5614
5581
  for (const field of parsed.fields.values()) {
5615
5582
  if (field.name === "id") continue;
5616
5583
  if (isEntityRefField(field)) continue;
5617
- out.push(deriveFieldMeta(field));
5584
+ const defaults = syncShape && EXTERNAL_SYNC_FIELDS.has(field.name) ? { group: EXTERNAL_SYNC_GROUP } : void 0;
5585
+ out.push(deriveFieldMeta(field, defaults, opts));
5618
5586
  }
5619
5587
  return out;
5620
5588
  }
5589
+ function quote(s) {
5590
+ return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
5591
+ }
5621
5592
  function renderFieldMeta(meta) {
5622
5593
  const lines = [
5623
5594
  ` field: '${meta.field}',`,
5624
- ` label: '${meta.label}',`,
5595
+ ` label: '${quote(meta.label)}',`,
5625
5596
  ` type: '${meta.type}' as FieldType,`,
5626
5597
  ` importance: '${meta.importance}' as FieldImportance,`
5627
5598
  ];
5628
5599
  if (meta.sortable) lines.push(" sortable: true,");
5629
5600
  if (meta.filterable) lines.push(" filterable: true,");
5601
+ if (meta.group !== void 0) lines.push(` group: '${quote(meta.group)}',`);
5602
+ if (meta.visible !== void 0) lines.push(` visible: ${meta.visible},`);
5603
+ if (meta.placeholder !== void 0) {
5604
+ lines.push(` placeholder: '${quote(meta.placeholder)}',`);
5605
+ }
5606
+ if (meta.help !== void 0) lines.push(` help: '${quote(meta.help)}',`);
5607
+ if (meta.format !== void 0) {
5608
+ lines.push(` format: ${JSON.stringify(meta.format)},`);
5609
+ }
5630
5610
  if (meta.choices) lines.push(` choices: ${JSON.stringify(meta.choices)},`);
5631
5611
  if (meta.reference) lines.push(` reference: '${meta.reference}',`);
5612
+ if (meta.isKeyField) {
5613
+ lines.push(" isKeyField: true,");
5614
+ if (meta.keyFieldOrder !== void 0) {
5615
+ lines.push(` keyFieldOrder: ${meta.keyFieldOrder},`);
5616
+ }
5617
+ }
5632
5618
  return ` ${meta.field}: {
5633
5619
  ${lines.join("\n")}
5634
5620
  },`;
@@ -5639,9 +5625,10 @@ function humanizeClass(className) {
5639
5625
  function buildEntityFieldsFile(entity, ctx) {
5640
5626
  const parsed = ctx.parsed.get(entity.name);
5641
5627
  const { camelName, className, classNamePlural, name, plural } = entity;
5642
- const fields = displayFields(parsed);
5628
+ const fields = displayFields(parsed, { textareaThreshold: ctx.config.textareaThreshold });
5643
5629
  const rels = resolvableRels(entity, ctx);
5644
5630
  const ts3 = hasTimestamps(parsed);
5631
+ const sd = hasSoftDelete(parsed);
5645
5632
  const fieldEntries = fields.map(renderFieldMeta);
5646
5633
  const relEntries = rels.map(
5647
5634
  (r) => ` ${r.propertyName}: {
@@ -5668,8 +5655,22 @@ function buildEntityFieldsFile(entity, ctx) {
5668
5655
  format: { dateFormat: 'relative' },
5669
5656
  },`
5670
5657
  ] : [];
5671
- const allEntries = [...fieldEntries, ...relEntries, ...tsEntries].join("\n");
5658
+ const sdEntries = sd ? [
5659
+ ` deletedAt: {
5660
+ field: 'deletedAt',
5661
+ label: 'Deleted',
5662
+ type: 'datetime' as FieldType,
5663
+ importance: 'tertiary' as FieldImportance,
5664
+ format: { dateFormat: 'relative' },
5665
+ },`
5666
+ ] : [];
5667
+ const allEntries = [...fieldEntries, ...relEntries, ...tsEntries, ...sdEntries].join(
5668
+ "\n"
5669
+ );
5672
5670
  const primaryFields = fields.filter((f) => f.importance === "primary").map((f) => ` '${f.field}',`).join("\n");
5671
+ const keyFields = fields.filter((f) => f.isKeyField).sort(
5672
+ (a, b) => (a.keyFieldOrder ?? Number.MAX_SAFE_INTEGER) - (b.keyFieldOrder ?? Number.MAX_SAFE_INTEGER)
5673
+ ).map((f) => ` '${f.field}',`).join("\n");
5673
5674
  const searchFields = fields.filter((f) => f.filterable).map((f) => ` '${f.field}',`).join("\n");
5674
5675
  const defaultSortField = ts3 ? "createdAt" : "id";
5675
5676
  const expose = parsed?.expose ?? ["repository", "rest", "trpc"];
@@ -5691,6 +5692,9 @@ export const ${camelName}Metadata = {
5691
5692
 
5692
5693
  primaryFields: [
5693
5694
  ${primaryFields}
5695
+ ],
5696
+ keyFields: [
5697
+ ${keyFields}
5694
5698
  ],
5695
5699
  searchFields: [
5696
5700
  ${searchFields}
@@ -5950,11 +5954,20 @@ var FrontendCatalogConfigSchema = z.object({
5950
5954
  }).strict()
5951
5955
  ).default([])
5952
5956
  }).default({});
5957
+ var FrontendFieldsConfigSchema = z.object({
5958
+ /**
5959
+ * String → textarea cutoff (strictly greater than). Absent or `undefined`
5960
+ * ⇒ 500. Explicit `null` ⇒ heuristic disabled (all bounded strings stay
5961
+ * `text` unless the author sets `ui_type: textarea`).
5962
+ */
5963
+ textareaThreshold: z.number().int().positive().nullable().default(500)
5964
+ }).strict().default({});
5953
5965
  var FrontendConfigSchema = z.object({
5954
5966
  auth: FrontendAuthConfigSchema,
5955
5967
  parsers: z.record(z.string()).default({ timestamptz: "(date: string) => new Date(date)" }),
5956
5968
  sync: FrontendSyncConfigSchema,
5957
- catalog: FrontendCatalogConfigSchema
5969
+ catalog: FrontendCatalogConfigSchema,
5970
+ fields: FrontendFieldsConfigSchema
5958
5971
  }).strict().default({});
5959
5972
 
5960
5973
  // src/emitters/frontend/load-context.ts
@@ -6002,7 +6015,8 @@ function mapFrontendEmitConfig(config) {
6002
6015
  parsers: fe.parsers,
6003
6016
  architecture,
6004
6017
  dbEntitiesImport: dbEntities.import,
6005
- catalogCategories: fe.catalog.categories
6018
+ catalogCategories: fe.catalog.categories,
6019
+ textareaThreshold: fe.fields.textareaThreshold
6006
6020
  };
6007
6021
  }
6008
6022
  function loadProviderCatalogInputs(cwd, config) {
@@ -8657,7 +8671,7 @@ function buildAuthImportRewriter(subsystemsRoot) {
8657
8671
  const relPosix = rel2.split(path24.sep).join("/");
8658
8672
  return content.replace(
8659
8673
  AUTH_BARE_IMPORT_RE,
8660
- (_match, quote) => `${quote}${relPosix}${quote}`
8674
+ (_match, quote2) => `${quote2}${relPosix}${quote2}`
8661
8675
  );
8662
8676
  };
8663
8677
  }