@happyvertical/smrt-cli 0.51.24 → 0.51.26
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.md +1 -0
- package/README.md +1 -0
- package/dist/{ApiKey-BZmbOTnL-niFNV-7x.js → ApiKey-BZmbOTnL-R0YuUNnd.js} +2 -2
- package/dist/ApiKeyCollection-Bfb_nw81-BjaP6WB4.js +2 -0
- package/dist/AuditLogCollection-B1YonCAP-Bp6kDil8.js +2 -0
- package/dist/{NostrIdentity-n70E0vck-C3qsu8zD.js → NostrIdentity-n70E0vck-C3A6vRT7.js} +3 -3
- package/dist/NostrIdentityCollection-Ca74dkaL-oEUnuR0g.js +2 -0
- package/dist/{OidcIdentity-K8V4u0CR-CwvImYYY.js → OidcIdentity-K8V4u0CR--RbxfFxK.js} +2 -2
- package/dist/OidcIdentityCollection-gnrLoF08-5tNcW3tG.js +2 -0
- package/dist/ProfileAssetCollection-CmbeSgDi-CuuWlS3F.js +2 -0
- package/dist/{ProfileCollection-DTT4KNpQ-BSl_c1i_.js → ProfileCollection-DTT4KNpQ-BAPC6Q3f.js} +30 -653
- package/dist/{ProfileMetadataCollection-DxX_BJKV-kpa3rgiI.js → ProfileMetadataCollection-DxX_BJKV-jSqlQyvB.js} +1 -1
- package/dist/{ProfileMetafieldCollection-CMKhVi2I-HKsCJDn7.js → ProfileMetafieldCollection-CMKhVi2I-CHI-aX_c.js} +1 -1
- package/dist/{ProfileRelationshipCollection-DUVgaIqf-DVwIEN1I.js → ProfileRelationshipCollection-DUVgaIqf-DkDxcHHB.js} +1 -1
- package/dist/{ProfileRelationshipTermCollection-DtA9OM23-DhMqV5y2.js → ProfileRelationshipTermCollection-DtA9OM23-BYAqAb7S.js} +1 -1
- package/dist/{ProfileRelationshipType-BRiRka6t-CZxd9f0l.js → ProfileRelationshipType-BRiRka6t-CBf_ReQk.js} +1 -1
- package/dist/{ProfileRelationshipTypeCollection-BdXwd7Kf-DWDh61w6.js → ProfileRelationshipTypeCollection-BdXwd7Kf-gXXsCQrv.js} +1 -1
- package/dist/{commands-CclKGZRp.js → commands-CF3-GhBK.js} +61 -1
- package/dist/dist--NU7xe0a.js +813 -0
- package/dist/{dist-C-yxvpyT.js → dist-C2Irk8dl.js} +25 -25
- package/dist/{dist-BHR0tsIO.js → dist-CACaNztx.js} +3 -3
- package/dist/dist-CbOoSQdV.js +1235 -0
- package/dist/index.js +9 -9
- package/dist/{oidcProvisioningPrimitives-0-3n3D6f-iCSXDIAZ.js → oidcProvisioningPrimitives-0-3n3D6f-bOuKYhnr.js} +4 -4
- package/dist/resolveIdentity-BrJDCjYi-wdS1avq8.js +2 -0
- package/package.json +9 -8
- package/dist/ApiKeyCollection-Bfb_nw81-CNPNkzCL.js +0 -2
- package/dist/AuditLogCollection-B1YonCAP-IB02mJPz.js +0 -2
- package/dist/NostrIdentityCollection-Ca74dkaL-CUV-1Hzs.js +0 -2
- package/dist/OidcIdentityCollection-gnrLoF08-WIx_hLet.js +0 -2
- package/dist/ProfileAssetCollection-CmbeSgDi-BQd2qiDK.js +0 -2
- package/dist/dist-0QjiSFH4.js +0 -190
- package/dist/resolveIdentity-BrJDCjYi-BtP8skcX.js +0 -2
|
@@ -0,0 +1,813 @@
|
|
|
1
|
+
import { ObjectRegistry, SmrtCollection, SmrtObject, applyPendingDecoratorRegistrations, crossPackageRef, field, registerCompatibleFieldDecorator, smrt } from "@happyvertical/smrt-core";
|
|
2
|
+
import { createLogger } from "@happyvertical/logger";
|
|
3
|
+
import { getPackageConfig } from "@happyvertical/smrt-config";
|
|
4
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
|
+
//#region ../tenancy/dist/chunks/context-CwbLwyIV.js
|
|
6
|
+
var SYSTEM_CONTEXT_MARKER = /* @__PURE__ */ Symbol.for("smrt:system-context");
|
|
7
|
+
var TENANT_STORAGE_KEY = /* @__PURE__ */ Symbol.for("smrt:tenant-context-storage");
|
|
8
|
+
function resolveTenantStorage() {
|
|
9
|
+
const root = globalThis;
|
|
10
|
+
root[TENANT_STORAGE_KEY] ??= new AsyncLocalStorage();
|
|
11
|
+
return root[TENANT_STORAGE_KEY];
|
|
12
|
+
}
|
|
13
|
+
var tenantStorage = resolveTenantStorage();
|
|
14
|
+
function getCurrentTenant() {
|
|
15
|
+
const store = tenantStorage.getStore();
|
|
16
|
+
if (store === SYSTEM_CONTEXT_MARKER) return;
|
|
17
|
+
return store;
|
|
18
|
+
}
|
|
19
|
+
function getTenantId() {
|
|
20
|
+
const store = tenantStorage.getStore();
|
|
21
|
+
if (store === SYSTEM_CONTEXT_MARKER) return;
|
|
22
|
+
return store?.tenantId;
|
|
23
|
+
}
|
|
24
|
+
function isSystemContext() {
|
|
25
|
+
return tenantStorage.getStore() === SYSTEM_CONTEXT_MARKER;
|
|
26
|
+
}
|
|
27
|
+
function isSuperAdminBypass() {
|
|
28
|
+
const store = tenantStorage.getStore();
|
|
29
|
+
if (store === SYSTEM_CONTEXT_MARKER) return false;
|
|
30
|
+
return store?.superAdminBypass === true;
|
|
31
|
+
}
|
|
32
|
+
async function withSystemContext(fn) {
|
|
33
|
+
return tenantStorage.run(SYSTEM_CONTEXT_MARKER, fn);
|
|
34
|
+
}
|
|
35
|
+
var TenantIsolationError = class extends Error {
|
|
36
|
+
/** Stable error code; always `'TENANT_ISOLATION_VIOLATION'`. */
|
|
37
|
+
code = "TENANT_ISOLATION_VIOLATION";
|
|
38
|
+
/** The tenant ID that is active in the current context. */
|
|
39
|
+
tenantId;
|
|
40
|
+
/** The tenant ID that was attempted (and rejected). */
|
|
41
|
+
attemptedTenantId;
|
|
42
|
+
constructor(message, details) {
|
|
43
|
+
super(message);
|
|
44
|
+
this.name = "TenantIsolationError";
|
|
45
|
+
this.tenantId = details?.tenantId;
|
|
46
|
+
this.attemptedTenantId = details?.attemptedTenantId;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region ../tenancy/dist/chunks/testing-s12-pjzJ.js
|
|
51
|
+
var DEFAULT_CONFIG = {
|
|
52
|
+
mode: "required",
|
|
53
|
+
field: "tenantId",
|
|
54
|
+
autoFilter: true,
|
|
55
|
+
autoPopulate: true,
|
|
56
|
+
allowSuperAdminBypass: false
|
|
57
|
+
};
|
|
58
|
+
var tenantScopedClasses = /* @__PURE__ */ new Map();
|
|
59
|
+
var unregisteredDecoratorRegistrations = /* @__PURE__ */ new Map();
|
|
60
|
+
function registerTenantScopedConstructor(target, config = {}) {
|
|
61
|
+
const resolved = {
|
|
62
|
+
...DEFAULT_CONFIG,
|
|
63
|
+
...config
|
|
64
|
+
};
|
|
65
|
+
unregisteredDecoratorRegistrations.set(target.name, resolved);
|
|
66
|
+
tenantScopedClasses.set(target.name, resolved);
|
|
67
|
+
}
|
|
68
|
+
var KEY = /* @__PURE__ */ Symbol.for("smrt:tenant-global-read-scope");
|
|
69
|
+
var root = globalThis;
|
|
70
|
+
root[KEY] ??= new AsyncLocalStorage();
|
|
71
|
+
root[KEY];
|
|
72
|
+
function assertTenantReadAllowed(tenantId, label) {
|
|
73
|
+
const tenantContext = getCurrentTenant();
|
|
74
|
+
if (tenantContext && !isSuperAdminBypass() && tenantContext.tenantId !== tenantId) throw new TenantIsolationError(`Tenant isolation violation in ${label}: context tenant is '${tenantContext.tenantId}' but query requested '${tenantId}'`, {
|
|
75
|
+
tenantId: tenantContext.tenantId,
|
|
76
|
+
attemptedTenantId: tenantId
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
async function queryGlobal(collection) {
|
|
80
|
+
const metaType = collection.getStiChildMetaType();
|
|
81
|
+
const where = metaType ? "WHERE _meta_type = ? AND tenant_id IS NULL" : "WHERE tenant_id IS NULL";
|
|
82
|
+
const params = metaType ? [metaType] : [];
|
|
83
|
+
return await collection.query(`SELECT * FROM ${collection.tableName} ${where}`, params, { allowRawOnTenantScoped: true });
|
|
84
|
+
}
|
|
85
|
+
async function queryWithGlobals(collection, tenantId, label) {
|
|
86
|
+
assertTenantReadAllowed(tenantId, label);
|
|
87
|
+
const metaType = collection.getStiChildMetaType();
|
|
88
|
+
const where = metaType ? "WHERE _meta_type = ? AND (tenant_id = ? OR tenant_id IS NULL)" : "WHERE tenant_id = ? OR tenant_id IS NULL";
|
|
89
|
+
const params = metaType ? [metaType, tenantId] : [tenantId];
|
|
90
|
+
return await collection.query(`SELECT * FROM ${collection.tableName} ${where}`, params, { allowRawOnTenantScoped: true });
|
|
91
|
+
}
|
|
92
|
+
createLogger({ level: "info" });
|
|
93
|
+
//#endregion
|
|
94
|
+
//#region ../tenancy/dist/index.js
|
|
95
|
+
ObjectRegistry.registerPackageManifest(JSON.parse("{\"version\":\"1.0.0\",\"timestamp\":0,\"packageName\":\"@happyvertical/smrt-tenancy\",\"packageVersion\":\"0.51.26\",\"objects\":{\"@happyvertical/smrt-tenancy:BillingRelationship\":{\"name\":\"billingrelationship\",\"className\":\"BillingRelationship\",\"qualifiedName\":\"@happyvertical/smrt-tenancy:BillingRelationship\",\"collection\":\"billingrelationships\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/tenancy/src/billing-relationship.ts\",\"packageName\":\"@happyvertical/smrt-tenancy\",\"fields\":{\"childTenantId\":{\"type\":\"crossPackageRef\",\"required\":true,\"related\":\"@happyvertical/smrt-users:Tenant\",\"_meta\":{\"required\":true}},\"resellerTenantId\":{\"type\":\"crossPackageRef\",\"required\":true,\"related\":\"@happyvertical/smrt-users:Tenant\",\"_meta\":{\"required\":true}},\"billingOwnerMode\":{\"type\":\"text\",\"required\":false,\"default\":\"self\"}},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"_smrt_billing_relationships\",\"conflictColumns\":[\"child_tenant_id\"],\"api\":false,\"cli\":false,\"mcp\":false},\"extends\":\"SmrtObject\",\"exportName\":\"BillingRelationship\",\"collectionExportName\":\"BillingRelationshipCollection\",\"validationRules\":[{\"field\":\"childTenantId\",\"rule\":\"required\",\"fieldType\":\"crossPackageRef\"},{\"field\":\"resellerTenantId\",\"rule\":\"required\",\"fieldType\":\"crossPackageRef\"}],\"schema\":{\"tableName\":\"_smrt_billing_relationships\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"_smrt_billing_relationships\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"child_tenant_id\\\" UUID NOT NULL,\\n \\\"reseller_tenant_id\\\" UUID NOT NULL,\\n \\\"billing_owner_mode\\\" TEXT DEFAULT 'self'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"child_tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":true,\"unique\":false},\"reseller_tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":true,\"unique\":false},\"billing_owner_mode\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"self\"}},\"indexes\":[{\"name\":\"_smrt_billing_relationships_child_tenant_id_idx\",\"columns\":[\"child_tenant_id\"],\"unique\":true},{\"name\":\"_smrt_billing_relationships_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"_smrt_billing_relationships_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"_smrt_billing_relationships_reseller_tenant_id_idx\",\"columns\":[\"reseller_tenant_id\"]}],\"version\":\"4d7f410a\"},\"importPath\":\"@happyvertical/smrt-tenancy\"},\"@happyvertical/smrt-tenancy:BillingRelationshipCollection\":{\"name\":\"billingrelationshipcollection\",\"className\":\"BillingRelationshipCollection\",\"qualifiedName\":\"@happyvertical/smrt-tenancy:BillingRelationshipCollection\",\"collection\":\"billingrelationships\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/tenancy/src/billing-relationship.ts\",\"packageName\":\"@happyvertical/smrt-tenancy\",\"fields\":{},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"_smrt_billing_relationships\",\"api\":false,\"mcp\":false,\"cli\":false},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"BillingRelationship\",\"exportName\":\"BillingRelationshipCollection\",\"collectionExportName\":\"BillingRelationshipCollectionCollection\",\"schema\":{\"tableName\":\"_smrt_billing_relationships\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"_smrt_billing_relationships\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"child_tenant_id\\\" UUID NOT NULL,\\n \\\"reseller_tenant_id\\\" UUID NOT NULL,\\n \\\"billing_owner_mode\\\" TEXT DEFAULT 'self'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"child_tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":true,\"unique\":false},\"reseller_tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":true,\"unique\":false},\"billing_owner_mode\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"self\"}},\"indexes\":[{\"name\":\"_smrt_billing_relationships_child_tenant_id_idx\",\"columns\":[\"child_tenant_id\"],\"unique\":true},{\"name\":\"_smrt_billing_relationships_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"_smrt_billing_relationships_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"_smrt_billing_relationships_reseller_tenant_id_idx\",\"columns\":[\"reseller_tenant_id\"]}],\"version\":\"4d7f410a\"},\"importPath\":\"@happyvertical/smrt-tenancy\"}},\"moduleType\":\"smrt\",\"smrtDependencies\":[\"@happyvertical/smrt-core\"]}"));
|
|
96
|
+
var __defProp$2 = Object.defineProperty;
|
|
97
|
+
var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
|
|
98
|
+
var __decorateClass$1 = (decorators, target, key, kind) => {
|
|
99
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
|
|
100
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
101
|
+
if (kind && result) __defProp$2(target, key, result);
|
|
102
|
+
return result;
|
|
103
|
+
};
|
|
104
|
+
var BillingRelationshipError = class extends Error {
|
|
105
|
+
constructor(message, code) {
|
|
106
|
+
super(message);
|
|
107
|
+
this.code = code;
|
|
108
|
+
this.name = "BillingRelationshipError";
|
|
109
|
+
}
|
|
110
|
+
code;
|
|
111
|
+
};
|
|
112
|
+
var BillingRelationship = class extends SmrtObject {
|
|
113
|
+
childTenantId = "";
|
|
114
|
+
resellerTenantId = "";
|
|
115
|
+
billingOwnerMode = "self";
|
|
116
|
+
async validateBeforeSave() {
|
|
117
|
+
await super.validateBeforeSave();
|
|
118
|
+
this.childTenantId = canonicalTenantId(this.childTenantId);
|
|
119
|
+
this.resellerTenantId = canonicalTenantId(this.resellerTenantId);
|
|
120
|
+
assertMode(this.billingOwnerMode);
|
|
121
|
+
if (this.childTenantId === this.resellerTenantId) throw new BillingRelationshipError("A tenant cannot resell to itself.", "CIRCULAR_RELATIONSHIP");
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
__decorateClass$1([crossPackageRef("@happyvertical/smrt-users:Tenant"), field({ required: true })], BillingRelationship.prototype, "childTenantId", 2);
|
|
125
|
+
__decorateClass$1([crossPackageRef("@happyvertical/smrt-users:Tenant"), field({ required: true })], BillingRelationship.prototype, "resellerTenantId", 2);
|
|
126
|
+
BillingRelationship = __decorateClass$1([smrt({
|
|
127
|
+
tableName: "_smrt_billing_relationships",
|
|
128
|
+
conflictColumns: ["child_tenant_id"],
|
|
129
|
+
api: false,
|
|
130
|
+
cli: false,
|
|
131
|
+
mcp: false
|
|
132
|
+
})], BillingRelationship);
|
|
133
|
+
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
134
|
+
function assertTenantId(id) {
|
|
135
|
+
if (typeof id !== "string" || !UUID_PATTERN.test(id)) throw new BillingRelationshipError("Tenant IDs must be UUIDs.", "INVALID_TENANT");
|
|
136
|
+
}
|
|
137
|
+
function canonicalTenantId(id) {
|
|
138
|
+
assertTenantId(id);
|
|
139
|
+
return id.toLowerCase();
|
|
140
|
+
}
|
|
141
|
+
function assertMode(mode) {
|
|
142
|
+
if (mode !== "self" && mode !== "reseller") throw new BillingRelationshipError("Billing owner mode must be self or reseller.", "INVALID_OWNER_MODE");
|
|
143
|
+
}
|
|
144
|
+
function TenantScoped(options = {}) {
|
|
145
|
+
return (target, decoratorContext) => {
|
|
146
|
+
applyPendingDecoratorRegistrations(target, decoratorContext);
|
|
147
|
+
const config = {
|
|
148
|
+
mode: options.mode ?? "required",
|
|
149
|
+
field: options.field ?? "tenantId",
|
|
150
|
+
autoFilter: options.autoFilter ?? true,
|
|
151
|
+
autoPopulate: options.autoPopulate ?? true,
|
|
152
|
+
allowSuperAdminBypass: options.allowSuperAdminBypass ?? false
|
|
153
|
+
};
|
|
154
|
+
registerTenantScopedConstructor(target, config);
|
|
155
|
+
ObjectRegistry.reconcileTenantScopedConfig(target, {
|
|
156
|
+
mode: config.mode ?? "required",
|
|
157
|
+
field: config.field ?? "tenantId",
|
|
158
|
+
autoFilter: config.autoFilter ?? true,
|
|
159
|
+
autoPopulate: config.autoPopulate ?? true,
|
|
160
|
+
allowSuperAdminBypass: config.allowSuperAdminBypass ?? false
|
|
161
|
+
});
|
|
162
|
+
return target;
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function tenantId(options = {}) {
|
|
166
|
+
const opts = {
|
|
167
|
+
autoFilter: true,
|
|
168
|
+
required: true,
|
|
169
|
+
autoPopulate: true,
|
|
170
|
+
nullable: false,
|
|
171
|
+
...options
|
|
172
|
+
};
|
|
173
|
+
return ((targetOrValue, propertyKeyOrContext) => {
|
|
174
|
+
registerCompatibleFieldDecorator(targetOrValue, propertyKeyOrContext, (className, propertyKey, ctor) => {
|
|
175
|
+
const fieldOptions = {
|
|
176
|
+
type: "foreignKey",
|
|
177
|
+
related: "Tenant",
|
|
178
|
+
sqlType: "UUID",
|
|
179
|
+
required: opts.required,
|
|
180
|
+
nullable: opts.nullable,
|
|
181
|
+
__tenancy: {
|
|
182
|
+
...opts,
|
|
183
|
+
isTenantIdField: true
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
ObjectRegistry.registerFieldDecorator(className, propertyKey, fieldOptions, ctor);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region ../prompts/dist/index.js
|
|
192
|
+
var __defProp$1 = Object.defineProperty;
|
|
193
|
+
var __exportAll = (all, no_symbols) => {
|
|
194
|
+
let target = {};
|
|
195
|
+
for (var name in all) __defProp$1(target, name, {
|
|
196
|
+
get: all[name],
|
|
197
|
+
enumerable: true
|
|
198
|
+
});
|
|
199
|
+
if (!no_symbols) __defProp$1(target, Symbol.toStringTag, { value: "Module" });
|
|
200
|
+
return target;
|
|
201
|
+
};
|
|
202
|
+
ObjectRegistry.registerPackageManifest(JSON.parse("{\"version\":\"1.0.0\",\"timestamp\":0,\"packageName\":\"@happyvertical/smrt-prompts\",\"packageVersion\":\"0.51.26\",\"objects\":{\"@happyvertical/smrt-prompts:PromptOverrideCollection\":{\"name\":\"promptoverridecollection\",\"className\":\"PromptOverrideCollection\",\"qualifiedName\":\"@happyvertical/smrt-prompts:PromptOverrideCollection\",\"collection\":\"promptoverrides\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/prompts/src/collections/PromptOverrideCollection.ts\",\"packageName\":\"@happyvertical/smrt-prompts\",\"fields\":{},\"methods\":{\"getAppOverride\":{\"name\":\"getAppOverride\",\"async\":true,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false},{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string\"]}],\"returnType\":\"Promise<PromptOverride | null>\",\"isStatic\":false,\"isPublic\":true},\"getTenantOverride\":{\"name\":\"getTenantOverride\",\"async\":true,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false},{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string\"]}],\"returnType\":\"Promise<PromptOverride | null>\",\"isStatic\":false,\"isPublic\":true},\"getResolutionLayers\":{\"name\":\"getResolutionLayers\",\"async\":true,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false},{\"name\":\"tenantId\",\"type\":\"string | null\",\"optional\":true,\"unionBranches\":[{\"type\":\"string\"},{\"type\":\"null\"}]},{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string\"]}],\"returnType\":\"Promise<object>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"_smrt_prompt_overrides\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"PromptOverride\",\"exportName\":\"PromptOverrideCollection\",\"collectionExportName\":\"PromptOverrideCollectionCollection\",\"schema\":{\"tableName\":\"_smrt_prompt_overrides\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"_smrt_prompt_overrides\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"key\\\" TEXT NOT NULL DEFAULT '',\\n \\\"tenant_id\\\" TEXT,\\n \\\"template\\\" TEXT,\\n \\\"profile\\\" TEXT,\\n \\\"model\\\" TEXT,\\n \\\"params\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"key\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"tenant_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"template\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"profile\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"model\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"params\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"_smrt_prompt_overrides_key_context_idx\",\"columns\":[\"key\",\"context\"],\"unique\":true},{\"name\":\"_smrt_prompt_overrides_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"_smrt_prompt_overrides_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"6f475427\"},\"importPath\":\"@happyvertical/smrt-prompts\"},\"@happyvertical/smrt-prompts:PromptOverride\":{\"name\":\"promptoverride\",\"className\":\"PromptOverride\",\"qualifiedName\":\"@happyvertical/smrt-prompts:PromptOverride\",\"collection\":\"promptoverrides\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/prompts/src/models/PromptOverride.ts\",\"packageName\":\"@happyvertical/smrt-prompts\",\"fields\":{\"key\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"template\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"profile\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"model\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"params\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}}},\"methods\":{\"getParams\":{\"name\":\"getParams\",\"async\":false,\"parameters\":[],\"returnType\":\"PromptParams\",\"isStatic\":false,\"isPublic\":true},\"setParams\":{\"name\":\"setParams\",\"async\":false,\"parameters\":[{\"name\":\"params\",\"type\":\"PromptParams | null\",\"optional\":false,\"unionBranches\":[{\"type\":\"PromptParams\"},{\"type\":\"null\"}]}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"toPromptLayer\":{\"name\":\"toPromptLayer\",\"async\":false,\"parameters\":[],\"returnType\":\"PromptLayer\",\"isStatic\":false,\"isPublic\":true},\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"delete\":{\"name\":\"delete\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"_smrt_prompt_overrides\",\"conflictColumns\":[\"key\",\"context\"],\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"cli\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"],\"exclude\":[\"getParams\",\"setParams\",\"toPromptLayer\"]},\"mcp\":{\"include\":[]}},\"extends\":\"SmrtObject\",\"exportName\":\"PromptOverride\",\"collectionExportName\":\"PromptOverrideCollection\",\"validationRules\":[{\"field\":\"key\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"_smrt_prompt_overrides\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"_smrt_prompt_overrides\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"key\\\" TEXT NOT NULL DEFAULT '',\\n \\\"tenant_id\\\" TEXT,\\n \\\"template\\\" TEXT,\\n \\\"profile\\\" TEXT,\\n \\\"model\\\" TEXT,\\n \\\"params\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"key\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"tenant_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"template\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"profile\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"model\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"params\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"_smrt_prompt_overrides_key_context_idx\",\"columns\":[\"key\",\"context\"],\"unique\":true},{\"name\":\"_smrt_prompt_overrides_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"_smrt_prompt_overrides_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"6f475427\"},\"importPath\":\"@happyvertical/smrt-prompts\"}},\"moduleType\":\"smrt\",\"smrtDependencies\":[\"@happyvertical/smrt-core\",\"@happyvertical/smrt-tenancy\"]}"));
|
|
203
|
+
var PROMPT_CACHE_TTL_MS = 3e4;
|
|
204
|
+
var promptCache = /* @__PURE__ */ new Map();
|
|
205
|
+
var cacheGenerations = /* @__PURE__ */ new Map();
|
|
206
|
+
var nextGeneration = 1;
|
|
207
|
+
var clearedThrough = 0;
|
|
208
|
+
var dbInstanceIds = /* @__PURE__ */ new WeakMap();
|
|
209
|
+
var nextDbId = 1;
|
|
210
|
+
function getDbNamespace(db) {
|
|
211
|
+
if (!db) return "no-db";
|
|
212
|
+
if (typeof db === "string") return `db:${db}`;
|
|
213
|
+
if (typeof db === "object") {
|
|
214
|
+
const dbObject = db;
|
|
215
|
+
if (typeof dbObject.query === "function") {
|
|
216
|
+
if (!dbInstanceIds.has(dbObject)) dbInstanceIds.set(dbObject, `db-instance:${nextDbId++}`);
|
|
217
|
+
const namespace = dbInstanceIds.get(dbObject);
|
|
218
|
+
if (namespace) return namespace;
|
|
219
|
+
return "db-instance:unknown";
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
return `db-config:${JSON.stringify(dbObject)}`;
|
|
223
|
+
} catch {
|
|
224
|
+
return "db-config:opaque";
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return "db:unknown";
|
|
228
|
+
}
|
|
229
|
+
function buildCacheKey(key, tenantId, db) {
|
|
230
|
+
return `${getDbNamespace(db)}::${key}::${tenantId ?? "app"}`;
|
|
231
|
+
}
|
|
232
|
+
function buildGenerationKey(key, db) {
|
|
233
|
+
return `${getDbNamespace(db)}::${key}`;
|
|
234
|
+
}
|
|
235
|
+
function bumpGeneration(key, db) {
|
|
236
|
+
cacheGenerations.set(buildGenerationKey(key, db), nextGeneration++);
|
|
237
|
+
}
|
|
238
|
+
function getCachedPromptBase(key, tenantId, db) {
|
|
239
|
+
const cacheKey = buildCacheKey(key, tenantId, db);
|
|
240
|
+
const cached = promptCache.get(cacheKey);
|
|
241
|
+
if (!cached) return null;
|
|
242
|
+
if (cached.expiresAt <= Date.now()) {
|
|
243
|
+
promptCache.delete(cacheKey);
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
return cached.value;
|
|
247
|
+
}
|
|
248
|
+
function getPromptCacheGeneration(key, db) {
|
|
249
|
+
const generation = cacheGenerations.get(buildGenerationKey(key, db)) ?? 0;
|
|
250
|
+
return generation > clearedThrough ? generation : clearedThrough;
|
|
251
|
+
}
|
|
252
|
+
function setCachedPromptBase(key, tenantId, db, value, loadedAtGeneration) {
|
|
253
|
+
if (getPromptCacheGeneration(key, db) !== loadedAtGeneration) return;
|
|
254
|
+
promptCache.set(buildCacheKey(key, tenantId, db), {
|
|
255
|
+
expiresAt: Date.now() + PROMPT_CACHE_TTL_MS,
|
|
256
|
+
value
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
function invalidatePromptCache(key, tenantId, db) {
|
|
260
|
+
const dbNamespace = getDbNamespace(db);
|
|
261
|
+
bumpGeneration(key, db);
|
|
262
|
+
if (tenantId !== null && tenantId !== void 0) {
|
|
263
|
+
promptCache.delete(buildCacheKey(key, tenantId, db));
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
const keyPrefix = `${dbNamespace}::${key}::`;
|
|
267
|
+
for (const cacheKey of promptCache.keys()) if (cacheKey.startsWith(keyPrefix)) promptCache.delete(cacheKey);
|
|
268
|
+
}
|
|
269
|
+
var DEFAULT_EDITABLE = {
|
|
270
|
+
template: false,
|
|
271
|
+
profile: false,
|
|
272
|
+
model: false,
|
|
273
|
+
params: false
|
|
274
|
+
};
|
|
275
|
+
var TOP_LEVEL_RESERVED_KEYS = /* @__PURE__ */ new Set([
|
|
276
|
+
"key",
|
|
277
|
+
"editable",
|
|
278
|
+
"template",
|
|
279
|
+
"ai",
|
|
280
|
+
"profile",
|
|
281
|
+
"provider",
|
|
282
|
+
"model",
|
|
283
|
+
"params",
|
|
284
|
+
"temperature",
|
|
285
|
+
"maxTokens"
|
|
286
|
+
]);
|
|
287
|
+
var AI_RESERVED_KEYS = /* @__PURE__ */ new Set([
|
|
288
|
+
"profile",
|
|
289
|
+
"provider",
|
|
290
|
+
"model",
|
|
291
|
+
"params",
|
|
292
|
+
"temperature",
|
|
293
|
+
"maxTokens"
|
|
294
|
+
]);
|
|
295
|
+
var AI_ROUTING_PARAM_KEYS = /* @__PURE__ */ new Set([
|
|
296
|
+
"profile",
|
|
297
|
+
"provider",
|
|
298
|
+
"type",
|
|
299
|
+
"model",
|
|
300
|
+
"defaultModel"
|
|
301
|
+
]);
|
|
302
|
+
function isPlainObject(value) {
|
|
303
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
304
|
+
}
|
|
305
|
+
function normalizeEditableConfig(editable) {
|
|
306
|
+
return {
|
|
307
|
+
template: editable?.template ?? DEFAULT_EDITABLE.template,
|
|
308
|
+
profile: editable?.profile ?? DEFAULT_EDITABLE.profile,
|
|
309
|
+
model: editable?.model ?? DEFAULT_EDITABLE.model,
|
|
310
|
+
params: editable?.params ?? DEFAULT_EDITABLE.params
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
function extractPromptParams(source, reservedKeys) {
|
|
314
|
+
const params = {};
|
|
315
|
+
if (isPlainObject(source.params)) Object.assign(params, sanitizePromptParams(source.params));
|
|
316
|
+
if ("temperature" in source && source.temperature !== void 0) params.temperature = source.temperature;
|
|
317
|
+
if ("maxTokens" in source && source.maxTokens !== void 0) params.maxTokens = source.maxTokens;
|
|
318
|
+
for (const [key, value] of Object.entries(source)) {
|
|
319
|
+
if (reservedKeys.has(key) || value === void 0) continue;
|
|
320
|
+
assignPromptParam(params, key, value);
|
|
321
|
+
}
|
|
322
|
+
return params;
|
|
323
|
+
}
|
|
324
|
+
function assignPromptParam(params, key, value) {
|
|
325
|
+
if (AI_ROUTING_PARAM_KEYS.has(key) || value === void 0) return;
|
|
326
|
+
params[key] = value;
|
|
327
|
+
}
|
|
328
|
+
function sanitizePromptParams(params) {
|
|
329
|
+
const sanitized = {};
|
|
330
|
+
if (!params) return sanitized;
|
|
331
|
+
for (const [key, value] of Object.entries(params)) assignPromptParam(sanitized, key, value);
|
|
332
|
+
return sanitized;
|
|
333
|
+
}
|
|
334
|
+
function mergePromptParams(...paramLayers) {
|
|
335
|
+
const merged = {};
|
|
336
|
+
for (const layer of paramLayers) {
|
|
337
|
+
if (!layer) continue;
|
|
338
|
+
for (const [key, value] of Object.entries(layer)) assignPromptParam(merged, key, value);
|
|
339
|
+
}
|
|
340
|
+
return merged;
|
|
341
|
+
}
|
|
342
|
+
function normalizeAIInput(ai) {
|
|
343
|
+
if (!isPlainObject(ai)) return { params: {} };
|
|
344
|
+
const profile = typeof ai.profile === "string" || ai.profile === null ? ai.profile : void 0;
|
|
345
|
+
const model = typeof ai.model === "string" || ai.model === null ? ai.model : void 0;
|
|
346
|
+
return {
|
|
347
|
+
profile: profile ?? void 0,
|
|
348
|
+
model: model ?? void 0,
|
|
349
|
+
params: extractPromptParams(ai, AI_RESERVED_KEYS)
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
function normalizePromptDefinitionInput(input) {
|
|
353
|
+
return {
|
|
354
|
+
key: input.key,
|
|
355
|
+
template: input.template,
|
|
356
|
+
ai: normalizeAIInput(input.ai),
|
|
357
|
+
editable: normalizeEditableConfig(input.editable)
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
function normalizePromptLayer(input) {
|
|
361
|
+
if (!isPlainObject(input)) return {};
|
|
362
|
+
const nestedAi = isPlainObject(input.ai) ? normalizeAIInput(input.ai) : { params: {} };
|
|
363
|
+
const topLevelParams = extractPromptParams(input, TOP_LEVEL_RESERVED_KEYS);
|
|
364
|
+
return {
|
|
365
|
+
template: input.template === void 0 ? void 0 : input.template === null ? null : String(input.template),
|
|
366
|
+
profile: input.profile === void 0 ? nestedAi.profile : input.profile === null ? null : String(input.profile),
|
|
367
|
+
model: input.model === void 0 ? nestedAi.model : input.model === null ? null : String(input.model),
|
|
368
|
+
params: mergePromptParams(topLevelParams, nestedAi.params)
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
function mergePromptLayers(...layers) {
|
|
372
|
+
let template = "";
|
|
373
|
+
let profile;
|
|
374
|
+
let model;
|
|
375
|
+
let params = {};
|
|
376
|
+
for (const layer of layers) {
|
|
377
|
+
if (!layer) continue;
|
|
378
|
+
if (layer.template !== void 0 && layer.template !== null) template = layer.template;
|
|
379
|
+
if (layer.profile !== void 0 && layer.profile !== null) profile = layer.profile;
|
|
380
|
+
if (layer.model !== void 0 && layer.model !== null) model = layer.model;
|
|
381
|
+
if (layer.params !== void 0 && layer.params !== null) params = mergePromptParams(params, layer.params);
|
|
382
|
+
}
|
|
383
|
+
return {
|
|
384
|
+
template,
|
|
385
|
+
ai: {
|
|
386
|
+
profile,
|
|
387
|
+
model,
|
|
388
|
+
params
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
function normalizeProfileConfig(profile) {
|
|
393
|
+
const params = extractPromptParams(isPlainObject(profile) ? profile : {}, /* @__PURE__ */ new Set(["provider", "model"]));
|
|
394
|
+
return {
|
|
395
|
+
provider: String(profile.provider),
|
|
396
|
+
model: String(profile.model),
|
|
397
|
+
params
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
function validateProfileName(profileName, config) {
|
|
401
|
+
if (profileName.trim() === "") throw new Error("Prompt profile names cannot be empty");
|
|
402
|
+
const allowedProfileNames = config.allowedProfileNames;
|
|
403
|
+
if (Array.isArray(allowedProfileNames) && !allowedProfileNames.includes(profileName)) throw new Error(`Prompt profile "${profileName}" is not in the allowed profile list`);
|
|
404
|
+
if (!config.profiles?.[profileName]) throw new Error(`Prompt profile "${profileName}" is not configured`);
|
|
405
|
+
}
|
|
406
|
+
function validateModelName(modelName, config) {
|
|
407
|
+
if (modelName.trim() === "") throw new Error("Prompt model overrides cannot be empty");
|
|
408
|
+
const allowedModels = config.allowedModels;
|
|
409
|
+
if (Array.isArray(allowedModels) && !allowedModels.includes(modelName)) throw new Error(`Prompt model "${modelName}" is not in the allowed model list`);
|
|
410
|
+
}
|
|
411
|
+
function buildResolvedAI(ai, config) {
|
|
412
|
+
let provider;
|
|
413
|
+
let model = ai.model;
|
|
414
|
+
let params = ai.params;
|
|
415
|
+
if (ai.profile) {
|
|
416
|
+
validateProfileName(ai.profile, config);
|
|
417
|
+
const configuredProfile = config.profiles?.[ai.profile];
|
|
418
|
+
if (!configuredProfile) throw new Error(`Prompt profile "${ai.profile}" is not configured`);
|
|
419
|
+
const profileConfig = normalizeProfileConfig(configuredProfile);
|
|
420
|
+
provider = profileConfig.provider;
|
|
421
|
+
model = model ?? profileConfig.model;
|
|
422
|
+
params = mergePromptParams(profileConfig.params, params);
|
|
423
|
+
}
|
|
424
|
+
if (ai.model) validateModelName(ai.model, config);
|
|
425
|
+
if (ai.model && !ai.profile) throw new Error("Direct prompt model overrides require an effective prompt profile");
|
|
426
|
+
if (model && !ai.model && config.allowedModels) validateModelName(model, config);
|
|
427
|
+
const resolved = {
|
|
428
|
+
...params,
|
|
429
|
+
profile: ai.profile,
|
|
430
|
+
provider,
|
|
431
|
+
model,
|
|
432
|
+
...config.allowedModels ? { allowedModels: [...config.allowedModels] } : {},
|
|
433
|
+
params
|
|
434
|
+
};
|
|
435
|
+
if (typeof params.temperature === "number") resolved.temperature = params.temperature;
|
|
436
|
+
if (typeof params.maxTokens === "number") resolved.maxTokens = params.maxTokens;
|
|
437
|
+
return resolved;
|
|
438
|
+
}
|
|
439
|
+
function renderPromptTemplate(template, variables) {
|
|
440
|
+
if (!variables || Object.keys(variables).length === 0) return template;
|
|
441
|
+
return template.replace(/\{([^{}]+)\}/g, (_match, rawKey) => {
|
|
442
|
+
const value = variables[rawKey.trim()];
|
|
443
|
+
if (value === void 0 || value === null) return "";
|
|
444
|
+
if (value instanceof Date) return value.toISOString();
|
|
445
|
+
if (Array.isArray(value) || isPlainObject(value)) try {
|
|
446
|
+
return JSON.stringify(value);
|
|
447
|
+
} catch {
|
|
448
|
+
return "";
|
|
449
|
+
}
|
|
450
|
+
return String(value);
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
function parsePromptParams(raw) {
|
|
454
|
+
if (!raw) return {};
|
|
455
|
+
try {
|
|
456
|
+
const parsed = JSON.parse(raw);
|
|
457
|
+
return isPlainObject(parsed) ? sanitizePromptParams(parsed) : {};
|
|
458
|
+
} catch {
|
|
459
|
+
return {};
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
function serializePromptParams(params) {
|
|
463
|
+
if (params === null || params === void 0) return null;
|
|
464
|
+
return JSON.stringify(sanitizePromptParams(params));
|
|
465
|
+
}
|
|
466
|
+
function getRegistry() {
|
|
467
|
+
if (!globalThis.__smrtPromptRegistry) globalThis.__smrtPromptRegistry = /* @__PURE__ */ new Map();
|
|
468
|
+
return globalThis.__smrtPromptRegistry;
|
|
469
|
+
}
|
|
470
|
+
function stableStringify(value) {
|
|
471
|
+
if (Array.isArray(value)) return `[${value.map((item) => stableStringify(item)).join(",")}]`;
|
|
472
|
+
if (value && typeof value === "object") return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`).join(",")}}`;
|
|
473
|
+
return JSON.stringify(value);
|
|
474
|
+
}
|
|
475
|
+
var PromptRegistry = {
|
|
476
|
+
register(input) {
|
|
477
|
+
if (!input.key || input.key.trim() === "") throw new Error("Prompt definitions require a non-empty key");
|
|
478
|
+
const definition = normalizePromptDefinitionInput(input);
|
|
479
|
+
const registry = getRegistry();
|
|
480
|
+
const existing = registry.get(definition.key);
|
|
481
|
+
if (existing) {
|
|
482
|
+
if (stableStringify(existing) !== stableStringify(definition)) throw new Error(`Prompt "${definition.key}" is already registered with a different definition`);
|
|
483
|
+
return existing;
|
|
484
|
+
}
|
|
485
|
+
registry.set(definition.key, definition);
|
|
486
|
+
return definition;
|
|
487
|
+
},
|
|
488
|
+
get(key) {
|
|
489
|
+
return getRegistry().get(key);
|
|
490
|
+
},
|
|
491
|
+
has(key) {
|
|
492
|
+
return getRegistry().has(key);
|
|
493
|
+
},
|
|
494
|
+
getAll() {
|
|
495
|
+
return Array.from(getRegistry().values());
|
|
496
|
+
},
|
|
497
|
+
clear() {
|
|
498
|
+
getRegistry().clear();
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
function definePrompt(input) {
|
|
502
|
+
return PromptRegistry.register(input);
|
|
503
|
+
}
|
|
504
|
+
var __defProp = Object.defineProperty;
|
|
505
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
506
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
507
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
508
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
509
|
+
if (kind && result) __defProp(target, key, result);
|
|
510
|
+
return result;
|
|
511
|
+
};
|
|
512
|
+
function getPromptConfig$1() {
|
|
513
|
+
return getPackageConfig("prompts", {
|
|
514
|
+
profiles: {},
|
|
515
|
+
prompts: {}
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
var PromptOverride = class extends SmrtObject {
|
|
519
|
+
key = "";
|
|
520
|
+
tenantId = null;
|
|
521
|
+
template = null;
|
|
522
|
+
profile = null;
|
|
523
|
+
model = null;
|
|
524
|
+
params = null;
|
|
525
|
+
constructor(options = {}) {
|
|
526
|
+
super(options);
|
|
527
|
+
if (options.key !== void 0) this.key = options.key;
|
|
528
|
+
if (options.tenantId !== void 0) this.tenantId = options.tenantId;
|
|
529
|
+
if (options.template !== void 0) this.template = options.template;
|
|
530
|
+
if (options.profile !== void 0) this.profile = options.profile;
|
|
531
|
+
if (options.model !== void 0) this.model = options.model;
|
|
532
|
+
if (options.params !== void 0) if (typeof options.params === "string" || options.params === null) this.params = options.params;
|
|
533
|
+
else this.params = serializePromptParams(options.params);
|
|
534
|
+
}
|
|
535
|
+
getParams() {
|
|
536
|
+
return parsePromptParams(this.params);
|
|
537
|
+
}
|
|
538
|
+
setParams(params) {
|
|
539
|
+
this.params = serializePromptParams(params);
|
|
540
|
+
}
|
|
541
|
+
toPromptLayer() {
|
|
542
|
+
return {
|
|
543
|
+
template: this.template,
|
|
544
|
+
profile: this.profile,
|
|
545
|
+
model: this.model,
|
|
546
|
+
params: this.params === null ? null : this.getParams()
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
async save() {
|
|
550
|
+
const previousIdentity = await this.getPersistedIdentity();
|
|
551
|
+
this.normalizeParamsForPersistence();
|
|
552
|
+
await this.validatePromptOverride();
|
|
553
|
+
this.context = this.tenantId ?? "__app__";
|
|
554
|
+
const identityChanged = previousIdentity && (previousIdentity.key !== this.key || previousIdentity.tenantId !== this.tenantId);
|
|
555
|
+
const result = identityChanged && previousIdentity ? await this.saveAfterIdentityChange() : await super.save();
|
|
556
|
+
if (identityChanged && previousIdentity) invalidatePromptCache(previousIdentity.key, previousIdentity.tenantId, this.db);
|
|
557
|
+
invalidatePromptCache(this.key, this.tenantId, this.db);
|
|
558
|
+
return result;
|
|
559
|
+
}
|
|
560
|
+
async saveAfterIdentityChange() {
|
|
561
|
+
if (typeof this.db.beginTransaction === "function") return this.saveAfterIdentityChangeInTransaction();
|
|
562
|
+
return this.saveAfterIdentityChangeWithDeferredDelete();
|
|
563
|
+
}
|
|
564
|
+
async saveAfterIdentityChangeInTransaction() {
|
|
565
|
+
const originalDb = this._db;
|
|
566
|
+
const originalOptionsDb = this.options.db;
|
|
567
|
+
const tx = await this.db.beginTransaction?.();
|
|
568
|
+
if (!tx) return this.saveAfterIdentityChangeWithDeferredDelete();
|
|
569
|
+
try {
|
|
570
|
+
this._db = tx;
|
|
571
|
+
this.options.db = tx;
|
|
572
|
+
await super.delete();
|
|
573
|
+
const result = await super.save();
|
|
574
|
+
await tx.commit();
|
|
575
|
+
return result;
|
|
576
|
+
} catch (error) {
|
|
577
|
+
try {
|
|
578
|
+
await tx.rollback();
|
|
579
|
+
} catch {}
|
|
580
|
+
throw error;
|
|
581
|
+
} finally {
|
|
582
|
+
this._db = originalDb;
|
|
583
|
+
this.options.db = originalOptionsDb;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
async saveAfterIdentityChangeWithDeferredDelete() {
|
|
587
|
+
const previousId = this.id;
|
|
588
|
+
if (!previousId) return super.save();
|
|
589
|
+
const replacementId = crypto.randomUUID();
|
|
590
|
+
let replacementSaved = false;
|
|
591
|
+
this.id = replacementId;
|
|
592
|
+
try {
|
|
593
|
+
const result = await super.save();
|
|
594
|
+
replacementSaved = true;
|
|
595
|
+
await this.db.delete(this.tableName, { id: previousId });
|
|
596
|
+
return result;
|
|
597
|
+
} catch (error) {
|
|
598
|
+
if (replacementSaved) try {
|
|
599
|
+
await this.db.delete(this.tableName, { id: replacementId });
|
|
600
|
+
} catch {}
|
|
601
|
+
this.id = previousId;
|
|
602
|
+
throw error;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
async delete() {
|
|
606
|
+
const key = this.key;
|
|
607
|
+
const tenantId = this.tenantId;
|
|
608
|
+
await super.delete();
|
|
609
|
+
invalidatePromptCache(key, tenantId, this.db);
|
|
610
|
+
}
|
|
611
|
+
async validatePromptOverride() {
|
|
612
|
+
if (!this.key || this.key.trim() === "") throw new Error("PromptOverride.key is required");
|
|
613
|
+
const definition = PromptRegistry.get(this.key);
|
|
614
|
+
if (!definition) throw new Error(`Unknown prompt key "${this.key}"`);
|
|
615
|
+
const config = getPromptConfig$1();
|
|
616
|
+
const editable = definition.editable;
|
|
617
|
+
if (this.template !== null && !editable.template) throw new Error(`Prompt "${this.key}" does not allow template overrides`);
|
|
618
|
+
if (this.profile !== null && !editable.profile) throw new Error(`Prompt "${this.key}" does not allow profile overrides`);
|
|
619
|
+
if (this.model !== null && !editable.model) throw new Error(`Prompt "${this.key}" does not allow model overrides`);
|
|
620
|
+
if (this.params !== null && !editable.params) throw new Error(`Prompt "${this.key}" does not allow params overrides`);
|
|
621
|
+
if (this.params !== null) try {
|
|
622
|
+
const parsed = JSON.parse(this.params);
|
|
623
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("Prompt params must be a JSON object");
|
|
624
|
+
} catch (error) {
|
|
625
|
+
throw new Error(`Prompt "${this.key}" has invalid params JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
626
|
+
}
|
|
627
|
+
if (this.profile !== null) validateProfileName(this.profile, config);
|
|
628
|
+
if (this.model !== null) validateModelName(this.model, config);
|
|
629
|
+
const lowerLayers = await this.getLowerPrecedenceLayers();
|
|
630
|
+
const currentLayer = this.toPromptLayer();
|
|
631
|
+
const merged = mergePromptLayers(...lowerLayers, currentLayer);
|
|
632
|
+
if (currentLayer.model && !merged.ai.profile) throw new Error(`Prompt "${this.key}" model overrides require an effective prompt profile`);
|
|
633
|
+
}
|
|
634
|
+
async getLowerPrecedenceLayers() {
|
|
635
|
+
const definition = PromptRegistry.get(this.key);
|
|
636
|
+
const config = getPromptConfig$1();
|
|
637
|
+
const layers = [];
|
|
638
|
+
if (definition) layers.push({
|
|
639
|
+
template: definition.template,
|
|
640
|
+
profile: definition.ai.profile ?? null,
|
|
641
|
+
model: definition.ai.model ?? null,
|
|
642
|
+
params: definition.ai.params
|
|
643
|
+
});
|
|
644
|
+
layers.push(normalizePromptLayer(config.prompts?.[this.key]));
|
|
645
|
+
const { PromptOverrideCollection } = await Promise.resolve().then(() => PromptOverrideCollection_exports);
|
|
646
|
+
const collection = await PromptOverrideCollection.create({ db: this.options.db ?? this.options.persistence });
|
|
647
|
+
if (this.tenantId) {
|
|
648
|
+
const appOverride = await collection.getAppOverride(this.key, { excludeId: this.id ?? void 0 });
|
|
649
|
+
if (appOverride) layers.push(appOverride.toPromptLayer());
|
|
650
|
+
}
|
|
651
|
+
return layers;
|
|
652
|
+
}
|
|
653
|
+
normalizeParamsForPersistence() {
|
|
654
|
+
const rawParams = this.params;
|
|
655
|
+
if (rawParams === null || rawParams === void 0) {
|
|
656
|
+
this.params = null;
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
if (typeof rawParams === "string") {
|
|
660
|
+
this.params = rawParams;
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
if (typeof rawParams === "object" && !Array.isArray(rawParams)) {
|
|
664
|
+
this.params = serializePromptParams(rawParams);
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
throw new Error(`Prompt "${this.key}" params must be a JSON object or JSON string`);
|
|
668
|
+
}
|
|
669
|
+
async getPersistedIdentity() {
|
|
670
|
+
if (!this.id) return null;
|
|
671
|
+
const existing = await this.db.get(this.tableName, { id: this.id });
|
|
672
|
+
if (!existing) return null;
|
|
673
|
+
return {
|
|
674
|
+
key: String(existing.key ?? this.key),
|
|
675
|
+
tenantId: existing.tenantId !== void 0 ? existing.tenantId : existing.tenant_id ?? null
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
__decorateClass([field({ required: true })], PromptOverride.prototype, "key", 2);
|
|
680
|
+
__decorateClass([field({
|
|
681
|
+
type: "text",
|
|
682
|
+
nullable: true
|
|
683
|
+
})], PromptOverride.prototype, "tenantId", 2);
|
|
684
|
+
__decorateClass([field({
|
|
685
|
+
type: "text",
|
|
686
|
+
nullable: true
|
|
687
|
+
})], PromptOverride.prototype, "template", 2);
|
|
688
|
+
__decorateClass([field({
|
|
689
|
+
type: "text",
|
|
690
|
+
nullable: true
|
|
691
|
+
})], PromptOverride.prototype, "profile", 2);
|
|
692
|
+
__decorateClass([field({
|
|
693
|
+
type: "text",
|
|
694
|
+
nullable: true
|
|
695
|
+
})], PromptOverride.prototype, "model", 2);
|
|
696
|
+
__decorateClass([field({
|
|
697
|
+
type: "text",
|
|
698
|
+
nullable: true
|
|
699
|
+
})], PromptOverride.prototype, "params", 2);
|
|
700
|
+
PromptOverride = __decorateClass([smrt({
|
|
701
|
+
tableName: "_smrt_prompt_overrides",
|
|
702
|
+
conflictColumns: ["key", "context"],
|
|
703
|
+
api: { include: [
|
|
704
|
+
"list",
|
|
705
|
+
"get",
|
|
706
|
+
"create",
|
|
707
|
+
"update",
|
|
708
|
+
"delete"
|
|
709
|
+
] },
|
|
710
|
+
cli: {
|
|
711
|
+
include: [
|
|
712
|
+
"list",
|
|
713
|
+
"get",
|
|
714
|
+
"create",
|
|
715
|
+
"update",
|
|
716
|
+
"delete"
|
|
717
|
+
],
|
|
718
|
+
exclude: [
|
|
719
|
+
"getParams",
|
|
720
|
+
"setParams",
|
|
721
|
+
"toPromptLayer"
|
|
722
|
+
]
|
|
723
|
+
},
|
|
724
|
+
mcp: { include: [] }
|
|
725
|
+
})], PromptOverride);
|
|
726
|
+
var PromptOverrideCollection_exports = /* @__PURE__ */ __exportAll({ PromptOverrideCollection: () => PromptOverrideCollection });
|
|
727
|
+
var PromptOverrideCollection = class extends SmrtCollection {
|
|
728
|
+
static _itemClass = PromptOverride;
|
|
729
|
+
excludeOverrideId(items, excludeId) {
|
|
730
|
+
return items.filter((item) => excludeId ? item.id !== excludeId : true);
|
|
731
|
+
}
|
|
732
|
+
async getAppOverride(key, options = {}) {
|
|
733
|
+
const items = await this.list({ where: {
|
|
734
|
+
key,
|
|
735
|
+
tenantId: null
|
|
736
|
+
} });
|
|
737
|
+
return this.excludeOverrideId(items, options.excludeId)[0] ?? null;
|
|
738
|
+
}
|
|
739
|
+
async getTenantOverride(key, tenantId, options = {}) {
|
|
740
|
+
const items = await this.list({ where: {
|
|
741
|
+
key,
|
|
742
|
+
tenantId
|
|
743
|
+
} });
|
|
744
|
+
return this.excludeOverrideId(items, options.excludeId)[0] ?? null;
|
|
745
|
+
}
|
|
746
|
+
async getResolutionLayers(key, tenantId, options = {}) {
|
|
747
|
+
const [app, tenant] = await Promise.all([this.getAppOverride(key, options), tenantId != null ? this.getTenantOverride(key, tenantId, options) : Promise.resolve(null)]);
|
|
748
|
+
return {
|
|
749
|
+
app,
|
|
750
|
+
tenant
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
};
|
|
754
|
+
function getPromptConfig() {
|
|
755
|
+
return getPackageConfig("prompts", {
|
|
756
|
+
profiles: {},
|
|
757
|
+
prompts: {}
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
async function loadPromptBase(key, options) {
|
|
761
|
+
const definition = PromptRegistry.get(key);
|
|
762
|
+
if (!definition) throw new Error(`Unknown prompt key "${key}"`);
|
|
763
|
+
const tenantId = options.tenantId !== void 0 ? options.tenantId : getTenantId() ?? null;
|
|
764
|
+
let collection = null;
|
|
765
|
+
let cacheDb = options.db;
|
|
766
|
+
if (options.db) {
|
|
767
|
+
const initializedCollection = await PromptOverrideCollection.create({ db: options.db });
|
|
768
|
+
collection = initializedCollection;
|
|
769
|
+
cacheDb = initializedCollection.db;
|
|
770
|
+
}
|
|
771
|
+
const cached = getCachedPromptBase(key, tenantId, cacheDb);
|
|
772
|
+
if (cached) return cached;
|
|
773
|
+
const loadedAtGeneration = getPromptCacheGeneration(key, cacheDb);
|
|
774
|
+
const config = getPromptConfig();
|
|
775
|
+
const layers = [{
|
|
776
|
+
template: definition.template,
|
|
777
|
+
profile: definition.ai.profile ?? null,
|
|
778
|
+
model: definition.ai.model ?? null,
|
|
779
|
+
params: definition.ai.params
|
|
780
|
+
}, normalizePromptLayer(config.prompts?.[key])];
|
|
781
|
+
if (collection) {
|
|
782
|
+
const stored = await collection.getResolutionLayers(key, tenantId);
|
|
783
|
+
if (stored.app) layers.push(stored.app.toPromptLayer());
|
|
784
|
+
if (stored.tenant) layers.push(stored.tenant.toPromptLayer());
|
|
785
|
+
}
|
|
786
|
+
const merged = mergePromptLayers(...layers);
|
|
787
|
+
const value = {
|
|
788
|
+
key,
|
|
789
|
+
template: merged.template,
|
|
790
|
+
ai: merged.ai
|
|
791
|
+
};
|
|
792
|
+
setCachedPromptBase(key, tenantId, cacheDb, value, loadedAtGeneration);
|
|
793
|
+
return value;
|
|
794
|
+
}
|
|
795
|
+
async function resolvePrompt(key, options = {}) {
|
|
796
|
+
const config = getPromptConfig();
|
|
797
|
+
const base = await loadPromptBase(key, options);
|
|
798
|
+
const runtimeOverride = normalizePromptLayer(options.override);
|
|
799
|
+
const merged = mergePromptLayers({
|
|
800
|
+
template: base.template,
|
|
801
|
+
profile: base.ai.profile ?? null,
|
|
802
|
+
model: base.ai.model ?? null,
|
|
803
|
+
params: base.ai.params
|
|
804
|
+
}, runtimeOverride);
|
|
805
|
+
return {
|
|
806
|
+
key,
|
|
807
|
+
template: merged.template,
|
|
808
|
+
text: renderPromptTemplate(merged.template, options.variables),
|
|
809
|
+
ai: buildResolvedAI(merged.ai, config)
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
//#endregion
|
|
813
|
+
export { queryGlobal as a, withSystemContext as c, tenantId as i, resolvePrompt as n, queryWithGlobals as o, TenantScoped as r, isSystemContext as s, definePrompt as t };
|