@objectstack/core 16.0.0 → 17.0.0-rc.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/index.cjs +301 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +154 -4
- package/dist/index.d.ts +154 -4
- package/dist/index.js +296 -30
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1252,6 +1252,7 @@ function createMemoryMetadata() {
|
|
|
1252
1252
|
}
|
|
1253
1253
|
|
|
1254
1254
|
// src/fallbacks/authored-translation-sync.ts
|
|
1255
|
+
import { LEGACY_OBJECT_FIRST_KEYS } from "@objectstack/spec/system";
|
|
1255
1256
|
var OWNER_PROP = "__authoredTranslationSyncOwner";
|
|
1256
1257
|
var LOCALE_LIKE = /^[a-z]{2,3}([_-]([A-Za-z]{4}|[A-Za-z]{2}|[0-9]{3}))?$/;
|
|
1257
1258
|
async function readAuthoredTranslationLayer(engine, logger) {
|
|
@@ -1281,14 +1282,32 @@ async function readAuthoredTranslationLayer(engine, logger) {
|
|
|
1281
1282
|
continue;
|
|
1282
1283
|
}
|
|
1283
1284
|
if (!data || typeof data !== "object") continue;
|
|
1284
|
-
const
|
|
1285
|
+
const legacyKeys = LEGACY_OBJECT_FIRST_KEYS.filter((key) => data[key] !== void 0);
|
|
1286
|
+
if (legacyKeys.length > 0) {
|
|
1287
|
+
logger?.warn?.(
|
|
1288
|
+
`[i18n] authored translation '${row?.name}' uses the retired object-first shape (${legacyKeys.join(", ")}) \u2014 nothing resolves from it; re-author it under 'objects.<object_name>' with a top-level 'locale' \u2014 skipped`
|
|
1289
|
+
);
|
|
1290
|
+
continue;
|
|
1291
|
+
}
|
|
1292
|
+
const locale = typeof data?.locale === "string" && data.locale || (typeof row?.name === "string" && LOCALE_LIKE.test(row.name) ? row.name : void 0) || void 0;
|
|
1285
1293
|
if (!locale) {
|
|
1286
1294
|
logger?.warn?.(
|
|
1287
|
-
`[i18n] authored translation '${row?.name}' has no resolvable locale (set
|
|
1295
|
+
`[i18n] authored translation '${row?.name}' has no resolvable locale (set the top-level 'locale', or name the item after its BCP-47 locale) \u2014 skipped`
|
|
1288
1296
|
);
|
|
1289
1297
|
continue;
|
|
1290
1298
|
}
|
|
1291
|
-
const {
|
|
1299
|
+
const {
|
|
1300
|
+
name: _n,
|
|
1301
|
+
locale: _l,
|
|
1302
|
+
_packageId: _p,
|
|
1303
|
+
_packageVersion: _pv,
|
|
1304
|
+
_provenance: _pr,
|
|
1305
|
+
_lock: _lk,
|
|
1306
|
+
_lockReason: _lr,
|
|
1307
|
+
_lockDocsUrl: _ld,
|
|
1308
|
+
_lockSource: _ls,
|
|
1309
|
+
...payload
|
|
1310
|
+
} = data;
|
|
1292
1311
|
byLocale[locale] = deepMerge(byLocale[locale] ?? {}, payload);
|
|
1293
1312
|
}
|
|
1294
1313
|
return byLocale;
|
|
@@ -4212,7 +4231,7 @@ import {
|
|
|
4212
4231
|
mapMembershipRole,
|
|
4213
4232
|
BUILTIN_IDENTITY_PLATFORM_ADMIN,
|
|
4214
4233
|
ADMIN_FULL_ACCESS,
|
|
4215
|
-
|
|
4234
|
+
ORGANIZATION_ADMIN_GRANTS
|
|
4216
4235
|
} from "@objectstack/spec";
|
|
4217
4236
|
|
|
4218
4237
|
// src/security/grant-validity.ts
|
|
@@ -4320,7 +4339,8 @@ async function resolveAuthzContext(input) {
|
|
|
4320
4339
|
positions: [],
|
|
4321
4340
|
permissions: [],
|
|
4322
4341
|
systemPermissions: [],
|
|
4323
|
-
org_user_ids: []
|
|
4342
|
+
org_user_ids: [],
|
|
4343
|
+
accessible_org_ids: []
|
|
4324
4344
|
};
|
|
4325
4345
|
let userId;
|
|
4326
4346
|
let tenantId;
|
|
@@ -4346,6 +4366,33 @@ async function resolveAuthzContext(input) {
|
|
|
4346
4366
|
ctx.userId = userId;
|
|
4347
4367
|
if (tenantId) ctx.tenantId = tenantId;
|
|
4348
4368
|
if (!ql || typeof ql.find !== "function") return ctx;
|
|
4369
|
+
const grants = await resolveUserAuthzGrants(ql, userId, {
|
|
4370
|
+
tenantId,
|
|
4371
|
+
nowMs: input.nowMs,
|
|
4372
|
+
seedPermissions: ctx.permissions,
|
|
4373
|
+
seedEmail: ctx.email
|
|
4374
|
+
});
|
|
4375
|
+
ctx.positions = grants.positions;
|
|
4376
|
+
ctx.permissions = grants.permissions;
|
|
4377
|
+
ctx.systemPermissions = grants.systemPermissions;
|
|
4378
|
+
ctx.org_user_ids = grants.org_user_ids;
|
|
4379
|
+
ctx.accessible_org_ids = grants.accessible_org_ids;
|
|
4380
|
+
if (grants.tabPermissions) ctx.tabPermissions = grants.tabPermissions;
|
|
4381
|
+
if (grants.posture) ctx.posture = grants.posture;
|
|
4382
|
+
if (grants.email && !ctx.email) ctx.email = grants.email;
|
|
4383
|
+
return ctx;
|
|
4384
|
+
}
|
|
4385
|
+
async function resolveUserAuthzGrants(ql, userId, opts = {}) {
|
|
4386
|
+
const { tenantId } = opts;
|
|
4387
|
+
const grants = {
|
|
4388
|
+
positions: [],
|
|
4389
|
+
permissions: Array.isArray(opts.seedPermissions) ? [...opts.seedPermissions] : [],
|
|
4390
|
+
systemPermissions: [],
|
|
4391
|
+
org_user_ids: [userId],
|
|
4392
|
+
accessible_org_ids: []
|
|
4393
|
+
};
|
|
4394
|
+
if (opts.seedEmail) grants.email = opts.seedEmail;
|
|
4395
|
+
if (!ql || typeof ql.find !== "function") return grants;
|
|
4349
4396
|
let userRowLoaded = false;
|
|
4350
4397
|
let userRow;
|
|
4351
4398
|
const getUserRow = async () => {
|
|
@@ -4356,28 +4403,35 @@ async function resolveAuthzContext(input) {
|
|
|
4356
4403
|
}
|
|
4357
4404
|
return userRow;
|
|
4358
4405
|
};
|
|
4359
|
-
if (!
|
|
4406
|
+
if (!grants.email) {
|
|
4360
4407
|
const u = await getUserRow();
|
|
4361
|
-
if (u?.email)
|
|
4408
|
+
if (u?.email) grants.email = String(u.email);
|
|
4362
4409
|
}
|
|
4363
|
-
const
|
|
4364
|
-
const members = await tryFind(ql, "sys_member",
|
|
4410
|
+
const nowMs = opts.nowMs ?? Date.now();
|
|
4411
|
+
const members = await tryFind(ql, "sys_member", { user_id: userId }, 200);
|
|
4412
|
+
const accessibleOrgIds = /* @__PURE__ */ new Set();
|
|
4365
4413
|
for (const m of members) {
|
|
4414
|
+
if (!isGrantActive(m, nowMs)) continue;
|
|
4415
|
+
const org = m.organization_id ?? m.organizationId;
|
|
4416
|
+
if (typeof org === "string" && org) accessibleOrgIds.add(org);
|
|
4417
|
+
}
|
|
4418
|
+
grants.accessible_org_ids = Array.from(accessibleOrgIds);
|
|
4419
|
+
const activeMembers = tenantId ? members.filter((m) => (m.organization_id ?? m.organizationId) === tenantId) : members;
|
|
4420
|
+
for (const m of activeMembers) {
|
|
4366
4421
|
if (m.role && typeof m.role === "string") {
|
|
4367
4422
|
for (const raw of m.role.split(",").map((s) => s.trim()).filter(Boolean)) {
|
|
4368
4423
|
const r = mapMembershipRole(raw);
|
|
4369
|
-
if (!
|
|
4424
|
+
if (!grants.positions.includes(r)) grants.positions.push(r);
|
|
4370
4425
|
}
|
|
4371
4426
|
}
|
|
4372
4427
|
}
|
|
4373
|
-
const nowMs = input.nowMs ?? Date.now();
|
|
4374
4428
|
const userPositionRows = await tryFind(ql, "sys_user_position", { user_id: userId }, 200);
|
|
4375
4429
|
for (const ur of userPositionRows) {
|
|
4376
4430
|
const org = ur.organization_id ?? null;
|
|
4377
4431
|
if (org && tenantId && org !== tenantId) continue;
|
|
4378
4432
|
if (!isGrantActive(ur, nowMs)) continue;
|
|
4379
4433
|
const r = ur.position;
|
|
4380
|
-
if (typeof r === "string" && r && !
|
|
4434
|
+
if (typeof r === "string" && r && !grants.positions.includes(r)) grants.positions.push(r);
|
|
4381
4435
|
}
|
|
4382
4436
|
if (tenantId) {
|
|
4383
4437
|
const orgMembers = await tryFind(ql, "sys_member", { organization_id: tenantId }, 1e3);
|
|
@@ -4385,9 +4439,7 @@ async function resolveAuthzContext(input) {
|
|
|
4385
4439
|
orgMembers.map((m) => m.user_id ?? m.userId).filter((v) => typeof v === "string" && v.length > 0)
|
|
4386
4440
|
);
|
|
4387
4441
|
ids.add(userId);
|
|
4388
|
-
|
|
4389
|
-
} else {
|
|
4390
|
-
ctx.org_user_ids = [userId];
|
|
4442
|
+
grants.org_user_ids = Array.from(ids);
|
|
4391
4443
|
}
|
|
4392
4444
|
const upsRowsAll = await tryFind(ql, "sys_user_permission_set", { user_id: userId }, 100);
|
|
4393
4445
|
const upsRows = upsRowsAll.filter((r) => isGrantActive(r, nowMs));
|
|
@@ -4401,9 +4453,9 @@ async function resolveAuthzContext(input) {
|
|
|
4401
4453
|
upsRows.filter((r) => (r.organization_id ?? r.organizationId ?? null) === null).map((r) => r.permission_set_id ?? r.permissionSetId).filter(Boolean)
|
|
4402
4454
|
);
|
|
4403
4455
|
let hasPlatformAdminGrant = false;
|
|
4404
|
-
if (!
|
|
4405
|
-
if (
|
|
4406
|
-
const positionRows = await tryFind(ql, "sys_position", { name: { $in:
|
|
4456
|
+
if (!grants.positions.includes("everyone")) grants.positions.push("everyone");
|
|
4457
|
+
if (grants.positions.length > 0) {
|
|
4458
|
+
const positionRows = await tryFind(ql, "sys_position", { name: { $in: grants.positions } }, 100);
|
|
4407
4459
|
const positionIds = positionRows.map((r) => r.id).filter(Boolean);
|
|
4408
4460
|
if (positionIds.length > 0) {
|
|
4409
4461
|
const rpsRows = await tryFind(ql, "sys_position_permission_set", { position_id: { $in: positionIds } }, 500);
|
|
@@ -4418,12 +4470,12 @@ async function resolveAuthzContext(input) {
|
|
|
4418
4470
|
const tabRank = { hidden: 0, default_off: 1, default_on: 2, visible: 3 };
|
|
4419
4471
|
const mergedTabs = {};
|
|
4420
4472
|
for (const ps of psRows) {
|
|
4421
|
-
if (ps.name && !
|
|
4473
|
+
if (ps.name && !grants.permissions.includes(ps.name)) grants.permissions.push(ps.name);
|
|
4422
4474
|
if (ps.name === ADMIN_FULL_ACCESS && unscopedUserPsIds.has(ps.id)) hasPlatformAdminGrant = true;
|
|
4423
4475
|
const sysPerms = typeof ps.system_permissions === "string" ? safeJsonParse2(ps.system_permissions, []) : ps.system_permissions ?? ps.systemPermissions;
|
|
4424
4476
|
if (Array.isArray(sysPerms)) {
|
|
4425
4477
|
for (const p of sysPerms) {
|
|
4426
|
-
if (typeof p === "string" && !
|
|
4478
|
+
if (typeof p === "string" && !grants.systemPermissions.includes(p)) grants.systemPermissions.push(p);
|
|
4427
4479
|
}
|
|
4428
4480
|
}
|
|
4429
4481
|
const tabs = typeof ps.tab_permissions === "string" ? safeJsonParse2(ps.tab_permissions, {}) : ps.tab_permissions ?? ps.tabPermissions;
|
|
@@ -4437,20 +4489,22 @@ async function resolveAuthzContext(input) {
|
|
|
4437
4489
|
}
|
|
4438
4490
|
}
|
|
4439
4491
|
}
|
|
4440
|
-
if (Object.keys(mergedTabs).length > 0)
|
|
4492
|
+
if (Object.keys(mergedTabs).length > 0) grants.tabPermissions = mergedTabs;
|
|
4441
4493
|
}
|
|
4442
|
-
if (hasPlatformAdminGrant && !
|
|
4443
|
-
|
|
4494
|
+
if (hasPlatformAdminGrant && !grants.positions.includes(BUILTIN_IDENTITY_PLATFORM_ADMIN)) {
|
|
4495
|
+
grants.positions.unshift(BUILTIN_IDENTITY_PLATFORM_ADMIN);
|
|
4444
4496
|
}
|
|
4445
|
-
|
|
4497
|
+
grants.posture = derivePosture({
|
|
4446
4498
|
isPlatformAdmin: hasPlatformAdminGrant,
|
|
4447
|
-
|
|
4499
|
+
// [ADR-0105 D4] Either org-admin capability set resolves the rung — the
|
|
4500
|
+
// wall-less variant differs only by withholding the superuser bits.
|
|
4501
|
+
isTenantAdmin: ORGANIZATION_ADMIN_GRANTS.some((n) => grants.permissions.includes(n))
|
|
4448
4502
|
});
|
|
4449
|
-
if (!
|
|
4503
|
+
if (!grants.permissions.includes("ai_seat")) {
|
|
4450
4504
|
const aiAccess = (await getUserRow())?.ai_access;
|
|
4451
|
-
if (aiAccess === true || aiAccess === 1 || aiAccess === "1")
|
|
4505
|
+
if (aiAccess === true || aiAccess === 1 || aiAccess === "1") grants.permissions.push("ai_seat");
|
|
4452
4506
|
}
|
|
4453
|
-
return
|
|
4507
|
+
return grants;
|
|
4454
4508
|
}
|
|
4455
4509
|
function isValidTimeZone(tz) {
|
|
4456
4510
|
try {
|
|
@@ -4575,8 +4629,8 @@ function calendarPartsInTzOrUtc(d, tz) {
|
|
|
4575
4629
|
day: d.getUTCDate()
|
|
4576
4630
|
};
|
|
4577
4631
|
}
|
|
4578
|
-
function zonedDateStartToUtcMs(
|
|
4579
|
-
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(
|
|
4632
|
+
function zonedDateStartToUtcMs(ymd2, tz) {
|
|
4633
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(ymd2);
|
|
4580
4634
|
const wallAsUtc = m ? Date.UTC(Number(m[1]), Number(m[2]) - 1, Number(m[3])) : NaN;
|
|
4581
4635
|
if (!tz || tz === "UTC" || Number.isNaN(wallAsUtc)) return wallAsUtc;
|
|
4582
4636
|
try {
|
|
@@ -4792,6 +4846,212 @@ async function bulkWrite(rows, opts) {
|
|
|
4792
4846
|
return results;
|
|
4793
4847
|
}
|
|
4794
4848
|
|
|
4849
|
+
// src/utils/filter-tokens.ts
|
|
4850
|
+
import {
|
|
4851
|
+
classifyFilterToken,
|
|
4852
|
+
parseDateMacroParam
|
|
4853
|
+
} from "@objectstack/spec/data";
|
|
4854
|
+
var UnknownFilterTokenError = class extends Error {
|
|
4855
|
+
constructor(token, suggestion) {
|
|
4856
|
+
super(
|
|
4857
|
+
`Unresolvable filter placeholder "{${token}}". ` + (suggestion ? `Did you mean "{${suggestion}}"? ` : "Resolvable placeholders are the context tokens ({current_user_id}, {current_org_id}) and the date macros ({today}, {current_quarter_start}, {30_days_ago}, \u2026). ") + "Sending it to the data engine verbatim would compare it as a literal string and match nothing, which is indistinguishable from an empty result."
|
|
4858
|
+
);
|
|
4859
|
+
this.status = 400;
|
|
4860
|
+
this.code = "FILTER_TOKEN_UNKNOWN";
|
|
4861
|
+
this.name = "UnknownFilterTokenError";
|
|
4862
|
+
this.token = token;
|
|
4863
|
+
this.suggestion = suggestion;
|
|
4864
|
+
}
|
|
4865
|
+
};
|
|
4866
|
+
var UnresolvedFilterTokenError = class extends Error {
|
|
4867
|
+
constructor(token, detail) {
|
|
4868
|
+
super(`Filter placeholder "{${token}}" cannot be resolved: ${detail}`);
|
|
4869
|
+
/** 400, not 500 — see {@link UnknownFilterTokenError}. */
|
|
4870
|
+
this.status = 400;
|
|
4871
|
+
this.code = "FILTER_TOKEN_UNRESOLVED";
|
|
4872
|
+
this.name = "UnresolvedFilterTokenError";
|
|
4873
|
+
this.token = token;
|
|
4874
|
+
}
|
|
4875
|
+
};
|
|
4876
|
+
function ymd(year, month, day) {
|
|
4877
|
+
const p = (n) => String(n).padStart(2, "0");
|
|
4878
|
+
return `${year}-${p(month)}-${p(day)}`;
|
|
4879
|
+
}
|
|
4880
|
+
function proxyDay(now, timezone) {
|
|
4881
|
+
const { year, month, day } = calendarPartsInTzOrUtc(now, timezone);
|
|
4882
|
+
return new Date(Date.UTC(year, month - 1, day));
|
|
4883
|
+
}
|
|
4884
|
+
var asYmd = (d) => ymd(d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate());
|
|
4885
|
+
function startOfPeriod(kind, d) {
|
|
4886
|
+
const r = new Date(d.getTime());
|
|
4887
|
+
switch (kind) {
|
|
4888
|
+
case "week": {
|
|
4889
|
+
const dow = (r.getUTCDay() + 6) % 7;
|
|
4890
|
+
r.setUTCDate(r.getUTCDate() - dow);
|
|
4891
|
+
return r;
|
|
4892
|
+
}
|
|
4893
|
+
case "month":
|
|
4894
|
+
return new Date(Date.UTC(r.getUTCFullYear(), r.getUTCMonth(), 1));
|
|
4895
|
+
case "quarter":
|
|
4896
|
+
return new Date(Date.UTC(r.getUTCFullYear(), Math.floor(r.getUTCMonth() / 3) * 3, 1));
|
|
4897
|
+
case "year":
|
|
4898
|
+
return new Date(Date.UTC(r.getUTCFullYear(), 0, 1));
|
|
4899
|
+
}
|
|
4900
|
+
}
|
|
4901
|
+
function daysInMonth(year, month) {
|
|
4902
|
+
return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
|
|
4903
|
+
}
|
|
4904
|
+
function addMonthsClamped(d, n) {
|
|
4905
|
+
const year = d.getUTCFullYear();
|
|
4906
|
+
const month = d.getUTCMonth() + n;
|
|
4907
|
+
const targetYear = year + Math.floor(month / 12);
|
|
4908
|
+
const targetMonth = (month % 12 + 12) % 12;
|
|
4909
|
+
const day = Math.min(d.getUTCDate(), daysInMonth(targetYear, targetMonth));
|
|
4910
|
+
return new Date(Date.UTC(
|
|
4911
|
+
targetYear,
|
|
4912
|
+
targetMonth,
|
|
4913
|
+
day,
|
|
4914
|
+
d.getUTCHours(),
|
|
4915
|
+
d.getUTCMinutes(),
|
|
4916
|
+
d.getUTCSeconds(),
|
|
4917
|
+
d.getUTCMilliseconds()
|
|
4918
|
+
));
|
|
4919
|
+
}
|
|
4920
|
+
function addPeriods(kind, d, n) {
|
|
4921
|
+
switch (kind) {
|
|
4922
|
+
case "week": {
|
|
4923
|
+
const r = new Date(d.getTime());
|
|
4924
|
+
r.setUTCDate(r.getUTCDate() + n * 7);
|
|
4925
|
+
return r;
|
|
4926
|
+
}
|
|
4927
|
+
case "month":
|
|
4928
|
+
return addMonthsClamped(d, n);
|
|
4929
|
+
case "quarter":
|
|
4930
|
+
return addMonthsClamped(d, n * 3);
|
|
4931
|
+
case "year":
|
|
4932
|
+
return addMonthsClamped(d, n * 12);
|
|
4933
|
+
}
|
|
4934
|
+
}
|
|
4935
|
+
function addUnits(unit, d, n) {
|
|
4936
|
+
const r = new Date(d.getTime());
|
|
4937
|
+
switch (unit) {
|
|
4938
|
+
case "minute":
|
|
4939
|
+
r.setUTCMinutes(r.getUTCMinutes() + n);
|
|
4940
|
+
return r;
|
|
4941
|
+
case "hour":
|
|
4942
|
+
r.setUTCHours(r.getUTCHours() + n);
|
|
4943
|
+
return r;
|
|
4944
|
+
case "day":
|
|
4945
|
+
r.setUTCDate(r.getUTCDate() + n);
|
|
4946
|
+
return r;
|
|
4947
|
+
case "week":
|
|
4948
|
+
r.setUTCDate(r.getUTCDate() + n * 7);
|
|
4949
|
+
return r;
|
|
4950
|
+
// Month/year steps clamp rather than overflow — see addMonthsClamped.
|
|
4951
|
+
case "month":
|
|
4952
|
+
return addMonthsClamped(d, n);
|
|
4953
|
+
case "year":
|
|
4954
|
+
return addMonthsClamped(d, n * 12);
|
|
4955
|
+
}
|
|
4956
|
+
}
|
|
4957
|
+
var PERIOD_RE = /^(?:(current|last|next)_)?(week|month|quarter|year)_(start|end)$/;
|
|
4958
|
+
function resolvePeriodToken(token, today) {
|
|
4959
|
+
const m = PERIOD_RE.exec(token);
|
|
4960
|
+
if (!m) return void 0;
|
|
4961
|
+
const rel = m[1] ?? "current";
|
|
4962
|
+
const kind = m[2];
|
|
4963
|
+
const bound = m[3];
|
|
4964
|
+
const offset = rel === "last" ? -1 : rel === "next" ? 1 : 0;
|
|
4965
|
+
const periodStart = startOfPeriod(kind, addPeriods(kind, startOfPeriod(kind, today), offset));
|
|
4966
|
+
if (bound === "start") return asYmd(periodStart);
|
|
4967
|
+
const next = addPeriods(kind, periodStart, 1);
|
|
4968
|
+
next.setUTCDate(next.getUTCDate() - 1);
|
|
4969
|
+
return asYmd(next);
|
|
4970
|
+
}
|
|
4971
|
+
function resolveFilterToken(token, ctx = {}) {
|
|
4972
|
+
const now = ctx.now ?? /* @__PURE__ */ new Date();
|
|
4973
|
+
if (token === "current_user_id") {
|
|
4974
|
+
if (!ctx.userId) {
|
|
4975
|
+
throw new UnresolvedFilterTokenError(
|
|
4976
|
+
token,
|
|
4977
|
+
"the request has no authenticated user. A filter scoped to the signed-in user cannot run for an anonymous or system caller \u2014 gate the surface on authentication, or drop the token from the filter."
|
|
4978
|
+
);
|
|
4979
|
+
}
|
|
4980
|
+
return ctx.userId;
|
|
4981
|
+
}
|
|
4982
|
+
if (token === "current_org_id") {
|
|
4983
|
+
if (!ctx.orgId) {
|
|
4984
|
+
throw new UnresolvedFilterTokenError(
|
|
4985
|
+
token,
|
|
4986
|
+
"the request carries no active organization (ExecutionContext.tenantId is unset). Set the active org on the request, or drop the token from the filter."
|
|
4987
|
+
);
|
|
4988
|
+
}
|
|
4989
|
+
return ctx.orgId;
|
|
4990
|
+
}
|
|
4991
|
+
const today = proxyDay(now, ctx.timezone);
|
|
4992
|
+
switch (token) {
|
|
4993
|
+
case "now":
|
|
4994
|
+
return now.toISOString();
|
|
4995
|
+
case "today":
|
|
4996
|
+
return asYmd(today);
|
|
4997
|
+
case "yesterday":
|
|
4998
|
+
return asYmd(addUnits("day", today, -1));
|
|
4999
|
+
case "tomorrow":
|
|
5000
|
+
return asYmd(addUnits("day", today, 1));
|
|
5001
|
+
}
|
|
5002
|
+
const period = resolvePeriodToken(token, today);
|
|
5003
|
+
if (period !== void 0) return period;
|
|
5004
|
+
const param = parseDateMacroParam(token);
|
|
5005
|
+
if (param) {
|
|
5006
|
+
const sign = param.direction === "ago" ? -1 : 1;
|
|
5007
|
+
if (param.unit === "minute" || param.unit === "hour") {
|
|
5008
|
+
return addUnits(param.unit, now, sign * param.n).toISOString();
|
|
5009
|
+
}
|
|
5010
|
+
return asYmd(addUnits(param.unit, today, sign * param.n));
|
|
5011
|
+
}
|
|
5012
|
+
return void 0;
|
|
5013
|
+
}
|
|
5014
|
+
function hasFilterToken(node) {
|
|
5015
|
+
if (typeof node === "string") return classifyFilterToken(node) !== null;
|
|
5016
|
+
if (Array.isArray(node)) return node.some(hasFilterToken);
|
|
5017
|
+
if (node && typeof node === "object" && !(node instanceof Date)) {
|
|
5018
|
+
return Object.values(node).some(hasFilterToken);
|
|
5019
|
+
}
|
|
5020
|
+
return false;
|
|
5021
|
+
}
|
|
5022
|
+
function resolveFilterTokens(filter, ctx = {}) {
|
|
5023
|
+
if (filter == null) return filter;
|
|
5024
|
+
if (!hasFilterToken(filter)) return filter;
|
|
5025
|
+
const pinned = { ...ctx, now: ctx.now ?? /* @__PURE__ */ new Date() };
|
|
5026
|
+
const walk = (node) => {
|
|
5027
|
+
if (typeof node === "string") {
|
|
5028
|
+
const cls = classifyFilterToken(node);
|
|
5029
|
+
if (!cls) return node;
|
|
5030
|
+
if (cls.kind === "unknown") throw new UnknownFilterTokenError(cls.token, cls.suggestion);
|
|
5031
|
+
const resolved = resolveFilterToken(cls.token, pinned);
|
|
5032
|
+
if (resolved === void 0) throw new UnknownFilterTokenError(cls.token);
|
|
5033
|
+
return resolved;
|
|
5034
|
+
}
|
|
5035
|
+
if (Array.isArray(node)) return node.map(walk);
|
|
5036
|
+
if (node && typeof node === "object") {
|
|
5037
|
+
if (node instanceof Date) return node;
|
|
5038
|
+
const out = {};
|
|
5039
|
+
for (const [k, v] of Object.entries(node)) out[k] = walk(v);
|
|
5040
|
+
return out;
|
|
5041
|
+
}
|
|
5042
|
+
return node;
|
|
5043
|
+
};
|
|
5044
|
+
return walk(filter);
|
|
5045
|
+
}
|
|
5046
|
+
function filterTokenContextFrom(execCtx, now) {
|
|
5047
|
+
return {
|
|
5048
|
+
now,
|
|
5049
|
+
timezone: execCtx?.timezone,
|
|
5050
|
+
userId: execCtx?.userId,
|
|
5051
|
+
orgId: execCtx?.tenantId
|
|
5052
|
+
};
|
|
5053
|
+
}
|
|
5054
|
+
|
|
4795
5055
|
// src/health-monitor.ts
|
|
4796
5056
|
var PluginHealthMonitor = class {
|
|
4797
5057
|
constructor(logger) {
|
|
@@ -5736,6 +5996,8 @@ export {
|
|
|
5736
5996
|
SecurePluginContext,
|
|
5737
5997
|
SemanticVersionManager,
|
|
5738
5998
|
ServiceLifecycle,
|
|
5999
|
+
UnknownFilterTokenError,
|
|
6000
|
+
UnresolvedFilterTokenError,
|
|
5739
6001
|
bucketKeyToCalendarRange,
|
|
5740
6002
|
buildPermissionsFromGrants,
|
|
5741
6003
|
bulkWrite,
|
|
@@ -5756,6 +6018,7 @@ export {
|
|
|
5756
6018
|
derivePosture,
|
|
5757
6019
|
evaluateAuthGate,
|
|
5758
6020
|
extractApiKey,
|
|
6021
|
+
filterTokenContextFrom,
|
|
5759
6022
|
generateApiKey,
|
|
5760
6023
|
generateEd25519KeyPair,
|
|
5761
6024
|
getEnv,
|
|
@@ -5772,8 +6035,11 @@ export {
|
|
|
5772
6035
|
readAuthoredTranslationLayer,
|
|
5773
6036
|
resolveApiKeyPrincipal,
|
|
5774
6037
|
resolveAuthzContext,
|
|
6038
|
+
resolveFilterToken,
|
|
6039
|
+
resolveFilterTokens,
|
|
5775
6040
|
resolveLocale,
|
|
5776
6041
|
resolveLocalizationContext,
|
|
6042
|
+
resolveUserAuthzGrants,
|
|
5777
6043
|
safeExit,
|
|
5778
6044
|
shouldDenyAnonymous,
|
|
5779
6045
|
signPayload,
|