@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.
- package/agents/object-runtime.md +7 -0
- package/agents/schema-paths.md +17 -0
- package/dist/cascade.d.ts.map +1 -1
- package/dist/cascade.js +9 -6
- package/dist/cascade.js.map +1 -1
- package/dist/collection.d.ts +0 -1
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +32 -44
- package/dist/collection.js.map +1 -1
- package/dist/decorators/compatibility.d.ts +1 -1
- package/dist/decorators/compatibility.d.ts.map +1 -1
- package/dist/decorators/compatibility.js +2 -2
- package/dist/decorators/compatibility.js.map +1 -1
- package/dist/decorators/index.d.ts.map +1 -1
- package/dist/decorators/index.js +33 -24
- package/dist/decorators/index.js.map +1 -1
- package/dist/interceptors.d.ts +3 -1
- package/dist/interceptors.d.ts.map +1 -1
- package/dist/interceptors.js +3 -2
- package/dist/interceptors.js.map +1 -1
- package/dist/manifest/static-manifest.js +1 -1
- package/dist/manifest/static-manifest.js.map +1 -1
- package/dist/manifest/store.js +1 -1
- package/dist/manifest.json +1 -1
- package/dist/object.d.ts +1 -5
- package/dist/object.d.ts.map +1 -1
- package/dist/object.js +28 -37
- package/dist/object.js.map +1 -1
- package/dist/registry/class-registration.d.ts +2 -1
- package/dist/registry/class-registration.d.ts.map +1 -1
- package/dist/registry/class-registration.js +47 -16
- package/dist/registry/class-registration.js.map +1 -1
- package/dist/registry/name-resolver.d.ts.map +1 -1
- package/dist/registry/name-resolver.js +3 -3
- package/dist/registry/name-resolver.js.map +1 -1
- package/dist/registry/relationship-graph.d.ts +2 -0
- package/dist/registry/relationship-graph.d.ts.map +1 -1
- package/dist/registry/relationship-graph.js +60 -5
- package/dist/registry/relationship-graph.js.map +1 -1
- package/dist/registry/schema-builder.d.ts.map +1 -1
- package/dist/registry/schema-builder.js +4 -1
- package/dist/registry/schema-builder.js.map +1 -1
- package/dist/registry/shared-state.d.ts +18 -0
- package/dist/registry/shared-state.d.ts.map +1 -1
- package/dist/registry/shared-state.js +25 -1
- package/dist/registry/shared-state.js.map +1 -1
- package/dist/registry/types.d.ts +8 -0
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/registry.d.ts +32 -5
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +120 -12
- package/dist/registry.js.map +1 -1
- package/dist/relationship-loader.d.ts +6 -0
- package/dist/relationship-loader.d.ts.map +1 -0
- package/dist/relationship-loader.js +35 -0
- package/dist/relationship-loader.js.map +1 -0
- package/dist/scanner/manifest-generator.d.ts.map +1 -1
- package/dist/scanner/manifest-generator.js +6 -3
- package/dist/scanner/manifest-generator.js.map +1 -1
- package/dist/schema/generator.d.ts +2 -0
- package/dist/schema/generator.d.ts.map +1 -1
- package/dist/schema/generator.js +16 -9
- package/dist/schema/generator.js.map +1 -1
- package/dist/schema/utils.d.ts.map +1 -1
- package/dist/schema/utils.js +2 -1
- package/dist/schema/utils.js.map +1 -1
- package/dist/smrt-knowledge.json +7 -7
- package/dist/test-utils.d.ts.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +2 -1
- package/dist/utils.js.map +1 -1
- 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;
|
|
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,
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
736
|
-
|
|
765
|
+
if (existing.tenantScopedConfigSource !== "explicit") {
|
|
766
|
+
const tenantScopedConfig = normalizeTenantScopedConfig(manifestConfig.tenantScoped);
|
|
737
767
|
existing.tenantScopedConfig = tenantScopedConfig;
|
|
738
|
-
|
|
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 =
|
|
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
|