Skip to content

Commit 78a5bcb

Browse files
committed
feat: update dependencies and enhance configuration resolution
#80 - Added new dependencies: `eastasianwidth`, `emoji-regex`, and `liquidjs` to improve functionality and support for various features. - Enhanced the `CronHooksService` and `LifecycleHooksService` to utilize the `resolveConfigVariables` function for better handling of configuration options, ensuring more robust and flexible execution of commands and lifecycle rules. - Updated `string-width` package to include new versions with improved features and dependencies.
1 parent 318d453 commit 78a5bcb

File tree

5 files changed

+169
-7
lines changed

5 files changed

+169
-7
lines changed

apps/api/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"ioredis": "^5.4.1",
5555
"is-plain-object": "^5.0.0",
5656
"joi": "^18.0.1",
57+
"liquidjs": "^10.25.0",
5758
"loglevel": "^1.9.1",
5859
"lru-cache": "^11.0.2",
5960
"microdiff": "^1.5.0",
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import dayjs from 'dayjs'
2+
import { Liquid } from 'liquidjs'
3+
4+
const liquidEngine = new Liquid({
5+
strictVariables: false,
6+
strictFilters: false,
7+
})
8+
9+
function normalizeDate(value: unknown): dayjs.Dayjs {
10+
if (value instanceof Date) {
11+
return dayjs(value)
12+
}
13+
if (typeof value === 'number' || typeof value === 'string') {
14+
return dayjs(value)
15+
}
16+
return dayjs()
17+
}
18+
19+
liquidEngine.registerFilter('dateFormat', (value: unknown, format: string = 'YYYY-MM-DD HH:mm:ss') => {
20+
return normalizeDate(value).format(format)
21+
})
22+
23+
liquidEngine.registerFilter('unixMs', (value: unknown) => {
24+
return normalizeDate(value).valueOf()
25+
})
26+
27+
liquidEngine.registerFilter('unixSeconds', (value: unknown) => {
28+
return normalizeDate(value).unix()
29+
})
30+
31+
function buildTemplateContext(): Record<string, unknown> {
32+
const now = dayjs()
33+
return {
34+
date: {
35+
now: now.valueOf(),
36+
isoNow: now.toISOString(),
37+
nowDate: now.toDate(),
38+
unix: now.valueOf(),
39+
unixSeconds: now.unix(),
40+
today: now.format('YYYY-MM-DD'),
41+
yesterday: now.subtract(1, 'day').format('YYYY-MM-DD'),
42+
tomorrow: now.add(1, 'day').format('YYYY-MM-DD'),
43+
},
44+
}
45+
}
46+
47+
function getValueFromPath(context: Record<string, unknown>, path: string): unknown {
48+
const segments = path.split('.').filter(Boolean)
49+
let current: unknown = context
50+
51+
for (const segment of segments) {
52+
if (!current || typeof current !== 'object') {
53+
return undefined
54+
}
55+
current = (current as Record<string, unknown>)[segment]
56+
}
57+
58+
return current
59+
}
60+
61+
export async function resolveConfigVariables<T>(input: T): Promise<T> {
62+
if (input === null || input === undefined) {
63+
return input
64+
}
65+
66+
if (Array.isArray(input)) {
67+
const resolved = await Promise.all(input.map((item) => resolveConfigVariables(item)))
68+
return resolved as T
69+
}
70+
71+
if (typeof input === 'object') {
72+
const entries = await Promise.all(
73+
Object.entries(input as Record<string, unknown>).map(async ([key, value]) => {
74+
return [key, await resolveConfigVariables(value)] as const
75+
}),
76+
)
77+
78+
return Object.fromEntries(entries) as T
79+
}
80+
81+
if (typeof input === 'string') {
82+
if (!input.includes('{{')) {
83+
return input
84+
}
85+
86+
const context = buildTemplateContext()
87+
const exactTemplate = input.match(/^\{\{\s*([a-zA-Z0-9._-]+)\s*\}\}$/)
88+
if (exactTemplate) {
89+
try {
90+
await liquidEngine.parseAndRender(input, context)
91+
const fromContext = getValueFromPath(context, exactTemplate[1])
92+
if (fromContext !== undefined) {
93+
return fromContext as T
94+
}
95+
} catch {
96+
return input
97+
}
98+
}
99+
100+
try {
101+
const rendered = await liquidEngine.parseAndRender(input, context)
102+
return rendered as T
103+
} catch {
104+
return input
105+
}
106+
}
107+
108+
return input
109+
}

apps/api/src/core/cron/cron-hooks.service.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { CronTaskDTO } from './_dto/config-task.dto'
88
import { loadcronTasks } from './_functions/load-cron-tasks.function'
99
import { ConfigService } from '@nestjs/config'
1010
import { createHandlerLogger } from '~/_common/functions/handler-logger'
11+
import { resolveConfigVariables } from '~/_common/functions/resolve-config-variables.function'
1112

1213
@Injectable()
1314
export class CronHooksService {
@@ -293,9 +294,10 @@ export class CronHooksService {
293294

294295
private async executeHandlerCommand(name: string, handler: string, options?: Record<string, any>): Promise<void> {
295296
const args: string[] = []
297+
const resolvedOptions = await resolveConfigVariables(options)
296298

297-
if (options && typeof options === 'object') {
298-
for (const [k, v] of Object.entries(options)) {
299+
if (resolvedOptions && typeof resolvedOptions === 'object') {
300+
for (const [k, v] of Object.entries(resolvedOptions)) {
299301
if (typeof v === 'boolean') {
300302
if (v) args.push(`--${k}`)
301303
} else if (v === null || v === undefined) {

apps/api/src/management/lifecycle/lifecycle-hooks.service.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { AbstractLifecycleService } from './_abstracts/abstract.lifecycle.servic
99
import { ConfigRulesObjectSchemaDTO } from './_dto/config-rules.dto'
1010
import { loadCustomStates } from './_functions/load-custom-states.function'
1111
import { loadLifecycleRules } from './_functions/load-lifecycle-rules.function'
12+
import { resolveConfigVariables } from '~/_common/functions/resolve-config-variables.function'
1213

1314
@Injectable()
1415
export class LifecycleHooksService extends AbstractLifecycleService {
@@ -278,14 +279,16 @@ export class LifecycleHooksService extends AbstractLifecycleService {
278279
for (const idRule of lfr.identities) {
279280
if (typeof idRule.trigger === 'number' && (idRule.trigger > 0 || ignoreTrigger)) {
280281
const dateKey = idRule.dateKey || 'lastSync'
282+
const resolvedRules = await resolveConfigVariables(idRule.rules ?? {})
283+
const resolvedMutation = await resolveConfigVariables(idRule.mutation ?? {})
281284

282285
try {
283286
const checkDate = new Date(Date.now() - (idRule.trigger * 1000))
284287
const filterDate = {}
285288
filterDate[dateKey] = { $lte: checkDate }
286289

287290
const req = {
288-
...idRule.rules,
291+
...resolvedRules,
289292
lifecycle: {
290293
$in: idRule.sources,
291294
},
@@ -306,7 +309,7 @@ export class LifecycleHooksService extends AbstractLifecycleService {
306309
{ _id: identity._id },
307310
{
308311
$set: {
309-
...idRule.mutation,
312+
...resolvedMutation,
310313
lifecycle: idRule.target,
311314
lastLifecycleUpdate: new Date(),
312315
},
@@ -450,6 +453,8 @@ export class LifecycleHooksService extends AbstractLifecycleService {
450453

451454
for (const lcs of this.lifecycleSources[after.lifecycle]) {
452455
this.logger.verbose(`Processing lifecycle source <${after.lifecycle}> with rules: ${JSON.stringify(lcs.rules)}`)
456+
const resolvedRules = await resolveConfigVariables(lcs.rules ?? {})
457+
const resolvedMutation = await resolveConfigVariables(lcs.mutation ?? {})
453458

454459
if (lcs.trigger) {
455460
this.logger.debug(`Skipping lifecycle source <${after.lifecycle}> with trigger: ${lcs.trigger}`)
@@ -458,13 +463,13 @@ export class LifecycleHooksService extends AbstractLifecycleService {
458463

459464
const res = await this.identitiesService.model.findOneAndUpdate(
460465
{
461-
...lcs.rules,
466+
...resolvedRules,
462467
_id: after._id,
463468
ignoreLifecycle: { $ne: true },
464469
},
465470
{
466471
$set: {
467-
...lcs.mutation,
472+
...resolvedMutation,
468473
lifecycle: lcs.target,
469474
lastLifecycleUpdate: new Date(),
470475
},

yarn.lock

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8586,6 +8586,11 @@ duplexer@^0.1.2:
85868586
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
85878587
integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
85888588

8589+
eastasianwidth@^0.2.0:
8590+
version "0.2.0"
8591+
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
8592+
integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
8593+
85898594
ecdsa-sig-formatter@1.0.11:
85908595
version "1.0.11"
85918596
resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
@@ -8633,11 +8638,21 @@ emittery@^0.13.1:
86338638
resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad"
86348639
integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==
86358640

8641+
emoji-regex@^10.3.0:
8642+
version "10.6.0"
8643+
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.6.0.tgz#bf3d6e8f7f8fd22a65d9703475bc0147357a6b0d"
8644+
integrity sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==
8645+
86368646
emoji-regex@^8.0.0:
86378647
version "8.0.0"
86388648
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
86398649
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
86408650

8651+
emoji-regex@^9.2.2:
8652+
version "9.2.2"
8653+
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
8654+
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
8655+
86418656
enabled@2.0.x:
86428657
version "2.0.0"
86438658
resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2"
@@ -9732,6 +9747,11 @@ get-caller-file@^2.0.5:
97329747
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
97339748
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
97349749

9750+
get-east-asian-width@^1.0.0:
9751+
version "1.5.0"
9752+
resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz#ce7008fe345edcf5497a6f557cfa54bc318a9ce7"
9753+
integrity sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==
9754+
97359755
get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0:
97369756
version "1.3.0"
97379757
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01"
@@ -11495,6 +11515,13 @@ liquidjs@^10.11.1:
1149511515
dependencies:
1149611516
commander "^10.0.0"
1149711517

11518+
liquidjs@^10.25.0:
11519+
version "10.25.0"
11520+
resolved "https://registry.yarnpkg.com/liquidjs/-/liquidjs-10.25.0.tgz#a5ec7063c3202348dc5988343502ad27072f4997"
11521+
integrity sha512-XpO7AiGULTG4xcTlwkcTI5JreFG7b6esLCLp+aUSh7YuQErJZEoUXre9u9rbdb0057pfWG4l0VursvLd5Q/eAw==
11522+
dependencies:
11523+
commander "^10.0.0"
11524+
1149811525
listhen@^1.9.0:
1149911526
version "1.9.0"
1150011527
resolved "https://registry.yarnpkg.com/listhen/-/listhen-1.9.0.tgz#59355f7e4fc1eefda6bc494ae7e9ed13aa7658ef"
@@ -15302,7 +15329,7 @@ string-length@^4.0.1:
1530215329
is-fullwidth-code-point "^3.0.0"
1530315330
strip-ansi "^6.0.1"
1530415331

15305-
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3, string-width@^5.0.1, string-width@^5.1.2, string-width@^7.2.0:
15332+
string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
1530615333
version "4.2.3"
1530715334
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
1530815335
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -15311,6 +15338,24 @@ string-length@^4.0.1:
1531115338
is-fullwidth-code-point "^3.0.0"
1531215339
strip-ansi "^6.0.1"
1531315340

15341+
string-width@^5.0.1, string-width@^5.1.2:
15342+
version "5.1.2"
15343+
resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
15344+
integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==
15345+
dependencies:
15346+
eastasianwidth "^0.2.0"
15347+
emoji-regex "^9.2.2"
15348+
strip-ansi "^7.0.1"
15349+
15350+
string-width@^7.2.0:
15351+
version "7.2.0"
15352+
resolved "https://registry.yarnpkg.com/string-width/-/string-width-7.2.0.tgz#b5bb8e2165ce275d4d43476dd2700ad9091db6dc"
15353+
integrity sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==
15354+
dependencies:
15355+
emoji-regex "^10.3.0"
15356+
get-east-asian-width "^1.0.0"
15357+
strip-ansi "^7.1.0"
15358+
1531415359
string_decoder@^1.1.1, string_decoder@^1.3.0:
1531515360
version "1.3.0"
1531615361
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"

0 commit comments

Comments
 (0)