@happyvertical/smrt-core 0.48.0 → 0.49.1

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 (72) hide show
  1. package/agents/object-runtime.md +7 -0
  2. package/agents/schema-paths.md +17 -0
  3. package/dist/cascade.d.ts.map +1 -1
  4. package/dist/cascade.js +9 -6
  5. package/dist/cascade.js.map +1 -1
  6. package/dist/collection.d.ts +0 -1
  7. package/dist/collection.d.ts.map +1 -1
  8. package/dist/collection.js +32 -44
  9. package/dist/collection.js.map +1 -1
  10. package/dist/decorators/compatibility.d.ts +1 -1
  11. package/dist/decorators/compatibility.d.ts.map +1 -1
  12. package/dist/decorators/compatibility.js +2 -2
  13. package/dist/decorators/compatibility.js.map +1 -1
  14. package/dist/decorators/index.d.ts.map +1 -1
  15. package/dist/decorators/index.js +33 -24
  16. package/dist/decorators/index.js.map +1 -1
  17. package/dist/interceptors.d.ts +3 -1
  18. package/dist/interceptors.d.ts.map +1 -1
  19. package/dist/interceptors.js +3 -2
  20. package/dist/interceptors.js.map +1 -1
  21. package/dist/manifest/static-manifest.js +1 -1
  22. package/dist/manifest/static-manifest.js.map +1 -1
  23. package/dist/manifest/store.js +1 -1
  24. package/dist/manifest.json +1 -1
  25. package/dist/object.d.ts +1 -5
  26. package/dist/object.d.ts.map +1 -1
  27. package/dist/object.js +28 -37
  28. package/dist/object.js.map +1 -1
  29. package/dist/registry/class-registration.d.ts +2 -1
  30. package/dist/registry/class-registration.d.ts.map +1 -1
  31. package/dist/registry/class-registration.js +47 -16
  32. package/dist/registry/class-registration.js.map +1 -1
  33. package/dist/registry/name-resolver.d.ts.map +1 -1
  34. package/dist/registry/name-resolver.js +3 -3
  35. package/dist/registry/name-resolver.js.map +1 -1
  36. package/dist/registry/relationship-graph.d.ts +2 -0
  37. package/dist/registry/relationship-graph.d.ts.map +1 -1
  38. package/dist/registry/relationship-graph.js +60 -5
  39. package/dist/registry/relationship-graph.js.map +1 -1
  40. package/dist/registry/schema-builder.d.ts.map +1 -1
  41. package/dist/registry/schema-builder.js +4 -1
  42. package/dist/registry/schema-builder.js.map +1 -1
  43. package/dist/registry/shared-state.d.ts +18 -0
  44. package/dist/registry/shared-state.d.ts.map +1 -1
  45. package/dist/registry/shared-state.js +25 -1
  46. package/dist/registry/shared-state.js.map +1 -1
  47. package/dist/registry/types.d.ts +8 -0
  48. package/dist/registry/types.d.ts.map +1 -1
  49. package/dist/registry.d.ts +32 -5
  50. package/dist/registry.d.ts.map +1 -1
  51. package/dist/registry.js +120 -12
  52. package/dist/registry.js.map +1 -1
  53. package/dist/relationship-loader.d.ts +6 -0
  54. package/dist/relationship-loader.d.ts.map +1 -0
  55. package/dist/relationship-loader.js +35 -0
  56. package/dist/relationship-loader.js.map +1 -0
  57. package/dist/scanner/manifest-generator.d.ts.map +1 -1
  58. package/dist/scanner/manifest-generator.js +6 -3
  59. package/dist/scanner/manifest-generator.js.map +1 -1
  60. package/dist/schema/generator.d.ts +2 -0
  61. package/dist/schema/generator.d.ts.map +1 -1
  62. package/dist/schema/generator.js +16 -9
  63. package/dist/schema/generator.js.map +1 -1
  64. package/dist/schema/utils.d.ts.map +1 -1
  65. package/dist/schema/utils.js +2 -1
  66. package/dist/schema/utils.js.map +1 -1
  67. package/dist/smrt-knowledge.json +7 -7
  68. package/dist/test-utils.d.ts.map +1 -1
  69. package/dist/utils.d.ts.map +1 -1
  70. package/dist/utils.js +2 -1
  71. package/dist/utils.js.map +1 -1
  72. package/package.json +4 -4
@@ -1,8 +1,9 @@
1
1
  import { SmrtObject } from '../object';
2
2
  import { SmartObjectDefinition } from '../scanner/types.js';
3
- import { RegisteredClass, SmartObjectConfig } from './types.js';
3
+ import { RegisteredClass, RegisteredField, SmartObjectConfig } from './types.js';
4
4
  export declare function register(ctor: typeof SmrtObject, config?: SmartObjectConfig): void;
5
5
  export declare function registerCollection(objectName: string, collectionConstructor: NonNullable<RegisteredClass['collectionConstructor']>): void;
6
+ export declare function ensureTenantScopedField(fields: Map<string, RegisteredField>, tenantScopedConfig: RegisteredClass['tenantScopedConfig'] | undefined): void;
6
7
  /**
7
8
  * Invalidate cached inheritance state (chain + inheritedFields +
8
9
  * inheritedMethods) on `existing` AND every descendant whose `extends` or
@@ -1 +1 @@
1
- {"version":3,"file":"class-registration.d.ts","sourceRoot":"","sources":["../../src/registry/class-registration.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAUH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,KAAK,EAKV,qBAAqB,EAGtB,MAAM,qBAAqB,CAAC;AAsC7B,OAAO,KAAK,EACV,eAAe,EAEf,iBAAiB,EAElB,MAAM,YAAY,CAAC;AA0dpB,wBAAgB,QAAQ,CACtB,IAAI,EAAE,OAAO,UAAU,EACvB,MAAM,GAAE,iBAAsB,GAC7B,IAAI,CAqwBN;AAED,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAMlB,qBAAqB,EAAE,WAAW,CAAC,eAAe,CAAC,uBAAuB,CAAC,CAAC,GAC3E,IAAI,CAeN;AA6LD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,eAAe,EACzB,gBAAgB,CAAC,EAAE;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GACA,IAAI,CA2CN;AA0ID,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,qBAAqB,EAChC,WAAW,CAAC,EAAE,MAAM,GACnB,IAAI,CA4QN"}
1
+ {"version":3,"file":"class-registration.d.ts","sourceRoot":"","sources":["../../src/registry/class-registration.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAUH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,KAAK,EAKV,qBAAqB,EAGtB,MAAM,qBAAqB,CAAC;AAwC7B,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,iBAAiB,EAElB,MAAM,YAAY,CAAC;AA0dpB,wBAAgB,QAAQ,CACtB,IAAI,EAAE,OAAO,UAAU,EACvB,MAAM,GAAE,iBAAsB,GAC7B,IAAI,CA6zBN;AAyCD,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAMlB,qBAAqB,EAAE,WAAW,CAAC,eAAe,CAAC,uBAAuB,CAAC,CAAC,GAC3E,IAAI,CAeN;AA+BD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,EACpC,kBAAkB,EAAE,eAAe,CAAC,oBAAoB,CAAC,GAAG,SAAS,GACpE,IAAI,CAuCN;AAoHD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,eAAe,EACzB,gBAAgB,CAAC,EAAE;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GACA,IAAI,CA2CN;AA4JD,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,qBAAqB,EAChC,WAAW,CAAC,EAAE,MAAM,GACnB,IAAI,CA4QN"}
@@ -2,7 +2,7 @@ import { ConfigurationError } from "../errors.js";
2
2
  import { toSnakeCase } from "../utils/naming.js";
3
3
  import { createQualifiedName, isQualifiedName } from "../utils/qualified-names.js";
4
4
  import { cloneManifestSchemaColumns } from "../manifest/store.js";
5
- import { getClasses, getCollections, getConstructorIndex, getFieldDecorators, getInheritanceCache, getSourceFileFromStack, getStiSiblingsLoaded, verboseLog } from "./shared-state.js";
5
+ import { getClasses, getCollections, getConstructorFieldDecorators, getConstructorIndex, getConstructorTenantScopedDeclarations, getInheritanceCache, getLegacyFieldDecorators, getSourceFileFromStack, getStiSiblingsLoaded, verboseLog } from "./shared-state.js";
6
6
  import { findClass, getCanonicalClassName, hasClassCaseInsensitive, qualifyExtendsName } from "./name-resolver.js";
7
7
  import { buildInheritanceChain } from "./inheritance-resolver.js";
8
8
  import { discoverManifestSync, discoverSTISiblingsSync, getPackageName, lookupInManifest } from "../manifest/manifest-loader.js";
@@ -253,6 +253,7 @@ function register(ctor, config = {}) {
253
253
  if (config._manifestKey) {
254
254
  if (!explicitPackageName || !config._manifest) throw new ConfigurationError("Generated isolated manifest registration requires packageName and _manifest.", "CONFIG_INVALID_ISOLATED_MANIFEST");
255
255
  isolatedManifestEntry = validateIsolatedRegistrationManifest(config._manifest, config._manifestKey, name, explicitPackageName);
256
+ if (config.tenantScoped === void 0 && normalizeTenantScopedConfig(isolatedManifestEntry.decoratorConfig?.tenantScoped) === void 0 && getConstructorTenantScopedDeclarations().get(ctor)) throw new ConfigurationError(`Manifest for '${name}' omits or disables tenantScoped but its runtime constructor is decorated with @TenantScoped(). Regenerate the manifest so tenancy schema and runtime enforcement agree.`, "CONFIG_TENANT_MANIFEST_CONFLICT");
256
257
  }
257
258
  function upsertExistingEntry(existingKey, existing) {
258
259
  const nextPackageName = explicitPackageName || existing.packageName;
@@ -367,6 +368,8 @@ function register(ctor, config = {}) {
367
368
  let manifestEntry;
368
369
  if (config._manifest) manifestEntry = lookupRegistrationManifest(config._manifest, name, explicitPackageName, config._manifestKey);
369
370
  if (!manifestEntry) manifestEntry = discoverManifestSync(name);
371
+ const runtimeTenantScopedDeclaration = getConstructorTenantScopedDeclarations().get(ctor);
372
+ if (manifestEntry && config.tenantScoped === void 0 && normalizeTenantScopedConfig(manifestEntry.decoratorConfig?.tenantScoped) === void 0 && runtimeTenantScopedDeclaration) throw new ConfigurationError(`Manifest for '${name}' omits or disables tenantScoped but its runtime constructor is decorated with @TenantScoped(). Regenerate the manifest so tenancy schema and runtime enforcement agree.`, "CONFIG_TENANT_MANIFEST_CONFLICT");
370
373
  const fields = /* @__PURE__ */ new Map();
371
374
  const methods = /* @__PURE__ */ new Map();
372
375
  let packageName;
@@ -399,7 +402,14 @@ function register(ctor, config = {}) {
399
402
  verboseLog(`[registry] ⚠️ No manifest entry for ${name} - fields will be loaded later`);
400
403
  packageName = packageNameFromStack;
401
404
  }
402
- const decorators = getFieldDecorators().get(isolatedManifestEntry ? ctor.name : name);
405
+ const decoratorKey = isolatedManifestEntry ? ctor.name : name;
406
+ const simpleDecorators = getLegacyFieldDecorators().get(decoratorKey);
407
+ const constructorDecorators = getConstructorFieldDecorators().get(ctor);
408
+ const decorators = new Map(simpleDecorators);
409
+ for (const [fieldName, options] of constructorDecorators ?? []) decorators.set(fieldName, {
410
+ ...decorators.get(fieldName),
411
+ ...options
412
+ });
403
413
  if (decorators && decorators.size > 0) {
404
414
  verboseLog(`[registry] Applying ${decorators.size} field decorators for ${name}`);
405
415
  for (const [fieldName, decoratorOptions] of decorators) {
@@ -458,16 +468,13 @@ function register(ctor, config = {}) {
458
468
  }
459
469
  }
460
470
  let tenantScopedConfig;
461
- const effectiveTenantScoped = config.tenantScoped ?? manifestEntry?.decoratorConfig?.tenantScoped;
471
+ const constructorTenantScopedDeclaration = manifestEntry ? void 0 : runtimeTenantScopedDeclaration;
472
+ const fieldTenantScopedConfig = tenantScopedConfigFromFieldMetadata(fields);
473
+ const tenantScopedConfigSource = config.tenantScoped !== void 0 ? "explicit" : manifestEntry?.decoratorConfig?.tenantScoped !== void 0 ? "manifest" : manifestEntry ? "manifest" : constructorTenantScopedDeclaration ? "tenant-decorator" : fieldTenantScopedConfig ? "field-fallback" : void 0;
474
+ const effectiveTenantScoped = config.tenantScoped ?? manifestEntry?.decoratorConfig?.tenantScoped ?? (manifestEntry ? void 0 : constructorTenantScopedDeclaration ?? fieldTenantScopedConfig);
462
475
  if (effectiveTenantScoped) {
463
- const tenantOpts = typeof effectiveTenantScoped === "boolean" ? {} : effectiveTenantScoped;
464
- tenantScopedConfig = {
465
- mode: tenantOpts.mode ?? "required",
466
- field: tenantOpts.field ?? "tenantId",
467
- autoFilter: tenantOpts.autoFilter ?? true,
468
- autoPopulate: tenantOpts.autoPopulate ?? true,
469
- allowSuperAdminBypass: tenantOpts.allowSuperAdminBypass ?? false
470
- };
476
+ tenantScopedConfig = normalizeTenantScopedConfig(effectiveTenantScoped);
477
+ if (!tenantScopedConfig) return;
471
478
  const fieldName = tenantScopedConfig.field;
472
479
  const hadTenantField = fields.has(fieldName);
473
480
  ensureTenantScopedField(fields, tenantScopedConfig);
@@ -564,6 +571,7 @@ function register(ctor, config = {}) {
564
571
  extends: extendsClass,
565
572
  extendsTypeArg: manifestEntry?.extendsTypeArg,
566
573
  tenantScopedConfig,
574
+ tenantScopedConfigSource,
567
575
  visibility
568
576
  });
569
577
  getConstructorIndex().set(ctor, registrationKey);
@@ -584,6 +592,26 @@ function register(ctor, config = {}) {
584
592
  }
585
593
  }
586
594
  }
595
+ /**
596
+ * Resolve the core-visible tenancy contract from a `@tenantId()` field when a
597
+ * runtime registration has no manifest entry. `@TenantScoped()` lives in the
598
+ * tenancy package, so core cannot import its registry without a cycle; the
599
+ * field decorator runs before `@smrt()`. A nullable tenant identifier is the
600
+ * runtime representation of optional tenancy used by that decorator.
601
+ */
602
+ function tenantScopedConfigFromFieldMetadata(fields) {
603
+ for (const [fieldName, field] of fields) {
604
+ const tenancy = field._meta?.__tenancy;
605
+ if (tenancy?.isTenantIdField !== true) continue;
606
+ return {
607
+ mode: tenancy.mode === "required" ? "required" : tenancy.mode === "optional" || field._meta?.nullable === true ? "optional" : "required",
608
+ field: typeof tenancy.field === "string" ? tenancy.field : fieldName,
609
+ autoFilter: tenancy.autoFilter !== false,
610
+ autoPopulate: tenancy.autoPopulate !== false,
611
+ allowSuperAdminBypass: tenancy.allowSuperAdminBypass === true
612
+ };
613
+ }
614
+ }
587
615
  function registerCollection(objectName, collectionConstructor) {
588
616
  const registered = findClass(objectName);
589
617
  if (registered) registered.collectionConstructor = collectionConstructor;
@@ -717,6 +745,8 @@ function invalidateInheritanceEntries(existing, previousIdentity) {
717
745
  }
718
746
  function mergeManifestIntoExistingRegistration(existing, objectDef, packageName) {
719
747
  const manifestConfig = objectDef.decoratorConfig || {};
748
+ const runtimeTenantScopedDeclaration = getConstructorTenantScopedDeclarations().get(existing.constructor);
749
+ if (existing.tenantScopedConfigSource !== "explicit" && normalizeTenantScopedConfig(manifestConfig.tenantScoped) === void 0 && runtimeTenantScopedDeclaration) throw new ConfigurationError(`Manifest for '${existing.qualifiedName || existing.name}' omits or disables tenantScoped but its runtime constructor is decorated with @TenantScoped(). Regenerate the manifest so tenancy schema and runtime enforcement agree.`, "CONFIG_TENANT_MANIFEST_CONFLICT");
720
750
  const manifestTableName = objectDef.schema?.tableName || manifestConfig.tableName || existing.schema?.tableName || existing.config.tableName || tableNameFromClass(existing.constructor);
721
751
  existing.config = {
722
752
  ...manifestConfig,
@@ -732,10 +762,11 @@ function mergeManifestIntoExistingRegistration(existing, objectDef, packageName)
732
762
  if (!existingField) continue;
733
763
  existing.fields.set(fieldName, mergeManifestField(existingField, fd));
734
764
  }
735
- const tenantScopedConfig = normalizeTenantScopedConfig(existing.config.tenantScoped);
736
- if (tenantScopedConfig) {
765
+ if (existing.tenantScopedConfigSource !== "explicit") {
766
+ const tenantScopedConfig = normalizeTenantScopedConfig(manifestConfig.tenantScoped);
737
767
  existing.tenantScopedConfig = tenantScopedConfig;
738
- ensureTenantScopedField(existing.fields, tenantScopedConfig);
768
+ existing.tenantScopedConfigSource = "manifest";
769
+ if (tenantScopedConfig) ensureTenantScopedField(existing.fields, tenantScopedConfig);
739
770
  }
740
771
  if (objectDef.methods) for (const [methodName, methodDef] of Object.entries(objectDef.methods)) existing.methods.set(methodName, methodDef);
741
772
  if (objectDef.schema) {
@@ -836,7 +867,7 @@ function registerFromManifest(name, objectDef, packageName) {
836
867
  };
837
868
  Object.defineProperty(stubConstructor, "name", { value: simpleClassName });
838
869
  const fields = /* @__PURE__ */ new Map();
839
- const decorators = getFieldDecorators().get(simpleClassName);
870
+ const decorators = getLegacyFieldDecorators().get(simpleClassName);
840
871
  if (objectDef.fields) for (const [fieldName, fd] of Object.entries(objectDef.fields)) fields.set(fieldName, createFieldFromManifest(fd));
841
872
  const methods = /* @__PURE__ */ new Map();
842
873
  if (objectDef.methods) for (const [methodName, methodDef] of Object.entries(objectDef.methods)) methods.set(methodName, methodDef);
@@ -922,6 +953,6 @@ function registerFromManifest(name, objectDef, packageName) {
922
953
  }
923
954
  }
924
955
  //#endregion
925
- export { invalidateInheritanceEntries, register, registerCollection, registerFromManifest };
956
+ export { ensureTenantScopedField, invalidateInheritanceEntries, register, registerCollection, registerFromManifest };
926
957
 
927
958
  //# sourceMappingURL=class-registration.js.map