@objectstack/core 16.0.0-rc.1 → 16.1.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 +46 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +51 -1
- package/dist/index.d.ts +51 -1
- package/dist/index.js +45 -21
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.cts
CHANGED
|
@@ -1781,6 +1781,56 @@ interface ResolveAuthzInput {
|
|
|
1781
1781
|
* never throws. Anonymous requests yield `{ positions: [], permissions: [], ... }`.
|
|
1782
1782
|
*/
|
|
1783
1783
|
declare function resolveAuthzContext(input: ResolveAuthzInput): Promise<ResolvedAuthzContext>;
|
|
1784
|
+
/** The authorization grants a KNOWN user holds — a subset of {@link ResolvedAuthzContext}. */
|
|
1785
|
+
interface UserAuthzGrants {
|
|
1786
|
+
positions: string[];
|
|
1787
|
+
permissions: string[];
|
|
1788
|
+
systemPermissions: string[];
|
|
1789
|
+
/** Fellow-org user IDs for RLS scoping of identity tables (`id IN (...)`). */
|
|
1790
|
+
org_user_ids: string[];
|
|
1791
|
+
tabPermissions?: Record<string, 'visible' | 'hidden' | 'default_on' | 'default_off'>;
|
|
1792
|
+
posture?: AuthzPosture;
|
|
1793
|
+
/** The user's unique email (`sys_user`), for `current_user.email` owner RLS. */
|
|
1794
|
+
email?: string;
|
|
1795
|
+
}
|
|
1796
|
+
interface ResolveUserAuthzGrantsOptions {
|
|
1797
|
+
/** Active org/tenant id — scopes org-bound grants (a null-org row is global). */
|
|
1798
|
+
tenantId?: string;
|
|
1799
|
+
/** Clock injection for grant validity windows (tests). */
|
|
1800
|
+
nowMs?: number;
|
|
1801
|
+
/**
|
|
1802
|
+
* Permission names the CALLER already resolved (e.g. API-key scopes) to seed
|
|
1803
|
+
* `permissions` BEFORE permission-set names are appended, so a mixed
|
|
1804
|
+
* API-key+session principal keeps every scope and the ordering is preserved.
|
|
1805
|
+
* Copied, never mutated.
|
|
1806
|
+
*/
|
|
1807
|
+
seedPermissions?: string[];
|
|
1808
|
+
/** A caller-supplied email (e.g. from the session) that wins over the `sys_user` read. */
|
|
1809
|
+
seedEmail?: string;
|
|
1810
|
+
}
|
|
1811
|
+
/**
|
|
1812
|
+
* resolveUserAuthzGrants — the userId-driven core of {@link resolveAuthzContext}.
|
|
1813
|
+
*
|
|
1814
|
+
* Given a KNOWN user id, aggregate the authorization grants that user holds:
|
|
1815
|
+
* org-admin positions (`sys_member`), platform-RBAC positions
|
|
1816
|
+
* (`sys_user_position`), user- and position-bound permission sets
|
|
1817
|
+
* (`sys_user_permission_set` / `sys_position_permission_set` →
|
|
1818
|
+
* `sys_permission_set`), the derived `platform_admin` built-in + posture rung,
|
|
1819
|
+
* fellow-org peers for identity-table RLS, and the env-side `ai_seat`.
|
|
1820
|
+
*
|
|
1821
|
+
* Factored out of `resolveAuthzContext` so a surface that already knows WHO the
|
|
1822
|
+
* principal is — with no HTTP request to resolve it from — can build the SAME
|
|
1823
|
+
* envelope through the ONE resolver, instead of re-reading `sys_member` /
|
|
1824
|
+
* `sys_user_position` / `sys_*_permission_set` itself. The motivating consumer
|
|
1825
|
+
* is a `runAs:'user'` automation run resolving the triggering user's grants
|
|
1826
|
+
* (#3356): the record-change hook session carries only a `userId`, so the
|
|
1827
|
+
* automation engine calls this to run the flow's data ops exactly as that user
|
|
1828
|
+
* — not the bare member/everyone fallback the missing grants used to leave it.
|
|
1829
|
+
*
|
|
1830
|
+
* Fail-closed like its parent: every read is defensive, a missing engine/table
|
|
1831
|
+
* yields an empty-but-valid envelope, and it never throws.
|
|
1832
|
+
*/
|
|
1833
|
+
declare function resolveUserAuthzGrants(ql: any, userId: string, opts?: ResolveUserAuthzGrantsOptions): Promise<UserAuthzGrants>;
|
|
1784
1834
|
interface ResolveLocalizationInput {
|
|
1785
1835
|
ql: any;
|
|
1786
1836
|
/** Settings service exposing `get(namespace, key, { tenantId, userId })`. */
|
|
@@ -2637,4 +2687,4 @@ declare class NamespaceResolver {
|
|
|
2637
2687
|
private suggestAlternative;
|
|
2638
2688
|
}
|
|
2639
2689
|
|
|
2640
|
-
export { ANONYMOUS_DENY_BODY, ANONYMOUS_DENY_CODE, ANONYMOUS_DENY_MESSAGE, ANONYMOUS_DENY_STATUS, API_KEY_PREFIX, type AnonymousDenyInput, type ApiKeyPrincipal, ApiRegistry, type ApiRegistryPluginConfig, type AuthGate, type BucketGranularity, type BulkWriteOptions, type BulkWriteRowResult, CORE_FALLBACK_FACTORIES, type CalendarParts, DependencyResolver, type GeneratedApiKey, type GrantValidityWindow, HotReloadManager, type KernelState, type KeyInput, type LadderPrincipal, type LadderRow, LiteKernel, type NamespaceCheckResult, type NamespaceConflict, type NamespaceEntry, NamespaceResolver, ObjectKernel, ObjectKernelBase, type ObjectKernelConfig, ObjectLogger, POSTURE_INJECTION_RULE, POSTURE_LADDER, POSTURE_RANK, type ParsedSignature, type PermissionCheckResult$1 as PermissionCheckResult, type PermissionGrant, type Plugin, type PluginArtifactVerifyResult, PluginConfigValidator, type PluginContext, PluginHealthMonitor, type PluginHealthStatus, type PluginLoadResult, PluginLoader, type PluginMetadata, type PermissionCheckResult as PluginPermissionCheckResult, PluginPermissionEnforcer, PluginPermissionManager, type PluginPermissions, PluginSandboxRuntime, PluginSecurityScanner, type PluginSignatureConfig, PluginSignatureVerifier, type PluginStartupResult, type PostureEvidence, type PublisherVerifyResult, index as QA, type ResolveAuthzInput, type ResolveLocalizationInput, type ResolvedAuthzContext, type ResourceUsage, type RetryOptions, SIGNATURE_ALG, type SandboxContext, type ScanTarget, SecurePluginContext, type SecurityIssue, SemanticVersionManager, type ServiceFactory, ServiceLifecycle, type ServiceRegistration, type SignatureVerificationResult, type VersionCompatibility, bucketKeyToCalendarRange, buildPermissionsFromGrants, bulkWrite, calendarPartsInTz, calendarPartsInTzOrUtc, counterSignPayload, createApiRegistryPlugin, createMemoryCache, createMemoryI18n, createMemoryJob, createMemoryMetadata, createMemoryQueue, createPluginConfigValidator, createPluginPermissionEnforcer, deepMerge, defaultIsTransientError, derivePosture, evaluateAuthGate, extractApiKey, generateApiKey, generateEd25519KeyPair, getEnv, getMemoryUsage, hashApiKey, isAuthGateAllowlisted, isExpired, isGrantActive, isGrantExpired, isNode, parseScopes, parseSignature, postureVisibleRows, readAuthoredTranslationLayer, resolveApiKeyPrincipal, resolveAuthzContext, resolveLocale, resolveLocalizationContext, safeExit, shouldDenyAnonymous, signPayload, verifyPayload, verifyPlatformSignature, verifyPluginArtifact, verifyPublisherSignature, wireAuthoredTranslationSync, withTransientRetry, zonedDateStartToUtcMs };
|
|
2690
|
+
export { ANONYMOUS_DENY_BODY, ANONYMOUS_DENY_CODE, ANONYMOUS_DENY_MESSAGE, ANONYMOUS_DENY_STATUS, API_KEY_PREFIX, type AnonymousDenyInput, type ApiKeyPrincipal, ApiRegistry, type ApiRegistryPluginConfig, type AuthGate, type BucketGranularity, type BulkWriteOptions, type BulkWriteRowResult, CORE_FALLBACK_FACTORIES, type CalendarParts, DependencyResolver, type GeneratedApiKey, type GrantValidityWindow, HotReloadManager, type KernelState, type KeyInput, type LadderPrincipal, type LadderRow, LiteKernel, type NamespaceCheckResult, type NamespaceConflict, type NamespaceEntry, NamespaceResolver, ObjectKernel, ObjectKernelBase, type ObjectKernelConfig, ObjectLogger, POSTURE_INJECTION_RULE, POSTURE_LADDER, POSTURE_RANK, type ParsedSignature, type PermissionCheckResult$1 as PermissionCheckResult, type PermissionGrant, type Plugin, type PluginArtifactVerifyResult, PluginConfigValidator, type PluginContext, PluginHealthMonitor, type PluginHealthStatus, type PluginLoadResult, PluginLoader, type PluginMetadata, type PermissionCheckResult as PluginPermissionCheckResult, PluginPermissionEnforcer, PluginPermissionManager, type PluginPermissions, PluginSandboxRuntime, PluginSecurityScanner, type PluginSignatureConfig, PluginSignatureVerifier, type PluginStartupResult, type PostureEvidence, type PublisherVerifyResult, index as QA, type ResolveAuthzInput, type ResolveLocalizationInput, type ResolveUserAuthzGrantsOptions, type ResolvedAuthzContext, type ResourceUsage, type RetryOptions, SIGNATURE_ALG, type SandboxContext, type ScanTarget, SecurePluginContext, type SecurityIssue, SemanticVersionManager, type ServiceFactory, ServiceLifecycle, type ServiceRegistration, type SignatureVerificationResult, type UserAuthzGrants, type VersionCompatibility, bucketKeyToCalendarRange, buildPermissionsFromGrants, bulkWrite, calendarPartsInTz, calendarPartsInTzOrUtc, counterSignPayload, createApiRegistryPlugin, createMemoryCache, createMemoryI18n, createMemoryJob, createMemoryMetadata, createMemoryQueue, createPluginConfigValidator, createPluginPermissionEnforcer, deepMerge, defaultIsTransientError, derivePosture, evaluateAuthGate, extractApiKey, generateApiKey, generateEd25519KeyPair, getEnv, getMemoryUsage, hashApiKey, isAuthGateAllowlisted, isExpired, isGrantActive, isGrantExpired, isNode, parseScopes, parseSignature, postureVisibleRows, readAuthoredTranslationLayer, resolveApiKeyPrincipal, resolveAuthzContext, resolveLocale, resolveLocalizationContext, resolveUserAuthzGrants, safeExit, shouldDenyAnonymous, signPayload, verifyPayload, verifyPlatformSignature, verifyPluginArtifact, verifyPublisherSignature, wireAuthoredTranslationSync, withTransientRetry, zonedDateStartToUtcMs };
|
package/dist/index.d.ts
CHANGED
|
@@ -1781,6 +1781,56 @@ interface ResolveAuthzInput {
|
|
|
1781
1781
|
* never throws. Anonymous requests yield `{ positions: [], permissions: [], ... }`.
|
|
1782
1782
|
*/
|
|
1783
1783
|
declare function resolveAuthzContext(input: ResolveAuthzInput): Promise<ResolvedAuthzContext>;
|
|
1784
|
+
/** The authorization grants a KNOWN user holds — a subset of {@link ResolvedAuthzContext}. */
|
|
1785
|
+
interface UserAuthzGrants {
|
|
1786
|
+
positions: string[];
|
|
1787
|
+
permissions: string[];
|
|
1788
|
+
systemPermissions: string[];
|
|
1789
|
+
/** Fellow-org user IDs for RLS scoping of identity tables (`id IN (...)`). */
|
|
1790
|
+
org_user_ids: string[];
|
|
1791
|
+
tabPermissions?: Record<string, 'visible' | 'hidden' | 'default_on' | 'default_off'>;
|
|
1792
|
+
posture?: AuthzPosture;
|
|
1793
|
+
/** The user's unique email (`sys_user`), for `current_user.email` owner RLS. */
|
|
1794
|
+
email?: string;
|
|
1795
|
+
}
|
|
1796
|
+
interface ResolveUserAuthzGrantsOptions {
|
|
1797
|
+
/** Active org/tenant id — scopes org-bound grants (a null-org row is global). */
|
|
1798
|
+
tenantId?: string;
|
|
1799
|
+
/** Clock injection for grant validity windows (tests). */
|
|
1800
|
+
nowMs?: number;
|
|
1801
|
+
/**
|
|
1802
|
+
* Permission names the CALLER already resolved (e.g. API-key scopes) to seed
|
|
1803
|
+
* `permissions` BEFORE permission-set names are appended, so a mixed
|
|
1804
|
+
* API-key+session principal keeps every scope and the ordering is preserved.
|
|
1805
|
+
* Copied, never mutated.
|
|
1806
|
+
*/
|
|
1807
|
+
seedPermissions?: string[];
|
|
1808
|
+
/** A caller-supplied email (e.g. from the session) that wins over the `sys_user` read. */
|
|
1809
|
+
seedEmail?: string;
|
|
1810
|
+
}
|
|
1811
|
+
/**
|
|
1812
|
+
* resolveUserAuthzGrants — the userId-driven core of {@link resolveAuthzContext}.
|
|
1813
|
+
*
|
|
1814
|
+
* Given a KNOWN user id, aggregate the authorization grants that user holds:
|
|
1815
|
+
* org-admin positions (`sys_member`), platform-RBAC positions
|
|
1816
|
+
* (`sys_user_position`), user- and position-bound permission sets
|
|
1817
|
+
* (`sys_user_permission_set` / `sys_position_permission_set` →
|
|
1818
|
+
* `sys_permission_set`), the derived `platform_admin` built-in + posture rung,
|
|
1819
|
+
* fellow-org peers for identity-table RLS, and the env-side `ai_seat`.
|
|
1820
|
+
*
|
|
1821
|
+
* Factored out of `resolveAuthzContext` so a surface that already knows WHO the
|
|
1822
|
+
* principal is — with no HTTP request to resolve it from — can build the SAME
|
|
1823
|
+
* envelope through the ONE resolver, instead of re-reading `sys_member` /
|
|
1824
|
+
* `sys_user_position` / `sys_*_permission_set` itself. The motivating consumer
|
|
1825
|
+
* is a `runAs:'user'` automation run resolving the triggering user's grants
|
|
1826
|
+
* (#3356): the record-change hook session carries only a `userId`, so the
|
|
1827
|
+
* automation engine calls this to run the flow's data ops exactly as that user
|
|
1828
|
+
* — not the bare member/everyone fallback the missing grants used to leave it.
|
|
1829
|
+
*
|
|
1830
|
+
* Fail-closed like its parent: every read is defensive, a missing engine/table
|
|
1831
|
+
* yields an empty-but-valid envelope, and it never throws.
|
|
1832
|
+
*/
|
|
1833
|
+
declare function resolveUserAuthzGrants(ql: any, userId: string, opts?: ResolveUserAuthzGrantsOptions): Promise<UserAuthzGrants>;
|
|
1784
1834
|
interface ResolveLocalizationInput {
|
|
1785
1835
|
ql: any;
|
|
1786
1836
|
/** Settings service exposing `get(namespace, key, { tenantId, userId })`. */
|
|
@@ -2637,4 +2687,4 @@ declare class NamespaceResolver {
|
|
|
2637
2687
|
private suggestAlternative;
|
|
2638
2688
|
}
|
|
2639
2689
|
|
|
2640
|
-
export { ANONYMOUS_DENY_BODY, ANONYMOUS_DENY_CODE, ANONYMOUS_DENY_MESSAGE, ANONYMOUS_DENY_STATUS, API_KEY_PREFIX, type AnonymousDenyInput, type ApiKeyPrincipal, ApiRegistry, type ApiRegistryPluginConfig, type AuthGate, type BucketGranularity, type BulkWriteOptions, type BulkWriteRowResult, CORE_FALLBACK_FACTORIES, type CalendarParts, DependencyResolver, type GeneratedApiKey, type GrantValidityWindow, HotReloadManager, type KernelState, type KeyInput, type LadderPrincipal, type LadderRow, LiteKernel, type NamespaceCheckResult, type NamespaceConflict, type NamespaceEntry, NamespaceResolver, ObjectKernel, ObjectKernelBase, type ObjectKernelConfig, ObjectLogger, POSTURE_INJECTION_RULE, POSTURE_LADDER, POSTURE_RANK, type ParsedSignature, type PermissionCheckResult$1 as PermissionCheckResult, type PermissionGrant, type Plugin, type PluginArtifactVerifyResult, PluginConfigValidator, type PluginContext, PluginHealthMonitor, type PluginHealthStatus, type PluginLoadResult, PluginLoader, type PluginMetadata, type PermissionCheckResult as PluginPermissionCheckResult, PluginPermissionEnforcer, PluginPermissionManager, type PluginPermissions, PluginSandboxRuntime, PluginSecurityScanner, type PluginSignatureConfig, PluginSignatureVerifier, type PluginStartupResult, type PostureEvidence, type PublisherVerifyResult, index as QA, type ResolveAuthzInput, type ResolveLocalizationInput, type ResolvedAuthzContext, type ResourceUsage, type RetryOptions, SIGNATURE_ALG, type SandboxContext, type ScanTarget, SecurePluginContext, type SecurityIssue, SemanticVersionManager, type ServiceFactory, ServiceLifecycle, type ServiceRegistration, type SignatureVerificationResult, type VersionCompatibility, bucketKeyToCalendarRange, buildPermissionsFromGrants, bulkWrite, calendarPartsInTz, calendarPartsInTzOrUtc, counterSignPayload, createApiRegistryPlugin, createMemoryCache, createMemoryI18n, createMemoryJob, createMemoryMetadata, createMemoryQueue, createPluginConfigValidator, createPluginPermissionEnforcer, deepMerge, defaultIsTransientError, derivePosture, evaluateAuthGate, extractApiKey, generateApiKey, generateEd25519KeyPair, getEnv, getMemoryUsage, hashApiKey, isAuthGateAllowlisted, isExpired, isGrantActive, isGrantExpired, isNode, parseScopes, parseSignature, postureVisibleRows, readAuthoredTranslationLayer, resolveApiKeyPrincipal, resolveAuthzContext, resolveLocale, resolveLocalizationContext, safeExit, shouldDenyAnonymous, signPayload, verifyPayload, verifyPlatformSignature, verifyPluginArtifact, verifyPublisherSignature, wireAuthoredTranslationSync, withTransientRetry, zonedDateStartToUtcMs };
|
|
2690
|
+
export { ANONYMOUS_DENY_BODY, ANONYMOUS_DENY_CODE, ANONYMOUS_DENY_MESSAGE, ANONYMOUS_DENY_STATUS, API_KEY_PREFIX, type AnonymousDenyInput, type ApiKeyPrincipal, ApiRegistry, type ApiRegistryPluginConfig, type AuthGate, type BucketGranularity, type BulkWriteOptions, type BulkWriteRowResult, CORE_FALLBACK_FACTORIES, type CalendarParts, DependencyResolver, type GeneratedApiKey, type GrantValidityWindow, HotReloadManager, type KernelState, type KeyInput, type LadderPrincipal, type LadderRow, LiteKernel, type NamespaceCheckResult, type NamespaceConflict, type NamespaceEntry, NamespaceResolver, ObjectKernel, ObjectKernelBase, type ObjectKernelConfig, ObjectLogger, POSTURE_INJECTION_RULE, POSTURE_LADDER, POSTURE_RANK, type ParsedSignature, type PermissionCheckResult$1 as PermissionCheckResult, type PermissionGrant, type Plugin, type PluginArtifactVerifyResult, PluginConfigValidator, type PluginContext, PluginHealthMonitor, type PluginHealthStatus, type PluginLoadResult, PluginLoader, type PluginMetadata, type PermissionCheckResult as PluginPermissionCheckResult, PluginPermissionEnforcer, PluginPermissionManager, type PluginPermissions, PluginSandboxRuntime, PluginSecurityScanner, type PluginSignatureConfig, PluginSignatureVerifier, type PluginStartupResult, type PostureEvidence, type PublisherVerifyResult, index as QA, type ResolveAuthzInput, type ResolveLocalizationInput, type ResolveUserAuthzGrantsOptions, type ResolvedAuthzContext, type ResourceUsage, type RetryOptions, SIGNATURE_ALG, type SandboxContext, type ScanTarget, SecurePluginContext, type SecurityIssue, SemanticVersionManager, type ServiceFactory, ServiceLifecycle, type ServiceRegistration, type SignatureVerificationResult, type UserAuthzGrants, type VersionCompatibility, bucketKeyToCalendarRange, buildPermissionsFromGrants, bulkWrite, calendarPartsInTz, calendarPartsInTzOrUtc, counterSignPayload, createApiRegistryPlugin, createMemoryCache, createMemoryI18n, createMemoryJob, createMemoryMetadata, createMemoryQueue, createPluginConfigValidator, createPluginPermissionEnforcer, deepMerge, defaultIsTransientError, derivePosture, evaluateAuthGate, extractApiKey, generateApiKey, generateEd25519KeyPair, getEnv, getMemoryUsage, hashApiKey, isAuthGateAllowlisted, isExpired, isGrantActive, isGrantExpired, isNode, parseScopes, parseSignature, postureVisibleRows, readAuthoredTranslationLayer, resolveApiKeyPrincipal, resolveAuthzContext, resolveLocale, resolveLocalizationContext, resolveUserAuthzGrants, safeExit, shouldDenyAnonymous, signPayload, verifyPayload, verifyPlatformSignature, verifyPluginArtifact, verifyPublisherSignature, wireAuthoredTranslationSync, withTransientRetry, zonedDateStartToUtcMs };
|
package/dist/index.js
CHANGED
|
@@ -4346,6 +4346,31 @@ async function resolveAuthzContext(input) {
|
|
|
4346
4346
|
ctx.userId = userId;
|
|
4347
4347
|
if (tenantId) ctx.tenantId = tenantId;
|
|
4348
4348
|
if (!ql || typeof ql.find !== "function") return ctx;
|
|
4349
|
+
const grants = await resolveUserAuthzGrants(ql, userId, {
|
|
4350
|
+
tenantId,
|
|
4351
|
+
nowMs: input.nowMs,
|
|
4352
|
+
seedPermissions: ctx.permissions,
|
|
4353
|
+
seedEmail: ctx.email
|
|
4354
|
+
});
|
|
4355
|
+
ctx.positions = grants.positions;
|
|
4356
|
+
ctx.permissions = grants.permissions;
|
|
4357
|
+
ctx.systemPermissions = grants.systemPermissions;
|
|
4358
|
+
ctx.org_user_ids = grants.org_user_ids;
|
|
4359
|
+
if (grants.tabPermissions) ctx.tabPermissions = grants.tabPermissions;
|
|
4360
|
+
if (grants.posture) ctx.posture = grants.posture;
|
|
4361
|
+
if (grants.email && !ctx.email) ctx.email = grants.email;
|
|
4362
|
+
return ctx;
|
|
4363
|
+
}
|
|
4364
|
+
async function resolveUserAuthzGrants(ql, userId, opts = {}) {
|
|
4365
|
+
const { tenantId } = opts;
|
|
4366
|
+
const grants = {
|
|
4367
|
+
positions: [],
|
|
4368
|
+
permissions: Array.isArray(opts.seedPermissions) ? [...opts.seedPermissions] : [],
|
|
4369
|
+
systemPermissions: [],
|
|
4370
|
+
org_user_ids: [userId]
|
|
4371
|
+
};
|
|
4372
|
+
if (opts.seedEmail) grants.email = opts.seedEmail;
|
|
4373
|
+
if (!ql || typeof ql.find !== "function") return grants;
|
|
4349
4374
|
let userRowLoaded = false;
|
|
4350
4375
|
let userRow;
|
|
4351
4376
|
const getUserRow = async () => {
|
|
@@ -4356,9 +4381,9 @@ async function resolveAuthzContext(input) {
|
|
|
4356
4381
|
}
|
|
4357
4382
|
return userRow;
|
|
4358
4383
|
};
|
|
4359
|
-
if (!
|
|
4384
|
+
if (!grants.email) {
|
|
4360
4385
|
const u = await getUserRow();
|
|
4361
|
-
if (u?.email)
|
|
4386
|
+
if (u?.email) grants.email = String(u.email);
|
|
4362
4387
|
}
|
|
4363
4388
|
const memberWhere = tenantId ? { user_id: userId, organization_id: tenantId } : { user_id: userId };
|
|
4364
4389
|
const members = await tryFind(ql, "sys_member", memberWhere, 50);
|
|
@@ -4366,18 +4391,18 @@ async function resolveAuthzContext(input) {
|
|
|
4366
4391
|
if (m.role && typeof m.role === "string") {
|
|
4367
4392
|
for (const raw of m.role.split(",").map((s) => s.trim()).filter(Boolean)) {
|
|
4368
4393
|
const r = mapMembershipRole(raw);
|
|
4369
|
-
if (!
|
|
4394
|
+
if (!grants.positions.includes(r)) grants.positions.push(r);
|
|
4370
4395
|
}
|
|
4371
4396
|
}
|
|
4372
4397
|
}
|
|
4373
|
-
const nowMs =
|
|
4398
|
+
const nowMs = opts.nowMs ?? Date.now();
|
|
4374
4399
|
const userPositionRows = await tryFind(ql, "sys_user_position", { user_id: userId }, 200);
|
|
4375
4400
|
for (const ur of userPositionRows) {
|
|
4376
4401
|
const org = ur.organization_id ?? null;
|
|
4377
4402
|
if (org && tenantId && org !== tenantId) continue;
|
|
4378
4403
|
if (!isGrantActive(ur, nowMs)) continue;
|
|
4379
4404
|
const r = ur.position;
|
|
4380
|
-
if (typeof r === "string" && r && !
|
|
4405
|
+
if (typeof r === "string" && r && !grants.positions.includes(r)) grants.positions.push(r);
|
|
4381
4406
|
}
|
|
4382
4407
|
if (tenantId) {
|
|
4383
4408
|
const orgMembers = await tryFind(ql, "sys_member", { organization_id: tenantId }, 1e3);
|
|
@@ -4385,9 +4410,7 @@ async function resolveAuthzContext(input) {
|
|
|
4385
4410
|
orgMembers.map((m) => m.user_id ?? m.userId).filter((v) => typeof v === "string" && v.length > 0)
|
|
4386
4411
|
);
|
|
4387
4412
|
ids.add(userId);
|
|
4388
|
-
|
|
4389
|
-
} else {
|
|
4390
|
-
ctx.org_user_ids = [userId];
|
|
4413
|
+
grants.org_user_ids = Array.from(ids);
|
|
4391
4414
|
}
|
|
4392
4415
|
const upsRowsAll = await tryFind(ql, "sys_user_permission_set", { user_id: userId }, 100);
|
|
4393
4416
|
const upsRows = upsRowsAll.filter((r) => isGrantActive(r, nowMs));
|
|
@@ -4401,9 +4424,9 @@ async function resolveAuthzContext(input) {
|
|
|
4401
4424
|
upsRows.filter((r) => (r.organization_id ?? r.organizationId ?? null) === null).map((r) => r.permission_set_id ?? r.permissionSetId).filter(Boolean)
|
|
4402
4425
|
);
|
|
4403
4426
|
let hasPlatformAdminGrant = false;
|
|
4404
|
-
if (!
|
|
4405
|
-
if (
|
|
4406
|
-
const positionRows = await tryFind(ql, "sys_position", { name: { $in:
|
|
4427
|
+
if (!grants.positions.includes("everyone")) grants.positions.push("everyone");
|
|
4428
|
+
if (grants.positions.length > 0) {
|
|
4429
|
+
const positionRows = await tryFind(ql, "sys_position", { name: { $in: grants.positions } }, 100);
|
|
4407
4430
|
const positionIds = positionRows.map((r) => r.id).filter(Boolean);
|
|
4408
4431
|
if (positionIds.length > 0) {
|
|
4409
4432
|
const rpsRows = await tryFind(ql, "sys_position_permission_set", { position_id: { $in: positionIds } }, 500);
|
|
@@ -4418,12 +4441,12 @@ async function resolveAuthzContext(input) {
|
|
|
4418
4441
|
const tabRank = { hidden: 0, default_off: 1, default_on: 2, visible: 3 };
|
|
4419
4442
|
const mergedTabs = {};
|
|
4420
4443
|
for (const ps of psRows) {
|
|
4421
|
-
if (ps.name && !
|
|
4444
|
+
if (ps.name && !grants.permissions.includes(ps.name)) grants.permissions.push(ps.name);
|
|
4422
4445
|
if (ps.name === ADMIN_FULL_ACCESS && unscopedUserPsIds.has(ps.id)) hasPlatformAdminGrant = true;
|
|
4423
4446
|
const sysPerms = typeof ps.system_permissions === "string" ? safeJsonParse2(ps.system_permissions, []) : ps.system_permissions ?? ps.systemPermissions;
|
|
4424
4447
|
if (Array.isArray(sysPerms)) {
|
|
4425
4448
|
for (const p of sysPerms) {
|
|
4426
|
-
if (typeof p === "string" && !
|
|
4449
|
+
if (typeof p === "string" && !grants.systemPermissions.includes(p)) grants.systemPermissions.push(p);
|
|
4427
4450
|
}
|
|
4428
4451
|
}
|
|
4429
4452
|
const tabs = typeof ps.tab_permissions === "string" ? safeJsonParse2(ps.tab_permissions, {}) : ps.tab_permissions ?? ps.tabPermissions;
|
|
@@ -4437,20 +4460,20 @@ async function resolveAuthzContext(input) {
|
|
|
4437
4460
|
}
|
|
4438
4461
|
}
|
|
4439
4462
|
}
|
|
4440
|
-
if (Object.keys(mergedTabs).length > 0)
|
|
4463
|
+
if (Object.keys(mergedTabs).length > 0) grants.tabPermissions = mergedTabs;
|
|
4441
4464
|
}
|
|
4442
|
-
if (hasPlatformAdminGrant && !
|
|
4443
|
-
|
|
4465
|
+
if (hasPlatformAdminGrant && !grants.positions.includes(BUILTIN_IDENTITY_PLATFORM_ADMIN)) {
|
|
4466
|
+
grants.positions.unshift(BUILTIN_IDENTITY_PLATFORM_ADMIN);
|
|
4444
4467
|
}
|
|
4445
|
-
|
|
4468
|
+
grants.posture = derivePosture({
|
|
4446
4469
|
isPlatformAdmin: hasPlatformAdminGrant,
|
|
4447
|
-
isTenantAdmin:
|
|
4470
|
+
isTenantAdmin: grants.permissions.includes(ORGANIZATION_ADMIN)
|
|
4448
4471
|
});
|
|
4449
|
-
if (!
|
|
4472
|
+
if (!grants.permissions.includes("ai_seat")) {
|
|
4450
4473
|
const aiAccess = (await getUserRow())?.ai_access;
|
|
4451
|
-
if (aiAccess === true || aiAccess === 1 || aiAccess === "1")
|
|
4474
|
+
if (aiAccess === true || aiAccess === 1 || aiAccess === "1") grants.permissions.push("ai_seat");
|
|
4452
4475
|
}
|
|
4453
|
-
return
|
|
4476
|
+
return grants;
|
|
4454
4477
|
}
|
|
4455
4478
|
function isValidTimeZone(tz) {
|
|
4456
4479
|
try {
|
|
@@ -5774,6 +5797,7 @@ export {
|
|
|
5774
5797
|
resolveAuthzContext,
|
|
5775
5798
|
resolveLocale,
|
|
5776
5799
|
resolveLocalizationContext,
|
|
5800
|
+
resolveUserAuthzGrants,
|
|
5777
5801
|
safeExit,
|
|
5778
5802
|
shouldDenyAnonymous,
|
|
5779
5803
|
signPayload,
|