@okf/ootils 1.41.2 → 1.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/node.d.mts +6559 -1
- package/dist/node.d.ts +6559 -1
- package/dist/node.js +871 -19
- package/dist/node.mjs +861 -19
- package/package.json +2 -1
package/dist/node.mjs
CHANGED
|
@@ -940,7 +940,7 @@ var init_Tpl = __esm({
|
|
|
940
940
|
var require_MongoConnector = __commonJS({
|
|
941
941
|
"src/db/MongoConnector.js"(exports, module) {
|
|
942
942
|
"use strict";
|
|
943
|
-
var
|
|
943
|
+
var mongoose10 = __require("mongoose");
|
|
944
944
|
var { ServerApiVersion } = __require("mongodb");
|
|
945
945
|
var AnnotationsSchema = (init_Annotations(), __toCommonJS(Annotations_exports));
|
|
946
946
|
var PlatformConfigsSchema2 = (init_PlatformConfigs(), __toCommonJS(PlatformConfigs_exports));
|
|
@@ -1004,7 +1004,7 @@ var require_MongoConnector = __commonJS({
|
|
|
1004
1004
|
`Missing CLUSTER_NAME or CLUSTER_URI in cluster conf: ${JSON.stringify(clusterConf)}`
|
|
1005
1005
|
);
|
|
1006
1006
|
}
|
|
1007
|
-
this.clusterConnections[CLUSTER_NAME] =
|
|
1007
|
+
this.clusterConnections[CLUSTER_NAME] = mongoose10.createConnection(
|
|
1008
1008
|
CLUSTER_URI,
|
|
1009
1009
|
this.mongoOptions
|
|
1010
1010
|
);
|
|
@@ -1031,7 +1031,7 @@ var require_MongoConnector = __commonJS({
|
|
|
1031
1031
|
this.skippedClusters.add(CLUSTER_NAME);
|
|
1032
1032
|
return;
|
|
1033
1033
|
}
|
|
1034
|
-
const connection =
|
|
1034
|
+
const connection = mongoose10.createConnection(CLUSTER_URI, this.mongoOptions);
|
|
1035
1035
|
this.clusterConnections[CLUSTER_NAME] = connection;
|
|
1036
1036
|
this.initiateConnectionEventListeners(CLUSTER_NAME);
|
|
1037
1037
|
await new Promise((resolve, reject) => {
|
|
@@ -1496,7 +1496,7 @@ var require_getModelByTenant = __commonJS({
|
|
|
1496
1496
|
"use strict";
|
|
1497
1497
|
var { getDbByTenant: getDbByTenant2 } = (init_getDbByTenant(), __toCommonJS(getDbByTenant_exports));
|
|
1498
1498
|
var { AIChatSchema: AIChatSchema2, AnnotationSchema: AnnotationSchema2, PlatformConfigsSchema: PlatformConfigsSchema2, TplSchema: TplSchema2, GeneratedTopicsSchema: GeneratedTopicsSchema2, GeneratedEntitiesSchema: GeneratedEntitiesSchema2 } = (init_models(), __toCommonJS(models_exports));
|
|
1499
|
-
var
|
|
1499
|
+
var getModelByTenant4 = ({ tenant, modelName, schema, env }) => {
|
|
1500
1500
|
if (!tenant) {
|
|
1501
1501
|
throw new Error("tenant id has not been provided");
|
|
1502
1502
|
}
|
|
@@ -1506,48 +1506,48 @@ var require_getModelByTenant = __commonJS({
|
|
|
1506
1506
|
}
|
|
1507
1507
|
return db.model(modelName);
|
|
1508
1508
|
};
|
|
1509
|
-
var getAnnotationsModelByTenant2 = ({ tenant, env, mongodb, modelName }) =>
|
|
1509
|
+
var getAnnotationsModelByTenant2 = ({ tenant, env, mongodb, modelName }) => getModelByTenant4({
|
|
1510
1510
|
tenant,
|
|
1511
1511
|
modelName: modelName || "annotations",
|
|
1512
1512
|
schema: AnnotationSchema2,
|
|
1513
1513
|
env
|
|
1514
1514
|
});
|
|
1515
|
-
var getPlatformConfigsModelByTenant2 = ({ tenant, env, mongodb }) =>
|
|
1515
|
+
var getPlatformConfigsModelByTenant2 = ({ tenant, env, mongodb }) => getModelByTenant4({
|
|
1516
1516
|
tenant,
|
|
1517
1517
|
modelName: "platformConfigs",
|
|
1518
1518
|
schema: PlatformConfigsSchema2,
|
|
1519
1519
|
env
|
|
1520
1520
|
});
|
|
1521
|
-
var
|
|
1521
|
+
var getTplModelByTenant3 = ({ tenant, env, mongodb }) => getModelByTenant4({
|
|
1522
1522
|
tenant,
|
|
1523
1523
|
modelName: "tpl",
|
|
1524
1524
|
schema: TplSchema2,
|
|
1525
1525
|
env
|
|
1526
1526
|
});
|
|
1527
|
-
var getAIChatModelByTenant2 = ({ tenant, env, mongodb }) =>
|
|
1527
|
+
var getAIChatModelByTenant2 = ({ tenant, env, mongodb }) => getModelByTenant4({
|
|
1528
1528
|
tenant,
|
|
1529
1529
|
modelName: "aiChat",
|
|
1530
1530
|
schema: AIChatSchema2,
|
|
1531
1531
|
env
|
|
1532
1532
|
});
|
|
1533
|
-
var getGeneratedTopicsModelByTenant2 = ({ tenant, env }) =>
|
|
1533
|
+
var getGeneratedTopicsModelByTenant2 = ({ tenant, env }) => getModelByTenant4({
|
|
1534
1534
|
tenant,
|
|
1535
1535
|
modelName: "generatedTopics",
|
|
1536
1536
|
schema: GeneratedTopicsSchema2,
|
|
1537
1537
|
env
|
|
1538
1538
|
});
|
|
1539
|
-
var getGeneratedEntitiesModelByTenant2 = ({ tenant, env }) =>
|
|
1539
|
+
var getGeneratedEntitiesModelByTenant2 = ({ tenant, env }) => getModelByTenant4({
|
|
1540
1540
|
tenant,
|
|
1541
1541
|
modelName: "generatedEntities",
|
|
1542
1542
|
schema: GeneratedEntitiesSchema2,
|
|
1543
1543
|
env
|
|
1544
1544
|
});
|
|
1545
1545
|
module.exports = {
|
|
1546
|
-
getModelByTenant:
|
|
1546
|
+
getModelByTenant: getModelByTenant4,
|
|
1547
1547
|
getAIChatModelByTenant: getAIChatModelByTenant2,
|
|
1548
1548
|
getAnnotationsModelByTenant: getAnnotationsModelByTenant2,
|
|
1549
1549
|
getPlatformConfigsModelByTenant: getPlatformConfigsModelByTenant2,
|
|
1550
|
-
getTplModelByTenant:
|
|
1550
|
+
getTplModelByTenant: getTplModelByTenant3,
|
|
1551
1551
|
getGeneratedTopicsModelByTenant: getGeneratedTopicsModelByTenant2,
|
|
1552
1552
|
getGeneratedEntitiesModelByTenant: getGeneratedEntitiesModelByTenant2
|
|
1553
1553
|
};
|
|
@@ -2285,6 +2285,91 @@ var require_AnnosElasticSyncProducer = __commonJS({
|
|
|
2285
2285
|
}
|
|
2286
2286
|
});
|
|
2287
2287
|
|
|
2288
|
+
// src/bullmq/ContentElasticSyncProducer.js
|
|
2289
|
+
var require_ContentElasticSyncProducer = __commonJS({
|
|
2290
|
+
"src/bullmq/ContentElasticSyncProducer.js"(exports, module) {
|
|
2291
|
+
"use strict";
|
|
2292
|
+
var { BaseProducer: BaseProducer2 } = require_BaseProducer();
|
|
2293
|
+
var { GET_GLOBAL_BULLMQ_CONFIG: GET_GLOBAL_BULLMQ_CONFIG2 } = require_GET_GLOBAL_BULLMQ_CONFIG();
|
|
2294
|
+
var { SecretManagerConnector: SecretManagerConnector2 } = (init_SecretManagerConnector(), __toCommonJS(SecretManagerConnector_exports));
|
|
2295
|
+
var ContentElasticSyncProducer2 = class _ContentElasticSyncProducer extends BaseProducer2 {
|
|
2296
|
+
// Preserve class name through minification for ProducerManager lookup
|
|
2297
|
+
static get name() {
|
|
2298
|
+
return "ContentElasticSyncProducer";
|
|
2299
|
+
}
|
|
2300
|
+
// env is OPTIONAL — cross-env routing: jobs land in the target env's Redis
|
|
2301
|
+
// so that env's deployed workers pick them up (see okf-be
|
|
2302
|
+
// CreateChunksProducer for the rationale and the localhost `_local_<user>`
|
|
2303
|
+
// queue-id quirk).
|
|
2304
|
+
constructor(options = {}) {
|
|
2305
|
+
const env = options.env || process.env.ENV;
|
|
2306
|
+
const c = SecretManagerConnector2.getEnvSpecificConfigs(env);
|
|
2307
|
+
const redisCredentials = options.redisCredentials || {
|
|
2308
|
+
REDIS_HOST: c.REDIS_HOST,
|
|
2309
|
+
REDIS_PORT: c.REDIS_PORT,
|
|
2310
|
+
REDIS_PASSWORD: c.REDIS_PASSWORD
|
|
2311
|
+
};
|
|
2312
|
+
const GLOBAL_BULLMQ_CONFIG = GET_GLOBAL_BULLMQ_CONFIG2({
|
|
2313
|
+
env,
|
|
2314
|
+
redisCredentials
|
|
2315
|
+
});
|
|
2316
|
+
super(GLOBAL_BULLMQ_CONFIG.CONTENT_ELASTIC_SYNC_QUEUE);
|
|
2317
|
+
this.env = env;
|
|
2318
|
+
}
|
|
2319
|
+
async addJobs({ documents, tenant, contentType, operationType, sourceMetadata }) {
|
|
2320
|
+
if (!documents || documents.length === 0 || contentType === "staticPages") {
|
|
2321
|
+
return { jobCount: 0, jobIds: [] };
|
|
2322
|
+
}
|
|
2323
|
+
const batchSize = 200;
|
|
2324
|
+
let jobs = [];
|
|
2325
|
+
for (let i = 0; i < documents.length; i += batchSize) {
|
|
2326
|
+
const batch = documents.slice(i, i + batchSize);
|
|
2327
|
+
jobs.push({
|
|
2328
|
+
name: "processContentElasticSync",
|
|
2329
|
+
data: {
|
|
2330
|
+
docIds: batch.map((doc) => doc._id),
|
|
2331
|
+
tenant,
|
|
2332
|
+
env: this.env,
|
|
2333
|
+
contentType,
|
|
2334
|
+
operationType,
|
|
2335
|
+
sourceMetadata: {
|
|
2336
|
+
...sourceMetadata,
|
|
2337
|
+
contentId: batch.map((d) => d._id)
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
});
|
|
2341
|
+
}
|
|
2342
|
+
const addedJobs = await this.addBulkJobs(jobs);
|
|
2343
|
+
const jobIds = addedJobs.map((job) => job.id);
|
|
2344
|
+
console.log(`\u{1F4E6} Added ${addedJobs.length} jobs for ${contentType} contents sync atomically`);
|
|
2345
|
+
return {
|
|
2346
|
+
jobCount: addedJobs.length,
|
|
2347
|
+
jobIds
|
|
2348
|
+
};
|
|
2349
|
+
}
|
|
2350
|
+
static async addJobsAndClose(params) {
|
|
2351
|
+
const producer = new _ContentElasticSyncProducer({ env: params?.env });
|
|
2352
|
+
try {
|
|
2353
|
+
return await producer.addJobs(params);
|
|
2354
|
+
} finally {
|
|
2355
|
+
await producer.stop();
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
static async removeJobsAndClose(jobIds, env) {
|
|
2359
|
+
const producer = new _ContentElasticSyncProducer({ env });
|
|
2360
|
+
try {
|
|
2361
|
+
return await producer.removeJobs(jobIds);
|
|
2362
|
+
} finally {
|
|
2363
|
+
await producer.stop();
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
};
|
|
2367
|
+
module.exports = {
|
|
2368
|
+
ContentElasticSyncProducer: ContentElasticSyncProducer2
|
|
2369
|
+
};
|
|
2370
|
+
}
|
|
2371
|
+
});
|
|
2372
|
+
|
|
2288
2373
|
// src/utils/getterSetterDeleter/utils/set_deleteVal.ts
|
|
2289
2374
|
var set_deleteVal = (action, data, valuePath, value) => {
|
|
2290
2375
|
if (valuePath === void 0) return;
|
|
@@ -4934,7 +5019,751 @@ RedisCacheConnector.instance = null;
|
|
|
4934
5019
|
// src/node.ts
|
|
4935
5020
|
init_SecretManagerConnector();
|
|
4936
5021
|
init_getDbByTenant();
|
|
5022
|
+
var import_getModelByTenant4 = __toESM(require_getModelByTenant());
|
|
5023
|
+
|
|
5024
|
+
// src/contentSchema/genContentTypeSchema.js
|
|
5025
|
+
import mongoose9 from "mongoose";
|
|
5026
|
+
|
|
5027
|
+
// src/contentSchema/components/_backOfficeFields__contr.js
|
|
5028
|
+
import mongoose5 from "mongoose";
|
|
5029
|
+
var _backOfficeFields__contr = (thisContentModelRef) => ({
|
|
5030
|
+
//----- (USUSED AT THE MOMENT) version 2 properties for better tracking & interlinking of document clones ---- //
|
|
5031
|
+
isPrimaryDoc: Boolean,
|
|
5032
|
+
cloneStack: [mongoose5.Schema.Types.ObjectId],
|
|
5033
|
+
// the last item in the array being the last clone
|
|
5034
|
+
ogStack: [mongoose5.Schema.Types.ObjectId],
|
|
5035
|
+
// the last item in the array being the og-est og ( the primaryDoc )
|
|
5036
|
+
//----- END version 2 properties ---- //
|
|
5037
|
+
tagId: String,
|
|
5038
|
+
kp_published_status: {
|
|
5039
|
+
type: String,
|
|
5040
|
+
// options : draft | published | editPublished | awaitingModeration | underModeration
|
|
5041
|
+
default: "draft",
|
|
5042
|
+
required: true
|
|
5043
|
+
},
|
|
5044
|
+
warnings: [Object],
|
|
5045
|
+
kp_og_published_doc: {
|
|
5046
|
+
type: mongoose5.Schema.Types.ObjectId,
|
|
5047
|
+
ref: thisContentModelRef
|
|
5048
|
+
},
|
|
5049
|
+
// ----- mod rel --- //
|
|
5050
|
+
kp_pre_mod_doc: {
|
|
5051
|
+
type: mongoose5.Schema.Types.ObjectId
|
|
5052
|
+
},
|
|
5053
|
+
kp_is_pbl_taken_into_mod: Boolean,
|
|
5054
|
+
kp_is_mod_clone: Boolean,
|
|
5055
|
+
kp_moderator: {
|
|
5056
|
+
type: mongoose5.Schema.Types.ObjectId,
|
|
5057
|
+
ref: "user"
|
|
5058
|
+
},
|
|
5059
|
+
kp_date_mod_begin: Date,
|
|
5060
|
+
kp_date_mod_end: Date,
|
|
5061
|
+
kp_date_submitted: Date,
|
|
5062
|
+
// ----- END mod rel --- //
|
|
5063
|
+
kp_date_created: Date,
|
|
5064
|
+
kp_date_last_saved: Date,
|
|
5065
|
+
kp_date_published: {
|
|
5066
|
+
type: Date
|
|
5067
|
+
},
|
|
5068
|
+
editPublishedDocId: {
|
|
5069
|
+
//only comes on og docs that have an editPbl clone
|
|
5070
|
+
type: mongoose5.Schema.Types.ObjectId,
|
|
5071
|
+
ref: thisContentModelRef
|
|
5072
|
+
},
|
|
5073
|
+
currentEditor: {
|
|
5074
|
+
type: mongoose5.Schema.Types.ObjectId,
|
|
5075
|
+
//relevant for segments : staticPages & collection, where author dont matter.
|
|
5076
|
+
ref: "user"
|
|
5077
|
+
},
|
|
5078
|
+
lastActivity: {
|
|
5079
|
+
date: {
|
|
5080
|
+
type: Date
|
|
5081
|
+
}
|
|
5082
|
+
}
|
|
5083
|
+
});
|
|
5084
|
+
|
|
5085
|
+
// src/contentSchema/components/_comments__contr.js
|
|
5086
|
+
import mongoose6 from "mongoose";
|
|
5087
|
+
var baseCommentsObj = {
|
|
5088
|
+
user: {
|
|
5089
|
+
userId: { type: mongoose6.Schema.Types.ObjectId, ref: "user" },
|
|
5090
|
+
profileType: String,
|
|
5091
|
+
name: String,
|
|
5092
|
+
avatar: Object
|
|
5093
|
+
},
|
|
5094
|
+
text: Object,
|
|
5095
|
+
dateCreated: Date,
|
|
5096
|
+
dateModified: [Date]
|
|
5097
|
+
//the start of tracking mod dates on things..experiment...
|
|
5098
|
+
};
|
|
5099
|
+
var _comments__contr = {
|
|
5100
|
+
comments: [
|
|
5101
|
+
{
|
|
5102
|
+
...baseCommentsObj,
|
|
5103
|
+
responses: [baseCommentsObj]
|
|
5104
|
+
}
|
|
5105
|
+
]
|
|
5106
|
+
};
|
|
5107
|
+
|
|
5108
|
+
// src/contentSchema/components/_reaction_contr.js
|
|
5109
|
+
import mongoose7 from "mongoose";
|
|
5110
|
+
var baseSchema = {
|
|
5111
|
+
type: {
|
|
5112
|
+
type: String,
|
|
5113
|
+
enum: ["like", "celebrate", "inspiring", "learnings"]
|
|
5114
|
+
},
|
|
5115
|
+
dateCreated: Date,
|
|
5116
|
+
userId: { type: mongoose7.Schema.Types.ObjectId, ref: "user" }
|
|
5117
|
+
};
|
|
5118
|
+
var _reaction_contr = {
|
|
5119
|
+
reactions: [
|
|
5120
|
+
{
|
|
5121
|
+
...baseSchema
|
|
5122
|
+
}
|
|
5123
|
+
]
|
|
5124
|
+
};
|
|
5125
|
+
|
|
5126
|
+
// src/contentSchema/components/_constantMeta__contr.js
|
|
5127
|
+
import mongoose8 from "mongoose";
|
|
5128
|
+
var _constantMeta__contr = {
|
|
5129
|
+
kp_contributed_by: {
|
|
5130
|
+
type: mongoose8.Schema.Types.ObjectId,
|
|
5131
|
+
ref: "user",
|
|
5132
|
+
required: true
|
|
5133
|
+
},
|
|
5134
|
+
kp_content_type: {
|
|
5135
|
+
type: String,
|
|
5136
|
+
required: true
|
|
5137
|
+
},
|
|
5138
|
+
// "thematic" or "attribute" — distinguishes thematic sub-themes/tags from
|
|
5139
|
+
// attribute classification categories (speech act, emotion, etc.).
|
|
5140
|
+
taxonomyRole: {
|
|
5141
|
+
type: String
|
|
5142
|
+
},
|
|
5143
|
+
// Only meaningful on sub-theme docs. When false, new tags cannot be created under
|
|
5144
|
+
// this sub-theme (by humans via API or by the inductive AI annotator).
|
|
5145
|
+
// Absent/true = allowed (default).
|
|
5146
|
+
allowNewTags: {
|
|
5147
|
+
type: Boolean
|
|
5148
|
+
},
|
|
5149
|
+
// Only meaningful on attribute-role sub-themes. "single" = pick one tag,
|
|
5150
|
+
// "multi" = pick one or more. Default "multi".
|
|
5151
|
+
selectMode: {
|
|
5152
|
+
type: String
|
|
5153
|
+
},
|
|
5154
|
+
// "autoAI" | "humanInTheLoop" — absent means human editor (default).
|
|
5155
|
+
createdVia: {
|
|
5156
|
+
type: String
|
|
5157
|
+
}
|
|
5158
|
+
};
|
|
5159
|
+
|
|
5160
|
+
// src/contentSchema/components/_fixedMainFields__contr.js
|
|
5161
|
+
var _fixedMainFields__contr = {
|
|
5162
|
+
/**
|
|
5163
|
+
* hard coding title & subtitle is required because,
|
|
5164
|
+
* in tpl categories like 'researchNotes' the title comp is never defined in the template.
|
|
5165
|
+
* instead, it is hardcoded in the code, and it expects a 'main.title' value path.
|
|
5166
|
+
* Hence the hardcode below. Besides its not a problem, since, if in the template a
|
|
5167
|
+
* main.title component is indeed defined, then these hardcodes would be overwritten by
|
|
5168
|
+
* mainExtract. Which is what we want.
|
|
5169
|
+
*/
|
|
5170
|
+
title: {
|
|
5171
|
+
type: String,
|
|
5172
|
+
cast: (v) => typeof v === "string" ? String(v) : Object(v)
|
|
5173
|
+
},
|
|
5174
|
+
subtitle: {
|
|
5175
|
+
type: String,
|
|
5176
|
+
cast: (v) => typeof v === "string" ? String(v) : Object(v)
|
|
5177
|
+
},
|
|
5178
|
+
titleInfo: String
|
|
5179
|
+
// this is used to show the meta text ("This story is supported by AI-assisted bot") on the published page
|
|
5180
|
+
};
|
|
5181
|
+
|
|
5182
|
+
// src/contentSchema/extractAllUniqueAnnoTagTypesFromTpl.js
|
|
5183
|
+
var extractAllUniqueAnnoTagTypesFromTpl = (extractedBlocks, { smTagTypesConfig } = {}) => {
|
|
5184
|
+
return Array.from(
|
|
5185
|
+
new Set(
|
|
5186
|
+
blockRegistry.getAnnotationEnabledBlocks(extractedBlocks).flatMap((bl) => [
|
|
5187
|
+
...blockRegistry.getTagTypesConfig(bl, smTagTypesConfig).map((tt) => tt.tagType),
|
|
5188
|
+
...bl.props?.annotation?.toggleTagTypesConfig?.map((tt) => tt.tagType) || []
|
|
5189
|
+
])
|
|
5190
|
+
)
|
|
5191
|
+
);
|
|
5192
|
+
};
|
|
5193
|
+
|
|
5194
|
+
// src/contentSchema/getTypesForSchemaFromTpl/compToTypeMap/getConditionalDataType.js
|
|
5195
|
+
var getConditionalDataType = ({ block }) => {
|
|
5196
|
+
if (block.props?.saveValueAsString)
|
|
5197
|
+
return {
|
|
5198
|
+
type: Number,
|
|
5199
|
+
cast: (v) => {
|
|
5200
|
+
if (typeof v === "number" && !isNaN(v)) {
|
|
5201
|
+
return Number(v);
|
|
5202
|
+
} else if (typeof v === "string") {
|
|
5203
|
+
return String(v);
|
|
5204
|
+
} else {
|
|
5205
|
+
return Boolean(v);
|
|
5206
|
+
}
|
|
5207
|
+
}
|
|
5208
|
+
};
|
|
5209
|
+
else {
|
|
5210
|
+
const returnValue = ["DropdownMulti", "CheckboxList"].includes(block.comp) ? { type: Array } : { type: Object };
|
|
5211
|
+
return returnValue;
|
|
5212
|
+
}
|
|
5213
|
+
};
|
|
5214
|
+
|
|
5215
|
+
// src/contentSchema/utils/extractNumberFromValue.js
|
|
5216
|
+
var extractNumberFromValue = (value) => {
|
|
5217
|
+
if (value === null || value === void 0) return void 0;
|
|
5218
|
+
if (typeof value === "number") return isNaN(value) ? void 0 : value;
|
|
5219
|
+
const str = String(value).trim();
|
|
5220
|
+
if (str === "") return void 0;
|
|
5221
|
+
const directParse = Number(str);
|
|
5222
|
+
if (!isNaN(directParse)) return directParse;
|
|
5223
|
+
const commaNumberMatch = str.match(/-?\d[\d,]*\d(?:\.\d+)?/);
|
|
5224
|
+
if (commaNumberMatch && commaNumberMatch[0].includes(",")) {
|
|
5225
|
+
const num = Number(commaNumberMatch[0].replace(/,/g, ""));
|
|
5226
|
+
if (!isNaN(num)) return num;
|
|
5227
|
+
}
|
|
5228
|
+
const numberMatch = str.match(/-?\d+(?:\.\d+)?/);
|
|
5229
|
+
if (numberMatch) {
|
|
5230
|
+
const num = Number(numberMatch[0]);
|
|
5231
|
+
return isNaN(num) ? void 0 : num;
|
|
5232
|
+
}
|
|
5233
|
+
return void 0;
|
|
5234
|
+
};
|
|
5235
|
+
|
|
5236
|
+
// src/contentSchema/getTypesForSchemaFromTpl/compToTypeMap/index.js
|
|
5237
|
+
var compToTypeMap = ({ block }) => {
|
|
5238
|
+
const comp = block.comp;
|
|
5239
|
+
const blockDef = blockRegistry.getBlock(comp);
|
|
5240
|
+
if (blockDef) return blockDef.mongoSchemaType;
|
|
5241
|
+
switch (comp) {
|
|
5242
|
+
case "SummaryInput":
|
|
5243
|
+
case "KPRichInput":
|
|
5244
|
+
//deprecated
|
|
5245
|
+
case "RichTextEditor":
|
|
5246
|
+
//deprecated
|
|
5247
|
+
case "StaticRichText":
|
|
5248
|
+
case "CardRadioInput":
|
|
5249
|
+
case "NumberRangeInput":
|
|
5250
|
+
case "KPLikeContactChannelsBlock":
|
|
5251
|
+
case "TitleInput":
|
|
5252
|
+
case "SubtitleInput":
|
|
5253
|
+
case "PluginSentinel":
|
|
5254
|
+
case "DynamicRefetchDropdown":
|
|
5255
|
+
case "VideoInput":
|
|
5256
|
+
// data type for videoinput should actually be array, but since the old version of the comp used a string data type, we are currently setting it to object to avoid error
|
|
5257
|
+
case "SimpleTable":
|
|
5258
|
+
case "GroupQuestionsInputSingle":
|
|
5259
|
+
return { type: Object };
|
|
5260
|
+
case "ProfileImageInput":
|
|
5261
|
+
case "ResourceInput":
|
|
5262
|
+
case "ImageInput":
|
|
5263
|
+
case "VideoInput":
|
|
5264
|
+
case "Repeater":
|
|
5265
|
+
case "RepeaterTabs":
|
|
5266
|
+
case "PDFInput":
|
|
5267
|
+
case "TextInputToArray":
|
|
5268
|
+
return { type: Array };
|
|
5269
|
+
case "RichTextAsPlainText":
|
|
5270
|
+
case "PasswordInput":
|
|
5271
|
+
case "EmailInput":
|
|
5272
|
+
case "TextInput":
|
|
5273
|
+
case "URLInput":
|
|
5274
|
+
case "PhoneInput":
|
|
5275
|
+
case "KPMetaPrimary":
|
|
5276
|
+
case "IFrameInput":
|
|
5277
|
+
case "JSONInput":
|
|
5278
|
+
return { type: String };
|
|
5279
|
+
case "NumberInput":
|
|
5280
|
+
return {
|
|
5281
|
+
type: Number,
|
|
5282
|
+
// Smart extraction of numbers from messy values (e.g. "18+", "18 years old", "$100")
|
|
5283
|
+
// Uses extractNumberFromValue utility for consistent behavior with direct import
|
|
5284
|
+
set: extractNumberFromValue
|
|
5285
|
+
};
|
|
5286
|
+
case "DropdownSingleLanguage":
|
|
5287
|
+
case "ComboboxSingleLanguage":
|
|
5288
|
+
return {
|
|
5289
|
+
type: [
|
|
5290
|
+
{
|
|
5291
|
+
display: String,
|
|
5292
|
+
value: String
|
|
5293
|
+
}
|
|
5294
|
+
]
|
|
5295
|
+
};
|
|
5296
|
+
case "DatePicker":
|
|
5297
|
+
return { type: Date };
|
|
5298
|
+
case "DateTimePicker":
|
|
5299
|
+
return { type: Date };
|
|
5300
|
+
case "TimePicker":
|
|
5301
|
+
return {
|
|
5302
|
+
type: String,
|
|
5303
|
+
// Validates time is in 24-hour format (00:00-23:59) with hours 00-23, a colon, and minutes 00-59
|
|
5304
|
+
validate: {
|
|
5305
|
+
validator: function(v) {
|
|
5306
|
+
return /^([01]\d|2[0-3]):([0-5]\d)$/.test(v);
|
|
5307
|
+
},
|
|
5308
|
+
message: (props) => `${props.value} is not a valid time format!`
|
|
5309
|
+
}
|
|
5310
|
+
};
|
|
5311
|
+
case "CheckboxButton":
|
|
5312
|
+
return { type: Boolean };
|
|
5313
|
+
case "TagsInputMulti":
|
|
5314
|
+
case "FragmentsSet":
|
|
5315
|
+
case "FragmentsDict":
|
|
5316
|
+
case "TagsInputSingle":
|
|
5317
|
+
return {
|
|
5318
|
+
type: {
|
|
5319
|
+
collectionId: String,
|
|
5320
|
+
data: [
|
|
5321
|
+
{
|
|
5322
|
+
_id: {
|
|
5323
|
+
type: String,
|
|
5324
|
+
index: block.index === true
|
|
5325
|
+
},
|
|
5326
|
+
display: String,
|
|
5327
|
+
tagId: String
|
|
5328
|
+
}
|
|
5329
|
+
]
|
|
5330
|
+
}
|
|
5331
|
+
};
|
|
5332
|
+
case "SPECIAL_AnnotationTagsField":
|
|
5333
|
+
return {
|
|
5334
|
+
/**
|
|
5335
|
+
* very important that we wrap the whole thing in type,
|
|
5336
|
+
* because, if the tag name itself is type (like in the case of noora),
|
|
5337
|
+
* then it completely confuses mongoose, since type is a reserved word,
|
|
5338
|
+
* and causes all sorts of bugs.
|
|
5339
|
+
*/
|
|
5340
|
+
type: {
|
|
5341
|
+
collectionId: String,
|
|
5342
|
+
data: Array
|
|
5343
|
+
//leaving this weakly typed for now cuz annotations have several other properties in here which i am not aware of..
|
|
5344
|
+
}
|
|
5345
|
+
};
|
|
5346
|
+
case "LinkEmbedWithInput":
|
|
5347
|
+
return {
|
|
5348
|
+
type: {
|
|
5349
|
+
url: String,
|
|
5350
|
+
metadata: Object
|
|
5351
|
+
}
|
|
5352
|
+
};
|
|
5353
|
+
case "CheckboxList":
|
|
5354
|
+
//new
|
|
5355
|
+
case "RadioList":
|
|
5356
|
+
//new
|
|
5357
|
+
case "DropdownSingle":
|
|
5358
|
+
//new
|
|
5359
|
+
case "DropdownMulti":
|
|
5360
|
+
//new
|
|
5361
|
+
case "SwitchDouble":
|
|
5362
|
+
case "SwitchSingle":
|
|
5363
|
+
return getConditionalDataType({ block });
|
|
5364
|
+
case "DateTimeRangePicker":
|
|
5365
|
+
return {
|
|
5366
|
+
type: {
|
|
5367
|
+
date: Date,
|
|
5368
|
+
timeRange: Array
|
|
5369
|
+
}
|
|
5370
|
+
};
|
|
5371
|
+
case "DateRangePicker":
|
|
5372
|
+
return { type: Array };
|
|
5373
|
+
}
|
|
5374
|
+
};
|
|
5375
|
+
|
|
5376
|
+
// src/contentSchema/getTypesForSchemaFromTpl/index.js
|
|
5377
|
+
var getTypesForSchemaFromTpl = (options = {}) => {
|
|
5378
|
+
const { tpl, smTagTypesConfig } = options;
|
|
5379
|
+
const defaultSchemaFieldsByTplLayout = {
|
|
5380
|
+
researchNotes2: {
|
|
5381
|
+
tags: {
|
|
5382
|
+
quotes: {
|
|
5383
|
+
collectionId: String,
|
|
5384
|
+
data: Array
|
|
5385
|
+
},
|
|
5386
|
+
vocabs: {
|
|
5387
|
+
collectionId: String,
|
|
5388
|
+
data: Array
|
|
5389
|
+
}
|
|
5390
|
+
}
|
|
5391
|
+
}
|
|
5392
|
+
};
|
|
5393
|
+
let mainExtract = {};
|
|
5394
|
+
let metaExtract = {};
|
|
5395
|
+
let tagsExtract = {};
|
|
5396
|
+
let rootExtract = {};
|
|
5397
|
+
let annoExtract = {
|
|
5398
|
+
...defaultSchemaFieldsByTplLayout[tpl?.category] || {}
|
|
5399
|
+
};
|
|
5400
|
+
const extractedBlocks = extractAllBlocksFromTpl({ tpl });
|
|
5401
|
+
const annotationTagTypes = extractAllUniqueAnnoTagTypesFromTpl(extractedBlocks, {
|
|
5402
|
+
smTagTypesConfig
|
|
5403
|
+
});
|
|
5404
|
+
annotationTagTypes.forEach((annoTagType) => {
|
|
5405
|
+
const annotationFieldDef = compToTypeMap({
|
|
5406
|
+
block: { comp: "SPECIAL_AnnotationTagsField" }
|
|
5407
|
+
});
|
|
5408
|
+
annoExtract = setVal(annoExtract, `tags.${annoTagType}`, annotationFieldDef);
|
|
5409
|
+
});
|
|
5410
|
+
extractedBlocks.forEach((block) => {
|
|
5411
|
+
const { valuePath } = block;
|
|
5412
|
+
if (!valuePath) return;
|
|
5413
|
+
const pathSegments = valuePath.split(".");
|
|
5414
|
+
const [prefix, ...remainingPath] = pathSegments;
|
|
5415
|
+
const nestedPath = remainingPath.join(".");
|
|
5416
|
+
const fieldDefinition = compToTypeMap({ block });
|
|
5417
|
+
switch (prefix) {
|
|
5418
|
+
case "meta":
|
|
5419
|
+
metaExtract = setVal(
|
|
5420
|
+
metaExtract,
|
|
5421
|
+
nestedPath,
|
|
5422
|
+
// "author.name" (without "meta" prefix)
|
|
5423
|
+
fieldDefinition
|
|
5424
|
+
);
|
|
5425
|
+
break;
|
|
5426
|
+
case "main":
|
|
5427
|
+
mainExtract = setVal(
|
|
5428
|
+
mainExtract,
|
|
5429
|
+
nestedPath,
|
|
5430
|
+
// "content.title" (without "main" prefix)
|
|
5431
|
+
fieldDefinition
|
|
5432
|
+
);
|
|
5433
|
+
break;
|
|
5434
|
+
case "tags":
|
|
5435
|
+
tagsExtract = setVal(
|
|
5436
|
+
tagsExtract,
|
|
5437
|
+
nestedPath,
|
|
5438
|
+
// "categories.primary" (without "tags" prefix)
|
|
5439
|
+
fieldDefinition
|
|
5440
|
+
);
|
|
5441
|
+
break;
|
|
5442
|
+
default:
|
|
5443
|
+
if (block.comp && block.comp !== "TplMetaBlock" && valuePath !== ".") {
|
|
5444
|
+
rootExtract = setVal(
|
|
5445
|
+
rootExtract,
|
|
5446
|
+
valuePath,
|
|
5447
|
+
// Use full path since it's not prefixed
|
|
5448
|
+
fieldDefinition
|
|
5449
|
+
);
|
|
5450
|
+
}
|
|
5451
|
+
break;
|
|
5452
|
+
}
|
|
5453
|
+
});
|
|
5454
|
+
return {
|
|
5455
|
+
metaExtract,
|
|
5456
|
+
mainExtract,
|
|
5457
|
+
tagsExtract,
|
|
5458
|
+
rootExtract,
|
|
5459
|
+
annoExtract
|
|
5460
|
+
};
|
|
5461
|
+
};
|
|
5462
|
+
|
|
5463
|
+
// src/contentSchema/genContentTypeSchema.js
|
|
5464
|
+
var genContentTypeSchema = ({ contentType, segment, contentTypeConfig, smTagTypesConfig }) => {
|
|
5465
|
+
let SchemaToReturn;
|
|
5466
|
+
let {
|
|
5467
|
+
mainExtract = {},
|
|
5468
|
+
metaExtract = {},
|
|
5469
|
+
tagsExtract = {},
|
|
5470
|
+
rootExtract = {},
|
|
5471
|
+
annoExtract = {}
|
|
5472
|
+
} = getTypesForSchemaFromTpl({ tpl: contentTypeConfig, smTagTypesConfig });
|
|
5473
|
+
const schemaDef = {
|
|
5474
|
+
/**
|
|
5475
|
+
* this metadata is v.important from an optimization point of view.
|
|
5476
|
+
* it helps with getAllContrModelsByTenant, without having to
|
|
5477
|
+
* query the database for content type configurations.
|
|
5478
|
+
*/
|
|
5479
|
+
metadata: {
|
|
5480
|
+
isContentType: { type: String, default: true },
|
|
5481
|
+
contentType: { type: String, default: contentType },
|
|
5482
|
+
segment: { type: String, default: segment }
|
|
5483
|
+
},
|
|
5484
|
+
..._backOfficeFields__contr(contentType),
|
|
5485
|
+
...rootExtract,
|
|
5486
|
+
tags: {
|
|
5487
|
+
...tagsExtract
|
|
5488
|
+
},
|
|
5489
|
+
annotations: {
|
|
5490
|
+
...annoExtract
|
|
5491
|
+
},
|
|
5492
|
+
meta: {
|
|
5493
|
+
..._constantMeta__contr,
|
|
5494
|
+
...metaExtract
|
|
5495
|
+
},
|
|
5496
|
+
main: {
|
|
5497
|
+
..._fixedMainFields__contr,
|
|
5498
|
+
...mainExtract
|
|
5499
|
+
},
|
|
5500
|
+
archive: Object,
|
|
5501
|
+
//burial ground for past fields that have eventually been removed from the tpl (and therefore the schema)
|
|
5502
|
+
translations: Object,
|
|
5503
|
+
reviewerNotes: Object,
|
|
5504
|
+
..._reaction_contr,
|
|
5505
|
+
..._comments__contr,
|
|
5506
|
+
...segment === "publishing" && {
|
|
5507
|
+
shares: {
|
|
5508
|
+
count: {
|
|
5509
|
+
type: Number,
|
|
5510
|
+
default: 0
|
|
5511
|
+
}
|
|
5512
|
+
},
|
|
5513
|
+
views: {
|
|
5514
|
+
count: {
|
|
5515
|
+
type: Number,
|
|
5516
|
+
default: 0
|
|
5517
|
+
}
|
|
5518
|
+
}
|
|
5519
|
+
},
|
|
5520
|
+
updates: Object
|
|
5521
|
+
// DEPRECATED. DONT USE IT. DONT DELETE EITHER. ELSE WE WILL HAVE TO MAKE DATA UPDATES
|
|
5522
|
+
};
|
|
5523
|
+
SchemaToReturn = new mongoose9.Schema(schemaDef, {
|
|
5524
|
+
collection: contentType,
|
|
5525
|
+
toJSON: { virtuals: true },
|
|
5526
|
+
// So `res.json()` and other `JSON.stringify()` functions include virtuals
|
|
5527
|
+
toObject: { virtuals: true },
|
|
5528
|
+
// So `toObject()` output includes virtuals
|
|
5529
|
+
strict: "throw"
|
|
5530
|
+
//will throw an error if we try to add properties that arent on this schema
|
|
5531
|
+
});
|
|
5532
|
+
SchemaToReturn.index(
|
|
5533
|
+
{ tagId: 1 },
|
|
5534
|
+
...segment === "collections" ? [
|
|
5535
|
+
{
|
|
5536
|
+
unique: true,
|
|
5537
|
+
partialFilterExpression: {
|
|
5538
|
+
kp_published_status: { $eq: "published" }
|
|
5539
|
+
}
|
|
5540
|
+
}
|
|
5541
|
+
] : []
|
|
5542
|
+
);
|
|
5543
|
+
SchemaToReturn.index({
|
|
5544
|
+
kp_published_status: 1,
|
|
5545
|
+
kp_date_published: -1,
|
|
5546
|
+
_id: -1
|
|
5547
|
+
});
|
|
5548
|
+
SchemaToReturn.index(
|
|
5549
|
+
{ kp_published_status: 1, "main.title": 1, _id: 1 },
|
|
5550
|
+
{ collation: { locale: "en", numericOrdering: true } }
|
|
5551
|
+
);
|
|
5552
|
+
SchemaToReturn.index({ kp_published_status: 1, kp_is_mod_clone: 1 });
|
|
5553
|
+
return SchemaToReturn;
|
|
5554
|
+
};
|
|
5555
|
+
|
|
5556
|
+
// src/TenantRegistry.js
|
|
5557
|
+
import { Storage } from "@google-cloud/storage";
|
|
5558
|
+
var BUCKET_NAME = "dots-system-configs";
|
|
5559
|
+
var FILE_NAME = "tenantRegistry.json";
|
|
5560
|
+
var TenantRegistry = class {
|
|
5561
|
+
// ─── Initialization ─────────────────────────────────
|
|
5562
|
+
/**
|
|
5563
|
+
* Must be awaited at startup before any sync getter is called.
|
|
5564
|
+
* Uses Application Default Credentials (ADC) for GCS auth.
|
|
5565
|
+
*/
|
|
5566
|
+
static async init() {
|
|
5567
|
+
this._data = await this._load();
|
|
5568
|
+
this._rebuildCaches();
|
|
5569
|
+
this._lastRefreshAt = Date.now();
|
|
5570
|
+
}
|
|
5571
|
+
/**
|
|
5572
|
+
* Reload from GCS when this instance sees an unknown tenant/origin — likely one
|
|
5573
|
+
* provisioned on another instance after startup. Rate-limited; on failure keeps
|
|
5574
|
+
* the existing cache (never throws). Returns true if a reload actually ran.
|
|
5575
|
+
*/
|
|
5576
|
+
static async refreshIfStale() {
|
|
5577
|
+
const now = Date.now();
|
|
5578
|
+
if (now - this._lastRefreshAt < this.REFRESH_COOLDOWN_MS) return false;
|
|
5579
|
+
this._lastRefreshAt = now;
|
|
5580
|
+
try {
|
|
5581
|
+
this._data = await this._load();
|
|
5582
|
+
this._rebuildCaches();
|
|
5583
|
+
return true;
|
|
5584
|
+
} catch (err) {
|
|
5585
|
+
console.error(`[TenantRegistry] refresh failed (keeping cache): ${err.message}`);
|
|
5586
|
+
return false;
|
|
5587
|
+
}
|
|
5588
|
+
}
|
|
5589
|
+
// ─── Storage layer (swap only these to change backend) ───
|
|
5590
|
+
static async _load() {
|
|
5591
|
+
const storage = new Storage();
|
|
5592
|
+
const file = storage.bucket(BUCKET_NAME).file(FILE_NAME);
|
|
5593
|
+
const [buffer] = await file.download();
|
|
5594
|
+
const { data } = JSON.parse(buffer.toString("utf-8"));
|
|
5595
|
+
console.log(`[TenantRegistry] Loaded ${data.length} tenants from GCS`);
|
|
5596
|
+
return data;
|
|
5597
|
+
}
|
|
5598
|
+
static async _save() {
|
|
5599
|
+
const storage = new Storage();
|
|
5600
|
+
const file = storage.bucket(BUCKET_NAME).file(FILE_NAME);
|
|
5601
|
+
await file.save(JSON.stringify({ data: this._data }, null, 2), {
|
|
5602
|
+
contentType: "application/json"
|
|
5603
|
+
});
|
|
5604
|
+
}
|
|
5605
|
+
// ─── End storage layer ──────────────────────────────
|
|
5606
|
+
static _rebuildCaches() {
|
|
5607
|
+
this._byEnv = {};
|
|
5608
|
+
this._selfManagedSet = /* @__PURE__ */ new Set();
|
|
5609
|
+
for (const entry of this._data) {
|
|
5610
|
+
const { tenantId, urls, isSelfManaged } = entry;
|
|
5611
|
+
if (isSelfManaged) this._selfManagedSet.add(tenantId);
|
|
5612
|
+
for (const env of ["dev", "staging", "prod"]) {
|
|
5613
|
+
if (!urls[env]) continue;
|
|
5614
|
+
if (!this._byEnv[env]) this._byEnv[env] = {};
|
|
5615
|
+
this._byEnv[env][tenantId] = urls[env];
|
|
5616
|
+
}
|
|
5617
|
+
}
|
|
5618
|
+
}
|
|
5619
|
+
// ─── Sync getters ───────────────────────────────────
|
|
5620
|
+
/** { tenantId: url } for the given env */
|
|
5621
|
+
static getMappingsForEnv(env) {
|
|
5622
|
+
return this._byEnv[env] || {};
|
|
5623
|
+
}
|
|
5624
|
+
/** [url, url, ...] for the given env */
|
|
5625
|
+
static getUrlsForEnv(env) {
|
|
5626
|
+
return Object.values(this._byEnv[env] || {});
|
|
5627
|
+
}
|
|
5628
|
+
/** [tenantId, tenantId, ...] for the given env */
|
|
5629
|
+
static getTenantIdsForEnv(env) {
|
|
5630
|
+
return Object.keys(this._byEnv[env] || {});
|
|
5631
|
+
}
|
|
5632
|
+
/** Single URL for a tenant+env, or undefined */
|
|
5633
|
+
static getUrl(tenant, env) {
|
|
5634
|
+
return (this._byEnv[env] || {})[tenant];
|
|
5635
|
+
}
|
|
5636
|
+
static isSelfManaged(tenant) {
|
|
5637
|
+
return this._selfManagedSet.has(tenant);
|
|
5638
|
+
}
|
|
5639
|
+
static getSelfManagedTenantIds() {
|
|
5640
|
+
return [...this._selfManagedSet];
|
|
5641
|
+
}
|
|
5642
|
+
/** Full registry data array (read-only snapshot) */
|
|
5643
|
+
static getData() {
|
|
5644
|
+
return this._data;
|
|
5645
|
+
}
|
|
5646
|
+
// ─── Mutator ────────────────────────────────────────
|
|
5647
|
+
/**
|
|
5648
|
+
* Idempotent: removes existing entry for tenantId (if any), then adds.
|
|
5649
|
+
* Persists to GCS and updates in-memory caches.
|
|
5650
|
+
*/
|
|
5651
|
+
static async addTenant({ tenantId, urls, isSelfManaged = false }) {
|
|
5652
|
+
this._data = this._data.filter((e) => e.tenantId !== tenantId);
|
|
5653
|
+
this._data.push({ tenantId, urls, isSelfManaged });
|
|
5654
|
+
await this._save();
|
|
5655
|
+
this._rebuildCaches();
|
|
5656
|
+
}
|
|
5657
|
+
/**
|
|
5658
|
+
* Idempotent inverse of addTenant: drops the tenant's entry from the registry,
|
|
5659
|
+
* persists to GCS, and rebuilds in-memory caches (so the tenant stops resolving
|
|
5660
|
+
* on THIS instance immediately). Returns true if an entry was actually removed.
|
|
5661
|
+
* Other running instances pick up the removal via refreshIfStale() on their next
|
|
5662
|
+
* unknown-origin miss.
|
|
5663
|
+
*/
|
|
5664
|
+
static async removeTenant(tenantId) {
|
|
5665
|
+
const before = this._data.length;
|
|
5666
|
+
this._data = this._data.filter((e) => e.tenantId !== tenantId);
|
|
5667
|
+
const removed = this._data.length < before;
|
|
5668
|
+
if (removed) {
|
|
5669
|
+
await this._save();
|
|
5670
|
+
this._rebuildCaches();
|
|
5671
|
+
}
|
|
5672
|
+
return removed;
|
|
5673
|
+
}
|
|
5674
|
+
};
|
|
5675
|
+
// ─── In-memory state ────────────────────────────────
|
|
5676
|
+
__publicField(TenantRegistry, "_data", null);
|
|
5677
|
+
// [{ tenantId, urls: { dev, staging, prod }, isSelfManaged }]
|
|
5678
|
+
__publicField(TenantRegistry, "_byEnv", {});
|
|
5679
|
+
// { dev: { tenantId: url }, staging: {...}, prod: {...} }
|
|
5680
|
+
__publicField(TenantRegistry, "_selfManagedSet", /* @__PURE__ */ new Set());
|
|
5681
|
+
// On-miss refresh rate-limit (see refreshIfStale).
|
|
5682
|
+
__publicField(TenantRegistry, "_lastRefreshAt", 0);
|
|
5683
|
+
__publicField(TenantRegistry, "REFRESH_COOLDOWN_MS", 3e4);
|
|
5684
|
+
|
|
5685
|
+
// src/contentSchema/selfManagedAnnotationTagTypesConfig.js
|
|
5686
|
+
var SM_ANNOTATION_TAG_TYPES_CONFIG = [{ tagType: "tags" }];
|
|
5687
|
+
var getSmTagTypesConfigForTenant = async (tenant) => {
|
|
5688
|
+
return TenantRegistry.isSelfManaged(tenant) ? SM_ANNOTATION_TAG_TYPES_CONFIG : null;
|
|
5689
|
+
};
|
|
5690
|
+
|
|
5691
|
+
// src/db/getContrModelByTenant.js
|
|
5692
|
+
var import_getModelByTenant3 = __toESM(require_getModelByTenant());
|
|
5693
|
+
init_getDbByTenant();
|
|
5694
|
+
|
|
5695
|
+
// src/db/getTpl.js
|
|
4937
5696
|
var import_getModelByTenant2 = __toESM(require_getModelByTenant());
|
|
5697
|
+
var getTpl = async ({ tenant, contentType, env, source = "db" }) => {
|
|
5698
|
+
if (source === "cache") {
|
|
5699
|
+
return RedisCacheConnector.findOneConfigInCache({
|
|
5700
|
+
tenant,
|
|
5701
|
+
modelName: "tpl",
|
|
5702
|
+
type: contentType,
|
|
5703
|
+
env
|
|
5704
|
+
});
|
|
5705
|
+
}
|
|
5706
|
+
return (0, import_getModelByTenant2.getTplModelByTenant)({ tenant, env }).findOne({ kp_content_type: contentType }).lean();
|
|
5707
|
+
};
|
|
5708
|
+
|
|
5709
|
+
// src/db/getContrModelByTenant.js
|
|
5710
|
+
var getContrModelByTenant = async ({
|
|
5711
|
+
tenant,
|
|
5712
|
+
contentType,
|
|
5713
|
+
env = process.env.ENV,
|
|
5714
|
+
// v.imp, else the reuse check below always fails when env isn't passed (env is meant to be optional)
|
|
5715
|
+
tpl,
|
|
5716
|
+
//optional : if passed uses it instead of fetching the tpl for this contenttype from db. important in the case of _createTpl, where, within a transaction we create a tpl and then use this tpl to create some content against it. since this is within a transaction, this newly created tpl wont be available in the db just yet.
|
|
5717
|
+
tplSource = "db",
|
|
5718
|
+
// "db" (okf-be default, original semantics) | "cache" (okf-sub — tpl cache is kept in sync on every tpl write)
|
|
5719
|
+
/**
|
|
5720
|
+
* When true, the registered-model reuse is SKIPPED — the schema is rebuilt
|
|
5721
|
+
* from the current tpl on every call (~5-10ms CPU + the tpl read).
|
|
5722
|
+
*
|
|
5723
|
+
* okf-sub passes this on every collab call: unlike okf-be — which
|
|
5724
|
+
* invalidates registered models on tpl change via
|
|
5725
|
+
* reRegisterModelInLocalCache + the '${env}-tpl-model-recache' Pub/Sub —
|
|
5726
|
+
* okf-sub subscribes to nothing, so a reused model could carry a stale
|
|
5727
|
+
* schema after a tpl edit, and strict:"throw" would reject collab flushes
|
|
5728
|
+
* for newly added fields. Rebuilding every time is correct by
|
|
5729
|
+
* construction: no freshness bookkeeping for tpl write paths (or raw
|
|
5730
|
+
* mongodbscripts that mutate tpls + recache) to ever get wrong.
|
|
5731
|
+
*/
|
|
5732
|
+
rebuild = false
|
|
5733
|
+
}) => {
|
|
5734
|
+
try {
|
|
5735
|
+
const db = getDbByTenant({ tenant });
|
|
5736
|
+
if (!rebuild && db.models[contentType] && env === process.env.ENV && !tpl) {
|
|
5737
|
+
const modelToReturn = db.model(contentType);
|
|
5738
|
+
if (modelToReturn.schema.obj.metadata && modelToReturn.schema.obj.metadata.isContentType && modelToReturn.schema.obj.metadata.isContentType.default === true) {
|
|
5739
|
+
return modelToReturn;
|
|
5740
|
+
}
|
|
5741
|
+
return void 0;
|
|
5742
|
+
}
|
|
5743
|
+
const contentTypeConfig = tpl || await getTpl({ tenant, contentType, env, source: tplSource });
|
|
5744
|
+
if (!contentTypeConfig) return void 0;
|
|
5745
|
+
const smTagTypesConfig = await getSmTagTypesConfigForTenant(tenant);
|
|
5746
|
+
const thisSchema = genContentTypeSchema({
|
|
5747
|
+
contentType,
|
|
5748
|
+
segment: contentTypeConfig.general?.segment,
|
|
5749
|
+
contentTypeConfig,
|
|
5750
|
+
smTagTypesConfig
|
|
5751
|
+
});
|
|
5752
|
+
if (rebuild && db.models[contentType]) {
|
|
5753
|
+
db.deleteModel(contentType);
|
|
5754
|
+
}
|
|
5755
|
+
return (0, import_getModelByTenant3.getModelByTenant)({
|
|
5756
|
+
tenant,
|
|
5757
|
+
modelName: contentType,
|
|
5758
|
+
schema: thisSchema,
|
|
5759
|
+
env
|
|
5760
|
+
});
|
|
5761
|
+
} catch (err) {
|
|
5762
|
+
throw err;
|
|
5763
|
+
}
|
|
5764
|
+
};
|
|
5765
|
+
|
|
5766
|
+
// src/node.ts
|
|
4938
5767
|
init_models();
|
|
4939
5768
|
var import_WorkerManager = __toESM(require_WorkerManager());
|
|
4940
5769
|
var import_ProducerManager = __toESM(require_ProducerManager());
|
|
@@ -4943,24 +5772,26 @@ var import_BaseFlowProducer = __toESM(require_BaseFlowProducer());
|
|
|
4943
5772
|
var import_BaseWorker = __toESM(require_BaseWorker());
|
|
4944
5773
|
var import_ChunksElasticSyncProducer = __toESM(require_ChunksElasticSyncProducer());
|
|
4945
5774
|
var import_AnnosElasticSyncProducer = __toESM(require_AnnosElasticSyncProducer());
|
|
5775
|
+
var import_ContentElasticSyncProducer = __toESM(require_ContentElasticSyncProducer());
|
|
4946
5776
|
var import_GET_GLOBAL_BULLMQ_CONFIG = __toESM(require_GET_GLOBAL_BULLMQ_CONFIG());
|
|
4947
5777
|
var export_AnnosElasticSyncProducer = import_AnnosElasticSyncProducer.AnnosElasticSyncProducer;
|
|
4948
5778
|
var export_BaseFlowProducer = import_BaseFlowProducer.BaseFlowProducer;
|
|
4949
5779
|
var export_BaseProducer = import_BaseProducer.BaseProducer;
|
|
4950
5780
|
var export_BaseWorker = import_BaseWorker.BaseWorker;
|
|
4951
5781
|
var export_ChunksElasticSyncProducer = import_ChunksElasticSyncProducer.ChunksElasticSyncProducer;
|
|
5782
|
+
var export_ContentElasticSyncProducer = import_ContentElasticSyncProducer.ContentElasticSyncProducer;
|
|
4952
5783
|
var export_ElasticSearchConnector = import_ElasticSearchConnector.ElasticSearchConnector;
|
|
4953
5784
|
var export_GET_GLOBAL_BULLMQ_CONFIG = import_GET_GLOBAL_BULLMQ_CONFIG.GET_GLOBAL_BULLMQ_CONFIG;
|
|
4954
5785
|
var export_MongoConnector = import_MongoConnector3.MongoConnector;
|
|
4955
5786
|
var export_ProducerManager = import_ProducerManager.ProducerManager;
|
|
4956
5787
|
var export_WorkerManager = import_WorkerManager.WorkerManager;
|
|
4957
|
-
var export_getAIChatModelByTenant =
|
|
4958
|
-
var export_getAnnotationsModelByTenant =
|
|
4959
|
-
var export_getGeneratedEntitiesModelByTenant =
|
|
4960
|
-
var export_getGeneratedTopicsModelByTenant =
|
|
4961
|
-
var export_getModelByTenant =
|
|
4962
|
-
var export_getPlatformConfigsModelByTenant =
|
|
4963
|
-
var export_getTplModelByTenant =
|
|
5788
|
+
var export_getAIChatModelByTenant = import_getModelByTenant4.getAIChatModelByTenant;
|
|
5789
|
+
var export_getAnnotationsModelByTenant = import_getModelByTenant4.getAnnotationsModelByTenant;
|
|
5790
|
+
var export_getGeneratedEntitiesModelByTenant = import_getModelByTenant4.getGeneratedEntitiesModelByTenant;
|
|
5791
|
+
var export_getGeneratedTopicsModelByTenant = import_getModelByTenant4.getGeneratedTopicsModelByTenant;
|
|
5792
|
+
var export_getModelByTenant = import_getModelByTenant4.getModelByTenant;
|
|
5793
|
+
var export_getPlatformConfigsModelByTenant = import_getModelByTenant4.getPlatformConfigsModelByTenant;
|
|
5794
|
+
var export_getTplModelByTenant = import_getModelByTenant4.getTplModelByTenant;
|
|
4964
5795
|
export {
|
|
4965
5796
|
AIChat_default as AIChatSchema,
|
|
4966
5797
|
export_AnnosElasticSyncProducer as AnnosElasticSyncProducer,
|
|
@@ -4972,6 +5803,7 @@ export {
|
|
|
4972
5803
|
BlockRegistry,
|
|
4973
5804
|
CHUNKING_PRESETS,
|
|
4974
5805
|
export_ChunksElasticSyncProducer as ChunksElasticSyncProducer,
|
|
5806
|
+
export_ContentElasticSyncProducer as ContentElasticSyncProducer,
|
|
4975
5807
|
ELASTIC_MAPPING_PRESETS,
|
|
4976
5808
|
export_ElasticSearchConnector as ElasticSearchConnector,
|
|
4977
5809
|
FILTER_IDS,
|
|
@@ -4985,9 +5817,13 @@ export {
|
|
|
4985
5817
|
RedisCacheConnector,
|
|
4986
5818
|
SecretManagerConnector,
|
|
4987
5819
|
TEMP_removeDuplicateFilters,
|
|
5820
|
+
TenantRegistry,
|
|
4988
5821
|
Tpl_default as TplSchema,
|
|
4989
5822
|
UI_CONTENT,
|
|
4990
5823
|
export_WorkerManager as WorkerManager,
|
|
5824
|
+
_backOfficeFields__contr,
|
|
5825
|
+
_constantMeta__contr,
|
|
5826
|
+
_fixedMainFields__contr,
|
|
4991
5827
|
_self_managed_buildAnnoHierarchyConfig,
|
|
4992
5828
|
_self_managed_buildDocHierarchyConfig,
|
|
4993
5829
|
_self_managed_getFixedAnnoRollupBlocks,
|
|
@@ -4999,13 +5835,17 @@ export {
|
|
|
4999
5835
|
compareAndGroupBlocks,
|
|
5000
5836
|
deleteVal,
|
|
5001
5837
|
extractAllBlocksFromTpl,
|
|
5838
|
+
extractAllUniqueAnnoTagTypesFromTpl,
|
|
5002
5839
|
extractAndOrganizeBlocks,
|
|
5840
|
+
extractNumberFromValue,
|
|
5003
5841
|
genCleanCamelCaseId,
|
|
5842
|
+
genContentTypeSchema,
|
|
5004
5843
|
genTagId,
|
|
5005
5844
|
generateFilterKey,
|
|
5006
5845
|
export_getAIChatModelByTenant as getAIChatModelByTenant,
|
|
5007
5846
|
getAnnoFilterBucketKey,
|
|
5008
5847
|
export_getAnnotationsModelByTenant as getAnnotationsModelByTenant,
|
|
5848
|
+
getContrModelByTenant,
|
|
5009
5849
|
getDbByTenant,
|
|
5010
5850
|
getFilterKeyForBlock,
|
|
5011
5851
|
export_getGeneratedEntitiesModelByTenant as getGeneratedEntitiesModelByTenant,
|
|
@@ -5022,7 +5862,9 @@ export {
|
|
|
5022
5862
|
getRoutePathToReviewDashboard,
|
|
5023
5863
|
getRoutePathToTCI,
|
|
5024
5864
|
getRoutePathToTagCategoryLanding,
|
|
5865
|
+
getTpl,
|
|
5025
5866
|
export_getTplModelByTenant as getTplModelByTenant,
|
|
5867
|
+
getTypesForSchemaFromTpl,
|
|
5026
5868
|
getVal,
|
|
5027
5869
|
isTplAnnotationEnabled,
|
|
5028
5870
|
mergeAnnoDataIntoAnnotationsTags,
|