@happyvertical/smrt-facts 0.37.2 → 0.37.4
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/dist/chunks/fact-sources-BCx_bOF1.js +155 -0
- package/dist/chunks/fact-sources-BCx_bOF1.js.map +1 -0
- package/dist/chunks/fact-subjects-CzVv4VCE.js +176 -0
- package/dist/chunks/fact-subjects-CzVv4VCE.js.map +1 -0
- package/dist/chunks/rolldown-runtime-D7D4PA-g.js +13 -0
- package/dist/index.js +1293 -1954
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +2 -2
- package/dist/smrt-knowledge.json +7 -7
- package/dist/types.js +0 -2
- package/package.json +13 -13
- package/dist/types.js.map +0 -1
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
+
import { SmrtCollection, SmrtObject, field, foreignKey, smrt } from "@happyvertical/smrt-core";
|
|
3
|
+
import { TenantScoped, queryGlobal, queryWithGlobals, tenantId } from "@happyvertical/smrt-tenancy";
|
|
4
|
+
//#region src/fact-source.ts
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
8
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
9
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
10
|
+
if (kind && result) __defProp(target, key, result);
|
|
11
|
+
return result;
|
|
12
|
+
};
|
|
13
|
+
var FactSource = class extends SmrtObject {
|
|
14
|
+
factId = "";
|
|
15
|
+
sourceType = "";
|
|
16
|
+
sourceUrl = "";
|
|
17
|
+
sourceTitle = "";
|
|
18
|
+
credibility = 0;
|
|
19
|
+
extractedAt = /* @__PURE__ */ new Date();
|
|
20
|
+
metadata = "";
|
|
21
|
+
tenantId = null;
|
|
22
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
23
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
24
|
+
constructor(options = {}) {
|
|
25
|
+
super(options);
|
|
26
|
+
if (options.factId) this.factId = options.factId;
|
|
27
|
+
if (options.sourceType !== void 0) this.sourceType = options.sourceType;
|
|
28
|
+
if (options.sourceUrl !== void 0) this.sourceUrl = options.sourceUrl;
|
|
29
|
+
if (options.sourceTitle !== void 0) this.sourceTitle = options.sourceTitle;
|
|
30
|
+
if (options.credibility !== void 0) this.credibility = options.credibility;
|
|
31
|
+
if (options.extractedAt) this.extractedAt = options.extractedAt;
|
|
32
|
+
if (options.metadata !== void 0) if (typeof options.metadata === "string") this.metadata = options.metadata;
|
|
33
|
+
else this.metadata = JSON.stringify(options.metadata);
|
|
34
|
+
}
|
|
35
|
+
getMetadata() {
|
|
36
|
+
const raw = this.metadata;
|
|
37
|
+
if (!raw) return {};
|
|
38
|
+
if (typeof raw === "object") return raw;
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse(String(raw));
|
|
41
|
+
} catch {
|
|
42
|
+
return {};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
setMetadata(data) {
|
|
46
|
+
this.metadata = JSON.stringify(data);
|
|
47
|
+
}
|
|
48
|
+
updateMetadata(updates) {
|
|
49
|
+
const current = this.getMetadata();
|
|
50
|
+
this.metadata = JSON.stringify({
|
|
51
|
+
...current,
|
|
52
|
+
...updates
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get the fact this source belongs to
|
|
57
|
+
*/
|
|
58
|
+
async getFact() {
|
|
59
|
+
if (!this.factId) return null;
|
|
60
|
+
const { FactCollection } = await import("../index.js").then((n) => n.t);
|
|
61
|
+
return await (await FactCollection.create(this.options)).get({ id: this.factId });
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
__decorateClass([foreignKey("Fact", { required: true })], FactSource.prototype, "factId", 2);
|
|
65
|
+
__decorateClass([field()], FactSource.prototype, "sourceType", 2);
|
|
66
|
+
__decorateClass([field()], FactSource.prototype, "sourceUrl", 2);
|
|
67
|
+
__decorateClass([field()], FactSource.prototype, "sourceTitle", 2);
|
|
68
|
+
__decorateClass([field()], FactSource.prototype, "credibility", 2);
|
|
69
|
+
__decorateClass([field()], FactSource.prototype, "extractedAt", 2);
|
|
70
|
+
__decorateClass([field()], FactSource.prototype, "metadata", 2);
|
|
71
|
+
__decorateClass([tenantId({ nullable: true })], FactSource.prototype, "tenantId", 2);
|
|
72
|
+
__decorateClass([field()], FactSource.prototype, "createdAt", 2);
|
|
73
|
+
__decorateClass([field()], FactSource.prototype, "updatedAt", 2);
|
|
74
|
+
FactSource = __decorateClass([TenantScoped({ mode: "optional" }), smrt({
|
|
75
|
+
tableStrategy: "sti",
|
|
76
|
+
api: { include: [
|
|
77
|
+
"list",
|
|
78
|
+
"get",
|
|
79
|
+
"create",
|
|
80
|
+
"delete"
|
|
81
|
+
] },
|
|
82
|
+
mcp: { include: [
|
|
83
|
+
"list",
|
|
84
|
+
"get",
|
|
85
|
+
"create"
|
|
86
|
+
] },
|
|
87
|
+
cli: true
|
|
88
|
+
})], FactSource);
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/fact-sources.ts
|
|
91
|
+
var fact_sources_exports = /* @__PURE__ */ __exportAll({ FactSourceCollection: () => FactSourceCollection });
|
|
92
|
+
var FactSourceCollection = class extends SmrtCollection {
|
|
93
|
+
static _itemClass = FactSource;
|
|
94
|
+
/**
|
|
95
|
+
* Get all sources for a given fact
|
|
96
|
+
*/
|
|
97
|
+
async getForFact(factId) {
|
|
98
|
+
return this.list({ where: { factId } });
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Count sources for a given fact
|
|
102
|
+
*/
|
|
103
|
+
async countForFact(factId) {
|
|
104
|
+
return (await this.getForFact(factId)).length;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get sources by type
|
|
108
|
+
*/
|
|
109
|
+
async getByType(sourceType) {
|
|
110
|
+
return this.list({ where: { sourceType } });
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get sources with credibility above a threshold
|
|
114
|
+
*/
|
|
115
|
+
async getHighCredibility(minCredibility = .7) {
|
|
116
|
+
return this.list({ where: { "credibility >=": minCredibility } });
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Get average credibility for a fact's sources
|
|
120
|
+
*/
|
|
121
|
+
async getAverageCredibility(factId) {
|
|
122
|
+
const sources = await this.getForFact(factId);
|
|
123
|
+
if (sources.length === 0) return 0;
|
|
124
|
+
return sources.reduce((sum, s) => sum + s.credibility, 0) / sources.length;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Find all sources belonging to a specific tenant
|
|
128
|
+
*/
|
|
129
|
+
async findByTenant(tenantId) {
|
|
130
|
+
return this.list({ where: { tenantId } });
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Find all global (tenant-less) sources.
|
|
134
|
+
*
|
|
135
|
+
* Routes through the shared tenant-global helper so it does not throw under
|
|
136
|
+
* an active tenant context (an explicit `tenant_id IS NULL` filter would be
|
|
137
|
+
* flagged as an isolation violation). (#1600)
|
|
138
|
+
*/
|
|
139
|
+
async findGlobal() {
|
|
140
|
+
return queryGlobal(this);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Find sources for a tenant including global sources.
|
|
144
|
+
*
|
|
145
|
+
* Fails closed if an active tenant context requests a different tenant's
|
|
146
|
+
* rows; the admin/system path keeps the cross-tenant capability. (#1600)
|
|
147
|
+
*/
|
|
148
|
+
async findWithGlobals(tenantId) {
|
|
149
|
+
return queryWithGlobals(this, tenantId, "FactSource.findWithGlobals");
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
//#endregion
|
|
153
|
+
export { fact_sources_exports as n, FactSource as r, FactSourceCollection as t };
|
|
154
|
+
|
|
155
|
+
//# sourceMappingURL=fact-sources-BCx_bOF1.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fact-sources-BCx_bOF1.js","names":[],"sources":["../../src/fact-source.ts","../../src/fact-sources.ts"],"sourcesContent":["/**\n * FactSource model - Provenance tracking for facts\n *\n * Records where a fact came from, including source URL, type,\n * credibility, and extraction timestamp.\n */\n\nimport { field, foreignKey, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { FactSourceOptions } from './types';\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get', 'create', 'delete'] },\n mcp: { include: ['list', 'get', 'create'] },\n cli: true,\n})\nexport class FactSource extends SmrtObject {\n @foreignKey('Fact', { required: true })\n factId: string = '';\n\n @field()\n sourceType: string = '';\n @field()\n sourceUrl: string = '';\n @field()\n sourceTitle: string = '';\n @field()\n credibility: number = 0.0;\n @field()\n extractedAt: Date = new Date();\n @field()\n metadata: string = '';\n\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @field()\n createdAt: Date = new Date();\n @field()\n updatedAt: Date = new Date();\n\n constructor(options: FactSourceOptions = {}) {\n super(options);\n if (options.factId) this.factId = options.factId;\n if (options.sourceType !== undefined) this.sourceType = options.sourceType;\n if (options.sourceUrl !== undefined) this.sourceUrl = options.sourceUrl;\n if (options.sourceTitle !== undefined)\n this.sourceTitle = options.sourceTitle;\n if (options.credibility !== undefined)\n this.credibility = options.credibility;\n if (options.extractedAt) this.extractedAt = options.extractedAt;\n\n if (options.metadata !== undefined) {\n if (typeof options.metadata === 'string') {\n this.metadata = options.metadata;\n } else {\n this.metadata = JSON.stringify(options.metadata);\n }\n }\n }\n\n getMetadata(): Record<string, unknown> {\n const raw = this.metadata;\n if (!raw) return {};\n if (typeof raw === 'object') return raw as unknown as Record<string, unknown>;\n try {\n return JSON.parse(String(raw));\n } catch {\n return {};\n }\n }\n\n setMetadata(data: Record<string, unknown>): void {\n this.metadata = JSON.stringify(data);\n }\n\n updateMetadata(updates: Record<string, unknown>): void {\n const current = this.getMetadata();\n this.metadata = JSON.stringify({ ...current, ...updates });\n }\n\n /**\n * Get the fact this source belongs to\n */\n async getFact(): Promise<import('./fact').Fact | null> {\n if (!this.factId) return null;\n\n const { FactCollection } = await import('./facts');\n const collection = await FactCollection.create(this.options);\n return await collection.get({ id: this.factId });\n }\n}\n","/**\n * FactSourceCollection - Collection manager for FactSource objects\n *\n * Provides queries for sources by fact, type, and credibility.\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { FactSource } from './fact-source';\n\nexport class FactSourceCollection extends SmrtCollection<FactSource> {\n static readonly _itemClass = FactSource;\n\n /**\n * Get all sources for a given fact\n */\n async getForFact(factId: string): Promise<FactSource[]> {\n return this.list({ where: { factId } });\n }\n\n /**\n * Count sources for a given fact\n */\n async countForFact(factId: string): Promise<number> {\n const sources = await this.getForFact(factId);\n return sources.length;\n }\n\n /**\n * Get sources by type\n */\n async getByType(sourceType: string): Promise<FactSource[]> {\n return this.list({ where: { sourceType } });\n }\n\n /**\n * Get sources with credibility above a threshold\n */\n async getHighCredibility(\n minCredibility: number = 0.7,\n ): Promise<FactSource[]> {\n return this.list({ where: { 'credibility >=': minCredibility } });\n }\n\n /**\n * Get average credibility for a fact's sources\n */\n async getAverageCredibility(factId: string): Promise<number> {\n const sources = await this.getForFact(factId);\n if (sources.length === 0) return 0;\n const total = sources.reduce((sum, s) => sum + s.credibility, 0);\n return total / sources.length;\n }\n\n // =========================================================================\n // Tenant Helper Methods\n // =========================================================================\n\n /**\n * Find all sources belonging to a specific tenant\n */\n async findByTenant(tenantId: string): Promise<FactSource[]> {\n return this.list({ where: { tenantId } });\n }\n\n /**\n * Find all global (tenant-less) sources.\n *\n * Routes through the shared tenant-global helper so it does not throw under\n * an active tenant context (an explicit `tenant_id IS NULL` filter would be\n * flagged as an isolation violation). (#1600)\n */\n async findGlobal(): Promise<FactSource[]> {\n return queryGlobal<FactSource>(this);\n }\n\n /**\n * Find sources for a tenant including global sources.\n *\n * Fails closed if an active tenant context requests a different tenant's\n * rows; the admin/system path keeps the cross-tenant capability. (#1600)\n */\n async findWithGlobals(tenantId: string): Promise<FactSource[]> {\n return queryWithGlobals<FactSource>(\n this,\n tenantId,\n 'FactSource.findWithGlobals',\n );\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
+
import { SmrtCollection, SmrtObject, field, foreignKey, smrt } from "@happyvertical/smrt-core";
|
|
3
|
+
import { TenantScoped, queryGlobal, queryWithGlobals, tenantId } from "@happyvertical/smrt-tenancy";
|
|
4
|
+
//#region src/fact-subject.ts
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
8
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
9
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
10
|
+
if (kind && result) __defProp(target, key, result);
|
|
11
|
+
return result;
|
|
12
|
+
};
|
|
13
|
+
var FactSubject = class extends SmrtObject {
|
|
14
|
+
factId = "";
|
|
15
|
+
entityType = "";
|
|
16
|
+
entityId = "";
|
|
17
|
+
role = "subject";
|
|
18
|
+
metadata = "";
|
|
19
|
+
tenantId = null;
|
|
20
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
21
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
22
|
+
constructor(options = {}) {
|
|
23
|
+
super(options);
|
|
24
|
+
if (options.factId) this.factId = options.factId;
|
|
25
|
+
if (options.entityType) this.entityType = options.entityType;
|
|
26
|
+
if (options.entityId) this.entityId = options.entityId;
|
|
27
|
+
if (options.role !== void 0) this.role = options.role;
|
|
28
|
+
if (options.metadata !== void 0) if (typeof options.metadata === "string") this.metadata = options.metadata;
|
|
29
|
+
else this.metadata = JSON.stringify(options.metadata);
|
|
30
|
+
}
|
|
31
|
+
getRole() {
|
|
32
|
+
return this.role;
|
|
33
|
+
}
|
|
34
|
+
getMetadata() {
|
|
35
|
+
const raw = this.metadata;
|
|
36
|
+
if (!raw) return {};
|
|
37
|
+
if (typeof raw === "object") return raw;
|
|
38
|
+
try {
|
|
39
|
+
return JSON.parse(String(raw));
|
|
40
|
+
} catch {
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
setMetadata(data) {
|
|
45
|
+
this.metadata = JSON.stringify(data);
|
|
46
|
+
}
|
|
47
|
+
updateMetadata(updates) {
|
|
48
|
+
const current = this.getMetadata();
|
|
49
|
+
this.metadata = JSON.stringify({
|
|
50
|
+
...current,
|
|
51
|
+
...updates
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get the fact this subject is linked to
|
|
56
|
+
*/
|
|
57
|
+
async getFact() {
|
|
58
|
+
if (!this.factId) return null;
|
|
59
|
+
const { FactCollection } = await import("../index.js").then((n) => n.t);
|
|
60
|
+
return await (await FactCollection.create(this.options)).get({ id: this.factId });
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
__decorateClass([foreignKey("Fact", { required: true })], FactSubject.prototype, "factId", 2);
|
|
64
|
+
__decorateClass([field({ required: true })], FactSubject.prototype, "entityType", 2);
|
|
65
|
+
__decorateClass([field({ required: true })], FactSubject.prototype, "entityId", 2);
|
|
66
|
+
__decorateClass([field()], FactSubject.prototype, "role", 2);
|
|
67
|
+
__decorateClass([field()], FactSubject.prototype, "metadata", 2);
|
|
68
|
+
__decorateClass([tenantId({ nullable: true })], FactSubject.prototype, "tenantId", 2);
|
|
69
|
+
__decorateClass([field()], FactSubject.prototype, "createdAt", 2);
|
|
70
|
+
__decorateClass([field()], FactSubject.prototype, "updatedAt", 2);
|
|
71
|
+
FactSubject = __decorateClass([TenantScoped({ mode: "optional" }), smrt({
|
|
72
|
+
conflictColumns: [
|
|
73
|
+
"fact_id",
|
|
74
|
+
"entity_type",
|
|
75
|
+
"entity_id"
|
|
76
|
+
],
|
|
77
|
+
api: { include: [
|
|
78
|
+
"list",
|
|
79
|
+
"get",
|
|
80
|
+
"create",
|
|
81
|
+
"delete"
|
|
82
|
+
] },
|
|
83
|
+
mcp: { include: [
|
|
84
|
+
"list",
|
|
85
|
+
"get",
|
|
86
|
+
"create"
|
|
87
|
+
] },
|
|
88
|
+
cli: true
|
|
89
|
+
})], FactSubject);
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/fact-subjects.ts
|
|
92
|
+
var fact_subjects_exports = /* @__PURE__ */ __exportAll({ FactSubjectCollection: () => FactSubjectCollection });
|
|
93
|
+
var FactSubjectCollection = class extends SmrtCollection {
|
|
94
|
+
static _itemClass = FactSubject;
|
|
95
|
+
/**
|
|
96
|
+
* Get all subjects linked to a fact
|
|
97
|
+
*/
|
|
98
|
+
async getForFact(factId) {
|
|
99
|
+
return this.list({ where: { factId } });
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Get all fact-subject links for a given entity
|
|
103
|
+
*/
|
|
104
|
+
async getForEntity(entityType, entityId) {
|
|
105
|
+
return this.list({ where: {
|
|
106
|
+
entityType,
|
|
107
|
+
entityId
|
|
108
|
+
} });
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Link an entity to a fact
|
|
112
|
+
*/
|
|
113
|
+
async linkEntity(factId, entityType, entityId, role = "subject") {
|
|
114
|
+
return this.create({
|
|
115
|
+
factId,
|
|
116
|
+
entityType,
|
|
117
|
+
entityId,
|
|
118
|
+
role
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Unlink an entity from a fact
|
|
123
|
+
*/
|
|
124
|
+
async unlinkEntity(factId, entityType, entityId) {
|
|
125
|
+
const links = await this.list({ where: {
|
|
126
|
+
factId,
|
|
127
|
+
entityType,
|
|
128
|
+
entityId
|
|
129
|
+
} });
|
|
130
|
+
for (const link of links) await link.delete();
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get subjects by role for a fact
|
|
134
|
+
*/
|
|
135
|
+
async getByRole(factId, role) {
|
|
136
|
+
return this.list({ where: {
|
|
137
|
+
factId,
|
|
138
|
+
role
|
|
139
|
+
} });
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Count entities linked to a fact
|
|
143
|
+
*/
|
|
144
|
+
async countForFact(factId) {
|
|
145
|
+
return (await this.getForFact(factId)).length;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Find all subjects belonging to a specific tenant
|
|
149
|
+
*/
|
|
150
|
+
async findByTenant(tenantId) {
|
|
151
|
+
return this.list({ where: { tenantId } });
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Find all global (tenant-less) subjects.
|
|
155
|
+
*
|
|
156
|
+
* Routes through the shared tenant-global helper so it does not throw under
|
|
157
|
+
* an active tenant context (an explicit `tenant_id IS NULL` filter would be
|
|
158
|
+
* flagged as an isolation violation). (#1600)
|
|
159
|
+
*/
|
|
160
|
+
async findGlobal() {
|
|
161
|
+
return queryGlobal(this);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Find subjects for a tenant including global subjects.
|
|
165
|
+
*
|
|
166
|
+
* Fails closed if an active tenant context requests a different tenant's
|
|
167
|
+
* rows; the admin/system path keeps the cross-tenant capability. (#1600)
|
|
168
|
+
*/
|
|
169
|
+
async findWithGlobals(tenantId) {
|
|
170
|
+
return queryWithGlobals(this, tenantId, "FactSubject.findWithGlobals");
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
//#endregion
|
|
174
|
+
export { fact_subjects_exports as n, FactSubject as r, FactSubjectCollection as t };
|
|
175
|
+
|
|
176
|
+
//# sourceMappingURL=fact-subjects-CzVv4VCE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fact-subjects-CzVv4VCE.js","names":[],"sources":["../../src/fact-subject.ts","../../src/fact-subjects.ts"],"sourcesContent":["/**\n * FactSubject model - Polymorphic entity linking for facts\n *\n * Links facts to any entity type (profiles, places, events, etc.)\n * using polymorphic entityType + entityId with role classification.\n */\n\nimport { field, foreignKey, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { FactSubjectOptions, SubjectRole } from './types';\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n conflictColumns: ['fact_id', 'entity_type', 'entity_id'],\n api: { include: ['list', 'get', 'create', 'delete'] },\n mcp: { include: ['list', 'get', 'create'] },\n cli: true,\n})\nexport class FactSubject extends SmrtObject {\n @foreignKey('Fact', { required: true })\n factId: string = '';\n\n @field({ required: true })\n entityType: string = '';\n\n @field({ required: true })\n entityId: string = '';\n\n @field()\n role: string = 'subject';\n @field()\n metadata: string = '';\n\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @field()\n createdAt: Date = new Date();\n @field()\n updatedAt: Date = new Date();\n\n constructor(options: FactSubjectOptions = {}) {\n super(options);\n if (options.factId) this.factId = options.factId;\n if (options.entityType) this.entityType = options.entityType;\n if (options.entityId) this.entityId = options.entityId;\n if (options.role !== undefined) this.role = options.role;\n\n if (options.metadata !== undefined) {\n if (typeof options.metadata === 'string') {\n this.metadata = options.metadata;\n } else {\n this.metadata = JSON.stringify(options.metadata);\n }\n }\n }\n\n getRole(): SubjectRole {\n return this.role as SubjectRole;\n }\n\n getMetadata(): Record<string, unknown> {\n const raw = this.metadata;\n if (!raw) return {};\n if (typeof raw === 'object') return raw as unknown as Record<string, unknown>;\n try {\n return JSON.parse(String(raw));\n } catch {\n return {};\n }\n }\n\n setMetadata(data: Record<string, unknown>): void {\n this.metadata = JSON.stringify(data);\n }\n\n updateMetadata(updates: Record<string, unknown>): void {\n const current = this.getMetadata();\n this.metadata = JSON.stringify({ ...current, ...updates });\n }\n\n /**\n * Get the fact this subject is linked to\n */\n async getFact(): Promise<import('./fact').Fact | null> {\n if (!this.factId) return null;\n\n const { FactCollection } = await import('./facts');\n const collection = await FactCollection.create(this.options);\n return await collection.get({ id: this.factId });\n }\n}\n","/**\n * FactSubjectCollection - Collection manager for FactSubject objects\n *\n * Provides queries for polymorphic entity linking, including\n * link/unlink operations and entity-centric lookups.\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { FactSubject } from './fact-subject';\nimport type { SubjectRole } from './types';\n\nexport class FactSubjectCollection extends SmrtCollection<FactSubject> {\n static readonly _itemClass = FactSubject;\n\n /**\n * Get all subjects linked to a fact\n */\n async getForFact(factId: string): Promise<FactSubject[]> {\n return this.list({ where: { factId } });\n }\n\n /**\n * Get all fact-subject links for a given entity\n */\n async getForEntity(\n entityType: string,\n entityId: string,\n ): Promise<FactSubject[]> {\n return this.list({ where: { entityType, entityId } });\n }\n\n /**\n * Link an entity to a fact\n */\n async linkEntity(\n factId: string,\n entityType: string,\n entityId: string,\n role: SubjectRole = 'subject',\n ): Promise<FactSubject> {\n return this.create({\n factId,\n entityType,\n entityId,\n role,\n });\n }\n\n /**\n * Unlink an entity from a fact\n */\n async unlinkEntity(\n factId: string,\n entityType: string,\n entityId: string,\n ): Promise<void> {\n const links = await this.list({\n where: { factId, entityType, entityId },\n });\n for (const link of links) {\n await link.delete();\n }\n }\n\n /**\n * Get subjects by role for a fact\n */\n async getByRole(factId: string, role: SubjectRole): Promise<FactSubject[]> {\n return this.list({ where: { factId, role } });\n }\n\n /**\n * Count entities linked to a fact\n */\n async countForFact(factId: string): Promise<number> {\n const subjects = await this.getForFact(factId);\n return subjects.length;\n }\n\n // =========================================================================\n // Tenant Helper Methods\n // =========================================================================\n\n /**\n * Find all subjects belonging to a specific tenant\n */\n async findByTenant(tenantId: string): Promise<FactSubject[]> {\n return this.list({ where: { tenantId } });\n }\n\n /**\n * Find all global (tenant-less) subjects.\n *\n * Routes through the shared tenant-global helper so it does not throw under\n * an active tenant context (an explicit `tenant_id IS NULL` filter would be\n * flagged as an isolation violation). (#1600)\n */\n async findGlobal(): Promise<FactSubject[]> {\n return queryGlobal<FactSubject>(this);\n }\n\n /**\n * Find subjects for a tenant including global subjects.\n *\n * Fails closed if an active tenant context requests a different tenant's\n * rows; the admin/system path keeps the cross-tenant capability. (#1600)\n */\n async findWithGlobals(tenantId: string): Promise<FactSubject[]> {\n return queryWithGlobals<FactSubject>(\n this,\n tenantId,\n 'FactSubject.findWithGlobals',\n );\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __exportAll = (all, no_symbols) => {
|
|
4
|
+
let target = {};
|
|
5
|
+
for (var name in all) __defProp(target, name, {
|
|
6
|
+
get: all[name],
|
|
7
|
+
enumerable: true
|
|
8
|
+
});
|
|
9
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
10
|
+
return target;
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
export { __exportAll as t };
|