@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.d.cts CHANGED
@@ -1751,6 +1751,14 @@ interface ResolvedAuthzContext {
1751
1751
  tabPermissions?: Record<string, 'visible' | 'hidden' | 'default_on' | 'default_off'>;
1752
1752
  /** Fellow-org user IDs for RLS scoping of identity tables (`id IN (...)`). */
1753
1753
  org_user_ids: string[];
1754
+ /**
1755
+ * [ADR-0105 D2] Every organization this principal currently holds a VALID
1756
+ * membership in — the caller's org access set, and the read reach of the
1757
+ * `group` tenancy posture (Layer 0 becomes `organization_id IN (...)`).
1758
+ * Resolved here, once, so no surface re-derives it; empty for an anonymous or
1759
+ * membership-less principal, which fails the group wall closed.
1760
+ */
1761
+ accessible_org_ids: string[];
1754
1762
  /**
1755
1763
  * [ADR-0095 D2/D3] The monotonic posture rung this principal resolves to,
1756
1764
  * DERIVED once here from held capability grants (never a better-auth role):
@@ -1781,6 +1789,58 @@ interface ResolveAuthzInput {
1781
1789
  * never throws. Anonymous requests yield `{ positions: [], permissions: [], ... }`.
1782
1790
  */
1783
1791
  declare function resolveAuthzContext(input: ResolveAuthzInput): Promise<ResolvedAuthzContext>;
1792
+ /** The authorization grants a KNOWN user holds — a subset of {@link ResolvedAuthzContext}. */
1793
+ interface UserAuthzGrants {
1794
+ positions: string[];
1795
+ permissions: string[];
1796
+ systemPermissions: string[];
1797
+ /** Fellow-org user IDs for RLS scoping of identity tables (`id IN (...)`). */
1798
+ org_user_ids: string[];
1799
+ /** [ADR-0105 D2] Organizations this user holds a currently-valid membership in. */
1800
+ accessible_org_ids: string[];
1801
+ tabPermissions?: Record<string, 'visible' | 'hidden' | 'default_on' | 'default_off'>;
1802
+ posture?: AuthzPosture;
1803
+ /** The user's unique email (`sys_user`), for `current_user.email` owner RLS. */
1804
+ email?: string;
1805
+ }
1806
+ interface ResolveUserAuthzGrantsOptions {
1807
+ /** Active org/tenant id — scopes org-bound grants (a null-org row is global). */
1808
+ tenantId?: string;
1809
+ /** Clock injection for grant validity windows (tests). */
1810
+ nowMs?: number;
1811
+ /**
1812
+ * Permission names the CALLER already resolved (e.g. API-key scopes) to seed
1813
+ * `permissions` BEFORE permission-set names are appended, so a mixed
1814
+ * API-key+session principal keeps every scope and the ordering is preserved.
1815
+ * Copied, never mutated.
1816
+ */
1817
+ seedPermissions?: string[];
1818
+ /** A caller-supplied email (e.g. from the session) that wins over the `sys_user` read. */
1819
+ seedEmail?: string;
1820
+ }
1821
+ /**
1822
+ * resolveUserAuthzGrants — the userId-driven core of {@link resolveAuthzContext}.
1823
+ *
1824
+ * Given a KNOWN user id, aggregate the authorization grants that user holds:
1825
+ * org-admin positions (`sys_member`), platform-RBAC positions
1826
+ * (`sys_user_position`), user- and position-bound permission sets
1827
+ * (`sys_user_permission_set` / `sys_position_permission_set` →
1828
+ * `sys_permission_set`), the derived `platform_admin` built-in + posture rung,
1829
+ * fellow-org peers for identity-table RLS, and the env-side `ai_seat`.
1830
+ *
1831
+ * Factored out of `resolveAuthzContext` so a surface that already knows WHO the
1832
+ * principal is — with no HTTP request to resolve it from — can build the SAME
1833
+ * envelope through the ONE resolver, instead of re-reading `sys_member` /
1834
+ * `sys_user_position` / `sys_*_permission_set` itself. The motivating consumer
1835
+ * is a `runAs:'user'` automation run resolving the triggering user's grants
1836
+ * (#3356): the record-change hook session carries only a `userId`, so the
1837
+ * automation engine calls this to run the flow's data ops exactly as that user
1838
+ * — not the bare member/everyone fallback the missing grants used to leave it.
1839
+ *
1840
+ * Fail-closed like its parent: every read is defensive, a missing engine/table
1841
+ * yields an empty-but-valid envelope, and it never throws.
1842
+ */
1843
+ declare function resolveUserAuthzGrants(ql: any, userId: string, opts?: ResolveUserAuthzGrantsOptions): Promise<UserAuthzGrants>;
1784
1844
  interface ResolveLocalizationInput {
1785
1845
  ql: any;
1786
1846
  /** Settings service exposing `get(namespace, key, { tenantId, userId })`. */
@@ -2073,12 +2133,16 @@ type BucketGranularity = 'day' | 'week' | 'month' | 'quarter' | 'year';
2073
2133
  * `datetime` field in a reference timezone layers that on top (and, per
2074
2134
  * ADR-0053, a `date` field compares against these `YYYY-MM-DD` bounds directly).
2075
2135
  *
2076
- * Returns `null` for the null/empty bucket, an unparseable key, or a key that
2077
- * is shape-valid but out of range (e.g. `2026-13`, a `-W53` in a 52-week year,
2136
+ * Returns `null` for the empty bucket, an unparseable key, or a key that is
2137
+ * shape-valid but out of range (e.g. `2026-13`, a `-W53` in a 52-week year,
2078
2138
  * `2026-02-30`). Callers drop the range and fall back to an unscoped (superset)
2079
2139
  * drill rather than emit a wrong bound.
2140
+ *
2141
+ * `key` admits `null` because that IS the empty bucket's key on both aggregation
2142
+ * paths (#3839); callers pass a grouped row's dimension value straight through
2143
+ * rather than casting a lie.
2080
2144
  */
2081
- declare function bucketKeyToCalendarRange(key: string, granularity: BucketGranularity): {
2145
+ declare function bucketKeyToCalendarRange(key: string | null | undefined, granularity: BucketGranularity): {
2082
2146
  start: string;
2083
2147
  end: string;
2084
2148
  } | null;
@@ -2201,6 +2265,92 @@ declare function withTransientRetry<T>(fn: (attempt: number) => Promise<T>, opts
2201
2265
  */
2202
2266
  declare function bulkWrite<TRow, TRecord = any>(rows: TRow[], opts: BulkWriteOptions<TRow, TRecord>): Promise<BulkWriteRowResult<TRecord>[]>;
2203
2267
 
2268
+ /**
2269
+ * The slice of an execution context the resolver reads. Structural on purpose —
2270
+ * see {@link filterTokenContextFrom}.
2271
+ */
2272
+ interface ExecutionContextLike {
2273
+ readonly userId?: string;
2274
+ readonly tenantId?: string;
2275
+ readonly timezone?: string;
2276
+ }
2277
+ /**
2278
+ * The request-scoped values a placeholder can resolve against.
2279
+ *
2280
+ * `now` is captured ONCE per resolve call so every token in one filter shares
2281
+ * an instant — otherwise a `$gte {current_month_start}` / `$lt
2282
+ * {next_month_start}` pair evaluated microseconds apart could straddle a
2283
+ * month boundary and silently drop a row.
2284
+ */
2285
+ interface FilterTokenResolutionContext {
2286
+ /** Reference instant. Defaults to `new Date()` at call time. */
2287
+ now?: Date;
2288
+ /** IANA reference timezone for calendar boundaries. Defaults to UTC. */
2289
+ timezone?: string;
2290
+ /** Resolves `{current_user_id}`. */
2291
+ userId?: string;
2292
+ /** Resolves `{current_org_id}`. */
2293
+ orgId?: string;
2294
+ }
2295
+ /**
2296
+ * Raised when a filter carries a placeholder outside the vocabulary.
2297
+ *
2298
+ * Carries `status`/`code` so the REST layer's generic 4xx passthrough maps it
2299
+ * to a **400 with a fixable message** rather than a 500: the caller's filter is
2300
+ * malformed, the server is fine. (Same convention plugin-sharing uses for its
2301
+ * record-scope denial — no runtime dependency in either direction.)
2302
+ */
2303
+ declare class UnknownFilterTokenError extends Error {
2304
+ readonly token: string;
2305
+ readonly suggestion?: string;
2306
+ readonly status = 400;
2307
+ readonly code = "FILTER_TOKEN_UNKNOWN";
2308
+ constructor(token: string, suggestion?: string);
2309
+ }
2310
+ /**
2311
+ * Raised when a token IS in the vocabulary but the request carries no value
2312
+ * for it — an unauthenticated caller filtering on `{current_user_id}`.
2313
+ *
2314
+ * Distinct from {@link UnknownFilterTokenError} because the fix is different:
2315
+ * the metadata is correct, the context is not. Never silently resolves to
2316
+ * `null`/`undefined`, which on most drivers degrades to `IS NULL` and would
2317
+ * quietly hand back rows the filter was written to exclude.
2318
+ */
2319
+ declare class UnresolvedFilterTokenError extends Error {
2320
+ readonly token: string;
2321
+ /** 400, not 500 — see {@link UnknownFilterTokenError}. */
2322
+ readonly status = 400;
2323
+ readonly code = "FILTER_TOKEN_UNRESOLVED";
2324
+ constructor(token: string, detail: string);
2325
+ }
2326
+ /**
2327
+ * Resolve one token NAME (the bit inside the braces) to its concrete value.
2328
+ * Throws {@link UnresolvedFilterTokenError} for a vocabulary token the request
2329
+ * carries no value for. Returns `undefined` only when the token is outside the
2330
+ * vocabulary — callers turn that into {@link UnknownFilterTokenError}.
2331
+ */
2332
+ declare function resolveFilterToken(token: string, ctx?: FilterTokenResolutionContext): unknown;
2333
+ /**
2334
+ * Deep-replace every fully-wrapped placeholder in `filter` with its resolved
2335
+ * value, returning a NEW tree (the caller's metadata is never mutated — a view
2336
+ * or dataset definition is shared across requests, so resolving in place would
2337
+ * bake one request's user id, and one day's dates, into every later render).
2338
+ *
2339
+ * Returns the input unchanged, by reference, when it holds no placeholders.
2340
+ */
2341
+ declare function resolveFilterTokens<T>(filter: T, ctx?: FilterTokenResolutionContext): T;
2342
+ /**
2343
+ * Convenience bridge from an execution context to the resolver's inputs.
2344
+ * `{current_org_id}` reads `tenantId` — the active organization IS the tenant
2345
+ * on the read path (same value the RLS compiler binds to
2346
+ * `current_user.organization_id`).
2347
+ *
2348
+ * Typed structurally, not as `ExecutionContext`, so both the parsed context
2349
+ * (defaults applied) and the pre-parse `ExecutionContextInput` a caller holds
2350
+ * mid-pipeline satisfy it. The three fields read here are optional in both.
2351
+ */
2352
+ declare function filterTokenContextFrom(execCtx: ExecutionContextLike | undefined, now?: Date): FilterTokenResolutionContext;
2353
+
2204
2354
  /**
2205
2355
  * In-memory Map-backed cache fallback.
2206
2356
  *
@@ -2637,4 +2787,4 @@ declare class NamespaceResolver {
2637
2787
  private suggestAlternative;
2638
2788
  }
2639
2789
 
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 };
2790
+ 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 ExecutionContextLike, type FilterTokenResolutionContext, 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, UnknownFilterTokenError, UnresolvedFilterTokenError, type UserAuthzGrants, type VersionCompatibility, bucketKeyToCalendarRange, buildPermissionsFromGrants, bulkWrite, calendarPartsInTz, calendarPartsInTzOrUtc, counterSignPayload, createApiRegistryPlugin, createMemoryCache, createMemoryI18n, createMemoryJob, createMemoryMetadata, createMemoryQueue, createPluginConfigValidator, createPluginPermissionEnforcer, deepMerge, defaultIsTransientError, derivePosture, evaluateAuthGate, extractApiKey, filterTokenContextFrom, generateApiKey, generateEd25519KeyPair, getEnv, getMemoryUsage, hashApiKey, isAuthGateAllowlisted, isExpired, isGrantActive, isGrantExpired, isNode, parseScopes, parseSignature, postureVisibleRows, readAuthoredTranslationLayer, resolveApiKeyPrincipal, resolveAuthzContext, resolveFilterToken, resolveFilterTokens, resolveLocale, resolveLocalizationContext, resolveUserAuthzGrants, safeExit, shouldDenyAnonymous, signPayload, verifyPayload, verifyPlatformSignature, verifyPluginArtifact, verifyPublisherSignature, wireAuthoredTranslationSync, withTransientRetry, zonedDateStartToUtcMs };
package/dist/index.d.ts CHANGED
@@ -1751,6 +1751,14 @@ interface ResolvedAuthzContext {
1751
1751
  tabPermissions?: Record<string, 'visible' | 'hidden' | 'default_on' | 'default_off'>;
1752
1752
  /** Fellow-org user IDs for RLS scoping of identity tables (`id IN (...)`). */
1753
1753
  org_user_ids: string[];
1754
+ /**
1755
+ * [ADR-0105 D2] Every organization this principal currently holds a VALID
1756
+ * membership in — the caller's org access set, and the read reach of the
1757
+ * `group` tenancy posture (Layer 0 becomes `organization_id IN (...)`).
1758
+ * Resolved here, once, so no surface re-derives it; empty for an anonymous or
1759
+ * membership-less principal, which fails the group wall closed.
1760
+ */
1761
+ accessible_org_ids: string[];
1754
1762
  /**
1755
1763
  * [ADR-0095 D2/D3] The monotonic posture rung this principal resolves to,
1756
1764
  * DERIVED once here from held capability grants (never a better-auth role):
@@ -1781,6 +1789,58 @@ interface ResolveAuthzInput {
1781
1789
  * never throws. Anonymous requests yield `{ positions: [], permissions: [], ... }`.
1782
1790
  */
1783
1791
  declare function resolveAuthzContext(input: ResolveAuthzInput): Promise<ResolvedAuthzContext>;
1792
+ /** The authorization grants a KNOWN user holds — a subset of {@link ResolvedAuthzContext}. */
1793
+ interface UserAuthzGrants {
1794
+ positions: string[];
1795
+ permissions: string[];
1796
+ systemPermissions: string[];
1797
+ /** Fellow-org user IDs for RLS scoping of identity tables (`id IN (...)`). */
1798
+ org_user_ids: string[];
1799
+ /** [ADR-0105 D2] Organizations this user holds a currently-valid membership in. */
1800
+ accessible_org_ids: string[];
1801
+ tabPermissions?: Record<string, 'visible' | 'hidden' | 'default_on' | 'default_off'>;
1802
+ posture?: AuthzPosture;
1803
+ /** The user's unique email (`sys_user`), for `current_user.email` owner RLS. */
1804
+ email?: string;
1805
+ }
1806
+ interface ResolveUserAuthzGrantsOptions {
1807
+ /** Active org/tenant id — scopes org-bound grants (a null-org row is global). */
1808
+ tenantId?: string;
1809
+ /** Clock injection for grant validity windows (tests). */
1810
+ nowMs?: number;
1811
+ /**
1812
+ * Permission names the CALLER already resolved (e.g. API-key scopes) to seed
1813
+ * `permissions` BEFORE permission-set names are appended, so a mixed
1814
+ * API-key+session principal keeps every scope and the ordering is preserved.
1815
+ * Copied, never mutated.
1816
+ */
1817
+ seedPermissions?: string[];
1818
+ /** A caller-supplied email (e.g. from the session) that wins over the `sys_user` read. */
1819
+ seedEmail?: string;
1820
+ }
1821
+ /**
1822
+ * resolveUserAuthzGrants — the userId-driven core of {@link resolveAuthzContext}.
1823
+ *
1824
+ * Given a KNOWN user id, aggregate the authorization grants that user holds:
1825
+ * org-admin positions (`sys_member`), platform-RBAC positions
1826
+ * (`sys_user_position`), user- and position-bound permission sets
1827
+ * (`sys_user_permission_set` / `sys_position_permission_set` →
1828
+ * `sys_permission_set`), the derived `platform_admin` built-in + posture rung,
1829
+ * fellow-org peers for identity-table RLS, and the env-side `ai_seat`.
1830
+ *
1831
+ * Factored out of `resolveAuthzContext` so a surface that already knows WHO the
1832
+ * principal is — with no HTTP request to resolve it from — can build the SAME
1833
+ * envelope through the ONE resolver, instead of re-reading `sys_member` /
1834
+ * `sys_user_position` / `sys_*_permission_set` itself. The motivating consumer
1835
+ * is a `runAs:'user'` automation run resolving the triggering user's grants
1836
+ * (#3356): the record-change hook session carries only a `userId`, so the
1837
+ * automation engine calls this to run the flow's data ops exactly as that user
1838
+ * — not the bare member/everyone fallback the missing grants used to leave it.
1839
+ *
1840
+ * Fail-closed like its parent: every read is defensive, a missing engine/table
1841
+ * yields an empty-but-valid envelope, and it never throws.
1842
+ */
1843
+ declare function resolveUserAuthzGrants(ql: any, userId: string, opts?: ResolveUserAuthzGrantsOptions): Promise<UserAuthzGrants>;
1784
1844
  interface ResolveLocalizationInput {
1785
1845
  ql: any;
1786
1846
  /** Settings service exposing `get(namespace, key, { tenantId, userId })`. */
@@ -2073,12 +2133,16 @@ type BucketGranularity = 'day' | 'week' | 'month' | 'quarter' | 'year';
2073
2133
  * `datetime` field in a reference timezone layers that on top (and, per
2074
2134
  * ADR-0053, a `date` field compares against these `YYYY-MM-DD` bounds directly).
2075
2135
  *
2076
- * Returns `null` for the null/empty bucket, an unparseable key, or a key that
2077
- * is shape-valid but out of range (e.g. `2026-13`, a `-W53` in a 52-week year,
2136
+ * Returns `null` for the empty bucket, an unparseable key, or a key that is
2137
+ * shape-valid but out of range (e.g. `2026-13`, a `-W53` in a 52-week year,
2078
2138
  * `2026-02-30`). Callers drop the range and fall back to an unscoped (superset)
2079
2139
  * drill rather than emit a wrong bound.
2140
+ *
2141
+ * `key` admits `null` because that IS the empty bucket's key on both aggregation
2142
+ * paths (#3839); callers pass a grouped row's dimension value straight through
2143
+ * rather than casting a lie.
2080
2144
  */
2081
- declare function bucketKeyToCalendarRange(key: string, granularity: BucketGranularity): {
2145
+ declare function bucketKeyToCalendarRange(key: string | null | undefined, granularity: BucketGranularity): {
2082
2146
  start: string;
2083
2147
  end: string;
2084
2148
  } | null;
@@ -2201,6 +2265,92 @@ declare function withTransientRetry<T>(fn: (attempt: number) => Promise<T>, opts
2201
2265
  */
2202
2266
  declare function bulkWrite<TRow, TRecord = any>(rows: TRow[], opts: BulkWriteOptions<TRow, TRecord>): Promise<BulkWriteRowResult<TRecord>[]>;
2203
2267
 
2268
+ /**
2269
+ * The slice of an execution context the resolver reads. Structural on purpose —
2270
+ * see {@link filterTokenContextFrom}.
2271
+ */
2272
+ interface ExecutionContextLike {
2273
+ readonly userId?: string;
2274
+ readonly tenantId?: string;
2275
+ readonly timezone?: string;
2276
+ }
2277
+ /**
2278
+ * The request-scoped values a placeholder can resolve against.
2279
+ *
2280
+ * `now` is captured ONCE per resolve call so every token in one filter shares
2281
+ * an instant — otherwise a `$gte {current_month_start}` / `$lt
2282
+ * {next_month_start}` pair evaluated microseconds apart could straddle a
2283
+ * month boundary and silently drop a row.
2284
+ */
2285
+ interface FilterTokenResolutionContext {
2286
+ /** Reference instant. Defaults to `new Date()` at call time. */
2287
+ now?: Date;
2288
+ /** IANA reference timezone for calendar boundaries. Defaults to UTC. */
2289
+ timezone?: string;
2290
+ /** Resolves `{current_user_id}`. */
2291
+ userId?: string;
2292
+ /** Resolves `{current_org_id}`. */
2293
+ orgId?: string;
2294
+ }
2295
+ /**
2296
+ * Raised when a filter carries a placeholder outside the vocabulary.
2297
+ *
2298
+ * Carries `status`/`code` so the REST layer's generic 4xx passthrough maps it
2299
+ * to a **400 with a fixable message** rather than a 500: the caller's filter is
2300
+ * malformed, the server is fine. (Same convention plugin-sharing uses for its
2301
+ * record-scope denial — no runtime dependency in either direction.)
2302
+ */
2303
+ declare class UnknownFilterTokenError extends Error {
2304
+ readonly token: string;
2305
+ readonly suggestion?: string;
2306
+ readonly status = 400;
2307
+ readonly code = "FILTER_TOKEN_UNKNOWN";
2308
+ constructor(token: string, suggestion?: string);
2309
+ }
2310
+ /**
2311
+ * Raised when a token IS in the vocabulary but the request carries no value
2312
+ * for it — an unauthenticated caller filtering on `{current_user_id}`.
2313
+ *
2314
+ * Distinct from {@link UnknownFilterTokenError} because the fix is different:
2315
+ * the metadata is correct, the context is not. Never silently resolves to
2316
+ * `null`/`undefined`, which on most drivers degrades to `IS NULL` and would
2317
+ * quietly hand back rows the filter was written to exclude.
2318
+ */
2319
+ declare class UnresolvedFilterTokenError extends Error {
2320
+ readonly token: string;
2321
+ /** 400, not 500 — see {@link UnknownFilterTokenError}. */
2322
+ readonly status = 400;
2323
+ readonly code = "FILTER_TOKEN_UNRESOLVED";
2324
+ constructor(token: string, detail: string);
2325
+ }
2326
+ /**
2327
+ * Resolve one token NAME (the bit inside the braces) to its concrete value.
2328
+ * Throws {@link UnresolvedFilterTokenError} for a vocabulary token the request
2329
+ * carries no value for. Returns `undefined` only when the token is outside the
2330
+ * vocabulary — callers turn that into {@link UnknownFilterTokenError}.
2331
+ */
2332
+ declare function resolveFilterToken(token: string, ctx?: FilterTokenResolutionContext): unknown;
2333
+ /**
2334
+ * Deep-replace every fully-wrapped placeholder in `filter` with its resolved
2335
+ * value, returning a NEW tree (the caller's metadata is never mutated — a view
2336
+ * or dataset definition is shared across requests, so resolving in place would
2337
+ * bake one request's user id, and one day's dates, into every later render).
2338
+ *
2339
+ * Returns the input unchanged, by reference, when it holds no placeholders.
2340
+ */
2341
+ declare function resolveFilterTokens<T>(filter: T, ctx?: FilterTokenResolutionContext): T;
2342
+ /**
2343
+ * Convenience bridge from an execution context to the resolver's inputs.
2344
+ * `{current_org_id}` reads `tenantId` — the active organization IS the tenant
2345
+ * on the read path (same value the RLS compiler binds to
2346
+ * `current_user.organization_id`).
2347
+ *
2348
+ * Typed structurally, not as `ExecutionContext`, so both the parsed context
2349
+ * (defaults applied) and the pre-parse `ExecutionContextInput` a caller holds
2350
+ * mid-pipeline satisfy it. The three fields read here are optional in both.
2351
+ */
2352
+ declare function filterTokenContextFrom(execCtx: ExecutionContextLike | undefined, now?: Date): FilterTokenResolutionContext;
2353
+
2204
2354
  /**
2205
2355
  * In-memory Map-backed cache fallback.
2206
2356
  *
@@ -2637,4 +2787,4 @@ declare class NamespaceResolver {
2637
2787
  private suggestAlternative;
2638
2788
  }
2639
2789
 
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 };
2790
+ 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 ExecutionContextLike, type FilterTokenResolutionContext, 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, UnknownFilterTokenError, UnresolvedFilterTokenError, type UserAuthzGrants, type VersionCompatibility, bucketKeyToCalendarRange, buildPermissionsFromGrants, bulkWrite, calendarPartsInTz, calendarPartsInTzOrUtc, counterSignPayload, createApiRegistryPlugin, createMemoryCache, createMemoryI18n, createMemoryJob, createMemoryMetadata, createMemoryQueue, createPluginConfigValidator, createPluginPermissionEnforcer, deepMerge, defaultIsTransientError, derivePosture, evaluateAuthGate, extractApiKey, filterTokenContextFrom, generateApiKey, generateEd25519KeyPair, getEnv, getMemoryUsage, hashApiKey, isAuthGateAllowlisted, isExpired, isGrantActive, isGrantExpired, isNode, parseScopes, parseSignature, postureVisibleRows, readAuthoredTranslationLayer, resolveApiKeyPrincipal, resolveAuthzContext, resolveFilterToken, resolveFilterTokens, resolveLocale, resolveLocalizationContext, resolveUserAuthzGrants, safeExit, shouldDenyAnonymous, signPayload, verifyPayload, verifyPlatformSignature, verifyPluginArtifact, verifyPublisherSignature, wireAuthoredTranslationSync, withTransientRetry, zonedDateStartToUtcMs };