@objectstack/plugin-sharing 6.8.0 → 6.9.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.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/sharing-service.ts","../src/team-graph.ts","../src/department-graph.ts","../src/sharing-rule-service.ts","../src/rule-hooks.ts","../src/sharing-plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * @objectstack/plugin-sharing\n *\n * Record-level sharing for ObjectStack. Implements `ISharingService`\n * and installs an engine middleware that enforces\n * `object.sharingModel` (`private` / `read`) against the\n * authenticated execution context.\n */\n\nexport { SysRecordShare, SysSharingRule } from '@objectstack/platform-objects/security';\nexport { SysDepartment, SysDepartmentMember } from '@objectstack/platform-objects/identity';\nexport {\n SharingService,\n type SharingEngine,\n type SharingServiceOptions,\n} from './sharing-service.js';\nexport {\n SharingRuleService,\n type SharingRuleServiceOptions,\n} from './sharing-rule-service.js';\nexport { TeamGraphService, expandPrincipal, type TeamGraphOptions } from './team-graph.js';\nexport { DepartmentGraphService, type DepartmentGraphOptions } from './department-graph.js';\nexport { bindRuleHooks, unbindAllRuleHooks, SHARING_RULE_HOOK_PACKAGE } from './rule-hooks.js';\nexport {\n SharingServicePlugin,\n buildSharingMiddleware,\n type SharingPluginOptions,\n} from './sharing-plugin.js';\nexport type {\n ISharingService,\n ISharingRuleService,\n ITeamGraphService,\n IDepartmentGraphService,\n RecordShare,\n GrantShareInput,\n SharingExecutionContext,\n ShareAccessLevel,\n ShareRecipientType,\n ShareSource,\n SharingRuleRow,\n DefineSharingRuleInput,\n SharingRuleEvaluationResult,\n SharingRuleRecipientType,\n} from '@objectstack/spec/contracts';\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n ISharingService,\n RecordShare,\n GrantShareInput,\n SharingExecutionContext,\n ShareAccessLevel,\n} from '@objectstack/spec/contracts';\n\n/**\n * Shape of the data engine the service actually needs. Kept narrow so\n * unit tests can pass an in-memory fake without depending on the full\n * ObjectQL engine class.\n */\nexport interface SharingEngine {\n find(object: string, options?: any): Promise<any[]>;\n findOne?(object: string, options?: any): Promise<any>;\n insert(object: string, data: any, options?: any): Promise<any>;\n update(object: string, idOrData: any, dataOrOptions?: any, options?: any): Promise<any>;\n delete(object: string, options?: any): Promise<any>;\n getSchema?(object: string): any | undefined;\n}\n\n/**\n * Random share id. Keeps the plugin self-contained (no `crypto.randomUUID`\n * dependency in environments that don't expose it on `globalThis`).\n */\nfunction makeShareId(): string {\n const g: any = globalThis as any;\n if (g.crypto?.randomUUID) return `shr_${g.crypto.randomUUID()}`;\n return `shr_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/** System-elevated context for the plugin's own queries / mutations. */\nconst SYSTEM_CTX = { isSystem: true, roles: [], permissions: [] } as const;\n\n/**\n * Owner field convention. Hard-coded to `owner_id` for MVP — the\n * sharing model in Salesforce / ServiceNow / Dynamics all assume a\n * single owner field, and customising it is a follow-up. Objects\n * without `owner_id` are treated as \"unowned\" and read filters are\n * suppressed (they fall back to OWD-public behaviour).\n */\nconst OWNER_FIELD = 'owner_id';\n\n/**\n * Effective sharing model. Anything other than `private` / `read` is\n * treated as public — that includes objects that don't declare\n * `sharingModel` at all, so existing CRM behaviour is preserved\n * until an admin opts an object in.\n */\nfunction effectiveSharingModel(schema: any): 'private' | 'read' | 'public' {\n const m = schema?.sharingModel ?? schema?.security?.sharingModel;\n if (m === 'private') return 'private';\n if (m === 'read') return 'read';\n return 'public';\n}\n\nfunction hasOwnerField(schema: any): boolean {\n return Boolean(schema?.fields && OWNER_FIELD in schema.fields);\n}\n\nexport interface SharingServiceOptions {\n engine: SharingEngine;\n /** Object names that bypass sharing — typically platform internals. */\n bypassObjects?: string[];\n}\n\n/**\n * Default `ISharingService` implementation.\n *\n * Stores every grant in `sys_record_share`. The plugin layer registers\n * an engine middleware that calls `buildReadFilter` / `canEdit` so that\n * neither this class nor its callers need to know about middleware\n * plumbing.\n */\nexport class SharingService implements ISharingService {\n private readonly engine: SharingEngine;\n private readonly bypassObjects: Set<string>;\n\n constructor(options: SharingServiceOptions) {\n this.engine = options.engine;\n this.bypassObjects = new Set([\n 'sys_record_share',\n 'sys_user',\n 'sys_organization',\n 'sys_member',\n 'sys_role',\n 'sys_permission_set',\n 'sys_user_permission_set',\n 'sys_role_permission_set',\n ...(options.bypassObjects ?? []),\n ]);\n }\n\n /**\n * Build a `FilterCondition` restricting `find` to records the caller\n * may see. Returns `null` when no filter should be applied.\n */\n async buildReadFilter(\n object: string,\n context: SharingExecutionContext,\n ): Promise<unknown | null> {\n if (this.shouldBypass(object, context)) return null;\n\n const schema = this.engine.getSchema?.(object);\n if (!schema) return null;\n if (effectiveSharingModel(schema) !== 'private') return null;\n if (!hasOwnerField(schema)) return null;\n if (!context.userId) {\n // Authenticated context with no user id is a degenerate case\n // (e.g. anonymous API key). Restrict to nothing rather than\n // accidentally leaking owner-only data.\n return { id: '__deny_all__' };\n }\n\n const grants = await this.engine.find('sys_record_share', {\n filter: {\n object_name: object,\n recipient_type: 'user',\n recipient_id: context.userId,\n },\n fields: ['record_id', 'access_level'],\n limit: 5000,\n context: SYSTEM_CTX,\n });\n\n const grantedIds: string[] = Array.isArray(grants)\n ? grants.map((g: any) => String(g.record_id)).filter(Boolean)\n : [];\n\n if (grantedIds.length === 0) {\n return { [OWNER_FIELD]: context.userId };\n }\n\n return {\n $or: [\n { [OWNER_FIELD]: context.userId },\n { id: { $in: grantedIds } },\n ],\n };\n }\n\n /**\n * Return `true` if the caller may edit `(object, recordId)`. Always\n * `true` for system context, public objects, and objects without an\n * owner field.\n */\n async canEdit(\n object: string,\n recordId: string,\n context: SharingExecutionContext,\n ): Promise<boolean> {\n if (this.shouldBypass(object, context)) return true;\n\n const schema = this.engine.getSchema?.(object);\n if (!schema) return true;\n const model = effectiveSharingModel(schema);\n if (model === 'public') return true;\n if (!hasOwnerField(schema)) return true;\n if (!context.userId) return false;\n\n // 1) Ownership — fast path.\n const own = await this.engine.find(object, {\n filter: { id: recordId },\n fields: ['id', OWNER_FIELD],\n limit: 1,\n context: SYSTEM_CTX,\n });\n const owner = Array.isArray(own) && own[0] ? (own[0] as any)[OWNER_FIELD] : undefined;\n if (owner && String(owner) === String(context.userId)) return true;\n\n // 2) Explicit edit / full share.\n const editGrants = await this.engine.find('sys_record_share', {\n filter: {\n object_name: object,\n record_id: recordId,\n recipient_type: 'user',\n recipient_id: context.userId,\n access_level: { $in: ['edit', 'full'] },\n },\n fields: ['id'],\n limit: 1,\n context: SYSTEM_CTX,\n });\n return Array.isArray(editGrants) && editGrants.length > 0;\n }\n\n /**\n * Upsert a share row. Returning the existing row when an identical\n * grant already exists keeps the REST endpoint idempotent.\n */\n async grant(\n input: GrantShareInput,\n context: SharingExecutionContext,\n ): Promise<RecordShare> {\n if (!input.object) throw new Error('VALIDATION_FAILED: object is required');\n if (!input.recordId) throw new Error('VALIDATION_FAILED: recordId is required');\n if (!input.recipientId) throw new Error('VALIDATION_FAILED: recipientId is required');\n\n const recipientType = input.recipientType ?? 'user';\n const accessLevel: ShareAccessLevel = input.accessLevel ?? 'read';\n const source = input.source ?? 'manual';\n\n // Upsert: if a row with same (object, record, recipient) exists,\n // update its access level / reason; otherwise insert a new one.\n const existing = await this.engine.find('sys_record_share', {\n filter: {\n object_name: input.object,\n record_id: input.recordId,\n recipient_type: recipientType,\n recipient_id: input.recipientId,\n },\n limit: 1,\n context: SYSTEM_CTX,\n });\n const now = new Date().toISOString();\n if (Array.isArray(existing) && existing[0]) {\n const row: any = existing[0];\n const patch: any = {\n id: row.id,\n access_level: accessLevel,\n source,\n source_id: input.sourceId ?? row.source_id ?? null,\n reason: input.reason ?? row.reason ?? null,\n updated_at: now,\n };\n await this.engine.update('sys_record_share', patch, { context: SYSTEM_CTX });\n return { ...row, ...patch } as RecordShare;\n }\n\n const id = makeShareId();\n const row: any = {\n id,\n object_name: input.object,\n record_id: input.recordId,\n recipient_type: recipientType,\n recipient_id: input.recipientId,\n access_level: accessLevel,\n source,\n source_id: input.sourceId ?? null,\n granted_by: context.userId ?? null,\n reason: input.reason ?? null,\n created_at: now,\n updated_at: now,\n };\n await this.engine.insert('sys_record_share', row, { context: SYSTEM_CTX });\n return row as RecordShare;\n }\n\n /** Delete a share row by id. No-op when not found. */\n async revoke(shareId: string, _context: SharingExecutionContext): Promise<void> {\n if (!shareId) throw new Error('VALIDATION_FAILED: shareId is required');\n await this.engine.delete('sys_record_share', {\n where: { id: shareId },\n context: SYSTEM_CTX,\n });\n }\n\n /** List share rows for `(object, recordId)`. */\n async listShares(\n object: string,\n recordId: string,\n _context: SharingExecutionContext,\n ): Promise<RecordShare[]> {\n const rows = await this.engine.find('sys_record_share', {\n filter: { object_name: object, record_id: recordId },\n orderBy: [{ field: 'created_at', direction: 'desc' }],\n limit: 500,\n context: SYSTEM_CTX,\n });\n return Array.isArray(rows) ? (rows as RecordShare[]) : [];\n }\n\n // ── helpers ──────────────────────────────────────────────────────\n\n private shouldBypass(object: string, context: SharingExecutionContext): boolean {\n if (context?.isSystem) return true;\n if (this.bypassObjects.has(object)) return true;\n return false;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { ITeamGraphService } from '@objectstack/spec/contracts';\nimport type { SharingEngine } from './sharing-service.js';\n\nconst SYSTEM_CTX = { isSystem: true, roles: [], permissions: [] } as const;\n\ntype Cache = {\n expandUsers?: Map<string, string[]>;\n expandRole?: Map<string, string[]>;\n manager?: Map<string, string | null>;\n};\n\nexport interface TeamGraphOptions {\n engine: SharingEngine;\n /** Optional tenant scope; null means cross-tenant lookups. */\n organizationId?: string | null;\n /** Optional shared cache across one evaluator pass. */\n cache?: Cache;\n}\n\n/**\n * Default {@link ITeamGraphService} implementation backed by\n * `sys_team` + `sys_team_member` (better-auth's flat collaboration\n * grouping) plus `sys_member.role` for tenant role expansion.\n *\n * **This service does NOT walk a hierarchy.** Teams here are flat —\n * the enterprise org chart lives in `sys_department` and is served by\n * {@link DepartmentGraphService}.\n *\n * All queries elevate to {@link SYSTEM_CTX} since the graph is platform\n * metadata; callers (sharing rule evaluator, approval engine) own their\n * own enforcement.\n */\nexport class TeamGraphService implements ITeamGraphService {\n private readonly engine: SharingEngine;\n private readonly organizationId: string | null;\n private readonly cache: Cache;\n\n constructor(opts: TeamGraphOptions) {\n this.engine = opts.engine;\n this.organizationId = opts.organizationId ?? null;\n this.cache = opts.cache ?? {};\n this.cache.expandUsers ??= new Map();\n this.cache.expandRole ??= new Map();\n this.cache.manager ??= new Map();\n }\n\n async expandUsers(teamId: string): Promise<string[]> {\n if (!teamId) return [];\n const cached = this.cache.expandUsers!.get(teamId);\n if (cached) return cached;\n\n let rows: any[] = [];\n try {\n rows = await this.engine.find('sys_team_member', {\n filter: { team_id: teamId },\n fields: ['user_id'],\n limit: 10000,\n context: SYSTEM_CTX,\n });\n } catch {\n rows = [];\n }\n const users = Array.from(new Set((rows ?? []).map((r: any) => String(r.user_id ?? '')).filter(Boolean)));\n this.cache.expandUsers!.set(teamId, users);\n return users;\n }\n\n async expandRoleUsers(roleName: string, organizationId?: string): Promise<string[]> {\n if (!roleName) return [];\n const key = `${organizationId ?? this.organizationId ?? '*'}::${roleName}`;\n const cached = this.cache.expandRole!.get(key);\n if (cached) return cached;\n const filter: Record<string, unknown> = { role: roleName };\n const org = organizationId ?? this.organizationId;\n if (org) filter.organization_id = org;\n let rows: any[] = [];\n try {\n rows = await this.engine.find('sys_member', {\n filter,\n fields: ['user_id'],\n limit: 10000,\n context: SYSTEM_CTX,\n });\n } catch {\n rows = [];\n }\n const users = Array.from(new Set((rows ?? []).map((r: any) => String(r.user_id ?? '')).filter(Boolean)));\n this.cache.expandRole!.set(key, users);\n return users;\n }\n\n async managerOf(userId: string, _organizationId?: string): Promise<string | null> {\n if (!userId) return null;\n if (this.cache.manager!.has(userId)) return this.cache.manager!.get(userId) ?? null;\n let row: any = null;\n try {\n const rows = await this.engine.find('sys_user', {\n filter: { id: userId },\n fields: ['id', 'manager_id'],\n limit: 1,\n context: SYSTEM_CTX,\n });\n row = Array.isArray(rows) ? rows[0] : null;\n } catch {\n row = null;\n }\n const mgr = row?.manager_id ? String(row.manager_id) : null;\n this.cache.manager!.set(userId, mgr);\n return mgr;\n }\n}\n\n/**\n * Convenience helper used by the sharing-rule evaluator + approval\n * engine: expand an approver / recipient descriptor of the form\n * `{type, value}` into a flat list of user IDs by routing to the\n * appropriate graph service.\n *\n * `team` → flat team members (this service).\n * `department` → recursive department members (delegated; requires a\n * {@link IDepartmentGraphService} instance passed in `opts.dept`).\n * `role` → tenant role members.\n * `manager` → submitter's manager via `record[value] ?? record.owner_id`.\n * `field` → literal user id stored in `record[value]`.\n * `user` → literal value.\n * Anything else echoes `type:value` for back-compat with legacy\n * substring-match approver flows.\n */\nexport async function expandPrincipal(\n input: { type: string; value: string; record?: any },\n ctx: { team: TeamGraphService; dept?: { expandUsers(id: string): Promise<string[]> }; organizationId?: string | null },\n): Promise<string[]> {\n const t = input.type;\n const v = String(input.value ?? '');\n if (!v) return [];\n if (t === 'user') return [v];\n if (t === 'team') return ctx.team.expandUsers(v);\n if (t === 'department' || t === 'dept') {\n if (ctx.dept) return ctx.dept.expandUsers(v);\n return [`${t}:${v}`];\n }\n if (t === 'role') return ctx.team.expandRoleUsers(v, ctx.organizationId ?? undefined);\n if (t === 'field' && input.record) {\n const fv = (input.record as any)[v];\n return fv ? [String(fv)] : [];\n }\n if (t === 'manager' && input.record) {\n const subject = (input.record as any)[v] ?? (input.record as any).owner_id;\n if (!subject) return [];\n const mgr = await ctx.team.managerOf(String(subject), ctx.organizationId ?? undefined);\n return mgr ? [mgr] : [];\n }\n // queue / unknown — fall back to raw prefix string so existing\n // string-match approver flows keep working.\n return [`${t}:${v}`];\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { IDepartmentGraphService } from '@objectstack/spec/contracts';\nimport type { SharingEngine } from './sharing-service.js';\nimport { TeamGraphService } from './team-graph.js';\n\nconst SYSTEM_CTX = { isSystem: true, roles: [], permissions: [] } as const;\n\ntype DeptCache = {\n descendants?: Map<string, string[]>;\n expandUsers?: Map<string, string[]>;\n head?: Map<string, string | null>;\n};\n\nexport interface DepartmentGraphOptions {\n engine: SharingEngine;\n /** Optional tenant scope; null means cross-tenant lookups. */\n organizationId?: string | null;\n /** Optional shared cache across one evaluator pass. */\n cache?: DeptCache;\n /**\n * Optional team-graph instance to share role / manager lookups with —\n * department graph proxies `managerOf` through so callers only need one\n * service.\n */\n teamGraph?: TeamGraphService;\n}\n\n/**\n * Default {@link IDepartmentGraphService} implementation.\n *\n * Walks `sys_department.parent_department_id` for hierarchy and\n * `sys_department_member` for member expansion. Treats the optional\n * `active` flag as a hard filter (inactive departments contribute no\n * members and stop BFS descent into their subtrees).\n *\n * Reuses {@link TeamGraphService.managerOf} for user-level manager\n * lookup so callers can use this single service in approval / sharing\n * pipelines.\n */\nexport class DepartmentGraphService implements IDepartmentGraphService {\n private readonly engine: SharingEngine;\n private readonly organizationId: string | null;\n private readonly cache: DeptCache;\n private readonly teamGraph?: TeamGraphService;\n\n constructor(opts: DepartmentGraphOptions) {\n this.engine = opts.engine;\n this.organizationId = opts.organizationId ?? null;\n this.cache = opts.cache ?? {};\n this.cache.descendants ??= new Map();\n this.cache.expandUsers ??= new Map();\n this.cache.head ??= new Map();\n this.teamGraph = opts.teamGraph;\n }\n\n async descendants(departmentId: string): Promise<string[]> {\n if (!departmentId) return [];\n const cached = this.cache.descendants!.get(departmentId);\n if (cached) return cached;\n\n // Verify seed itself is active + within tenant scope.\n let seedActive = true;\n try {\n const seedRows = await this.engine.find('sys_department', {\n filter: this.orgScope({ id: departmentId }),\n fields: ['id', 'active'],\n limit: 1,\n context: SYSTEM_CTX,\n });\n const seedRow: any = Array.isArray(seedRows) ? seedRows[0] : null;\n if (!seedRow) seedActive = false;\n else if (seedRow.active === false) seedActive = false;\n } catch {\n seedActive = false;\n }\n if (!seedActive) {\n this.cache.descendants!.set(departmentId, []);\n return [];\n }\n\n const seen = new Set<string>([departmentId]);\n const queue: string[] = [departmentId];\n while (queue.length) {\n const parent = queue.shift()!;\n let children: any[] = [];\n try {\n children = await this.engine.find('sys_department', {\n filter: this.orgScope({ parent_department_id: parent, active: { $ne: false } }),\n fields: ['id'],\n limit: 1000,\n context: SYSTEM_CTX,\n });\n } catch {\n children = [];\n }\n for (const c of children ?? []) {\n const cid = String((c as any).id ?? '');\n if (cid && !seen.has(cid)) {\n seen.add(cid);\n queue.push(cid);\n }\n }\n }\n const out = Array.from(seen);\n this.cache.descendants!.set(departmentId, out);\n return out;\n }\n\n async expandUsers(departmentId: string): Promise<string[]> {\n if (!departmentId) return [];\n const cached = this.cache.expandUsers!.get(departmentId);\n if (cached) return cached;\n\n const depts = await this.descendants(departmentId);\n if (depts.length === 0) return [];\n\n let rows: any[] = [];\n try {\n rows = await this.engine.find('sys_department_member', {\n filter: { department_id: { $in: depts } },\n fields: ['user_id'],\n limit: 10000,\n context: SYSTEM_CTX,\n });\n } catch {\n rows = [];\n }\n const users = Array.from(\n new Set((rows ?? []).map((r: any) => String(r.user_id ?? '')).filter(Boolean)),\n );\n this.cache.expandUsers!.set(departmentId, users);\n return users;\n }\n\n async headOf(departmentId: string): Promise<string | null> {\n if (!departmentId) return null;\n if (this.cache.head!.has(departmentId)) return this.cache.head!.get(departmentId) ?? null;\n let row: any = null;\n try {\n const rows = await this.engine.find('sys_department', {\n filter: { id: departmentId },\n fields: ['id', 'manager_user_id'],\n limit: 1,\n context: SYSTEM_CTX,\n });\n row = Array.isArray(rows) ? rows[0] : null;\n } catch {\n row = null;\n }\n const head = row?.manager_user_id ? String(row.manager_user_id) : null;\n this.cache.head!.set(departmentId, head);\n return head;\n }\n\n async managerOf(userId: string, organizationId?: string): Promise<string | null> {\n if (this.teamGraph) return this.teamGraph.managerOf(userId, organizationId);\n // Standalone fallback: read sys_user.manager_id directly.\n if (!userId) return null;\n try {\n const rows = await this.engine.find('sys_user', {\n filter: { id: userId },\n fields: ['id', 'manager_id'],\n limit: 1,\n context: SYSTEM_CTX,\n });\n const row: any = Array.isArray(rows) ? rows[0] : null;\n return row?.manager_id ? String(row.manager_id) : null;\n } catch {\n return null;\n }\n }\n\n private orgScope(filter: Record<string, unknown>): Record<string, unknown> {\n if (this.organizationId) return { ...filter, organization_id: this.organizationId };\n return filter;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n ISharingRuleService,\n DefineSharingRuleInput,\n SharingRuleRow,\n SharingRuleEvaluationResult,\n SharingExecutionContext,\n ShareAccessLevel,\n SharingRuleRecipientType,\n} from '@objectstack/spec/contracts';\nimport type { SharingEngine } from './sharing-service.js';\nimport type { SharingService } from './sharing-service.js';\nimport { TeamGraphService } from './team-graph.js';\nimport { DepartmentGraphService } from './department-graph.js';\n\nconst SYSTEM_CTX = { isSystem: true, roles: [], permissions: [] } as const;\n\nfunction uid(prefix: string): string {\n const g: any = globalThis as any;\n if (g.crypto?.randomUUID) return `${prefix}_${g.crypto.randomUUID()}`;\n return `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction parseCriteria(raw: unknown): unknown | undefined {\n if (raw == null || raw === '') return undefined;\n if (typeof raw === 'string') {\n const trimmed = raw.trim();\n if (!trimmed) return undefined;\n try {\n return JSON.parse(trimmed);\n } catch {\n // Treat unparsable strings as opaque — most likely a CEL source\n // that v1's evaluator doesn't grok yet; rule will match nothing.\n return undefined;\n }\n }\n return raw;\n}\n\nfunction rowFromRule(row: any): SharingRuleRow {\n return {\n id: row.id,\n organization_id: row.organization_id ?? null,\n name: row.name,\n label: row.label,\n description: row.description ?? null,\n object_name: row.object_name,\n criteria: parseCriteria(row.criteria_json),\n recipient_type: row.recipient_type as SharingRuleRecipientType,\n recipient_id: row.recipient_id,\n access_level: row.access_level as ShareAccessLevel,\n active: row.active !== false,\n created_at: row.created_at ?? undefined,\n updated_at: row.updated_at ?? undefined,\n };\n}\n\nexport interface SharingRuleServiceOptions {\n engine: SharingEngine;\n sharing: SharingService;\n logger?: { info?: Function; warn?: Function; error?: Function; debug?: Function };\n}\n\n/**\n * Default {@link ISharingRuleService} implementation.\n *\n * Stores rule definitions in `sys_sharing_rule` and materialises grants\n * as `sys_record_share` rows with `source='rule'` and `source_id={ruleId}`\n * so reconcile can diff old grants vs fresh evaluation results without\n * touching manual / team-derived shares.\n */\nexport class SharingRuleService implements ISharingRuleService {\n private readonly engine: SharingEngine;\n private readonly sharing: SharingService;\n private readonly logger?: SharingRuleServiceOptions['logger'];\n\n constructor(opts: SharingRuleServiceOptions) {\n this.engine = opts.engine;\n this.sharing = opts.sharing;\n this.logger = opts.logger;\n }\n\n async defineRule(input: DefineSharingRuleInput, context: SharingExecutionContext): Promise<SharingRuleRow> {\n if (!input.name) throw new Error('VALIDATION_FAILED: name is required');\n if (!input.label) throw new Error('VALIDATION_FAILED: label is required');\n if (!input.object) throw new Error('VALIDATION_FAILED: object is required');\n if (!input.recipientType) throw new Error('VALIDATION_FAILED: recipientType is required');\n if (!input.recipientId) throw new Error('VALIDATION_FAILED: recipientId is required');\n\n const orgId = (context as any)?.organizationId ?? (context as any)?.tenantId ?? null;\n const now = new Date().toISOString();\n const accessLevel: ShareAccessLevel = input.accessLevel ?? 'read';\n const active = input.active !== false;\n const criteriaJson = input.criteria == null\n ? null\n : (typeof input.criteria === 'string' ? input.criteria : JSON.stringify(input.criteria));\n\n const existing = await this.engine.find('sys_sharing_rule', {\n filter: orgId ? { name: input.name, organization_id: orgId } : { name: input.name },\n limit: 1,\n context: SYSTEM_CTX,\n });\n if (Array.isArray(existing) && existing[0]) {\n const row: any = existing[0];\n const patch: any = {\n id: row.id,\n label: input.label,\n description: input.description ?? null,\n object_name: input.object,\n criteria_json: criteriaJson,\n recipient_type: input.recipientType,\n recipient_id: input.recipientId,\n access_level: accessLevel,\n active,\n updated_at: now,\n };\n await this.engine.update('sys_sharing_rule', patch, { context: SYSTEM_CTX });\n return rowFromRule({ ...row, ...patch });\n }\n\n const newRow: any = {\n id: uid('srule'),\n organization_id: orgId,\n name: input.name,\n label: input.label,\n description: input.description ?? null,\n object_name: input.object,\n criteria_json: criteriaJson,\n recipient_type: input.recipientType,\n recipient_id: input.recipientId,\n access_level: accessLevel,\n active,\n created_at: now,\n updated_at: now,\n };\n await this.engine.insert('sys_sharing_rule', newRow, { context: SYSTEM_CTX });\n return rowFromRule(newRow);\n }\n\n async listRules(\n filter: { object?: string; activeOnly?: boolean },\n context: SharingExecutionContext,\n ): Promise<SharingRuleRow[]> {\n const where: any = {};\n if (filter.object) where.object_name = filter.object;\n if (filter.activeOnly) where.active = true;\n const orgId = (context as any)?.organizationId ?? (context as any)?.tenantId;\n if (orgId) where.organization_id = orgId;\n const rows = await this.engine.find('sys_sharing_rule', {\n filter: where,\n orderBy: [{ field: 'name', direction: 'asc' }],\n limit: 1000,\n context: SYSTEM_CTX,\n });\n return Array.isArray(rows) ? rows.map(rowFromRule) : [];\n }\n\n async getRule(idOrName: string, context: SharingExecutionContext): Promise<SharingRuleRow | null> {\n if (!idOrName) return null;\n const orgId = (context as any)?.organizationId ?? (context as any)?.tenantId;\n const byId = await this.engine.find('sys_sharing_rule', {\n filter: { id: idOrName },\n limit: 1,\n context: SYSTEM_CTX,\n });\n if (Array.isArray(byId) && byId[0]) return rowFromRule(byId[0]);\n const byName = await this.engine.find('sys_sharing_rule', {\n filter: orgId ? { name: idOrName, organization_id: orgId } : { name: idOrName },\n limit: 1,\n context: SYSTEM_CTX,\n });\n if (Array.isArray(byName) && byName[0]) return rowFromRule(byName[0]);\n return null;\n }\n\n async deleteRule(idOrName: string, context: SharingExecutionContext): Promise<void> {\n const row = await this.getRule(idOrName, context);\n if (!row) return;\n // Drop materialised grants first so we don't orphan them.\n await this.engine.delete('sys_record_share', {\n where: { source: 'rule', source_id: row.id },\n context: SYSTEM_CTX,\n } as any);\n await this.engine.delete('sys_sharing_rule', {\n where: { id: row.id },\n context: SYSTEM_CTX,\n } as any);\n }\n\n async evaluateRule(idOrName: string, context: SharingExecutionContext): Promise<SharingRuleEvaluationResult> {\n const rule = await this.getRule(idOrName, context);\n if (!rule) throw new Error('RULE_NOT_FOUND');\n if (!rule.active) {\n // Inactive — purge any leftover grants and report revoke count.\n const revoked = await this.purgeRuleGrants(rule.id);\n return { ruleId: rule.id, matchedRecords: 0, expandedUsers: 0, grantsCreated: 0, grantsUpdated: 0, grantsRevoked: revoked };\n }\n const matches = await this.findMatchingRecords(rule);\n const users = await this.expandRecipient(rule);\n return this.reconcile(rule, matches, users);\n }\n\n async evaluateAllForRecord(\n object: string,\n recordId: string,\n context: SharingExecutionContext,\n ): Promise<SharingRuleEvaluationResult[]> {\n const rules = await this.listRules({ object, activeOnly: true }, context);\n if (rules.length === 0) return [];\n const results: SharingRuleEvaluationResult[] = [];\n for (const rule of rules) {\n const match = await this.recordMatches(rule, recordId);\n const users = match ? await this.expandRecipient(rule) : [];\n results.push(await this.reconcileForRecord(rule, recordId, match, users));\n }\n return results;\n }\n\n // ── internals ─────────────────────────────────────────────────────\n\n private async findMatchingRecords(rule: SharingRuleRow): Promise<string[]> {\n const filter = (rule.criteria ?? {}) as any;\n try {\n const rows = await this.engine.find(rule.object_name, {\n filter,\n fields: ['id'],\n limit: 5000,\n context: SYSTEM_CTX,\n });\n return Array.isArray(rows) ? rows.map((r: any) => String(r.id)).filter(Boolean) : [];\n } catch (err: any) {\n this.logger?.warn?.('[sharing-rule] criteria query failed', { rule: rule.name, error: err?.message });\n return [];\n }\n }\n\n private async recordMatches(rule: SharingRuleRow, recordId: string): Promise<boolean> {\n const filter = { ...((rule.criteria ?? {}) as any), id: recordId };\n try {\n const rows = await this.engine.find(rule.object_name, {\n filter,\n fields: ['id'],\n limit: 1,\n context: SYSTEM_CTX,\n });\n return Array.isArray(rows) && rows.length > 0;\n } catch {\n return false;\n }\n }\n\n private async expandRecipient(rule: SharingRuleRow): Promise<string[]> {\n const team = new TeamGraphService({\n engine: this.engine,\n organizationId: rule.organization_id ?? null,\n });\n if (rule.recipient_type === 'user') return [rule.recipient_id];\n if (rule.recipient_type === 'team') return team.expandUsers(rule.recipient_id);\n if (rule.recipient_type === 'department') {\n const dept = new DepartmentGraphService({\n engine: this.engine,\n organizationId: rule.organization_id ?? null,\n teamGraph: team,\n });\n return dept.expandUsers(rule.recipient_id);\n }\n if (rule.recipient_type === 'role') return team.expandRoleUsers(rule.recipient_id, rule.organization_id ?? undefined);\n // queue — v1 stores literal; treat as no-op until queue impl lands.\n return [];\n }\n\n private async reconcile(\n rule: SharingRuleRow,\n matchedIds: string[],\n users: string[],\n ): Promise<SharingRuleEvaluationResult> {\n const existing = await this.engine.find('sys_record_share', {\n filter: { source: 'rule', source_id: rule.id },\n fields: ['id', 'record_id', 'recipient_id', 'access_level'],\n limit: 100000,\n context: SYSTEM_CTX,\n });\n const desired = new Map<string, { record_id: string; recipient_id: string }>();\n for (const rid of matchedIds) {\n for (const uId of users) desired.set(`${rid}::${uId}`, { record_id: rid, recipient_id: uId });\n }\n const existingMap = new Map<string, any>();\n for (const row of (existing ?? [])) existingMap.set(`${row.record_id}::${row.recipient_id}`, row);\n\n let created = 0;\n let updated = 0;\n let revoked = 0;\n\n // Upsert desired.\n for (const [k, want] of desired.entries()) {\n const cur = existingMap.get(k);\n if (cur) {\n if (cur.access_level !== rule.access_level) {\n await this.sharing.grant(\n {\n object: rule.object_name,\n recordId: want.record_id,\n recipientType: 'user',\n recipientId: want.recipient_id,\n accessLevel: rule.access_level,\n source: 'rule',\n sourceId: rule.id,\n reason: `rule:${rule.name}`,\n } as any,\n SYSTEM_CTX as any,\n );\n updated += 1;\n }\n existingMap.delete(k);\n } else {\n await this.sharing.grant(\n {\n object: rule.object_name,\n recordId: want.record_id,\n recipientType: 'user',\n recipientId: want.recipient_id,\n accessLevel: rule.access_level,\n source: 'rule',\n sourceId: rule.id,\n reason: `rule:${rule.name}`,\n } as any,\n SYSTEM_CTX as any,\n );\n created += 1;\n }\n }\n // Revoke stale.\n for (const [, stale] of existingMap.entries()) {\n await this.sharing.revoke(stale.id, SYSTEM_CTX as any);\n revoked += 1;\n }\n\n return {\n ruleId: rule.id,\n matchedRecords: matchedIds.length,\n expandedUsers: users.length,\n grantsCreated: created,\n grantsUpdated: updated,\n grantsRevoked: revoked,\n };\n }\n\n private async reconcileForRecord(\n rule: SharingRuleRow,\n recordId: string,\n match: boolean,\n users: string[],\n ): Promise<SharingRuleEvaluationResult> {\n const existing = await this.engine.find('sys_record_share', {\n filter: { source: 'rule', source_id: rule.id, record_id: recordId },\n fields: ['id', 'record_id', 'recipient_id', 'access_level'],\n limit: 1000,\n context: SYSTEM_CTX,\n });\n const existingMap = new Map<string, any>();\n for (const row of (existing ?? [])) existingMap.set(String(row.recipient_id), row);\n\n let created = 0;\n let updated = 0;\n let revoked = 0;\n\n if (match) {\n for (const userId of users) {\n const cur = existingMap.get(userId);\n if (cur) {\n if (cur.access_level !== rule.access_level) {\n await this.sharing.grant(\n {\n object: rule.object_name,\n recordId,\n recipientType: 'user',\n recipientId: userId,\n accessLevel: rule.access_level,\n source: 'rule',\n sourceId: rule.id,\n reason: `rule:${rule.name}`,\n } as any,\n SYSTEM_CTX as any,\n );\n updated += 1;\n }\n existingMap.delete(userId);\n } else {\n await this.sharing.grant(\n {\n object: rule.object_name,\n recordId,\n recipientType: 'user',\n recipientId: userId,\n accessLevel: rule.access_level,\n source: 'rule',\n sourceId: rule.id,\n reason: `rule:${rule.name}`,\n } as any,\n SYSTEM_CTX as any,\n );\n created += 1;\n }\n }\n }\n // Anything still in existingMap is stale (either match=false or\n // user no longer in expanded set).\n for (const [, stale] of existingMap.entries()) {\n await this.sharing.revoke(stale.id, SYSTEM_CTX as any);\n revoked += 1;\n }\n\n return {\n ruleId: rule.id,\n matchedRecords: match ? 1 : 0,\n expandedUsers: users.length,\n grantsCreated: created,\n grantsUpdated: updated,\n grantsRevoked: revoked,\n };\n }\n\n private async purgeRuleGrants(ruleId: string): Promise<number> {\n const existing = await this.engine.find('sys_record_share', {\n filter: { source: 'rule', source_id: ruleId },\n fields: ['id'],\n limit: 100000,\n context: SYSTEM_CTX,\n });\n let revoked = 0;\n for (const row of (existing ?? [])) {\n await this.sharing.revoke((row as any).id, SYSTEM_CTX as any);\n revoked += 1;\n }\n return revoked;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { SharingRuleService } from './sharing-rule-service.js';\nimport type { SharingRuleRow } from '@objectstack/spec/contracts';\n\nconst SYSTEM_CTX = { isSystem: true, roles: [], permissions: [] } as const;\n\nexport const SHARING_RULE_HOOK_PACKAGE = 'plugin-sharing:rules';\n\ninterface MinimalEngine {\n registerHook(event: string, handler: (ctx: any) => any | Promise<any>, options?: {\n object?: string | string[];\n priority?: number;\n packageId?: string;\n }): void;\n unregisterHooksByPackage(packageId: string): number;\n}\n\ninterface MinimalLogger {\n info?: (msg: any, ...rest: any[]) => void;\n warn?: (msg: any, ...rest: any[]) => void;\n}\n\n/**\n * Bind afterInsert/afterUpdate hooks for every distinct object_name in\n * `rules`. Each hook calls `service.evaluateAllForRecord(object, id, …)`\n * with SYSTEM_CTX so the evaluator can write `sys_record_share` rows\n * without being blocked by its own enforcement.\n *\n * Caller is responsible for invoking {@link unbindAllRuleHooks} before\n * re-binding when the rule set changes.\n */\nexport function bindRuleHooks(\n engine: MinimalEngine,\n service: SharingRuleService,\n rules: SharingRuleRow[],\n logger?: MinimalLogger,\n): void {\n const objects = new Set<string>();\n for (const r of rules) {\n if (r.active === false) continue;\n if (r.object_name) objects.add(r.object_name);\n }\n for (const objectName of objects) {\n const handler = async (ctx: any) => {\n if ((ctx?.session as any)?.isSystem) return;\n try {\n const data = ctx?.result ?? ctx?.input?.data ?? {};\n const id = String((data as any)?.id ?? ctx?.input?.id ?? '');\n if (!id) return;\n await service.evaluateAllForRecord(objectName, id, SYSTEM_CTX as any);\n } catch (err: any) {\n logger?.warn?.('[sharing-rule] hook evaluation failed', { object: objectName, error: err?.message });\n }\n };\n engine.registerHook('afterInsert', handler, { object: objectName, packageId: SHARING_RULE_HOOK_PACKAGE, priority: 180 });\n engine.registerHook('afterUpdate', handler, { object: objectName, packageId: SHARING_RULE_HOOK_PACKAGE, priority: 180 });\n }\n logger?.info?.('[sharing-rule] hooks bound', { objects: Array.from(objects), ruleCount: rules.length });\n}\n\nexport function unbindAllRuleHooks(engine: MinimalEngine): number {\n return engine.unregisterHooksByPackage(SHARING_RULE_HOOK_PACKAGE);\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport type { EngineMiddleware, OperationContext } from '@objectstack/objectql';\nimport { SysRecordShare, SysSharingRule } from '@objectstack/platform-objects/security';\nimport { SysDepartment, SysDepartmentMember } from '@objectstack/platform-objects/identity';\nimport { SharingService, type SharingEngine } from './sharing-service.js';\nimport { SharingRuleService } from './sharing-rule-service.js';\nimport { bindRuleHooks, unbindAllRuleHooks } from './rule-hooks.js';\n\nexport interface SharingPluginOptions {\n /** Extra object names that bypass sharing entirely. */\n bypassObjects?: string[];\n /**\n * Disable enforcement (read filter + canEdit) while still registering\n * the schema + service. Useful in development to flip enforcement on\n * via env var without rebuilding.\n */\n enforce?: boolean;\n}\n\n/**\n * SharingServicePlugin — registers `sys_record_share`, the `sharing`\n * service, and the engine middleware that enforces\n * `object.sharingModel`.\n *\n * Enforcement is opt-in per object:\n *\n * - `sharingModel: 'private'` → reads filtered to `(owner_id == me) OR\n * (record explicitly shared with me)`. Writes require ownership or\n * an `edit`/`full` share.\n * - `sharingModel: 'read'` → reads unrestricted; writes gated as\n * above (typical \"everyone can see, only owner can edit\").\n * - any other value (or no value) → no enforcement. This keeps\n * existing CRM behaviour identical until admins explicitly enable\n * sharing on a per-object basis.\n *\n * @example\n * ```ts\n * import { SharingServicePlugin } from '@objectstack/plugin-sharing';\n *\n * kernel.use(new SharingServicePlugin());\n *\n * // Mark an object private — middleware enforces from this point on.\n * defineObject({\n * name: 'account',\n * sharingModel: 'private',\n * fields: { owner_id: Field.lookup('sys_user'), ... },\n * });\n * ```\n */\nexport class SharingServicePlugin implements Plugin {\n name = 'com.objectstack.service.sharing';\n version = '1.0.0';\n type = 'standard';\n dependencies = ['com.objectstack.engine.objectql'];\n\n private readonly options: SharingPluginOptions;\n private service?: SharingService;\n private ruleService?: SharingRuleService;\n\n constructor(options: SharingPluginOptions = {}) {\n this.options = options;\n }\n\n async init(ctx: PluginContext): Promise<void> {\n // Register sys_record_share via the manifest service.\n ctx.getService<{ register(m: any): void }>('manifest').register({\n id: 'com.objectstack.service.sharing',\n name: 'Sharing Service',\n version: '1.0.0',\n type: 'plugin',\n scope: 'system',\n defaultDatasource: 'cloud',\n namespace: 'sys',\n objects: [SysRecordShare, SysSharingRule, SysDepartment, SysDepartmentMember],\n });\n ctx.logger.info('SharingServicePlugin: schema registered');\n }\n\n async start(ctx: PluginContext): Promise<void> {\n ctx.hook('kernel:ready', async () => {\n let engine: any = null;\n try { engine = ctx.getService<any>('objectql'); }\n catch { try { engine = ctx.getService<any>('data'); } catch { /* ignore */ } }\n if (!engine) {\n ctx.logger.warn('SharingServicePlugin: no ObjectQL engine — service NOT registered');\n return;\n }\n\n this.service = new SharingService({\n engine: engine as SharingEngine,\n bypassObjects: this.options.bypassObjects,\n });\n ctx.registerService('sharing', this.service);\n\n if (this.options.enforce === false) {\n ctx.logger.info('SharingServicePlugin: enforcement disabled (enforce=false)');\n return;\n }\n\n const mw = buildSharingMiddleware(this.service);\n if (typeof engine.registerMiddleware === 'function') {\n engine.registerMiddleware(mw, { object: '*' });\n ctx.logger.info('SharingServicePlugin: enforcement middleware installed');\n } else {\n ctx.logger.warn('SharingServicePlugin: engine has no registerMiddleware — enforcement not applied');\n }\n\n // Rule evaluator + hot-rebindable lifecycle hooks.\n try {\n this.ruleService = new SharingRuleService({\n engine: engine as SharingEngine,\n sharing: this.service,\n logger: ctx.logger as any,\n });\n ctx.registerService('sharingRules', this.ruleService);\n\n if (typeof engine.registerHook === 'function' && typeof engine.unregisterHooksByPackage === 'function') {\n const rules = await this.ruleService.listRules({ activeOnly: true }, { isSystem: true } as any);\n unbindAllRuleHooks(engine);\n bindRuleHooks(engine, this.ruleService, rules, ctx.logger as any);\n } else {\n ctx.logger.warn('SharingServicePlugin: engine has no hook API — sharing rule auto-evaluation disabled');\n }\n } catch (err: any) {\n ctx.logger.warn('SharingServicePlugin: sharing-rule subsystem not started', { error: err?.message });\n }\n });\n }\n}\n\n/**\n * Build the engine middleware that injects read filters and gates\n * write operations. Exported so it can be unit-tested without booting\n * a kernel.\n */\nexport function buildSharingMiddleware(service: SharingService): EngineMiddleware {\n return async function sharingMiddleware(ctx: OperationContext, next: () => Promise<void>) {\n const op = ctx.operation;\n const exec = ctx.context as any;\n\n // READS — AND the visibility filter into the AST.\n if (op === 'find' || op === 'findOne' || op === 'count' || op === 'aggregate') {\n const filter = await service.buildReadFilter(ctx.object, exec ?? {});\n if (filter) {\n const ast: any = ctx.ast ?? {};\n ast.where = composeAnd(ast.where, filter);\n ast.filter = composeAnd(ast.filter, filter);\n ctx.ast = ast;\n }\n return next();\n }\n\n // WRITES — gate on canEdit for update / delete.\n if (op === 'update' || op === 'delete') {\n const data: any = ctx.data;\n const options: any = ctx.options;\n const id = inferTargetId(data, options);\n if (id != null) {\n const ok = await service.canEdit(ctx.object, String(id), exec ?? {});\n if (!ok) {\n const err: any = new Error(\n `FORBIDDEN: insufficient privileges to ${op} ${ctx.object} ${id}`,\n );\n err.code = 'FORBIDDEN';\n err.status = 403;\n throw err;\n }\n }\n return next();\n }\n\n // INSERT / others pass through — ownership stamping is the\n // application's job (and is enforced by existing field defaults).\n return next();\n };\n}\n\nfunction composeAnd(existing: unknown, addition: unknown): unknown {\n if (existing == null) return addition;\n if (addition == null) return existing;\n // Both objects — merge with $and.\n if (\n typeof existing === 'object' && existing !== null && !Array.isArray(existing) &&\n typeof addition === 'object' && addition !== null && !Array.isArray(addition)\n ) {\n const ex: any = existing;\n if (Array.isArray(ex.$and)) {\n return { $and: [...ex.$and, addition] };\n }\n // Heuristic: if existing has no operator keys, attempt shallow merge;\n // otherwise nest into $and to preserve semantics.\n return { $and: [existing, addition] };\n }\n return { $and: [existing, addition] };\n}\n\nfunction inferTargetId(data: any, options: any): string | number | undefined {\n if (data && typeof data === 'object' && data.id != null) return data.id;\n if (options && typeof options === 'object') {\n if (options.id != null) return options.id;\n if (options.where && typeof options.where === 'object' && options.where.id != null) {\n return options.where.id;\n }\n if (options.filter && typeof options.filter === 'object' && options.filter.id != null) {\n return options.filter.id;\n }\n }\n return undefined;\n}\n"],"mappings":"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","names":["import_security","import_identity","row","SYSTEM_CTX","SYSTEM_CTX","SYSTEM_CTX","SYSTEM_CTX"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/sharing-service.ts","../src/team-graph.ts","../src/department-graph.ts","../src/sharing-rule-service.ts","../src/share-link-service.ts","../src/share-link-routes.ts","../src/rule-hooks.ts","../src/sharing-plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * @objectstack/plugin-sharing\n *\n * Record-level sharing for ObjectStack. Implements `ISharingService`\n * and installs an engine middleware that enforces\n * `object.sharingModel` (`private` / `read`) against the\n * authenticated execution context.\n */\n\nexport { SysRecordShare, SysSharingRule, SysShareLink } from '@objectstack/platform-objects/security';\nexport { SysDepartment, SysDepartmentMember } from '@objectstack/platform-objects/identity';\nexport {\n SharingService,\n type SharingEngine,\n type SharingServiceOptions,\n} from './sharing-service.js';\nexport {\n SharingRuleService,\n type SharingRuleServiceOptions,\n} from './sharing-rule-service.js';\nexport {\n ShareLinkService,\n type ShareLinkServiceOptions,\n} from './share-link-service.js';\nexport {\n registerShareLinkRoutes,\n type ShareLinkRoutesOptions,\n} from './share-link-routes.js';\nexport { TeamGraphService, expandPrincipal, type TeamGraphOptions } from './team-graph.js';\nexport { DepartmentGraphService, type DepartmentGraphOptions } from './department-graph.js';\nexport { bindRuleHooks, unbindAllRuleHooks, SHARING_RULE_HOOK_PACKAGE } from './rule-hooks.js';\nexport {\n SharingServicePlugin,\n buildSharingMiddleware,\n type SharingPluginOptions,\n} from './sharing-plugin.js';\nexport type {\n ISharingService,\n ISharingRuleService,\n ITeamGraphService,\n IDepartmentGraphService,\n RecordShare,\n GrantShareInput,\n SharingExecutionContext,\n ShareAccessLevel,\n ShareRecipientType,\n ShareSource,\n SharingRuleRow,\n DefineSharingRuleInput,\n SharingRuleEvaluationResult,\n SharingRuleRecipientType,\n IShareLinkService,\n ShareLink,\n CreateShareLinkInput,\n ListShareLinksFilter,\n ResolveShareLinkResult,\n ShareLinkExecutionContext,\n ShareLinkPermission,\n ShareLinkAudience,\n} from '@objectstack/spec/contracts';\nexport { SHARE_LINK_SERVICE } from '@objectstack/spec/contracts';\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n ISharingService,\n RecordShare,\n GrantShareInput,\n SharingExecutionContext,\n ShareAccessLevel,\n} from '@objectstack/spec/contracts';\n\n/**\n * Shape of the data engine the service actually needs. Kept narrow so\n * unit tests can pass an in-memory fake without depending on the full\n * ObjectQL engine class.\n */\nexport interface SharingEngine {\n find(object: string, options?: any): Promise<any[]>;\n findOne?(object: string, options?: any): Promise<any>;\n insert(object: string, data: any, options?: any): Promise<any>;\n update(object: string, idOrData: any, dataOrOptions?: any, options?: any): Promise<any>;\n delete(object: string, options?: any): Promise<any>;\n getSchema?(object: string): any | undefined;\n}\n\n/**\n * Random share id. Keeps the plugin self-contained (no `crypto.randomUUID`\n * dependency in environments that don't expose it on `globalThis`).\n */\nfunction makeShareId(): string {\n const g: any = globalThis as any;\n if (g.crypto?.randomUUID) return `shr_${g.crypto.randomUUID()}`;\n return `shr_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/** System-elevated context for the plugin's own queries / mutations. */\nconst SYSTEM_CTX = { isSystem: true, roles: [], permissions: [] } as const;\n\n/**\n * Owner field convention. Hard-coded to `owner_id` for MVP — the\n * sharing model in Salesforce / ServiceNow / Dynamics all assume a\n * single owner field, and customising it is a follow-up. Objects\n * without `owner_id` are treated as \"unowned\" and read filters are\n * suppressed (they fall back to OWD-public behaviour).\n */\nconst OWNER_FIELD = 'owner_id';\n\n/**\n * Effective sharing model. Anything other than `private` / `read` is\n * treated as public — that includes objects that don't declare\n * `sharingModel` at all, so existing CRM behaviour is preserved\n * until an admin opts an object in.\n */\nfunction effectiveSharingModel(schema: any): 'private' | 'read' | 'public' {\n const m = schema?.sharingModel ?? schema?.security?.sharingModel;\n if (m === 'private') return 'private';\n if (m === 'read') return 'read';\n return 'public';\n}\n\nfunction hasOwnerField(schema: any): boolean {\n return Boolean(schema?.fields && OWNER_FIELD in schema.fields);\n}\n\nexport interface SharingServiceOptions {\n engine: SharingEngine;\n /** Object names that bypass sharing — typically platform internals. */\n bypassObjects?: string[];\n}\n\n/**\n * Default `ISharingService` implementation.\n *\n * Stores every grant in `sys_record_share`. The plugin layer registers\n * an engine middleware that calls `buildReadFilter` / `canEdit` so that\n * neither this class nor its callers need to know about middleware\n * plumbing.\n */\nexport class SharingService implements ISharingService {\n private readonly engine: SharingEngine;\n private readonly bypassObjects: Set<string>;\n\n constructor(options: SharingServiceOptions) {\n this.engine = options.engine;\n this.bypassObjects = new Set([\n 'sys_record_share',\n 'sys_user',\n 'sys_organization',\n 'sys_member',\n 'sys_role',\n 'sys_permission_set',\n 'sys_user_permission_set',\n 'sys_role_permission_set',\n ...(options.bypassObjects ?? []),\n ]);\n }\n\n /**\n * Build a `FilterCondition` restricting `find` to records the caller\n * may see. Returns `null` when no filter should be applied.\n */\n async buildReadFilter(\n object: string,\n context: SharingExecutionContext,\n ): Promise<unknown | null> {\n if (this.shouldBypass(object, context)) return null;\n\n const schema = this.engine.getSchema?.(object);\n if (!schema) return null;\n if (effectiveSharingModel(schema) !== 'private') return null;\n if (!hasOwnerField(schema)) return null;\n if (!context.userId) {\n // Authenticated context with no user id is a degenerate case\n // (e.g. anonymous API key). Restrict to nothing rather than\n // accidentally leaking owner-only data.\n return { id: '__deny_all__' };\n }\n\n const grants = await this.engine.find('sys_record_share', {\n filter: {\n object_name: object,\n recipient_type: 'user',\n recipient_id: context.userId,\n },\n fields: ['record_id', 'access_level'],\n limit: 5000,\n context: SYSTEM_CTX,\n });\n\n const grantedIds: string[] = Array.isArray(grants)\n ? grants.map((g: any) => String(g.record_id)).filter(Boolean)\n : [];\n\n if (grantedIds.length === 0) {\n return { [OWNER_FIELD]: context.userId };\n }\n\n return {\n $or: [\n { [OWNER_FIELD]: context.userId },\n { id: { $in: grantedIds } },\n ],\n };\n }\n\n /**\n * Return `true` if the caller may edit `(object, recordId)`. Always\n * `true` for system context, public objects, and objects without an\n * owner field.\n */\n async canEdit(\n object: string,\n recordId: string,\n context: SharingExecutionContext,\n ): Promise<boolean> {\n if (this.shouldBypass(object, context)) return true;\n\n const schema = this.engine.getSchema?.(object);\n if (!schema) return true;\n const model = effectiveSharingModel(schema);\n if (model === 'public') return true;\n if (!hasOwnerField(schema)) return true;\n if (!context.userId) return false;\n\n // 1) Ownership — fast path.\n const own = await this.engine.find(object, {\n filter: { id: recordId },\n fields: ['id', OWNER_FIELD],\n limit: 1,\n context: SYSTEM_CTX,\n });\n const owner = Array.isArray(own) && own[0] ? (own[0] as any)[OWNER_FIELD] : undefined;\n if (owner && String(owner) === String(context.userId)) return true;\n\n // 2) Explicit edit / full share.\n const editGrants = await this.engine.find('sys_record_share', {\n filter: {\n object_name: object,\n record_id: recordId,\n recipient_type: 'user',\n recipient_id: context.userId,\n access_level: { $in: ['edit', 'full'] },\n },\n fields: ['id'],\n limit: 1,\n context: SYSTEM_CTX,\n });\n return Array.isArray(editGrants) && editGrants.length > 0;\n }\n\n /**\n * Upsert a share row. Returning the existing row when an identical\n * grant already exists keeps the REST endpoint idempotent.\n */\n async grant(\n input: GrantShareInput,\n context: SharingExecutionContext,\n ): Promise<RecordShare> {\n if (!input.object) throw new Error('VALIDATION_FAILED: object is required');\n if (!input.recordId) throw new Error('VALIDATION_FAILED: recordId is required');\n if (!input.recipientId) throw new Error('VALIDATION_FAILED: recipientId is required');\n\n const recipientType = input.recipientType ?? 'user';\n const accessLevel: ShareAccessLevel = input.accessLevel ?? 'read';\n const source = input.source ?? 'manual';\n\n // Upsert: if a row with same (object, record, recipient) exists,\n // update its access level / reason; otherwise insert a new one.\n const existing = await this.engine.find('sys_record_share', {\n filter: {\n object_name: input.object,\n record_id: input.recordId,\n recipient_type: recipientType,\n recipient_id: input.recipientId,\n },\n limit: 1,\n context: SYSTEM_CTX,\n });\n const now = new Date().toISOString();\n if (Array.isArray(existing) && existing[0]) {\n const row: any = existing[0];\n const patch: any = {\n id: row.id,\n access_level: accessLevel,\n source,\n source_id: input.sourceId ?? row.source_id ?? null,\n reason: input.reason ?? row.reason ?? null,\n updated_at: now,\n };\n await this.engine.update('sys_record_share', patch, { context: SYSTEM_CTX });\n return { ...row, ...patch } as RecordShare;\n }\n\n const id = makeShareId();\n const row: any = {\n id,\n object_name: input.object,\n record_id: input.recordId,\n recipient_type: recipientType,\n recipient_id: input.recipientId,\n access_level: accessLevel,\n source,\n source_id: input.sourceId ?? null,\n granted_by: context.userId ?? null,\n reason: input.reason ?? null,\n created_at: now,\n updated_at: now,\n };\n await this.engine.insert('sys_record_share', row, { context: SYSTEM_CTX });\n return row as RecordShare;\n }\n\n /** Delete a share row by id. No-op when not found. */\n async revoke(shareId: string, _context: SharingExecutionContext): Promise<void> {\n if (!shareId) throw new Error('VALIDATION_FAILED: shareId is required');\n await this.engine.delete('sys_record_share', {\n where: { id: shareId },\n context: SYSTEM_CTX,\n });\n }\n\n /** List share rows for `(object, recordId)`. */\n async listShares(\n object: string,\n recordId: string,\n _context: SharingExecutionContext,\n ): Promise<RecordShare[]> {\n const rows = await this.engine.find('sys_record_share', {\n filter: { object_name: object, record_id: recordId },\n orderBy: [{ field: 'created_at', direction: 'desc' }],\n limit: 500,\n context: SYSTEM_CTX,\n });\n return Array.isArray(rows) ? (rows as RecordShare[]) : [];\n }\n\n // ── helpers ──────────────────────────────────────────────────────\n\n private shouldBypass(object: string, context: SharingExecutionContext): boolean {\n if (context?.isSystem) return true;\n if (this.bypassObjects.has(object)) return true;\n return false;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { ITeamGraphService } from '@objectstack/spec/contracts';\nimport type { SharingEngine } from './sharing-service.js';\n\nconst SYSTEM_CTX = { isSystem: true, roles: [], permissions: [] } as const;\n\ntype Cache = {\n expandUsers?: Map<string, string[]>;\n expandRole?: Map<string, string[]>;\n manager?: Map<string, string | null>;\n};\n\nexport interface TeamGraphOptions {\n engine: SharingEngine;\n /** Optional tenant scope; null means cross-tenant lookups. */\n organizationId?: string | null;\n /** Optional shared cache across one evaluator pass. */\n cache?: Cache;\n}\n\n/**\n * Default {@link ITeamGraphService} implementation backed by\n * `sys_team` + `sys_team_member` (better-auth's flat collaboration\n * grouping) plus `sys_member.role` for tenant role expansion.\n *\n * **This service does NOT walk a hierarchy.** Teams here are flat —\n * the enterprise org chart lives in `sys_department` and is served by\n * {@link DepartmentGraphService}.\n *\n * All queries elevate to {@link SYSTEM_CTX} since the graph is platform\n * metadata; callers (sharing rule evaluator, approval engine) own their\n * own enforcement.\n */\nexport class TeamGraphService implements ITeamGraphService {\n private readonly engine: SharingEngine;\n private readonly organizationId: string | null;\n private readonly cache: Cache;\n\n constructor(opts: TeamGraphOptions) {\n this.engine = opts.engine;\n this.organizationId = opts.organizationId ?? null;\n this.cache = opts.cache ?? {};\n this.cache.expandUsers ??= new Map();\n this.cache.expandRole ??= new Map();\n this.cache.manager ??= new Map();\n }\n\n async expandUsers(teamId: string): Promise<string[]> {\n if (!teamId) return [];\n const cached = this.cache.expandUsers!.get(teamId);\n if (cached) return cached;\n\n let rows: any[] = [];\n try {\n rows = await this.engine.find('sys_team_member', {\n filter: { team_id: teamId },\n fields: ['user_id'],\n limit: 10000,\n context: SYSTEM_CTX,\n });\n } catch {\n rows = [];\n }\n const users = Array.from(new Set((rows ?? []).map((r: any) => String(r.user_id ?? '')).filter(Boolean)));\n this.cache.expandUsers!.set(teamId, users);\n return users;\n }\n\n async expandRoleUsers(roleName: string, organizationId?: string): Promise<string[]> {\n if (!roleName) return [];\n const key = `${organizationId ?? this.organizationId ?? '*'}::${roleName}`;\n const cached = this.cache.expandRole!.get(key);\n if (cached) return cached;\n const filter: Record<string, unknown> = { role: roleName };\n const org = organizationId ?? this.organizationId;\n if (org) filter.organization_id = org;\n let rows: any[] = [];\n try {\n rows = await this.engine.find('sys_member', {\n filter,\n fields: ['user_id'],\n limit: 10000,\n context: SYSTEM_CTX,\n });\n } catch {\n rows = [];\n }\n const users = Array.from(new Set((rows ?? []).map((r: any) => String(r.user_id ?? '')).filter(Boolean)));\n this.cache.expandRole!.set(key, users);\n return users;\n }\n\n async managerOf(userId: string, _organizationId?: string): Promise<string | null> {\n if (!userId) return null;\n if (this.cache.manager!.has(userId)) return this.cache.manager!.get(userId) ?? null;\n let row: any = null;\n try {\n const rows = await this.engine.find('sys_user', {\n filter: { id: userId },\n fields: ['id', 'manager_id'],\n limit: 1,\n context: SYSTEM_CTX,\n });\n row = Array.isArray(rows) ? rows[0] : null;\n } catch {\n row = null;\n }\n const mgr = row?.manager_id ? String(row.manager_id) : null;\n this.cache.manager!.set(userId, mgr);\n return mgr;\n }\n}\n\n/**\n * Convenience helper used by the sharing-rule evaluator + approval\n * engine: expand an approver / recipient descriptor of the form\n * `{type, value}` into a flat list of user IDs by routing to the\n * appropriate graph service.\n *\n * `team` → flat team members (this service).\n * `department` → recursive department members (delegated; requires a\n * {@link IDepartmentGraphService} instance passed in `opts.dept`).\n * `role` → tenant role members.\n * `manager` → submitter's manager via `record[value] ?? record.owner_id`.\n * `field` → literal user id stored in `record[value]`.\n * `user` → literal value.\n * Anything else echoes `type:value` for back-compat with legacy\n * substring-match approver flows.\n */\nexport async function expandPrincipal(\n input: { type: string; value: string; record?: any },\n ctx: { team: TeamGraphService; dept?: { expandUsers(id: string): Promise<string[]> }; organizationId?: string | null },\n): Promise<string[]> {\n const t = input.type;\n const v = String(input.value ?? '');\n if (!v) return [];\n if (t === 'user') return [v];\n if (t === 'team') return ctx.team.expandUsers(v);\n if (t === 'department' || t === 'dept') {\n if (ctx.dept) return ctx.dept.expandUsers(v);\n return [`${t}:${v}`];\n }\n if (t === 'role') return ctx.team.expandRoleUsers(v, ctx.organizationId ?? undefined);\n if (t === 'field' && input.record) {\n const fv = (input.record as any)[v];\n return fv ? [String(fv)] : [];\n }\n if (t === 'manager' && input.record) {\n const subject = (input.record as any)[v] ?? (input.record as any).owner_id;\n if (!subject) return [];\n const mgr = await ctx.team.managerOf(String(subject), ctx.organizationId ?? undefined);\n return mgr ? [mgr] : [];\n }\n // queue / unknown — fall back to raw prefix string so existing\n // string-match approver flows keep working.\n return [`${t}:${v}`];\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { IDepartmentGraphService } from '@objectstack/spec/contracts';\nimport type { SharingEngine } from './sharing-service.js';\nimport { TeamGraphService } from './team-graph.js';\n\nconst SYSTEM_CTX = { isSystem: true, roles: [], permissions: [] } as const;\n\ntype DeptCache = {\n descendants?: Map<string, string[]>;\n expandUsers?: Map<string, string[]>;\n head?: Map<string, string | null>;\n};\n\nexport interface DepartmentGraphOptions {\n engine: SharingEngine;\n /** Optional tenant scope; null means cross-tenant lookups. */\n organizationId?: string | null;\n /** Optional shared cache across one evaluator pass. */\n cache?: DeptCache;\n /**\n * Optional team-graph instance to share role / manager lookups with —\n * department graph proxies `managerOf` through so callers only need one\n * service.\n */\n teamGraph?: TeamGraphService;\n}\n\n/**\n * Default {@link IDepartmentGraphService} implementation.\n *\n * Walks `sys_department.parent_department_id` for hierarchy and\n * `sys_department_member` for member expansion. Treats the optional\n * `active` flag as a hard filter (inactive departments contribute no\n * members and stop BFS descent into their subtrees).\n *\n * Reuses {@link TeamGraphService.managerOf} for user-level manager\n * lookup so callers can use this single service in approval / sharing\n * pipelines.\n */\nexport class DepartmentGraphService implements IDepartmentGraphService {\n private readonly engine: SharingEngine;\n private readonly organizationId: string | null;\n private readonly cache: DeptCache;\n private readonly teamGraph?: TeamGraphService;\n\n constructor(opts: DepartmentGraphOptions) {\n this.engine = opts.engine;\n this.organizationId = opts.organizationId ?? null;\n this.cache = opts.cache ?? {};\n this.cache.descendants ??= new Map();\n this.cache.expandUsers ??= new Map();\n this.cache.head ??= new Map();\n this.teamGraph = opts.teamGraph;\n }\n\n async descendants(departmentId: string): Promise<string[]> {\n if (!departmentId) return [];\n const cached = this.cache.descendants!.get(departmentId);\n if (cached) return cached;\n\n // Verify seed itself is active + within tenant scope.\n let seedActive = true;\n try {\n const seedRows = await this.engine.find('sys_department', {\n filter: this.orgScope({ id: departmentId }),\n fields: ['id', 'active'],\n limit: 1,\n context: SYSTEM_CTX,\n });\n const seedRow: any = Array.isArray(seedRows) ? seedRows[0] : null;\n if (!seedRow) seedActive = false;\n else if (seedRow.active === false) seedActive = false;\n } catch {\n seedActive = false;\n }\n if (!seedActive) {\n this.cache.descendants!.set(departmentId, []);\n return [];\n }\n\n const seen = new Set<string>([departmentId]);\n const queue: string[] = [departmentId];\n while (queue.length) {\n const parent = queue.shift()!;\n let children: any[] = [];\n try {\n children = await this.engine.find('sys_department', {\n filter: this.orgScope({ parent_department_id: parent, active: { $ne: false } }),\n fields: ['id'],\n limit: 1000,\n context: SYSTEM_CTX,\n });\n } catch {\n children = [];\n }\n for (const c of children ?? []) {\n const cid = String((c as any).id ?? '');\n if (cid && !seen.has(cid)) {\n seen.add(cid);\n queue.push(cid);\n }\n }\n }\n const out = Array.from(seen);\n this.cache.descendants!.set(departmentId, out);\n return out;\n }\n\n async expandUsers(departmentId: string): Promise<string[]> {\n if (!departmentId) return [];\n const cached = this.cache.expandUsers!.get(departmentId);\n if (cached) return cached;\n\n const depts = await this.descendants(departmentId);\n if (depts.length === 0) return [];\n\n let rows: any[] = [];\n try {\n rows = await this.engine.find('sys_department_member', {\n filter: { department_id: { $in: depts } },\n fields: ['user_id'],\n limit: 10000,\n context: SYSTEM_CTX,\n });\n } catch {\n rows = [];\n }\n const users = Array.from(\n new Set((rows ?? []).map((r: any) => String(r.user_id ?? '')).filter(Boolean)),\n );\n this.cache.expandUsers!.set(departmentId, users);\n return users;\n }\n\n async headOf(departmentId: string): Promise<string | null> {\n if (!departmentId) return null;\n if (this.cache.head!.has(departmentId)) return this.cache.head!.get(departmentId) ?? null;\n let row: any = null;\n try {\n const rows = await this.engine.find('sys_department', {\n filter: { id: departmentId },\n fields: ['id', 'manager_user_id'],\n limit: 1,\n context: SYSTEM_CTX,\n });\n row = Array.isArray(rows) ? rows[0] : null;\n } catch {\n row = null;\n }\n const head = row?.manager_user_id ? String(row.manager_user_id) : null;\n this.cache.head!.set(departmentId, head);\n return head;\n }\n\n async managerOf(userId: string, organizationId?: string): Promise<string | null> {\n if (this.teamGraph) return this.teamGraph.managerOf(userId, organizationId);\n // Standalone fallback: read sys_user.manager_id directly.\n if (!userId) return null;\n try {\n const rows = await this.engine.find('sys_user', {\n filter: { id: userId },\n fields: ['id', 'manager_id'],\n limit: 1,\n context: SYSTEM_CTX,\n });\n const row: any = Array.isArray(rows) ? rows[0] : null;\n return row?.manager_id ? String(row.manager_id) : null;\n } catch {\n return null;\n }\n }\n\n private orgScope(filter: Record<string, unknown>): Record<string, unknown> {\n if (this.organizationId) return { ...filter, organization_id: this.organizationId };\n return filter;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n ISharingRuleService,\n DefineSharingRuleInput,\n SharingRuleRow,\n SharingRuleEvaluationResult,\n SharingExecutionContext,\n ShareAccessLevel,\n SharingRuleRecipientType,\n} from '@objectstack/spec/contracts';\nimport type { SharingEngine } from './sharing-service.js';\nimport type { SharingService } from './sharing-service.js';\nimport { TeamGraphService } from './team-graph.js';\nimport { DepartmentGraphService } from './department-graph.js';\n\nconst SYSTEM_CTX = { isSystem: true, roles: [], permissions: [] } as const;\n\nfunction uid(prefix: string): string {\n const g: any = globalThis as any;\n if (g.crypto?.randomUUID) return `${prefix}_${g.crypto.randomUUID()}`;\n return `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction parseCriteria(raw: unknown): unknown | undefined {\n if (raw == null || raw === '') return undefined;\n if (typeof raw === 'string') {\n const trimmed = raw.trim();\n if (!trimmed) return undefined;\n try {\n return JSON.parse(trimmed);\n } catch {\n // Treat unparsable strings as opaque — most likely a CEL source\n // that v1's evaluator doesn't grok yet; rule will match nothing.\n return undefined;\n }\n }\n return raw;\n}\n\nfunction rowFromRule(row: any): SharingRuleRow {\n return {\n id: row.id,\n organization_id: row.organization_id ?? null,\n name: row.name,\n label: row.label,\n description: row.description ?? null,\n object_name: row.object_name,\n criteria: parseCriteria(row.criteria_json),\n recipient_type: row.recipient_type as SharingRuleRecipientType,\n recipient_id: row.recipient_id,\n access_level: row.access_level as ShareAccessLevel,\n active: row.active !== false,\n created_at: row.created_at ?? undefined,\n updated_at: row.updated_at ?? undefined,\n };\n}\n\nexport interface SharingRuleServiceOptions {\n engine: SharingEngine;\n sharing: SharingService;\n logger?: { info?: Function; warn?: Function; error?: Function; debug?: Function };\n}\n\n/**\n * Default {@link ISharingRuleService} implementation.\n *\n * Stores rule definitions in `sys_sharing_rule` and materialises grants\n * as `sys_record_share` rows with `source='rule'` and `source_id={ruleId}`\n * so reconcile can diff old grants vs fresh evaluation results without\n * touching manual / team-derived shares.\n */\nexport class SharingRuleService implements ISharingRuleService {\n private readonly engine: SharingEngine;\n private readonly sharing: SharingService;\n private readonly logger?: SharingRuleServiceOptions['logger'];\n\n constructor(opts: SharingRuleServiceOptions) {\n this.engine = opts.engine;\n this.sharing = opts.sharing;\n this.logger = opts.logger;\n }\n\n async defineRule(input: DefineSharingRuleInput, context: SharingExecutionContext): Promise<SharingRuleRow> {\n if (!input.name) throw new Error('VALIDATION_FAILED: name is required');\n if (!input.label) throw new Error('VALIDATION_FAILED: label is required');\n if (!input.object) throw new Error('VALIDATION_FAILED: object is required');\n if (!input.recipientType) throw new Error('VALIDATION_FAILED: recipientType is required');\n if (!input.recipientId) throw new Error('VALIDATION_FAILED: recipientId is required');\n\n const orgId = (context as any)?.organizationId ?? (context as any)?.tenantId ?? null;\n const now = new Date().toISOString();\n const accessLevel: ShareAccessLevel = input.accessLevel ?? 'read';\n const active = input.active !== false;\n const criteriaJson = input.criteria == null\n ? null\n : (typeof input.criteria === 'string' ? input.criteria : JSON.stringify(input.criteria));\n\n const existing = await this.engine.find('sys_sharing_rule', {\n filter: orgId ? { name: input.name, organization_id: orgId } : { name: input.name },\n limit: 1,\n context: SYSTEM_CTX,\n });\n if (Array.isArray(existing) && existing[0]) {\n const row: any = existing[0];\n const patch: any = {\n id: row.id,\n label: input.label,\n description: input.description ?? null,\n object_name: input.object,\n criteria_json: criteriaJson,\n recipient_type: input.recipientType,\n recipient_id: input.recipientId,\n access_level: accessLevel,\n active,\n updated_at: now,\n };\n await this.engine.update('sys_sharing_rule', patch, { context: SYSTEM_CTX });\n return rowFromRule({ ...row, ...patch });\n }\n\n const newRow: any = {\n id: uid('srule'),\n organization_id: orgId,\n name: input.name,\n label: input.label,\n description: input.description ?? null,\n object_name: input.object,\n criteria_json: criteriaJson,\n recipient_type: input.recipientType,\n recipient_id: input.recipientId,\n access_level: accessLevel,\n active,\n created_at: now,\n updated_at: now,\n };\n await this.engine.insert('sys_sharing_rule', newRow, { context: SYSTEM_CTX });\n return rowFromRule(newRow);\n }\n\n async listRules(\n filter: { object?: string; activeOnly?: boolean },\n context: SharingExecutionContext,\n ): Promise<SharingRuleRow[]> {\n const where: any = {};\n if (filter.object) where.object_name = filter.object;\n if (filter.activeOnly) where.active = true;\n const orgId = (context as any)?.organizationId ?? (context as any)?.tenantId;\n if (orgId) where.organization_id = orgId;\n const rows = await this.engine.find('sys_sharing_rule', {\n filter: where,\n orderBy: [{ field: 'name', direction: 'asc' }],\n limit: 1000,\n context: SYSTEM_CTX,\n });\n return Array.isArray(rows) ? rows.map(rowFromRule) : [];\n }\n\n async getRule(idOrName: string, context: SharingExecutionContext): Promise<SharingRuleRow | null> {\n if (!idOrName) return null;\n const orgId = (context as any)?.organizationId ?? (context as any)?.tenantId;\n const byId = await this.engine.find('sys_sharing_rule', {\n filter: { id: idOrName },\n limit: 1,\n context: SYSTEM_CTX,\n });\n if (Array.isArray(byId) && byId[0]) return rowFromRule(byId[0]);\n const byName = await this.engine.find('sys_sharing_rule', {\n filter: orgId ? { name: idOrName, organization_id: orgId } : { name: idOrName },\n limit: 1,\n context: SYSTEM_CTX,\n });\n if (Array.isArray(byName) && byName[0]) return rowFromRule(byName[0]);\n return null;\n }\n\n async deleteRule(idOrName: string, context: SharingExecutionContext): Promise<void> {\n const row = await this.getRule(idOrName, context);\n if (!row) return;\n // Drop materialised grants first so we don't orphan them.\n await this.engine.delete('sys_record_share', {\n where: { source: 'rule', source_id: row.id },\n context: SYSTEM_CTX,\n } as any);\n await this.engine.delete('sys_sharing_rule', {\n where: { id: row.id },\n context: SYSTEM_CTX,\n } as any);\n }\n\n async evaluateRule(idOrName: string, context: SharingExecutionContext): Promise<SharingRuleEvaluationResult> {\n const rule = await this.getRule(idOrName, context);\n if (!rule) throw new Error('RULE_NOT_FOUND');\n if (!rule.active) {\n // Inactive — purge any leftover grants and report revoke count.\n const revoked = await this.purgeRuleGrants(rule.id);\n return { ruleId: rule.id, matchedRecords: 0, expandedUsers: 0, grantsCreated: 0, grantsUpdated: 0, grantsRevoked: revoked };\n }\n const matches = await this.findMatchingRecords(rule);\n const users = await this.expandRecipient(rule);\n return this.reconcile(rule, matches, users);\n }\n\n async evaluateAllForRecord(\n object: string,\n recordId: string,\n context: SharingExecutionContext,\n ): Promise<SharingRuleEvaluationResult[]> {\n const rules = await this.listRules({ object, activeOnly: true }, context);\n if (rules.length === 0) return [];\n const results: SharingRuleEvaluationResult[] = [];\n for (const rule of rules) {\n const match = await this.recordMatches(rule, recordId);\n const users = match ? await this.expandRecipient(rule) : [];\n results.push(await this.reconcileForRecord(rule, recordId, match, users));\n }\n return results;\n }\n\n // ── internals ─────────────────────────────────────────────────────\n\n private async findMatchingRecords(rule: SharingRuleRow): Promise<string[]> {\n const filter = (rule.criteria ?? {}) as any;\n try {\n const rows = await this.engine.find(rule.object_name, {\n filter,\n fields: ['id'],\n limit: 5000,\n context: SYSTEM_CTX,\n });\n return Array.isArray(rows) ? rows.map((r: any) => String(r.id)).filter(Boolean) : [];\n } catch (err: any) {\n this.logger?.warn?.('[sharing-rule] criteria query failed', { rule: rule.name, error: err?.message });\n return [];\n }\n }\n\n private async recordMatches(rule: SharingRuleRow, recordId: string): Promise<boolean> {\n const filter = { ...((rule.criteria ?? {}) as any), id: recordId };\n try {\n const rows = await this.engine.find(rule.object_name, {\n filter,\n fields: ['id'],\n limit: 1,\n context: SYSTEM_CTX,\n });\n return Array.isArray(rows) && rows.length > 0;\n } catch {\n return false;\n }\n }\n\n private async expandRecipient(rule: SharingRuleRow): Promise<string[]> {\n const team = new TeamGraphService({\n engine: this.engine,\n organizationId: rule.organization_id ?? null,\n });\n if (rule.recipient_type === 'user') return [rule.recipient_id];\n if (rule.recipient_type === 'team') return team.expandUsers(rule.recipient_id);\n if (rule.recipient_type === 'department') {\n const dept = new DepartmentGraphService({\n engine: this.engine,\n organizationId: rule.organization_id ?? null,\n teamGraph: team,\n });\n return dept.expandUsers(rule.recipient_id);\n }\n if (rule.recipient_type === 'role') return team.expandRoleUsers(rule.recipient_id, rule.organization_id ?? undefined);\n // queue — v1 stores literal; treat as no-op until queue impl lands.\n return [];\n }\n\n private async reconcile(\n rule: SharingRuleRow,\n matchedIds: string[],\n users: string[],\n ): Promise<SharingRuleEvaluationResult> {\n const existing = await this.engine.find('sys_record_share', {\n filter: { source: 'rule', source_id: rule.id },\n fields: ['id', 'record_id', 'recipient_id', 'access_level'],\n limit: 100000,\n context: SYSTEM_CTX,\n });\n const desired = new Map<string, { record_id: string; recipient_id: string }>();\n for (const rid of matchedIds) {\n for (const uId of users) desired.set(`${rid}::${uId}`, { record_id: rid, recipient_id: uId });\n }\n const existingMap = new Map<string, any>();\n for (const row of (existing ?? [])) existingMap.set(`${row.record_id}::${row.recipient_id}`, row);\n\n let created = 0;\n let updated = 0;\n let revoked = 0;\n\n // Upsert desired.\n for (const [k, want] of desired.entries()) {\n const cur = existingMap.get(k);\n if (cur) {\n if (cur.access_level !== rule.access_level) {\n await this.sharing.grant(\n {\n object: rule.object_name,\n recordId: want.record_id,\n recipientType: 'user',\n recipientId: want.recipient_id,\n accessLevel: rule.access_level,\n source: 'rule',\n sourceId: rule.id,\n reason: `rule:${rule.name}`,\n } as any,\n SYSTEM_CTX as any,\n );\n updated += 1;\n }\n existingMap.delete(k);\n } else {\n await this.sharing.grant(\n {\n object: rule.object_name,\n recordId: want.record_id,\n recipientType: 'user',\n recipientId: want.recipient_id,\n accessLevel: rule.access_level,\n source: 'rule',\n sourceId: rule.id,\n reason: `rule:${rule.name}`,\n } as any,\n SYSTEM_CTX as any,\n );\n created += 1;\n }\n }\n // Revoke stale.\n for (const [, stale] of existingMap.entries()) {\n await this.sharing.revoke(stale.id, SYSTEM_CTX as any);\n revoked += 1;\n }\n\n return {\n ruleId: rule.id,\n matchedRecords: matchedIds.length,\n expandedUsers: users.length,\n grantsCreated: created,\n grantsUpdated: updated,\n grantsRevoked: revoked,\n };\n }\n\n private async reconcileForRecord(\n rule: SharingRuleRow,\n recordId: string,\n match: boolean,\n users: string[],\n ): Promise<SharingRuleEvaluationResult> {\n const existing = await this.engine.find('sys_record_share', {\n filter: { source: 'rule', source_id: rule.id, record_id: recordId },\n fields: ['id', 'record_id', 'recipient_id', 'access_level'],\n limit: 1000,\n context: SYSTEM_CTX,\n });\n const existingMap = new Map<string, any>();\n for (const row of (existing ?? [])) existingMap.set(String(row.recipient_id), row);\n\n let created = 0;\n let updated = 0;\n let revoked = 0;\n\n if (match) {\n for (const userId of users) {\n const cur = existingMap.get(userId);\n if (cur) {\n if (cur.access_level !== rule.access_level) {\n await this.sharing.grant(\n {\n object: rule.object_name,\n recordId,\n recipientType: 'user',\n recipientId: userId,\n accessLevel: rule.access_level,\n source: 'rule',\n sourceId: rule.id,\n reason: `rule:${rule.name}`,\n } as any,\n SYSTEM_CTX as any,\n );\n updated += 1;\n }\n existingMap.delete(userId);\n } else {\n await this.sharing.grant(\n {\n object: rule.object_name,\n recordId,\n recipientType: 'user',\n recipientId: userId,\n accessLevel: rule.access_level,\n source: 'rule',\n sourceId: rule.id,\n reason: `rule:${rule.name}`,\n } as any,\n SYSTEM_CTX as any,\n );\n created += 1;\n }\n }\n }\n // Anything still in existingMap is stale (either match=false or\n // user no longer in expanded set).\n for (const [, stale] of existingMap.entries()) {\n await this.sharing.revoke(stale.id, SYSTEM_CTX as any);\n revoked += 1;\n }\n\n return {\n ruleId: rule.id,\n matchedRecords: match ? 1 : 0,\n expandedUsers: users.length,\n grantsCreated: created,\n grantsUpdated: updated,\n grantsRevoked: revoked,\n };\n }\n\n private async purgeRuleGrants(ruleId: string): Promise<number> {\n const existing = await this.engine.find('sys_record_share', {\n filter: { source: 'rule', source_id: ruleId },\n fields: ['id'],\n limit: 100000,\n context: SYSTEM_CTX,\n });\n let revoked = 0;\n for (const row of (existing ?? [])) {\n await this.sharing.revoke((row as any).id, SYSTEM_CTX as any);\n revoked += 1;\n }\n return revoked;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n IShareLinkService,\n ShareLink,\n CreateShareLinkInput,\n ListShareLinksFilter,\n ResolveShareLinkResult,\n ShareLinkExecutionContext,\n ShareLinkPermission,\n ShareLinkAudience,\n} from '@objectstack/spec/contracts';\nimport type { SharingEngine } from './sharing-service.js';\n\n/** Service-elevated context for the plugin's own queries / mutations. */\nconst SYSTEM_CTX = { isSystem: true, roles: [], permissions: [] } as const;\n\n/** URL-safe alphabet (RFC 4648 base64url minus padding). 64 symbols. */\nconst TOKEN_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';\n\n/** ~144 bits of entropy at 24 chars — well above the OWASP recommendation. */\nconst TOKEN_LENGTH = 24;\n\n/** Default value when no per-object cap is configured. */\nconst DEFAULT_MAX_EXPIRY_DAYS = 365;\n\n/**\n * Generate a URL-safe token. Uses `crypto.getRandomValues` when present\n * (browsers, Node ≥ 19) and falls back to `Math.random` only for the\n * pathological case of a polyfill-less old runtime. The fallback is\n * still ≥ 100 bits of entropy because of TOKEN_LENGTH.\n */\nfunction generateToken(length: number = TOKEN_LENGTH): string {\n const g: any = globalThis as any;\n const bytes = new Uint8Array(length);\n if (g.crypto?.getRandomValues) {\n g.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < length; i++) bytes[i] = Math.floor(Math.random() * 256);\n }\n let out = '';\n for (let i = 0; i < length; i++) {\n out += TOKEN_ALPHABET[bytes[i] % TOKEN_ALPHABET.length];\n }\n return out;\n}\n\n/** Internal helper — extract publicSharing policy from an object schema. */\nfunction getPolicy(schema: any): {\n enabled: boolean;\n allowedAudiences: ShareLinkAudience[];\n allowedPermissions: ShareLinkPermission[];\n maxExpiryDays?: number;\n redactFields: string[];\n} {\n const raw = schema?.publicSharing;\n if (!raw || raw.enabled !== true) {\n return {\n enabled: false,\n allowedAudiences: [],\n allowedPermissions: [],\n redactFields: [],\n };\n }\n return {\n enabled: true,\n allowedAudiences: (raw.allowedAudiences as ShareLinkAudience[] | undefined) ?? ['link_only'],\n allowedPermissions: (raw.allowedPermissions as ShareLinkPermission[] | undefined) ?? ['view'],\n maxExpiryDays: typeof raw.maxExpiryDays === 'number' ? raw.maxExpiryDays : undefined,\n redactFields: Array.isArray(raw.redactFields) ? (raw.redactFields as string[]) : [],\n };\n}\n\n/** Parse `expiresAt` as either an ISO string or a relative duration like \"7d\", \"24h\", \"30m\". */\nfunction normaliseExpiresAt(input: string | null | undefined, maxDays: number): string | null {\n if (!input) return null;\n const now = Date.now();\n const cap = now + maxDays * 86_400_000;\n\n // Relative duration shorthand.\n const m = /^([0-9]+)(s|m|h|d)$/i.exec(input);\n if (m) {\n const n = Number(m[1]);\n const unit = m[2].toLowerCase();\n const ms = unit === 's' ? n * 1000 : unit === 'm' ? n * 60_000 : unit === 'h' ? n * 3_600_000 : n * 86_400_000;\n const at = now + ms;\n if (at > cap) {\n throw makeError(422, 'EXPIRY_TOO_LONG', `expiresAt exceeds the object's max of ${maxDays} days`);\n }\n return new Date(at).toISOString();\n }\n\n // Otherwise expect an ISO timestamp.\n const t = Date.parse(input);\n if (Number.isNaN(t)) {\n throw makeError(422, 'INVALID_EXPIRY', `expiresAt is not a valid ISO timestamp or duration: ${input}`);\n }\n if (t > cap) {\n throw makeError(422, 'EXPIRY_TOO_LONG', `expiresAt exceeds the object's max of ${maxDays} days`);\n }\n if (t <= now) {\n throw makeError(422, 'EXPIRY_IN_PAST', 'expiresAt must be in the future');\n }\n return new Date(t).toISOString();\n}\n\n/**\n * Weak password hash. Production deployments should swap in argon2 /\n * bcrypt via dependency injection (see `ShareLinkServiceOptions.hashPassword`).\n * The default uses SubtleCrypto SHA-256 with a per-row salt — strong\n * enough to keep the hash useless to a casual observer and to deflate\n * the cost of a database leak, but NOT a substitute for argon2 against\n * a determined attacker. The platform deliberately surfaces this in the\n * plugin docs so deployments can decide.\n */\nasync function defaultHashPassword(password: string): Promise<string> {\n const g: any = globalThis as any;\n const subtle = g.crypto?.subtle;\n const salt = generateToken(16);\n if (!subtle) {\n // Synthetic fallback — no SubtleCrypto means we're in a stripped\n // runtime; emit a clearly-marked placeholder so the deployment is\n // forced to wire in a real hasher rather than ship a weak one.\n return `weak$${salt}$${password}`;\n }\n const enc = new TextEncoder();\n const buf = await subtle.digest('SHA-256', enc.encode(salt + ':' + password));\n const hex = Array.from(new Uint8Array(buf))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n return `sha256$${salt}$${hex}`;\n}\n\nasync function defaultVerifyPassword(password: string, hash: string): Promise<boolean> {\n if (hash.startsWith('weak$')) {\n const [, , stored] = hash.split('$');\n return stored === password;\n }\n if (hash.startsWith('sha256$')) {\n const [, salt, expected] = hash.split('$');\n const g: any = globalThis as any;\n const subtle = g.crypto?.subtle;\n if (!subtle) return false;\n const enc = new TextEncoder();\n const buf = await subtle.digest('SHA-256', enc.encode(salt + ':' + password));\n const hex = Array.from(new Uint8Array(buf))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n return hex === expected;\n }\n return false;\n}\n\nfunction makeError(status: number, code: string, message: string): Error {\n const err: any = new Error(message);\n err.status = status;\n err.code = code;\n return err;\n}\n\nexport interface ShareLinkServiceOptions {\n engine: SharingEngine;\n /** Override the default SHA-256 hasher with argon2 / bcrypt for production. */\n hashPassword?: (plain: string) => Promise<string>;\n /** Companion verifier — must accept hashes produced by `hashPassword`. */\n verifyPassword?: (plain: string, hash: string) => Promise<boolean>;\n /**\n * Bypass the per-object opt-in check (useful when the schema scan is\n * happening after `start`). When omitted, calls against an object\n * without `publicSharing.enabled=true` are rejected with 422.\n */\n permissive?: boolean;\n}\n\n/**\n * Default `IShareLinkService` implementation.\n *\n * Persists every link in `sys_share_link`. The companion REST routes\n * (`registerShareLinkRoutes`) thin-wrap the service; the public\n * `/api/v1/share-links/:token` route resolves and re-injects the\n * \"share-link principal\" into the execution context so the standard\n * data middleware can authorise the downstream read.\n */\nexport class ShareLinkService implements IShareLinkService {\n private readonly engine: SharingEngine;\n private readonly permissive: boolean;\n private readonly hashPassword: (plain: string) => Promise<string>;\n private readonly verifyPassword: (plain: string, hash: string) => Promise<boolean>;\n\n constructor(opts: ShareLinkServiceOptions) {\n this.engine = opts.engine;\n this.permissive = opts.permissive ?? false;\n this.hashPassword = opts.hashPassword ?? defaultHashPassword;\n this.verifyPassword = opts.verifyPassword ?? defaultVerifyPassword;\n }\n\n async createLink(\n input: CreateShareLinkInput,\n context: ShareLinkExecutionContext,\n ): Promise<ShareLink> {\n if (!input.object) throw makeError(400, 'VALIDATION_FAILED', 'object is required');\n if (!input.recordId) throw makeError(400, 'VALIDATION_FAILED', 'recordId is required');\n\n const schema = this.engine.getSchema?.(input.object);\n const policy = getPolicy(schema);\n\n if (!policy.enabled && !this.permissive && !context.isSystem) {\n throw makeError(\n 422,\n 'SHARING_NOT_ENABLED',\n `Object '${input.object}' has not enabled publicSharing in its schema`,\n );\n }\n\n const permission: ShareLinkPermission = input.permission ?? 'view';\n if (policy.enabled && policy.allowedPermissions.length > 0 && !policy.allowedPermissions.includes(permission)) {\n throw makeError(\n 422,\n 'PERMISSION_NOT_ALLOWED',\n `Object '${input.object}' does not allow share permission '${permission}'. Allowed: ${policy.allowedPermissions.join(', ')}`,\n );\n }\n\n const audience: ShareLinkAudience = input.audience ?? 'link_only';\n if (policy.enabled && policy.allowedAudiences.length > 0 && !policy.allowedAudiences.includes(audience)) {\n throw makeError(\n 422,\n 'AUDIENCE_NOT_ALLOWED',\n `Object '${input.object}' does not allow audience '${audience}'. Allowed: ${policy.allowedAudiences.join(', ')}`,\n );\n }\n\n if (audience === 'email' && (!input.emailAllowlist || input.emailAllowlist.length === 0)) {\n throw makeError(400, 'VALIDATION_FAILED', 'emailAllowlist is required when audience=email');\n }\n\n // Confirm the target record actually exists — silently issuing\n // links against ghost rows is a footgun.\n const exists = await this.engine.find(input.object, {\n where: { id: input.recordId },\n fields: ['id'],\n limit: 1,\n context: SYSTEM_CTX,\n } as any);\n if (!Array.isArray(exists) || exists.length === 0) {\n throw makeError(404, 'RECORD_NOT_FOUND', `${input.object}/${input.recordId} does not exist`);\n }\n\n const maxDays = policy.maxExpiryDays ?? DEFAULT_MAX_EXPIRY_DAYS;\n const expires_at = normaliseExpiresAt(input.expiresAt, maxDays);\n\n const passwordHash = input.password ? await this.hashPassword(input.password) : null;\n\n const row: ShareLink = {\n id: `shl_${generateToken(16)}`,\n token: generateToken(TOKEN_LENGTH),\n object_name: input.object,\n record_id: input.recordId,\n permission,\n audience,\n expires_at,\n email_allowlist:\n input.emailAllowlist && input.emailAllowlist.length > 0\n ? input.emailAllowlist.map((e) => e.trim().toLowerCase()).filter(Boolean)\n : null,\n password_hash: passwordHash,\n redact_fields: input.redactFields && input.redactFields.length > 0 ? input.redactFields : null,\n label: input.label ?? null,\n revoked_at: null,\n created_by: context.userId ?? null,\n created_at: new Date().toISOString(),\n last_used_at: null,\n use_count: 0,\n };\n\n await this.engine.insert('sys_share_link', row, { context: SYSTEM_CTX });\n return row;\n }\n\n async revokeLink(idOrToken: string, _context: ShareLinkExecutionContext): Promise<void> {\n if (!idOrToken) throw makeError(400, 'VALIDATION_FAILED', 'id or token is required');\n const filter = idOrToken.startsWith('shl_') ? { id: idOrToken } : { token: idOrToken };\n const rows = await this.engine.find('sys_share_link', {\n where: filter,\n fields: ['id', 'revoked_at'],\n limit: 1,\n context: SYSTEM_CTX,\n } as any);\n const row = Array.isArray(rows) ? (rows[0] as any) : undefined;\n if (!row) return; // No-op when missing\n if (row.revoked_at) return; // Already revoked\n await this.engine.update(\n 'sys_share_link',\n { id: row.id, revoked_at: new Date().toISOString() },\n { context: SYSTEM_CTX },\n );\n }\n\n async listLinks(\n filter: ListShareLinksFilter,\n context: ShareLinkExecutionContext,\n ): Promise<ShareLink[]> {\n const where: Record<string, unknown> = {};\n if (filter.object) where.object_name = filter.object;\n if (filter.recordId) where.record_id = filter.recordId;\n if (filter.createdBy) where.created_by = filter.createdBy;\n if (!filter.includeRevoked) where.revoked_at = null;\n\n const rows = await this.engine.find('sys_share_link', {\n where,\n limit: 200,\n sort: [{ field: 'created_at', order: 'desc' }],\n context: context.isSystem ? SYSTEM_CTX : context,\n } as any);\n return Array.isArray(rows) ? (rows as ShareLink[]) : [];\n }\n\n async resolveToken(\n token: string,\n probe: { signedInUserId?: string; recipientEmail?: string; providedPassword?: string } = {},\n ): Promise<ResolveShareLinkResult | null> {\n if (!token || typeof token !== 'string' || token.length < 8) return null;\n\n const rows = await this.engine.find('sys_share_link', {\n where: { token },\n limit: 1,\n context: SYSTEM_CTX,\n } as any);\n const row = Array.isArray(rows) ? (rows[0] as ShareLink | undefined) : undefined;\n if (!row) return null;\n\n if (row.revoked_at) return null;\n if (row.expires_at && Date.parse(row.expires_at) <= Date.now()) return null;\n\n // Audience gating.\n if (row.audience === 'signed_in' && !probe.signedInUserId) return null;\n if (row.audience === 'email') {\n const allow = row.email_allowlist ?? [];\n const supplied = (probe.recipientEmail ?? '').trim().toLowerCase();\n if (!supplied || !allow.includes(supplied)) return null;\n }\n\n if (row.password_hash) {\n if (!probe.providedPassword) return null;\n const ok = await this.verifyPassword(probe.providedPassword, row.password_hash);\n if (!ok) return null;\n }\n\n // Compute the effective redaction set (object default ∪ per-link).\n const schema = this.engine.getSchema?.(row.object_name);\n const policy = getPolicy(schema);\n const redactFields = Array.from(\n new Set<string>([...(policy.redactFields ?? []), ...((row.redact_fields as string[]) ?? [])]),\n );\n\n // Stamp usage. Errors here MUST NOT block the read — log-and-continue.\n try {\n await this.engine.update(\n 'sys_share_link',\n {\n id: row.id,\n last_used_at: new Date().toISOString(),\n use_count: (row.use_count ?? 0) + 1,\n },\n { context: SYSTEM_CTX },\n );\n } catch {\n // best-effort — usage telemetry is a nice-to-have\n }\n\n return { link: row, redactFields };\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * REST surface for ShareLinkService.\n *\n * POST /api/v1/share-links → create a link\n * GET /api/v1/share-links → list links (?object, ?recordId, ?includeRevoked)\n * DELETE /api/v1/share-links/:idOrToken → revoke\n * GET /api/v1/share-links/:token/resolve → resolve token, returns { record, link, redactFields }\n *\n * The resolve route is intentionally public — it's the only endpoint\n * holders of a token need. It does:\n *\n * 1. Look up the row by token (via ShareLinkService.resolveToken,\n * which gates audience / expiry / password and stamps usage).\n * 2. Fetch the underlying record with a SYSTEM context (so the read\n * bypasses normal RLS — the token IS the authorisation).\n * 3. Strip `redactFields` from the record before returning.\n *\n * For browser-rendered share pages, the front-end calls this endpoint\n * and renders the response read-only.\n */\n\nimport type { IHttpServer, IHttpRequest, IHttpResponse, RouteHandler } from '@objectstack/spec/contracts';\nimport type { ShareLinkExecutionContext } from '@objectstack/spec/contracts';\nimport type { ShareLinkService } from './share-link-service.js';\nimport type { SharingEngine } from './sharing-service.js';\n\nconst SYSTEM_CTX = { isSystem: true, roles: [], permissions: [] } as const;\n\nexport interface ShareLinkRoutesOptions {\n basePath?: string;\n /** Read caller identity for authenticated routes. */\n contextFromRequest?: (req: IHttpRequest) => ShareLinkExecutionContext;\n}\n\nconst defaultContext = (req: IHttpRequest): ShareLinkExecutionContext => {\n const header = (name: string): string | undefined => {\n const v = req.headers?.[name];\n return Array.isArray(v) ? v[0] : v;\n };\n return {\n userId: header('x-user-id'),\n tenantId: header('x-tenant-id'),\n };\n};\n\nfunction sendError(res: IHttpResponse, status: number, code: string, message: string) {\n res.status(status).json({ error: { code, message } });\n}\n\n/** Strip `redactFields` from a record (also removes from nested arrays of objects). */\nfunction applyRedaction(record: any, redactFields: string[]): any {\n if (!record || typeof record !== 'object' || redactFields.length === 0) return record;\n if (Array.isArray(record)) return record.map((r) => applyRedaction(r, redactFields));\n const out: any = {};\n for (const [k, v] of Object.entries(record)) {\n if (redactFields.includes(k)) continue;\n out[k] = v;\n }\n return out;\n}\n\nexport function registerShareLinkRoutes(\n http: IHttpServer,\n service: ShareLinkService,\n engine: SharingEngine,\n opts: ShareLinkRoutesOptions = {},\n): void {\n const base = opts.basePath ?? '/api/v1/share-links';\n const ctxOf = opts.contextFromRequest ?? defaultContext;\n\n // ── CREATE ─────────────────────────────────────────────────────\n http.post(base, (async (req, res) => {\n try {\n const ctx = ctxOf(req);\n const body: any = req.body ?? {};\n if (!body.object || !body.recordId) {\n return sendError(res, 400, 'VALIDATION_FAILED', 'object and recordId are required');\n }\n const link = await service.createLink(\n {\n object: body.object,\n recordId: body.recordId,\n permission: body.permission,\n audience: body.audience,\n expiresAt: body.expiresAt ?? null,\n emailAllowlist: body.emailAllowlist,\n password: body.password,\n redactFields: body.redactFields,\n label: body.label,\n },\n ctx,\n );\n // Echo the token in the create response only — the listing\n // endpoint also returns it (admins need to copy/recreate URLs),\n // but downstream API consumers typically derive the public URL\n // from `link.token` immediately.\n await res.status(201).json({ link });\n } catch (err: any) {\n sendError(res, err?.status ?? 500, err?.code ?? 'INTERNAL', err?.message ?? 'Failed to create link');\n }\n }) satisfies RouteHandler);\n\n // ── LIST ───────────────────────────────────────────────────────\n http.get(base, (async (req, res) => {\n try {\n const ctx = ctxOf(req);\n const q = req.query ?? {};\n const link = await service.listLinks(\n {\n object: typeof q.object === 'string' ? q.object : undefined,\n recordId: typeof q.recordId === 'string' ? q.recordId : undefined,\n createdBy: typeof q.createdBy === 'string' ? q.createdBy : undefined,\n includeRevoked: q.includeRevoked === 'true' || q.includeRevoked === '1',\n },\n ctx,\n );\n await res.json({ links: link });\n } catch (err: any) {\n sendError(res, err?.status ?? 500, err?.code ?? 'INTERNAL', err?.message ?? 'Failed to list links');\n }\n }) satisfies RouteHandler);\n\n // ── REVOKE ─────────────────────────────────────────────────────\n http.delete(`${base}/:idOrToken`, (async (req, res) => {\n try {\n const ctx = ctxOf(req);\n await service.revokeLink(req.params.idOrToken, ctx);\n await res.status(200).json({ ok: true });\n } catch (err: any) {\n sendError(res, err?.status ?? 500, err?.code ?? 'INTERNAL', err?.message ?? 'Failed to revoke link');\n }\n }) satisfies RouteHandler);\n\n // ── PUBLIC RESOLVE ────────────────────────────────────────────\n //\n // No `ctxOf` here — the token IS the authorisation. We still allow\n // probes from a signed-in user so audience=signed_in is satisfiable.\n http.get(`${base}/:token/resolve`, (async (req, res) => {\n try {\n const q = req.query ?? {};\n const signedInUserId = (() => {\n const v = req.headers?.['x-user-id'];\n return Array.isArray(v) ? v[0] : v;\n })();\n const recipientEmail = typeof q.email === 'string' ? q.email : undefined;\n const providedPassword =\n typeof q.password === 'string'\n ? q.password\n : (() => {\n const v = req.headers?.['x-share-password'];\n return Array.isArray(v) ? v[0] : v;\n })();\n\n const resolved = await service.resolveToken(req.params.token, {\n signedInUserId,\n recipientEmail,\n providedPassword,\n });\n if (!resolved) {\n // Probe row to give a more useful status code (401 vs 404 vs 410).\n const probe = await engine.find('sys_share_link', {\n where: { token: req.params.token },\n limit: 1,\n context: SYSTEM_CTX,\n } as any);\n const row = Array.isArray(probe) && probe[0] ? (probe[0] as any) : null;\n if (row && !row.revoked_at && (!row.expires_at || Date.parse(row.expires_at) > Date.now())) {\n if (row.password_hash) {\n return sendError(\n res,\n 401,\n providedPassword ? 'WRONG_PASSWORD' : 'NEEDS_PASSWORD',\n providedPassword ? 'Incorrect password' : 'This link requires a password',\n );\n }\n if (row.audience === 'signed_in' && !signedInUserId) {\n return sendError(res, 401, 'SIGN_IN_REQUIRED', 'Please sign in to view this link');\n }\n }\n if (row && (row.revoked_at || (row.expires_at && Date.parse(row.expires_at) <= Date.now()))) {\n return sendError(res, 410, 'EXPIRED_OR_REVOKED', 'Share link has expired or been revoked');\n }\n return sendError(res, 404, 'INVALID_OR_EXPIRED', 'Share link is invalid, expired, or revoked');\n }\n\n // Fetch the underlying record with system context — the token\n // gates access, RLS does not.\n const rows = await engine.find(resolved.link.object_name, {\n where: { id: resolved.link.record_id },\n limit: 1,\n context: SYSTEM_CTX,\n } as any);\n const record = Array.isArray(rows) && rows[0] ? rows[0] : null;\n if (!record) {\n return sendError(res, 410, 'RECORD_GONE', 'The shared record no longer exists');\n }\n\n await res.json({\n record: applyRedaction(record, resolved.redactFields),\n link: {\n id: resolved.link.id,\n token: resolved.link.token,\n object_name: resolved.link.object_name,\n record_id: resolved.link.record_id,\n permission: resolved.link.permission,\n audience: resolved.link.audience,\n expires_at: resolved.link.expires_at,\n label: resolved.link.label,\n created_at: resolved.link.created_at,\n },\n redactFields: resolved.redactFields,\n });\n } catch (err: any) {\n sendError(res, err?.status ?? 500, err?.code ?? 'INTERNAL', err?.message ?? 'Failed to resolve link');\n }\n }) satisfies RouteHandler);\n\n // ──────────────────────────────────────────────────────────────\n // Object-specific related-records lookup.\n //\n // Some objects only make sense alongside their children — most\n // notably `ai_conversations` and the `ai_messages` they own. Rather\n // than baking every relationship into the resolver, we expose a\n // narrow, opt-in `GET /:token/messages` route that:\n //\n // 1. Re-validates the capability token (so revocation / expiry\n // kicks in even after the original resolve).\n // 2. Confirms the shared record really is an `ai_conversations`.\n // 3. Returns the conversation's messages, ordered by creation.\n //\n // Other object kinds can register additional public endpoints\n // following the same pattern.\n // ──────────────────────────────────────────────────────────────\n http.get(`${base}/:token/messages`, (async (req, res) => {\n try {\n const password =\n typeof req.query?.password === 'string' ? (req.query.password as string) : undefined;\n const resolved = await service.resolveToken(req.params.token, { providedPassword: password });\n if (!resolved) {\n sendError(res, 404, 'NOT_FOUND', 'Share link not found');\n return;\n }\n if (resolved.link.object_name !== 'ai_conversations') {\n sendError(res, 400, 'UNSUPPORTED', 'This share link does not expose messages');\n return;\n }\n const SYSTEM_CTX = { isSystem: true, roles: [], permissions: [] } as const;\n const rows = await engine.find('ai_messages', {\n where: { conversation_id: resolved.link.record_id },\n sort: [{ field: 'created_at', direction: 'asc' }],\n limit: 500,\n context: SYSTEM_CTX,\n } as any);\n res.status(200).json({ data: rows ?? [] });\n } catch (err: any) {\n sendError(\n res,\n err?.status ?? 500,\n err?.code ?? 'INTERNAL',\n err?.message ?? 'Failed to load messages',\n );\n }\n }) satisfies RouteHandler);\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { SharingRuleService } from './sharing-rule-service.js';\nimport type { SharingRuleRow } from '@objectstack/spec/contracts';\n\nconst SYSTEM_CTX = { isSystem: true, roles: [], permissions: [] } as const;\n\nexport const SHARING_RULE_HOOK_PACKAGE = 'plugin-sharing:rules';\n\ninterface MinimalEngine {\n registerHook(event: string, handler: (ctx: any) => any | Promise<any>, options?: {\n object?: string | string[];\n priority?: number;\n packageId?: string;\n }): void;\n unregisterHooksByPackage(packageId: string): number;\n}\n\ninterface MinimalLogger {\n info?: (msg: any, ...rest: any[]) => void;\n warn?: (msg: any, ...rest: any[]) => void;\n}\n\n/**\n * Bind afterInsert/afterUpdate hooks for every distinct object_name in\n * `rules`. Each hook calls `service.evaluateAllForRecord(object, id, …)`\n * with SYSTEM_CTX so the evaluator can write `sys_record_share` rows\n * without being blocked by its own enforcement.\n *\n * Caller is responsible for invoking {@link unbindAllRuleHooks} before\n * re-binding when the rule set changes.\n */\nexport function bindRuleHooks(\n engine: MinimalEngine,\n service: SharingRuleService,\n rules: SharingRuleRow[],\n logger?: MinimalLogger,\n): void {\n const objects = new Set<string>();\n for (const r of rules) {\n if (r.active === false) continue;\n if (r.object_name) objects.add(r.object_name);\n }\n for (const objectName of objects) {\n const handler = async (ctx: any) => {\n if ((ctx?.session as any)?.isSystem) return;\n try {\n const data = ctx?.result ?? ctx?.input?.data ?? {};\n const id = String((data as any)?.id ?? ctx?.input?.id ?? '');\n if (!id) return;\n await service.evaluateAllForRecord(objectName, id, SYSTEM_CTX as any);\n } catch (err: any) {\n logger?.warn?.('[sharing-rule] hook evaluation failed', { object: objectName, error: err?.message });\n }\n };\n engine.registerHook('afterInsert', handler, { object: objectName, packageId: SHARING_RULE_HOOK_PACKAGE, priority: 180 });\n engine.registerHook('afterUpdate', handler, { object: objectName, packageId: SHARING_RULE_HOOK_PACKAGE, priority: 180 });\n }\n logger?.info?.('[sharing-rule] hooks bound', { objects: Array.from(objects), ruleCount: rules.length });\n}\n\nexport function unbindAllRuleHooks(engine: MinimalEngine): number {\n return engine.unregisterHooksByPackage(SHARING_RULE_HOOK_PACKAGE);\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport type { EngineMiddleware, OperationContext } from '@objectstack/objectql';\nimport type { IHttpServer } from '@objectstack/spec/contracts';\nimport { SysRecordShare, SysSharingRule, SysShareLink } from '@objectstack/platform-objects/security';\nimport { SysDepartment, SysDepartmentMember } from '@objectstack/platform-objects/identity';\nimport { SharingService, type SharingEngine } from './sharing-service.js';\nimport { SharingRuleService } from './sharing-rule-service.js';\nimport { ShareLinkService } from './share-link-service.js';\nimport { registerShareLinkRoutes } from './share-link-routes.js';\nimport { bindRuleHooks, unbindAllRuleHooks } from './rule-hooks.js';\n\nexport interface SharingPluginOptions {\n /** Extra object names that bypass sharing entirely. */\n bypassObjects?: string[];\n /**\n * Disable enforcement (read filter + canEdit) while still registering\n * the schema + service. Useful in development to flip enforcement on\n * via env var without rebuilding.\n */\n enforce?: boolean;\n /**\n * Disable the public share-link REST routes. The `IShareLinkService`\n * is always registered (other services may depend on it); only the\n * HTTP surface is suppressed.\n */\n registerShareLinkRoutes?: boolean;\n /**\n * Base path for the share-link REST surface. Defaults to\n * `/api/v1/share-links`.\n */\n shareLinkBasePath?: string;\n}\n\n/**\n * SharingServicePlugin — registers `sys_record_share`, the `sharing`\n * service, and the engine middleware that enforces\n * `object.sharingModel`.\n *\n * Enforcement is opt-in per object:\n *\n * - `sharingModel: 'private'` → reads filtered to `(owner_id == me) OR\n * (record explicitly shared with me)`. Writes require ownership or\n * an `edit`/`full` share.\n * - `sharingModel: 'read'` → reads unrestricted; writes gated as\n * above (typical \"everyone can see, only owner can edit\").\n * - any other value (or no value) → no enforcement. This keeps\n * existing CRM behaviour identical until admins explicitly enable\n * sharing on a per-object basis.\n *\n * @example\n * ```ts\n * import { SharingServicePlugin } from '@objectstack/plugin-sharing';\n *\n * kernel.use(new SharingServicePlugin());\n *\n * // Mark an object private — middleware enforces from this point on.\n * defineObject({\n * name: 'account',\n * sharingModel: 'private',\n * fields: { owner_id: Field.lookup('sys_user'), ... },\n * });\n * ```\n */\nexport class SharingServicePlugin implements Plugin {\n name = 'com.objectstack.service.sharing';\n version = '1.0.0';\n type = 'standard';\n dependencies = ['com.objectstack.engine.objectql'];\n\n private readonly options: SharingPluginOptions;\n private service?: SharingService;\n private ruleService?: SharingRuleService;\n private linkService?: ShareLinkService;\n\n constructor(options: SharingPluginOptions = {}) {\n this.options = options;\n }\n\n async init(ctx: PluginContext): Promise<void> {\n // Register sys_record_share via the manifest service.\n ctx.getService<{ register(m: any): void }>('manifest').register({\n id: 'com.objectstack.service.sharing',\n name: 'Sharing Service',\n version: '1.0.0',\n type: 'plugin',\n scope: 'system',\n defaultDatasource: 'cloud',\n namespace: 'sys',\n objects: [SysRecordShare, SysSharingRule, SysDepartment, SysDepartmentMember, SysShareLink],\n });\n ctx.logger.info('SharingServicePlugin: schema registered');\n }\n\n async start(ctx: PluginContext): Promise<void> {\n ctx.hook('kernel:ready', async () => {\n let engine: any = null;\n try { engine = ctx.getService<any>('objectql'); }\n catch { try { engine = ctx.getService<any>('data'); } catch { /* ignore */ } }\n if (!engine) {\n ctx.logger.warn('SharingServicePlugin: no ObjectQL engine — service NOT registered');\n return;\n }\n\n this.service = new SharingService({\n engine: engine as SharingEngine,\n bypassObjects: this.options.bypassObjects,\n });\n ctx.registerService('sharing', this.service);\n\n if (this.options.enforce === false) {\n ctx.logger.info('SharingServicePlugin: enforcement disabled (enforce=false)');\n return;\n }\n\n const mw = buildSharingMiddleware(this.service);\n if (typeof engine.registerMiddleware === 'function') {\n engine.registerMiddleware(mw, { object: '*' });\n ctx.logger.info('SharingServicePlugin: enforcement middleware installed');\n } else {\n ctx.logger.warn('SharingServicePlugin: engine has no registerMiddleware — enforcement not applied');\n }\n\n // Rule evaluator + hot-rebindable lifecycle hooks.\n try {\n this.ruleService = new SharingRuleService({\n engine: engine as SharingEngine,\n sharing: this.service,\n logger: ctx.logger as any,\n });\n ctx.registerService('sharingRules', this.ruleService);\n\n if (typeof engine.registerHook === 'function' && typeof engine.unregisterHooksByPackage === 'function') {\n const rules = await this.ruleService.listRules({ activeOnly: true }, { isSystem: true } as any);\n unbindAllRuleHooks(engine);\n bindRuleHooks(engine, this.ruleService, rules, ctx.logger as any);\n } else {\n ctx.logger.warn('SharingServicePlugin: engine has no hook API — sharing rule auto-evaluation disabled');\n }\n } catch (err: any) {\n ctx.logger.warn('SharingServicePlugin: sharing-rule subsystem not started', { error: err?.message });\n }\n\n // ── Share-Link service (capability tokens) ────────────────\n //\n // Registered alongside the principal-based sharing service so\n // both surfaces resolve through the same kernel. The HTTP\n // endpoints are optional — services that just want programmatic\n // access can set `registerShareLinkRoutes: false` and call the\n // service via `ctx.getService('shareLinks')`.\n try {\n this.linkService = new ShareLinkService({ engine: engine as SharingEngine });\n ctx.registerService('shareLinks', this.linkService);\n\n if (this.options.registerShareLinkRoutes !== false) {\n let http: IHttpServer | null = null;\n try {\n http = ctx.getService<IHttpServer>('http-server');\n } catch {\n // No HTTP server — service still reachable via getService.\n }\n if (http) {\n registerShareLinkRoutes(http, this.linkService, engine as SharingEngine, {\n basePath: this.options.shareLinkBasePath,\n });\n ctx.logger.info(\n 'SharingServicePlugin: share-link routes mounted at ' +\n (this.options.shareLinkBasePath ?? '/api/v1/share-links'),\n );\n } else {\n ctx.logger.warn(\n 'SharingServicePlugin: no HTTP server — share-link REST routes not registered. ' +\n 'ShareLinkService is still reachable via kernel.getService(\"shareLinks\").',\n );\n }\n }\n } catch (err: any) {\n ctx.logger.warn('SharingServicePlugin: share-link subsystem not started', { error: err?.message });\n }\n });\n }\n}\n\n/**\n * Build the engine middleware that injects read filters and gates\n * write operations. Exported so it can be unit-tested without booting\n * a kernel.\n */\nexport function buildSharingMiddleware(service: SharingService): EngineMiddleware {\n return async function sharingMiddleware(ctx: OperationContext, next: () => Promise<void>) {\n const op = ctx.operation;\n const exec = ctx.context as any;\n\n // READS — AND the visibility filter into the AST.\n if (op === 'find' || op === 'findOne' || op === 'count' || op === 'aggregate') {\n const filter = await service.buildReadFilter(ctx.object, exec ?? {});\n if (filter) {\n const ast: any = ctx.ast ?? {};\n ast.where = composeAnd(ast.where, filter);\n ast.filter = composeAnd(ast.filter, filter);\n ctx.ast = ast;\n }\n return next();\n }\n\n // WRITES — gate on canEdit for update / delete.\n if (op === 'update' || op === 'delete') {\n const data: any = ctx.data;\n const options: any = ctx.options;\n const id = inferTargetId(data, options);\n if (id != null) {\n const ok = await service.canEdit(ctx.object, String(id), exec ?? {});\n if (!ok) {\n const err: any = new Error(\n `FORBIDDEN: insufficient privileges to ${op} ${ctx.object} ${id}`,\n );\n err.code = 'FORBIDDEN';\n err.status = 403;\n throw err;\n }\n }\n return next();\n }\n\n // INSERT / others pass through — ownership stamping is the\n // application's job (and is enforced by existing field defaults).\n return next();\n };\n}\n\nfunction composeAnd(existing: unknown, addition: unknown): unknown {\n if (existing == null) return addition;\n if (addition == null) return existing;\n // Both objects — merge with $and.\n if (\n typeof existing === 'object' && existing !== null && !Array.isArray(existing) &&\n typeof addition === 'object' && addition !== null && !Array.isArray(addition)\n ) {\n const ex: any = existing;\n if (Array.isArray(ex.$and)) {\n return { $and: [...ex.$and, addition] };\n }\n // Heuristic: if existing has no operator keys, attempt shallow merge;\n // otherwise nest into $and to preserve semantics.\n return { $and: [existing, addition] };\n }\n return { $and: [existing, addition] };\n}\n\nfunction inferTargetId(data: any, options: any): string | number | undefined {\n if (data && typeof data === 'object' && data.id != null) return data.id;\n if (options && typeof options === 'object') {\n if (options.id != null) return options.id;\n if (options.where && typeof options.where === 'object' && options.where.id != null) {\n return options.where.id;\n }\n if (options.filter && typeof options.filter === 'object' && options.filter.id != null) {\n return options.filter.id;\n }\n }\n return undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA,IAAAA,mBAA6D;AAC7D,IAAAC,mBAAmD;;;ACgBnD,SAAS,cAAsB;AAC7B,QAAM,IAAS;AACf,MAAI,EAAE,QAAQ,WAAY,QAAO,OAAO,EAAE,OAAO,WAAW,CAAC;AAC7D,SAAO,OAAO,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AAClF;AAGA,IAAM,aAAa,EAAE,UAAU,MAAM,OAAO,CAAC,GAAG,aAAa,CAAC,EAAE;AAShE,IAAM,cAAc;AAQpB,SAAS,sBAAsB,QAA4C;AACzE,QAAM,IAAI,QAAQ,gBAAgB,QAAQ,UAAU;AACpD,MAAI,MAAM,UAAW,QAAO;AAC5B,MAAI,MAAM,OAAQ,QAAO;AACzB,SAAO;AACT;AAEA,SAAS,cAAc,QAAsB;AAC3C,SAAO,QAAQ,QAAQ,UAAU,eAAe,OAAO,MAAM;AAC/D;AAgBO,IAAM,iBAAN,MAAgD;AAAA,EAIrD,YAAY,SAAgC;AAC1C,SAAK,SAAS,QAAQ;AACtB,SAAK,gBAAgB,oBAAI,IAAI;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAI,QAAQ,iBAAiB,CAAC;AAAA,IAChC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,gBACJ,QACA,SACyB;AACzB,QAAI,KAAK,aAAa,QAAQ,OAAO,EAAG,QAAO;AAE/C,UAAM,SAAS,KAAK,OAAO,YAAY,MAAM;AAC7C,QAAI,CAAC,OAAQ,QAAO;AACpB,QAAI,sBAAsB,MAAM,MAAM,UAAW,QAAO;AACxD,QAAI,CAAC,cAAc,MAAM,EAAG,QAAO;AACnC,QAAI,CAAC,QAAQ,QAAQ;AAInB,aAAO,EAAE,IAAI,eAAe;AAAA,IAC9B;AAEA,UAAM,SAAS,MAAM,KAAK,OAAO,KAAK,oBAAoB;AAAA,MACxD,QAAQ;AAAA,QACN,aAAa;AAAA,QACb,gBAAgB;AAAA,QAChB,cAAc,QAAQ;AAAA,MACxB;AAAA,MACA,QAAQ,CAAC,aAAa,cAAc;AAAA,MACpC,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAED,UAAM,aAAuB,MAAM,QAAQ,MAAM,IAC7C,OAAO,IAAI,CAAC,MAAW,OAAO,EAAE,SAAS,CAAC,EAAE,OAAO,OAAO,IAC1D,CAAC;AAEL,QAAI,WAAW,WAAW,GAAG;AAC3B,aAAO,EAAE,CAAC,WAAW,GAAG,QAAQ,OAAO;AAAA,IACzC;AAEA,WAAO;AAAA,MACL,KAAK;AAAA,QACH,EAAE,CAAC,WAAW,GAAG,QAAQ,OAAO;AAAA,QAChC,EAAE,IAAI,EAAE,KAAK,WAAW,EAAE;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,QACJ,QACA,UACA,SACkB;AAClB,QAAI,KAAK,aAAa,QAAQ,OAAO,EAAG,QAAO;AAE/C,UAAM,SAAS,KAAK,OAAO,YAAY,MAAM;AAC7C,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,QAAQ,sBAAsB,MAAM;AAC1C,QAAI,UAAU,SAAU,QAAO;AAC/B,QAAI,CAAC,cAAc,MAAM,EAAG,QAAO;AACnC,QAAI,CAAC,QAAQ,OAAQ,QAAO;AAG5B,UAAM,MAAM,MAAM,KAAK,OAAO,KAAK,QAAQ;AAAA,MACzC,QAAQ,EAAE,IAAI,SAAS;AAAA,MACvB,QAAQ,CAAC,MAAM,WAAW;AAAA,MAC1B,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AACD,UAAM,QAAQ,MAAM,QAAQ,GAAG,KAAK,IAAI,CAAC,IAAK,IAAI,CAAC,EAAU,WAAW,IAAI;AAC5E,QAAI,SAAS,OAAO,KAAK,MAAM,OAAO,QAAQ,MAAM,EAAG,QAAO;AAG9D,UAAM,aAAa,MAAM,KAAK,OAAO,KAAK,oBAAoB;AAAA,MAC5D,QAAQ;AAAA,QACN,aAAa;AAAA,QACb,WAAW;AAAA,QACX,gBAAgB;AAAA,QAChB,cAAc,QAAQ;AAAA,QACtB,cAAc,EAAE,KAAK,CAAC,QAAQ,MAAM,EAAE;AAAA,MACxC;AAAA,MACA,QAAQ,CAAC,IAAI;AAAA,MACb,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AACD,WAAO,MAAM,QAAQ,UAAU,KAAK,WAAW,SAAS;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,MACJ,OACA,SACsB;AACtB,QAAI,CAAC,MAAM,OAAQ,OAAM,IAAI,MAAM,uCAAuC;AAC1E,QAAI,CAAC,MAAM,SAAU,OAAM,IAAI,MAAM,yCAAyC;AAC9E,QAAI,CAAC,MAAM,YAAa,OAAM,IAAI,MAAM,4CAA4C;AAEpF,UAAM,gBAAgB,MAAM,iBAAiB;AAC7C,UAAM,cAAgC,MAAM,eAAe;AAC3D,UAAM,SAAS,MAAM,UAAU;AAI/B,UAAM,WAAW,MAAM,KAAK,OAAO,KAAK,oBAAoB;AAAA,MAC1D,QAAQ;AAAA,QACN,aAAa,MAAM;AAAA,QACnB,WAAW,MAAM;AAAA,QACjB,gBAAgB;AAAA,QAChB,cAAc,MAAM;AAAA,MACtB;AAAA,MACA,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AACD,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,QAAI,MAAM,QAAQ,QAAQ,KAAK,SAAS,CAAC,GAAG;AAC1C,YAAMC,OAAW,SAAS,CAAC;AAC3B,YAAM,QAAa;AAAA,QACjB,IAAIA,KAAI;AAAA,QACR,cAAc;AAAA,QACd;AAAA,QACA,WAAW,MAAM,YAAYA,KAAI,aAAa;AAAA,QAC9C,QAAQ,MAAM,UAAUA,KAAI,UAAU;AAAA,QACtC,YAAY;AAAA,MACd;AACA,YAAM,KAAK,OAAO,OAAO,oBAAoB,OAAO,EAAE,SAAS,WAAW,CAAC;AAC3E,aAAO,EAAE,GAAGA,MAAK,GAAG,MAAM;AAAA,IAC5B;AAEA,UAAM,KAAK,YAAY;AACvB,UAAM,MAAW;AAAA,MACf;AAAA,MACA,aAAa,MAAM;AAAA,MACnB,WAAW,MAAM;AAAA,MACjB,gBAAgB;AAAA,MAChB,cAAc,MAAM;AAAA,MACpB,cAAc;AAAA,MACd;AAAA,MACA,WAAW,MAAM,YAAY;AAAA,MAC7B,YAAY,QAAQ,UAAU;AAAA,MAC9B,QAAQ,MAAM,UAAU;AAAA,MACxB,YAAY;AAAA,MACZ,YAAY;AAAA,IACd;AACA,UAAM,KAAK,OAAO,OAAO,oBAAoB,KAAK,EAAE,SAAS,WAAW,CAAC;AACzE,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,OAAO,SAAiB,UAAkD;AAC9E,QAAI,CAAC,QAAS,OAAM,IAAI,MAAM,wCAAwC;AACtE,UAAM,KAAK,OAAO,OAAO,oBAAoB;AAAA,MAC3C,OAAO,EAAE,IAAI,QAAQ;AAAA,MACrB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,WACJ,QACA,UACA,UACwB;AACxB,UAAM,OAAO,MAAM,KAAK,OAAO,KAAK,oBAAoB;AAAA,MACtD,QAAQ,EAAE,aAAa,QAAQ,WAAW,SAAS;AAAA,MACnD,SAAS,CAAC,EAAE,OAAO,cAAc,WAAW,OAAO,CAAC;AAAA,MACpD,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AACD,WAAO,MAAM,QAAQ,IAAI,IAAK,OAAyB,CAAC;AAAA,EAC1D;AAAA;AAAA,EAIQ,aAAa,QAAgB,SAA2C;AAC9E,QAAI,SAAS,SAAU,QAAO;AAC9B,QAAI,KAAK,cAAc,IAAI,MAAM,EAAG,QAAO;AAC3C,WAAO;AAAA,EACT;AACF;;;ACrRA,IAAMC,cAAa,EAAE,UAAU,MAAM,OAAO,CAAC,GAAG,aAAa,CAAC,EAAE;AA6BzD,IAAM,mBAAN,MAAoD;AAAA,EAKzD,YAAY,MAAwB;AAvCtC;AAwCI,SAAK,SAAS,KAAK;AACnB,SAAK,iBAAiB,KAAK,kBAAkB;AAC7C,SAAK,QAAQ,KAAK,SAAS,CAAC;AAC5B,eAAK,OAAM,gBAAX,GAAW,cAAgB,oBAAI,IAAI;AACnC,eAAK,OAAM,eAAX,GAAW,aAAe,oBAAI,IAAI;AAClC,eAAK,OAAM,YAAX,GAAW,UAAY,oBAAI,IAAI;AAAA,EACjC;AAAA,EAEA,MAAM,YAAY,QAAmC;AACnD,QAAI,CAAC,OAAQ,QAAO,CAAC;AACrB,UAAM,SAAS,KAAK,MAAM,YAAa,IAAI,MAAM;AACjD,QAAI,OAAQ,QAAO;AAEnB,QAAI,OAAc,CAAC;AACnB,QAAI;AACF,aAAO,MAAM,KAAK,OAAO,KAAK,mBAAmB;AAAA,QAC/C,QAAQ,EAAE,SAAS,OAAO;AAAA,QAC1B,QAAQ,CAAC,SAAS;AAAA,QAClB,OAAO;AAAA,QACP,SAASA;AAAA,MACX,CAAC;AAAA,IACH,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AACA,UAAM,QAAQ,MAAM,KAAK,IAAI,KAAK,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAW,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,OAAO,CAAC,CAAC;AACvG,SAAK,MAAM,YAAa,IAAI,QAAQ,KAAK;AACzC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,gBAAgB,UAAkB,gBAA4C;AAClF,QAAI,CAAC,SAAU,QAAO,CAAC;AACvB,UAAM,MAAM,GAAG,kBAAkB,KAAK,kBAAkB,GAAG,KAAK,QAAQ;AACxE,UAAM,SAAS,KAAK,MAAM,WAAY,IAAI,GAAG;AAC7C,QAAI,OAAQ,QAAO;AACnB,UAAM,SAAkC,EAAE,MAAM,SAAS;AACzD,UAAM,MAAM,kBAAkB,KAAK;AACnC,QAAI,IAAK,QAAO,kBAAkB;AAClC,QAAI,OAAc,CAAC;AACnB,QAAI;AACF,aAAO,MAAM,KAAK,OAAO,KAAK,cAAc;AAAA,QAC1C;AAAA,QACA,QAAQ,CAAC,SAAS;AAAA,QAClB,OAAO;AAAA,QACP,SAASA;AAAA,MACX,CAAC;AAAA,IACH,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AACA,UAAM,QAAQ,MAAM,KAAK,IAAI,KAAK,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAW,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,OAAO,CAAC,CAAC;AACvG,SAAK,MAAM,WAAY,IAAI,KAAK,KAAK;AACrC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAAU,QAAgB,iBAAkD;AAChF,QAAI,CAAC,OAAQ,QAAO;AACpB,QAAI,KAAK,MAAM,QAAS,IAAI,MAAM,EAAG,QAAO,KAAK,MAAM,QAAS,IAAI,MAAM,KAAK;AAC/E,QAAI,MAAW;AACf,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,OAAO,KAAK,YAAY;AAAA,QAC9C,QAAQ,EAAE,IAAI,OAAO;AAAA,QACrB,QAAQ,CAAC,MAAM,YAAY;AAAA,QAC3B,OAAO;AAAA,QACP,SAASA;AAAA,MACX,CAAC;AACD,YAAM,MAAM,QAAQ,IAAI,IAAI,KAAK,CAAC,IAAI;AAAA,IACxC,QAAQ;AACN,YAAM;AAAA,IACR;AACA,UAAM,MAAM,KAAK,aAAa,OAAO,IAAI,UAAU,IAAI;AACvD,SAAK,MAAM,QAAS,IAAI,QAAQ,GAAG;AACnC,WAAO;AAAA,EACT;AACF;AAkBA,eAAsB,gBACpB,OACA,KACmB;AACnB,QAAM,IAAI,MAAM;AAChB,QAAM,IAAI,OAAO,MAAM,SAAS,EAAE;AAClC,MAAI,CAAC,EAAG,QAAO,CAAC;AAChB,MAAI,MAAM,OAAQ,QAAO,CAAC,CAAC;AAC3B,MAAI,MAAM,OAAQ,QAAO,IAAI,KAAK,YAAY,CAAC;AAC/C,MAAI,MAAM,gBAAgB,MAAM,QAAQ;AACtC,QAAI,IAAI,KAAM,QAAO,IAAI,KAAK,YAAY,CAAC;AAC3C,WAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;AAAA,EACrB;AACA,MAAI,MAAM,OAAQ,QAAO,IAAI,KAAK,gBAAgB,GAAG,IAAI,kBAAkB,MAAS;AACpF,MAAI,MAAM,WAAW,MAAM,QAAQ;AACjC,UAAM,KAAM,MAAM,OAAe,CAAC;AAClC,WAAO,KAAK,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC;AAAA,EAC9B;AACA,MAAI,MAAM,aAAa,MAAM,QAAQ;AACnC,UAAM,UAAW,MAAM,OAAe,CAAC,KAAM,MAAM,OAAe;AAClE,QAAI,CAAC,QAAS,QAAO,CAAC;AACtB,UAAM,MAAM,MAAM,IAAI,KAAK,UAAU,OAAO,OAAO,GAAG,IAAI,kBAAkB,MAAS;AACrF,WAAO,MAAM,CAAC,GAAG,IAAI,CAAC;AAAA,EACxB;AAGA,SAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;AACrB;;;ACvJA,IAAMC,cAAa,EAAE,UAAU,MAAM,OAAO,CAAC,GAAG,aAAa,CAAC,EAAE;AAkCzD,IAAM,yBAAN,MAAgE;AAAA,EAMrE,YAAY,MAA8B;AA9C5C;AA+CI,SAAK,SAAS,KAAK;AACnB,SAAK,iBAAiB,KAAK,kBAAkB;AAC7C,SAAK,QAAQ,KAAK,SAAS,CAAC;AAC5B,eAAK,OAAM,gBAAX,GAAW,cAAgB,oBAAI,IAAI;AACnC,eAAK,OAAM,gBAAX,GAAW,cAAgB,oBAAI,IAAI;AACnC,eAAK,OAAM,SAAX,GAAW,OAAS,oBAAI,IAAI;AAC5B,SAAK,YAAY,KAAK;AAAA,EACxB;AAAA,EAEA,MAAM,YAAY,cAAyC;AACzD,QAAI,CAAC,aAAc,QAAO,CAAC;AAC3B,UAAM,SAAS,KAAK,MAAM,YAAa,IAAI,YAAY;AACvD,QAAI,OAAQ,QAAO;AAGnB,QAAI,aAAa;AACjB,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,OAAO,KAAK,kBAAkB;AAAA,QACxD,QAAQ,KAAK,SAAS,EAAE,IAAI,aAAa,CAAC;AAAA,QAC1C,QAAQ,CAAC,MAAM,QAAQ;AAAA,QACvB,OAAO;AAAA,QACP,SAASA;AAAA,MACX,CAAC;AACD,YAAM,UAAe,MAAM,QAAQ,QAAQ,IAAI,SAAS,CAAC,IAAI;AAC7D,UAAI,CAAC,QAAS,cAAa;AAAA,eAClB,QAAQ,WAAW,MAAO,cAAa;AAAA,IAClD,QAAQ;AACN,mBAAa;AAAA,IACf;AACA,QAAI,CAAC,YAAY;AACf,WAAK,MAAM,YAAa,IAAI,cAAc,CAAC,CAAC;AAC5C,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,OAAO,oBAAI,IAAY,CAAC,YAAY,CAAC;AAC3C,UAAM,QAAkB,CAAC,YAAY;AACrC,WAAO,MAAM,QAAQ;AACnB,YAAM,SAAS,MAAM,MAAM;AAC3B,UAAI,WAAkB,CAAC;AACvB,UAAI;AACF,mBAAW,MAAM,KAAK,OAAO,KAAK,kBAAkB;AAAA,UAClD,QAAQ,KAAK,SAAS,EAAE,sBAAsB,QAAQ,QAAQ,EAAE,KAAK,MAAM,EAAE,CAAC;AAAA,UAC9E,QAAQ,CAAC,IAAI;AAAA,UACb,OAAO;AAAA,UACP,SAASA;AAAA,QACX,CAAC;AAAA,MACH,QAAQ;AACN,mBAAW,CAAC;AAAA,MACd;AACA,iBAAW,KAAK,YAAY,CAAC,GAAG;AAC9B,cAAM,MAAM,OAAQ,EAAU,MAAM,EAAE;AACtC,YAAI,OAAO,CAAC,KAAK,IAAI,GAAG,GAAG;AACzB,eAAK,IAAI,GAAG;AACZ,gBAAM,KAAK,GAAG;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AACA,UAAM,MAAM,MAAM,KAAK,IAAI;AAC3B,SAAK,MAAM,YAAa,IAAI,cAAc,GAAG;AAC7C,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,YAAY,cAAyC;AACzD,QAAI,CAAC,aAAc,QAAO,CAAC;AAC3B,UAAM,SAAS,KAAK,MAAM,YAAa,IAAI,YAAY;AACvD,QAAI,OAAQ,QAAO;AAEnB,UAAM,QAAQ,MAAM,KAAK,YAAY,YAAY;AACjD,QAAI,MAAM,WAAW,EAAG,QAAO,CAAC;AAEhC,QAAI,OAAc,CAAC;AACnB,QAAI;AACF,aAAO,MAAM,KAAK,OAAO,KAAK,yBAAyB;AAAA,QACrD,QAAQ,EAAE,eAAe,EAAE,KAAK,MAAM,EAAE;AAAA,QACxC,QAAQ,CAAC,SAAS;AAAA,QAClB,OAAO;AAAA,QACP,SAASA;AAAA,MACX,CAAC;AAAA,IACH,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AACA,UAAM,QAAQ,MAAM;AAAA,MAClB,IAAI,KAAK,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAW,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,OAAO,CAAC;AAAA,IAC/E;AACA,SAAK,MAAM,YAAa,IAAI,cAAc,KAAK;AAC/C,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAAO,cAA8C;AACzD,QAAI,CAAC,aAAc,QAAO;AAC1B,QAAI,KAAK,MAAM,KAAM,IAAI,YAAY,EAAG,QAAO,KAAK,MAAM,KAAM,IAAI,YAAY,KAAK;AACrF,QAAI,MAAW;AACf,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,OAAO,KAAK,kBAAkB;AAAA,QACpD,QAAQ,EAAE,IAAI,aAAa;AAAA,QAC3B,QAAQ,CAAC,MAAM,iBAAiB;AAAA,QAChC,OAAO;AAAA,QACP,SAASA;AAAA,MACX,CAAC;AACD,YAAM,MAAM,QAAQ,IAAI,IAAI,KAAK,CAAC,IAAI;AAAA,IACxC,QAAQ;AACN,YAAM;AAAA,IACR;AACA,UAAM,OAAO,KAAK,kBAAkB,OAAO,IAAI,eAAe,IAAI;AAClE,SAAK,MAAM,KAAM,IAAI,cAAc,IAAI;AACvC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAAU,QAAgB,gBAAiD;AAC/E,QAAI,KAAK,UAAW,QAAO,KAAK,UAAU,UAAU,QAAQ,cAAc;AAE1E,QAAI,CAAC,OAAQ,QAAO;AACpB,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,OAAO,KAAK,YAAY;AAAA,QAC9C,QAAQ,EAAE,IAAI,OAAO;AAAA,QACrB,QAAQ,CAAC,MAAM,YAAY;AAAA,QAC3B,OAAO;AAAA,QACP,SAASA;AAAA,MACX,CAAC;AACD,YAAM,MAAW,MAAM,QAAQ,IAAI,IAAI,KAAK,CAAC,IAAI;AACjD,aAAO,KAAK,aAAa,OAAO,IAAI,UAAU,IAAI;AAAA,IACpD,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEQ,SAAS,QAA0D;AACzE,QAAI,KAAK,eAAgB,QAAO,EAAE,GAAG,QAAQ,iBAAiB,KAAK,eAAe;AAClF,WAAO;AAAA,EACT;AACF;;;ACjKA,IAAMC,cAAa,EAAE,UAAU,MAAM,OAAO,CAAC,GAAG,aAAa,CAAC,EAAE;AAEhE,SAAS,IAAI,QAAwB;AACnC,QAAM,IAAS;AACf,MAAI,EAAE,QAAQ,WAAY,QAAO,GAAG,MAAM,IAAI,EAAE,OAAO,WAAW,CAAC;AACnE,SAAO,GAAG,MAAM,IAAI,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AACxF;AAEA,SAAS,cAAc,KAAmC;AACxD,MAAI,OAAO,QAAQ,QAAQ,GAAI,QAAO;AACtC,MAAI,OAAO,QAAQ,UAAU;AAC3B,UAAM,UAAU,IAAI,KAAK;AACzB,QAAI,CAAC,QAAS,QAAO;AACrB,QAAI;AACF,aAAO,KAAK,MAAM,OAAO;AAAA,IAC3B,QAAQ;AAGN,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,YAAY,KAA0B;AAC7C,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,iBAAiB,IAAI,mBAAmB;AAAA,IACxC,MAAM,IAAI;AAAA,IACV,OAAO,IAAI;AAAA,IACX,aAAa,IAAI,eAAe;AAAA,IAChC,aAAa,IAAI;AAAA,IACjB,UAAU,cAAc,IAAI,aAAa;AAAA,IACzC,gBAAgB,IAAI;AAAA,IACpB,cAAc,IAAI;AAAA,IAClB,cAAc,IAAI;AAAA,IAClB,QAAQ,IAAI,WAAW;AAAA,IACvB,YAAY,IAAI,cAAc;AAAA,IAC9B,YAAY,IAAI,cAAc;AAAA,EAChC;AACF;AAgBO,IAAM,qBAAN,MAAwD;AAAA,EAK7D,YAAY,MAAiC;AAC3C,SAAK,SAAS,KAAK;AACnB,SAAK,UAAU,KAAK;AACpB,SAAK,SAAS,KAAK;AAAA,EACrB;AAAA,EAEA,MAAM,WAAW,OAA+B,SAA2D;AACzG,QAAI,CAAC,MAAM,KAAM,OAAM,IAAI,MAAM,qCAAqC;AACtE,QAAI,CAAC,MAAM,MAAO,OAAM,IAAI,MAAM,sCAAsC;AACxE,QAAI,CAAC,MAAM,OAAQ,OAAM,IAAI,MAAM,uCAAuC;AAC1E,QAAI,CAAC,MAAM,cAAe,OAAM,IAAI,MAAM,8CAA8C;AACxF,QAAI,CAAC,MAAM,YAAa,OAAM,IAAI,MAAM,4CAA4C;AAEpF,UAAM,QAAS,SAAiB,kBAAmB,SAAiB,YAAY;AAChF,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,UAAM,cAAgC,MAAM,eAAe;AAC3D,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,eAAe,MAAM,YAAY,OACnC,OACC,OAAO,MAAM,aAAa,WAAW,MAAM,WAAW,KAAK,UAAU,MAAM,QAAQ;AAExF,UAAM,WAAW,MAAM,KAAK,OAAO,KAAK,oBAAoB;AAAA,MAC1D,QAAQ,QAAQ,EAAE,MAAM,MAAM,MAAM,iBAAiB,MAAM,IAAI,EAAE,MAAM,MAAM,KAAK;AAAA,MAClF,OAAO;AAAA,MACP,SAASA;AAAA,IACX,CAAC;AACD,QAAI,MAAM,QAAQ,QAAQ,KAAK,SAAS,CAAC,GAAG;AAC1C,YAAM,MAAW,SAAS,CAAC;AAC3B,YAAM,QAAa;AAAA,QACjB,IAAI,IAAI;AAAA,QACR,OAAO,MAAM;AAAA,QACb,aAAa,MAAM,eAAe;AAAA,QAClC,aAAa,MAAM;AAAA,QACnB,eAAe;AAAA,QACf,gBAAgB,MAAM;AAAA,QACtB,cAAc,MAAM;AAAA,QACpB,cAAc;AAAA,QACd;AAAA,QACA,YAAY;AAAA,MACd;AACA,YAAM,KAAK,OAAO,OAAO,oBAAoB,OAAO,EAAE,SAASA,YAAW,CAAC;AAC3E,aAAO,YAAY,EAAE,GAAG,KAAK,GAAG,MAAM,CAAC;AAAA,IACzC;AAEA,UAAM,SAAc;AAAA,MAClB,IAAI,IAAI,OAAO;AAAA,MACf,iBAAiB;AAAA,MACjB,MAAM,MAAM;AAAA,MACZ,OAAO,MAAM;AAAA,MACb,aAAa,MAAM,eAAe;AAAA,MAClC,aAAa,MAAM;AAAA,MACnB,eAAe;AAAA,MACf,gBAAgB,MAAM;AAAA,MACtB,cAAc,MAAM;AAAA,MACpB,cAAc;AAAA,MACd;AAAA,MACA,YAAY;AAAA,MACZ,YAAY;AAAA,IACd;AACA,UAAM,KAAK,OAAO,OAAO,oBAAoB,QAAQ,EAAE,SAASA,YAAW,CAAC;AAC5E,WAAO,YAAY,MAAM;AAAA,EAC3B;AAAA,EAEA,MAAM,UACJ,QACA,SAC2B;AAC3B,UAAM,QAAa,CAAC;AACpB,QAAI,OAAO,OAAQ,OAAM,cAAc,OAAO;AAC9C,QAAI,OAAO,WAAY,OAAM,SAAS;AACtC,UAAM,QAAS,SAAiB,kBAAmB,SAAiB;AACpE,QAAI,MAAO,OAAM,kBAAkB;AACnC,UAAM,OAAO,MAAM,KAAK,OAAO,KAAK,oBAAoB;AAAA,MACtD,QAAQ;AAAA,MACR,SAAS,CAAC,EAAE,OAAO,QAAQ,WAAW,MAAM,CAAC;AAAA,MAC7C,OAAO;AAAA,MACP,SAASA;AAAA,IACX,CAAC;AACD,WAAO,MAAM,QAAQ,IAAI,IAAI,KAAK,IAAI,WAAW,IAAI,CAAC;AAAA,EACxD;AAAA,EAEA,MAAM,QAAQ,UAAkB,SAAkE;AAChG,QAAI,CAAC,SAAU,QAAO;AACtB,UAAM,QAAS,SAAiB,kBAAmB,SAAiB;AACpE,UAAM,OAAO,MAAM,KAAK,OAAO,KAAK,oBAAoB;AAAA,MACtD,QAAQ,EAAE,IAAI,SAAS;AAAA,MACvB,OAAO;AAAA,MACP,SAASA;AAAA,IACX,CAAC;AACD,QAAI,MAAM,QAAQ,IAAI,KAAK,KAAK,CAAC,EAAG,QAAO,YAAY,KAAK,CAAC,CAAC;AAC9D,UAAM,SAAS,MAAM,KAAK,OAAO,KAAK,oBAAoB;AAAA,MACxD,QAAQ,QAAQ,EAAE,MAAM,UAAU,iBAAiB,MAAM,IAAI,EAAE,MAAM,SAAS;AAAA,MAC9E,OAAO;AAAA,MACP,SAASA;AAAA,IACX,CAAC;AACD,QAAI,MAAM,QAAQ,MAAM,KAAK,OAAO,CAAC,EAAG,QAAO,YAAY,OAAO,CAAC,CAAC;AACpE,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,WAAW,UAAkB,SAAiD;AAClF,UAAM,MAAM,MAAM,KAAK,QAAQ,UAAU,OAAO;AAChD,QAAI,CAAC,IAAK;AAEV,UAAM,KAAK,OAAO,OAAO,oBAAoB;AAAA,MAC3C,OAAO,EAAE,QAAQ,QAAQ,WAAW,IAAI,GAAG;AAAA,MAC3C,SAASA;AAAA,IACX,CAAQ;AACR,UAAM,KAAK,OAAO,OAAO,oBAAoB;AAAA,MAC3C,OAAO,EAAE,IAAI,IAAI,GAAG;AAAA,MACpB,SAASA;AAAA,IACX,CAAQ;AAAA,EACV;AAAA,EAEA,MAAM,aAAa,UAAkB,SAAwE;AAC3G,UAAM,OAAO,MAAM,KAAK,QAAQ,UAAU,OAAO;AACjD,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,gBAAgB;AAC3C,QAAI,CAAC,KAAK,QAAQ;AAEhB,YAAM,UAAU,MAAM,KAAK,gBAAgB,KAAK,EAAE;AAClD,aAAO,EAAE,QAAQ,KAAK,IAAI,gBAAgB,GAAG,eAAe,GAAG,eAAe,GAAG,eAAe,GAAG,eAAe,QAAQ;AAAA,IAC5H;AACA,UAAM,UAAU,MAAM,KAAK,oBAAoB,IAAI;AACnD,UAAM,QAAQ,MAAM,KAAK,gBAAgB,IAAI;AAC7C,WAAO,KAAK,UAAU,MAAM,SAAS,KAAK;AAAA,EAC5C;AAAA,EAEA,MAAM,qBACJ,QACA,UACA,SACwC;AACxC,UAAM,QAAQ,MAAM,KAAK,UAAU,EAAE,QAAQ,YAAY,KAAK,GAAG,OAAO;AACxE,QAAI,MAAM,WAAW,EAAG,QAAO,CAAC;AAChC,UAAM,UAAyC,CAAC;AAChD,eAAW,QAAQ,OAAO;AACxB,YAAM,QAAQ,MAAM,KAAK,cAAc,MAAM,QAAQ;AACrD,YAAM,QAAQ,QAAQ,MAAM,KAAK,gBAAgB,IAAI,IAAI,CAAC;AAC1D,cAAQ,KAAK,MAAM,KAAK,mBAAmB,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IAC1E;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAIA,MAAc,oBAAoB,MAAyC;AACzE,UAAM,SAAU,KAAK,YAAY,CAAC;AAClC,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,OAAO,KAAK,KAAK,aAAa;AAAA,QACpD;AAAA,QACA,QAAQ,CAAC,IAAI;AAAA,QACb,OAAO;AAAA,QACP,SAASA;AAAA,MACX,CAAC;AACD,aAAO,MAAM,QAAQ,IAAI,IAAI,KAAK,IAAI,CAAC,MAAW,OAAO,EAAE,EAAE,CAAC,EAAE,OAAO,OAAO,IAAI,CAAC;AAAA,IACrF,SAAS,KAAU;AACjB,WAAK,QAAQ,OAAO,wCAAwC,EAAE,MAAM,KAAK,MAAM,OAAO,KAAK,QAAQ,CAAC;AACpG,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAc,cAAc,MAAsB,UAAoC;AACpF,UAAM,SAAS,EAAE,GAAK,KAAK,YAAY,CAAC,GAAY,IAAI,SAAS;AACjE,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,OAAO,KAAK,KAAK,aAAa;AAAA,QACpD;AAAA,QACA,QAAQ,CAAC,IAAI;AAAA,QACb,OAAO;AAAA,QACP,SAASA;AAAA,MACX,CAAC;AACD,aAAO,MAAM,QAAQ,IAAI,KAAK,KAAK,SAAS;AAAA,IAC9C,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAc,gBAAgB,MAAyC;AACrE,UAAM,OAAO,IAAI,iBAAiB;AAAA,MAChC,QAAQ,KAAK;AAAA,MACb,gBAAgB,KAAK,mBAAmB;AAAA,IAC1C,CAAC;AACD,QAAI,KAAK,mBAAmB,OAAQ,QAAO,CAAC,KAAK,YAAY;AAC7D,QAAI,KAAK,mBAAmB,OAAQ,QAAO,KAAK,YAAY,KAAK,YAAY;AAC7E,QAAI,KAAK,mBAAmB,cAAc;AACxC,YAAM,OAAO,IAAI,uBAAuB;AAAA,QACtC,QAAQ,KAAK;AAAA,QACb,gBAAgB,KAAK,mBAAmB;AAAA,QACxC,WAAW;AAAA,MACb,CAAC;AACD,aAAO,KAAK,YAAY,KAAK,YAAY;AAAA,IAC3C;AACA,QAAI,KAAK,mBAAmB,OAAQ,QAAO,KAAK,gBAAgB,KAAK,cAAc,KAAK,mBAAmB,MAAS;AAEpH,WAAO,CAAC;AAAA,EACV;AAAA,EAEA,MAAc,UACZ,MACA,YACA,OACsC;AACtC,UAAM,WAAW,MAAM,KAAK,OAAO,KAAK,oBAAoB;AAAA,MAC1D,QAAQ,EAAE,QAAQ,QAAQ,WAAW,KAAK,GAAG;AAAA,MAC7C,QAAQ,CAAC,MAAM,aAAa,gBAAgB,cAAc;AAAA,MAC1D,OAAO;AAAA,MACP,SAASA;AAAA,IACX,CAAC;AACD,UAAM,UAAU,oBAAI,IAAyD;AAC7E,eAAW,OAAO,YAAY;AAC5B,iBAAW,OAAO,MAAO,SAAQ,IAAI,GAAG,GAAG,KAAK,GAAG,IAAI,EAAE,WAAW,KAAK,cAAc,IAAI,CAAC;AAAA,IAC9F;AACA,UAAM,cAAc,oBAAI,IAAiB;AACzC,eAAW,OAAQ,YAAY,CAAC,EAAI,aAAY,IAAI,GAAG,IAAI,SAAS,KAAK,IAAI,YAAY,IAAI,GAAG;AAEhG,QAAI,UAAU;AACd,QAAI,UAAU;AACd,QAAI,UAAU;AAGd,eAAW,CAAC,GAAG,IAAI,KAAK,QAAQ,QAAQ,GAAG;AACzC,YAAM,MAAM,YAAY,IAAI,CAAC;AAC7B,UAAI,KAAK;AACP,YAAI,IAAI,iBAAiB,KAAK,cAAc;AAC1C,gBAAM,KAAK,QAAQ;AAAA,YACjB;AAAA,cACE,QAAQ,KAAK;AAAA,cACb,UAAU,KAAK;AAAA,cACf,eAAe;AAAA,cACf,aAAa,KAAK;AAAA,cAClB,aAAa,KAAK;AAAA,cAClB,QAAQ;AAAA,cACR,UAAU,KAAK;AAAA,cACf,QAAQ,QAAQ,KAAK,IAAI;AAAA,YAC3B;AAAA,YACAA;AAAA,UACF;AACA,qBAAW;AAAA,QACb;AACA,oBAAY,OAAO,CAAC;AAAA,MACtB,OAAO;AACL,cAAM,KAAK,QAAQ;AAAA,UACjB;AAAA,YACE,QAAQ,KAAK;AAAA,YACb,UAAU,KAAK;AAAA,YACf,eAAe;AAAA,YACf,aAAa,KAAK;AAAA,YAClB,aAAa,KAAK;AAAA,YAClB,QAAQ;AAAA,YACR,UAAU,KAAK;AAAA,YACf,QAAQ,QAAQ,KAAK,IAAI;AAAA,UAC3B;AAAA,UACAA;AAAA,QACF;AACA,mBAAW;AAAA,MACb;AAAA,IACF;AAEA,eAAW,CAAC,EAAE,KAAK,KAAK,YAAY,QAAQ,GAAG;AAC7C,YAAM,KAAK,QAAQ,OAAO,MAAM,IAAIA,WAAiB;AACrD,iBAAW;AAAA,IACb;AAEA,WAAO;AAAA,MACL,QAAQ,KAAK;AAAA,MACb,gBAAgB,WAAW;AAAA,MAC3B,eAAe,MAAM;AAAA,MACrB,eAAe;AAAA,MACf,eAAe;AAAA,MACf,eAAe;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,MAAc,mBACZ,MACA,UACA,OACA,OACsC;AACtC,UAAM,WAAW,MAAM,KAAK,OAAO,KAAK,oBAAoB;AAAA,MAC1D,QAAQ,EAAE,QAAQ,QAAQ,WAAW,KAAK,IAAI,WAAW,SAAS;AAAA,MAClE,QAAQ,CAAC,MAAM,aAAa,gBAAgB,cAAc;AAAA,MAC1D,OAAO;AAAA,MACP,SAASA;AAAA,IACX,CAAC;AACD,UAAM,cAAc,oBAAI,IAAiB;AACzC,eAAW,OAAQ,YAAY,CAAC,EAAI,aAAY,IAAI,OAAO,IAAI,YAAY,GAAG,GAAG;AAEjF,QAAI,UAAU;AACd,QAAI,UAAU;AACd,QAAI,UAAU;AAEd,QAAI,OAAO;AACT,iBAAW,UAAU,OAAO;AAC1B,cAAM,MAAM,YAAY,IAAI,MAAM;AAClC,YAAI,KAAK;AACP,cAAI,IAAI,iBAAiB,KAAK,cAAc;AAC1C,kBAAM,KAAK,QAAQ;AAAA,cACjB;AAAA,gBACE,QAAQ,KAAK;AAAA,gBACb;AAAA,gBACA,eAAe;AAAA,gBACf,aAAa;AAAA,gBACb,aAAa,KAAK;AAAA,gBAClB,QAAQ;AAAA,gBACR,UAAU,KAAK;AAAA,gBACf,QAAQ,QAAQ,KAAK,IAAI;AAAA,cAC3B;AAAA,cACAA;AAAA,YACF;AACA,uBAAW;AAAA,UACb;AACA,sBAAY,OAAO,MAAM;AAAA,QAC3B,OAAO;AACL,gBAAM,KAAK,QAAQ;AAAA,YACjB;AAAA,cACE,QAAQ,KAAK;AAAA,cACb;AAAA,cACA,eAAe;AAAA,cACf,aAAa;AAAA,cACb,aAAa,KAAK;AAAA,cAClB,QAAQ;AAAA,cACR,UAAU,KAAK;AAAA,cACf,QAAQ,QAAQ,KAAK,IAAI;AAAA,YAC3B;AAAA,YACAA;AAAA,UACF;AACA,qBAAW;AAAA,QACb;AAAA,MACF;AAAA,IACF;AAGA,eAAW,CAAC,EAAE,KAAK,KAAK,YAAY,QAAQ,GAAG;AAC7C,YAAM,KAAK,QAAQ,OAAO,MAAM,IAAIA,WAAiB;AACrD,iBAAW;AAAA,IACb;AAEA,WAAO;AAAA,MACL,QAAQ,KAAK;AAAA,MACb,gBAAgB,QAAQ,IAAI;AAAA,MAC5B,eAAe,MAAM;AAAA,MACrB,eAAe;AAAA,MACf,eAAe;AAAA,MACf,eAAe;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,MAAc,gBAAgB,QAAiC;AAC7D,UAAM,WAAW,MAAM,KAAK,OAAO,KAAK,oBAAoB;AAAA,MAC1D,QAAQ,EAAE,QAAQ,QAAQ,WAAW,OAAO;AAAA,MAC5C,QAAQ,CAAC,IAAI;AAAA,MACb,OAAO;AAAA,MACP,SAASA;AAAA,IACX,CAAC;AACD,QAAI,UAAU;AACd,eAAW,OAAQ,YAAY,CAAC,GAAI;AAClC,YAAM,KAAK,QAAQ,OAAQ,IAAY,IAAIA,WAAiB;AAC5D,iBAAW;AAAA,IACb;AACA,WAAO;AAAA,EACT;AACF;;;ACtaA,IAAMC,cAAa,EAAE,UAAU,MAAM,OAAO,CAAC,GAAG,aAAa,CAAC,EAAE;AAGhE,IAAM,iBAAiB;AAGvB,IAAM,eAAe;AAGrB,IAAM,0BAA0B;AAQhC,SAAS,cAAc,SAAiB,cAAsB;AAC5D,QAAM,IAAS;AACf,QAAM,QAAQ,IAAI,WAAW,MAAM;AACnC,MAAI,EAAE,QAAQ,iBAAiB;AAC7B,MAAE,OAAO,gBAAgB,KAAK;AAAA,EAChC,OAAO;AACL,aAAS,IAAI,GAAG,IAAI,QAAQ,IAAK,OAAM,CAAC,IAAI,KAAK,MAAM,KAAK,OAAO,IAAI,GAAG;AAAA,EAC5E;AACA,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,WAAO,eAAe,MAAM,CAAC,IAAI,eAAe,MAAM;AAAA,EACxD;AACA,SAAO;AACT;AAGA,SAAS,UAAU,QAMjB;AACA,QAAM,MAAM,QAAQ;AACpB,MAAI,CAAC,OAAO,IAAI,YAAY,MAAM;AAChC,WAAO;AAAA,MACL,SAAS;AAAA,MACT,kBAAkB,CAAC;AAAA,MACnB,oBAAoB,CAAC;AAAA,MACrB,cAAc,CAAC;AAAA,IACjB;AAAA,EACF;AACA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,kBAAmB,IAAI,oBAAwD,CAAC,WAAW;AAAA,IAC3F,oBAAqB,IAAI,sBAA4D,CAAC,MAAM;AAAA,IAC5F,eAAe,OAAO,IAAI,kBAAkB,WAAW,IAAI,gBAAgB;AAAA,IAC3E,cAAc,MAAM,QAAQ,IAAI,YAAY,IAAK,IAAI,eAA4B,CAAC;AAAA,EACpF;AACF;AAGA,SAAS,mBAAmB,OAAkC,SAAgC;AAC5F,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,MAAM,MAAM,UAAU;AAG5B,QAAM,IAAI,uBAAuB,KAAK,KAAK;AAC3C,MAAI,GAAG;AACL,UAAM,IAAI,OAAO,EAAE,CAAC,CAAC;AACrB,UAAM,OAAO,EAAE,CAAC,EAAE,YAAY;AAC9B,UAAM,KAAK,SAAS,MAAM,IAAI,MAAO,SAAS,MAAM,IAAI,MAAS,SAAS,MAAM,IAAI,OAAY,IAAI;AACpG,UAAM,KAAK,MAAM;AACjB,QAAI,KAAK,KAAK;AACZ,YAAM,UAAU,KAAK,mBAAmB,yCAAyC,OAAO,OAAO;AAAA,IACjG;AACA,WAAO,IAAI,KAAK,EAAE,EAAE,YAAY;AAAA,EAClC;AAGA,QAAM,IAAI,KAAK,MAAM,KAAK;AAC1B,MAAI,OAAO,MAAM,CAAC,GAAG;AACnB,UAAM,UAAU,KAAK,kBAAkB,uDAAuD,KAAK,EAAE;AAAA,EACvG;AACA,MAAI,IAAI,KAAK;AACX,UAAM,UAAU,KAAK,mBAAmB,yCAAyC,OAAO,OAAO;AAAA,EACjG;AACA,MAAI,KAAK,KAAK;AACZ,UAAM,UAAU,KAAK,kBAAkB,iCAAiC;AAAA,EAC1E;AACA,SAAO,IAAI,KAAK,CAAC,EAAE,YAAY;AACjC;AAWA,eAAe,oBAAoB,UAAmC;AACpE,QAAM,IAAS;AACf,QAAM,SAAS,EAAE,QAAQ;AACzB,QAAM,OAAO,cAAc,EAAE;AAC7B,MAAI,CAAC,QAAQ;AAIX,WAAO,QAAQ,IAAI,IAAI,QAAQ;AAAA,EACjC;AACA,QAAM,MAAM,IAAI,YAAY;AAC5B,QAAM,MAAM,MAAM,OAAO,OAAO,WAAW,IAAI,OAAO,OAAO,MAAM,QAAQ,CAAC;AAC5E,QAAM,MAAM,MAAM,KAAK,IAAI,WAAW,GAAG,CAAC,EACvC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAC1C,KAAK,EAAE;AACV,SAAO,UAAU,IAAI,IAAI,GAAG;AAC9B;AAEA,eAAe,sBAAsB,UAAkB,MAAgC;AACrF,MAAI,KAAK,WAAW,OAAO,GAAG;AAC5B,UAAM,CAAC,EAAE,EAAE,MAAM,IAAI,KAAK,MAAM,GAAG;AACnC,WAAO,WAAW;AAAA,EACpB;AACA,MAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,UAAM,CAAC,EAAE,MAAM,QAAQ,IAAI,KAAK,MAAM,GAAG;AACzC,UAAM,IAAS;AACf,UAAM,SAAS,EAAE,QAAQ;AACzB,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,MAAM,IAAI,YAAY;AAC5B,UAAM,MAAM,MAAM,OAAO,OAAO,WAAW,IAAI,OAAO,OAAO,MAAM,QAAQ,CAAC;AAC5E,UAAM,MAAM,MAAM,KAAK,IAAI,WAAW,GAAG,CAAC,EACvC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAC1C,KAAK,EAAE;AACV,WAAO,QAAQ;AAAA,EACjB;AACA,SAAO;AACT;AAEA,SAAS,UAAU,QAAgB,MAAc,SAAwB;AACvE,QAAM,MAAW,IAAI,MAAM,OAAO;AAClC,MAAI,SAAS;AACb,MAAI,OAAO;AACX,SAAO;AACT;AAyBO,IAAM,mBAAN,MAAoD;AAAA,EAMzD,YAAY,MAA+B;AACzC,SAAK,SAAS,KAAK;AACnB,SAAK,aAAa,KAAK,cAAc;AACrC,SAAK,eAAe,KAAK,gBAAgB;AACzC,SAAK,iBAAiB,KAAK,kBAAkB;AAAA,EAC/C;AAAA,EAEA,MAAM,WACJ,OACA,SACoB;AACpB,QAAI,CAAC,MAAM,OAAQ,OAAM,UAAU,KAAK,qBAAqB,oBAAoB;AACjF,QAAI,CAAC,MAAM,SAAU,OAAM,UAAU,KAAK,qBAAqB,sBAAsB;AAErF,UAAM,SAAS,KAAK,OAAO,YAAY,MAAM,MAAM;AACnD,UAAM,SAAS,UAAU,MAAM;AAE/B,QAAI,CAAC,OAAO,WAAW,CAAC,KAAK,cAAc,CAAC,QAAQ,UAAU;AAC5D,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,WAAW,MAAM,MAAM;AAAA,MACzB;AAAA,IACF;AAEA,UAAM,aAAkC,MAAM,cAAc;AAC5D,QAAI,OAAO,WAAW,OAAO,mBAAmB,SAAS,KAAK,CAAC,OAAO,mBAAmB,SAAS,UAAU,GAAG;AAC7G,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,WAAW,MAAM,MAAM,sCAAsC,UAAU,eAAe,OAAO,mBAAmB,KAAK,IAAI,CAAC;AAAA,MAC5H;AAAA,IACF;AAEA,UAAM,WAA8B,MAAM,YAAY;AACtD,QAAI,OAAO,WAAW,OAAO,iBAAiB,SAAS,KAAK,CAAC,OAAO,iBAAiB,SAAS,QAAQ,GAAG;AACvG,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,WAAW,MAAM,MAAM,8BAA8B,QAAQ,eAAe,OAAO,iBAAiB,KAAK,IAAI,CAAC;AAAA,MAChH;AAAA,IACF;AAEA,QAAI,aAAa,YAAY,CAAC,MAAM,kBAAkB,MAAM,eAAe,WAAW,IAAI;AACxF,YAAM,UAAU,KAAK,qBAAqB,gDAAgD;AAAA,IAC5F;AAIA,UAAM,SAAS,MAAM,KAAK,OAAO,KAAK,MAAM,QAAQ;AAAA,MAClD,OAAO,EAAE,IAAI,MAAM,SAAS;AAAA,MAC5B,QAAQ,CAAC,IAAI;AAAA,MACb,OAAO;AAAA,MACP,SAASA;AAAA,IACX,CAAQ;AACR,QAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,OAAO,WAAW,GAAG;AACjD,YAAM,UAAU,KAAK,oBAAoB,GAAG,MAAM,MAAM,IAAI,MAAM,QAAQ,iBAAiB;AAAA,IAC7F;AAEA,UAAM,UAAU,OAAO,iBAAiB;AACxC,UAAM,aAAa,mBAAmB,MAAM,WAAW,OAAO;AAE9D,UAAM,eAAe,MAAM,WAAW,MAAM,KAAK,aAAa,MAAM,QAAQ,IAAI;AAEhF,UAAM,MAAiB;AAAA,MACrB,IAAI,OAAO,cAAc,EAAE,CAAC;AAAA,MAC5B,OAAO,cAAc,YAAY;AAAA,MACjC,aAAa,MAAM;AAAA,MACnB,WAAW,MAAM;AAAA,MACjB;AAAA,MACA;AAAA,MACA;AAAA,MACA,iBACE,MAAM,kBAAkB,MAAM,eAAe,SAAS,IAClD,MAAM,eAAe,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,EAAE,OAAO,OAAO,IACtE;AAAA,MACN,eAAe;AAAA,MACf,eAAe,MAAM,gBAAgB,MAAM,aAAa,SAAS,IAAI,MAAM,eAAe;AAAA,MAC1F,OAAO,MAAM,SAAS;AAAA,MACtB,YAAY;AAAA,MACZ,YAAY,QAAQ,UAAU;AAAA,MAC9B,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,MACnC,cAAc;AAAA,MACd,WAAW;AAAA,IACb;AAEA,UAAM,KAAK,OAAO,OAAO,kBAAkB,KAAK,EAAE,SAASA,YAAW,CAAC;AACvE,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,WAAW,WAAmB,UAAoD;AACtF,QAAI,CAAC,UAAW,OAAM,UAAU,KAAK,qBAAqB,yBAAyB;AACnF,UAAM,SAAS,UAAU,WAAW,MAAM,IAAI,EAAE,IAAI,UAAU,IAAI,EAAE,OAAO,UAAU;AACrF,UAAM,OAAO,MAAM,KAAK,OAAO,KAAK,kBAAkB;AAAA,MACpD,OAAO;AAAA,MACP,QAAQ,CAAC,MAAM,YAAY;AAAA,MAC3B,OAAO;AAAA,MACP,SAASA;AAAA,IACX,CAAQ;AACR,UAAM,MAAM,MAAM,QAAQ,IAAI,IAAK,KAAK,CAAC,IAAY;AACrD,QAAI,CAAC,IAAK;AACV,QAAI,IAAI,WAAY;AACpB,UAAM,KAAK,OAAO;AAAA,MAChB;AAAA,MACA,EAAE,IAAI,IAAI,IAAI,aAAY,oBAAI,KAAK,GAAE,YAAY,EAAE;AAAA,MACnD,EAAE,SAASA,YAAW;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,MAAM,UACJ,QACA,SACsB;AACtB,UAAM,QAAiC,CAAC;AACxC,QAAI,OAAO,OAAQ,OAAM,cAAc,OAAO;AAC9C,QAAI,OAAO,SAAU,OAAM,YAAY,OAAO;AAC9C,QAAI,OAAO,UAAW,OAAM,aAAa,OAAO;AAChD,QAAI,CAAC,OAAO,eAAgB,OAAM,aAAa;AAE/C,UAAM,OAAO,MAAM,KAAK,OAAO,KAAK,kBAAkB;AAAA,MACpD;AAAA,MACA,OAAO;AAAA,MACP,MAAM,CAAC,EAAE,OAAO,cAAc,OAAO,OAAO,CAAC;AAAA,MAC7C,SAAS,QAAQ,WAAWA,cAAa;AAAA,IAC3C,CAAQ;AACR,WAAO,MAAM,QAAQ,IAAI,IAAK,OAAuB,CAAC;AAAA,EACxD;AAAA,EAEA,MAAM,aACJ,OACA,QAAyF,CAAC,GAClD;AACxC,QAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,SAAS,EAAG,QAAO;AAEpE,UAAM,OAAO,MAAM,KAAK,OAAO,KAAK,kBAAkB;AAAA,MACpD,OAAO,EAAE,MAAM;AAAA,MACf,OAAO;AAAA,MACP,SAASA;AAAA,IACX,CAAQ;AACR,UAAM,MAAM,MAAM,QAAQ,IAAI,IAAK,KAAK,CAAC,IAA8B;AACvE,QAAI,CAAC,IAAK,QAAO;AAEjB,QAAI,IAAI,WAAY,QAAO;AAC3B,QAAI,IAAI,cAAc,KAAK,MAAM,IAAI,UAAU,KAAK,KAAK,IAAI,EAAG,QAAO;AAGvE,QAAI,IAAI,aAAa,eAAe,CAAC,MAAM,eAAgB,QAAO;AAClE,QAAI,IAAI,aAAa,SAAS;AAC5B,YAAM,QAAQ,IAAI,mBAAmB,CAAC;AACtC,YAAM,YAAY,MAAM,kBAAkB,IAAI,KAAK,EAAE,YAAY;AACjE,UAAI,CAAC,YAAY,CAAC,MAAM,SAAS,QAAQ,EAAG,QAAO;AAAA,IACrD;AAEA,QAAI,IAAI,eAAe;AACrB,UAAI,CAAC,MAAM,iBAAkB,QAAO;AACpC,YAAM,KAAK,MAAM,KAAK,eAAe,MAAM,kBAAkB,IAAI,aAAa;AAC9E,UAAI,CAAC,GAAI,QAAO;AAAA,IAClB;AAGA,UAAM,SAAS,KAAK,OAAO,YAAY,IAAI,WAAW;AACtD,UAAM,SAAS,UAAU,MAAM;AAC/B,UAAM,eAAe,MAAM;AAAA,MACzB,oBAAI,IAAY,CAAC,GAAI,OAAO,gBAAgB,CAAC,GAAI,GAAK,IAAI,iBAA8B,CAAC,CAAE,CAAC;AAAA,IAC9F;AAGA,QAAI;AACF,YAAM,KAAK,OAAO;AAAA,QAChB;AAAA,QACA;AAAA,UACE,IAAI,IAAI;AAAA,UACR,eAAc,oBAAI,KAAK,GAAE,YAAY;AAAA,UACrC,YAAY,IAAI,aAAa,KAAK;AAAA,QACpC;AAAA,QACA,EAAE,SAASA,YAAW;AAAA,MACxB;AAAA,IACF,QAAQ;AAAA,IAER;AAEA,WAAO,EAAE,MAAM,KAAK,aAAa;AAAA,EACnC;AACF;;;ACxVA,IAAMC,cAAa,EAAE,UAAU,MAAM,OAAO,CAAC,GAAG,aAAa,CAAC,EAAE;AAQhE,IAAM,iBAAiB,CAAC,QAAiD;AACvE,QAAM,SAAS,CAAC,SAAqC;AACnD,UAAM,IAAI,IAAI,UAAU,IAAI;AAC5B,WAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI;AAAA,EACnC;AACA,SAAO;AAAA,IACL,QAAQ,OAAO,WAAW;AAAA,IAC1B,UAAU,OAAO,aAAa;AAAA,EAChC;AACF;AAEA,SAAS,UAAU,KAAoB,QAAgB,MAAc,SAAiB;AACpF,MAAI,OAAO,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,EAAE,CAAC;AACtD;AAGA,SAAS,eAAe,QAAa,cAA6B;AAChE,MAAI,CAAC,UAAU,OAAO,WAAW,YAAY,aAAa,WAAW,EAAG,QAAO;AAC/E,MAAI,MAAM,QAAQ,MAAM,EAAG,QAAO,OAAO,IAAI,CAAC,MAAM,eAAe,GAAG,YAAY,CAAC;AACnF,QAAM,MAAW,CAAC;AAClB,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC3C,QAAI,aAAa,SAAS,CAAC,EAAG;AAC9B,QAAI,CAAC,IAAI;AAAA,EACX;AACA,SAAO;AACT;AAEO,SAAS,wBACd,MACA,SACA,QACA,OAA+B,CAAC,GAC1B;AACN,QAAM,OAAO,KAAK,YAAY;AAC9B,QAAM,QAAQ,KAAK,sBAAsB;AAGzC,OAAK,KAAK,OAAO,OAAO,KAAK,QAAQ;AACnC,QAAI;AACF,YAAM,MAAM,MAAM,GAAG;AACrB,YAAM,OAAY,IAAI,QAAQ,CAAC;AAC/B,UAAI,CAAC,KAAK,UAAU,CAAC,KAAK,UAAU;AAClC,eAAO,UAAU,KAAK,KAAK,qBAAqB,kCAAkC;AAAA,MACpF;AACA,YAAM,OAAO,MAAM,QAAQ;AAAA,QACzB;AAAA,UACE,QAAQ,KAAK;AAAA,UACb,UAAU,KAAK;AAAA,UACf,YAAY,KAAK;AAAA,UACjB,UAAU,KAAK;AAAA,UACf,WAAW,KAAK,aAAa;AAAA,UAC7B,gBAAgB,KAAK;AAAA,UACrB,UAAU,KAAK;AAAA,UACf,cAAc,KAAK;AAAA,UACnB,OAAO,KAAK;AAAA,QACd;AAAA,QACA;AAAA,MACF;AAKA,YAAM,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC;AAAA,IACrC,SAAS,KAAU;AACjB,gBAAU,KAAK,KAAK,UAAU,KAAK,KAAK,QAAQ,YAAY,KAAK,WAAW,uBAAuB;AAAA,IACrG;AAAA,EACF,EAAyB;AAGzB,OAAK,IAAI,OAAO,OAAO,KAAK,QAAQ;AAClC,QAAI;AACF,YAAM,MAAM,MAAM,GAAG;AACrB,YAAM,IAAI,IAAI,SAAS,CAAC;AACxB,YAAM,OAAO,MAAM,QAAQ;AAAA,QACzB;AAAA,UACE,QAAQ,OAAO,EAAE,WAAW,WAAW,EAAE,SAAS;AAAA,UAClD,UAAU,OAAO,EAAE,aAAa,WAAW,EAAE,WAAW;AAAA,UACxD,WAAW,OAAO,EAAE,cAAc,WAAW,EAAE,YAAY;AAAA,UAC3D,gBAAgB,EAAE,mBAAmB,UAAU,EAAE,mBAAmB;AAAA,QACtE;AAAA,QACA;AAAA,MACF;AACA,YAAM,IAAI,KAAK,EAAE,OAAO,KAAK,CAAC;AAAA,IAChC,SAAS,KAAU;AACjB,gBAAU,KAAK,KAAK,UAAU,KAAK,KAAK,QAAQ,YAAY,KAAK,WAAW,sBAAsB;AAAA,IACpG;AAAA,EACF,EAAyB;AAGzB,OAAK,OAAO,GAAG,IAAI,gBAAgB,OAAO,KAAK,QAAQ;AACrD,QAAI;AACF,YAAM,MAAM,MAAM,GAAG;AACrB,YAAM,QAAQ,WAAW,IAAI,OAAO,WAAW,GAAG;AAClD,YAAM,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC;AAAA,IACzC,SAAS,KAAU;AACjB,gBAAU,KAAK,KAAK,UAAU,KAAK,KAAK,QAAQ,YAAY,KAAK,WAAW,uBAAuB;AAAA,IACrG;AAAA,EACF,EAAyB;AAMzB,OAAK,IAAI,GAAG,IAAI,oBAAoB,OAAO,KAAK,QAAQ;AACtD,QAAI;AACF,YAAM,IAAI,IAAI,SAAS,CAAC;AACxB,YAAM,kBAAkB,MAAM;AAC5B,cAAM,IAAI,IAAI,UAAU,WAAW;AACnC,eAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI;AAAA,MACnC,GAAG;AACH,YAAM,iBAAiB,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ;AAC/D,YAAM,mBACJ,OAAO,EAAE,aAAa,WAClB,EAAE,YACD,MAAM;AACL,cAAM,IAAI,IAAI,UAAU,kBAAkB;AAC1C,eAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI;AAAA,MACnC,GAAG;AAET,YAAM,WAAW,MAAM,QAAQ,aAAa,IAAI,OAAO,OAAO;AAAA,QAC5D;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AACD,UAAI,CAAC,UAAU;AAEb,cAAM,QAAQ,MAAM,OAAO,KAAK,kBAAkB;AAAA,UAChD,OAAO,EAAE,OAAO,IAAI,OAAO,MAAM;AAAA,UACjC,OAAO;AAAA,UACP,SAASA;AAAA,QACX,CAAQ;AACR,cAAM,MAAM,MAAM,QAAQ,KAAK,KAAK,MAAM,CAAC,IAAK,MAAM,CAAC,IAAY;AACnE,YAAI,OAAO,CAAC,IAAI,eAAe,CAAC,IAAI,cAAc,KAAK,MAAM,IAAI,UAAU,IAAI,KAAK,IAAI,IAAI;AAC1F,cAAI,IAAI,eAAe;AACrB,mBAAO;AAAA,cACL;AAAA,cACA;AAAA,cACA,mBAAmB,mBAAmB;AAAA,cACtC,mBAAmB,uBAAuB;AAAA,YAC5C;AAAA,UACF;AACA,cAAI,IAAI,aAAa,eAAe,CAAC,gBAAgB;AACnD,mBAAO,UAAU,KAAK,KAAK,oBAAoB,kCAAkC;AAAA,UACnF;AAAA,QACF;AACA,YAAI,QAAQ,IAAI,cAAe,IAAI,cAAc,KAAK,MAAM,IAAI,UAAU,KAAK,KAAK,IAAI,IAAK;AAC3F,iBAAO,UAAU,KAAK,KAAK,sBAAsB,wCAAwC;AAAA,QAC3F;AACA,eAAO,UAAU,KAAK,KAAK,sBAAsB,4CAA4C;AAAA,MAC/F;AAIA,YAAM,OAAO,MAAM,OAAO,KAAK,SAAS,KAAK,aAAa;AAAA,QACxD,OAAO,EAAE,IAAI,SAAS,KAAK,UAAU;AAAA,QACrC,OAAO;AAAA,QACP,SAASA;AAAA,MACX,CAAQ;AACR,YAAM,SAAS,MAAM,QAAQ,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI;AAC1D,UAAI,CAAC,QAAQ;AACX,eAAO,UAAU,KAAK,KAAK,eAAe,oCAAoC;AAAA,MAChF;AAEA,YAAM,IAAI,KAAK;AAAA,QACb,QAAQ,eAAe,QAAQ,SAAS,YAAY;AAAA,QACpD,MAAM;AAAA,UACJ,IAAI,SAAS,KAAK;AAAA,UAClB,OAAO,SAAS,KAAK;AAAA,UACrB,aAAa,SAAS,KAAK;AAAA,UAC3B,WAAW,SAAS,KAAK;AAAA,UACzB,YAAY,SAAS,KAAK;AAAA,UAC1B,UAAU,SAAS,KAAK;AAAA,UACxB,YAAY,SAAS,KAAK;AAAA,UAC1B,OAAO,SAAS,KAAK;AAAA,UACrB,YAAY,SAAS,KAAK;AAAA,QAC5B;AAAA,QACA,cAAc,SAAS;AAAA,MACzB,CAAC;AAAA,IACH,SAAS,KAAU;AACjB,gBAAU,KAAK,KAAK,UAAU,KAAK,KAAK,QAAQ,YAAY,KAAK,WAAW,wBAAwB;AAAA,IACtG;AAAA,EACF,EAAyB;AAkBzB,OAAK,IAAI,GAAG,IAAI,qBAAqB,OAAO,KAAK,QAAQ;AACvD,QAAI;AACF,YAAM,WACJ,OAAO,IAAI,OAAO,aAAa,WAAY,IAAI,MAAM,WAAsB;AAC7E,YAAM,WAAW,MAAM,QAAQ,aAAa,IAAI,OAAO,OAAO,EAAE,kBAAkB,SAAS,CAAC;AAC5F,UAAI,CAAC,UAAU;AACb,kBAAU,KAAK,KAAK,aAAa,sBAAsB;AACvD;AAAA,MACF;AACA,UAAI,SAAS,KAAK,gBAAgB,oBAAoB;AACpD,kBAAU,KAAK,KAAK,eAAe,0CAA0C;AAC7E;AAAA,MACF;AACA,YAAMA,cAAa,EAAE,UAAU,MAAM,OAAO,CAAC,GAAG,aAAa,CAAC,EAAE;AAChE,YAAM,OAAO,MAAM,OAAO,KAAK,eAAe;AAAA,QAC5C,OAAO,EAAE,iBAAiB,SAAS,KAAK,UAAU;AAAA,QAClD,MAAM,CAAC,EAAE,OAAO,cAAc,WAAW,MAAM,CAAC;AAAA,QAChD,OAAO;AAAA,QACP,SAASA;AAAA,MACX,CAAQ;AACR,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC,EAAE,CAAC;AAAA,IAC3C,SAAS,KAAU;AACjB;AAAA,QACE;AAAA,QACA,KAAK,UAAU;AAAA,QACf,KAAK,QAAQ;AAAA,QACb,KAAK,WAAW;AAAA,MAClB;AAAA,IACF;AAAA,EACF,EAAyB;AAC3B;;;ACpQA,IAAMC,cAAa,EAAE,UAAU,MAAM,OAAO,CAAC,GAAG,aAAa,CAAC,EAAE;AAEzD,IAAM,4BAA4B;AAyBlC,SAAS,cACd,QACA,SACA,OACA,QACM;AACN,QAAM,UAAU,oBAAI,IAAY;AAChC,aAAW,KAAK,OAAO;AACrB,QAAI,EAAE,WAAW,MAAO;AACxB,QAAI,EAAE,YAAa,SAAQ,IAAI,EAAE,WAAW;AAAA,EAC9C;AACA,aAAW,cAAc,SAAS;AAChC,UAAM,UAAU,OAAO,QAAa;AAClC,UAAK,KAAK,SAAiB,SAAU;AACrC,UAAI;AACF,cAAM,OAAO,KAAK,UAAU,KAAK,OAAO,QAAQ,CAAC;AACjD,cAAM,KAAK,OAAQ,MAAc,MAAM,KAAK,OAAO,MAAM,EAAE;AAC3D,YAAI,CAAC,GAAI;AACT,cAAM,QAAQ,qBAAqB,YAAY,IAAIA,WAAiB;AAAA,MACtE,SAAS,KAAU;AACjB,gBAAQ,OAAO,yCAAyC,EAAE,QAAQ,YAAY,OAAO,KAAK,QAAQ,CAAC;AAAA,MACrG;AAAA,IACF;AACA,WAAO,aAAa,eAAe,SAAS,EAAE,QAAQ,YAAY,WAAW,2BAA2B,UAAU,IAAI,CAAC;AACvH,WAAO,aAAa,eAAe,SAAS,EAAE,QAAQ,YAAY,WAAW,2BAA2B,UAAU,IAAI,CAAC;AAAA,EACzH;AACA,UAAQ,OAAO,8BAA8B,EAAE,SAAS,MAAM,KAAK,OAAO,GAAG,WAAW,MAAM,OAAO,CAAC;AACxG;AAEO,SAAS,mBAAmB,QAA+B;AAChE,SAAO,OAAO,yBAAyB,yBAAyB;AAClE;;;AC1DA,sBAA6D;AAC7D,sBAAmD;AA2D5C,IAAM,uBAAN,MAA6C;AAAA,EAWlD,YAAY,UAAgC,CAAC,GAAG;AAVhD,gBAAO;AACP,mBAAU;AACV,gBAAO;AACP,wBAAe,CAAC,iCAAiC;AAQ/C,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,KAAK,KAAmC;AAE5C,QAAI,WAAuC,UAAU,EAAE,SAAS;AAAA,MAC9D,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM;AAAA,MACN,OAAO;AAAA,MACP,mBAAmB;AAAA,MACnB,WAAW;AAAA,MACX,SAAS,CAAC,gCAAgB,gCAAgB,+BAAe,qCAAqB,4BAAY;AAAA,IAC5F,CAAC;AACD,QAAI,OAAO,KAAK,yCAAyC;AAAA,EAC3D;AAAA,EAEA,MAAM,MAAM,KAAmC;AAC7C,QAAI,KAAK,gBAAgB,YAAY;AACnC,UAAI,SAAc;AAClB,UAAI;AAAE,iBAAS,IAAI,WAAgB,UAAU;AAAA,MAAG,QAC1C;AAAE,YAAI;AAAE,mBAAS,IAAI,WAAgB,MAAM;AAAA,QAAG,QAAQ;AAAA,QAAe;AAAA,MAAE;AAC7E,UAAI,CAAC,QAAQ;AACX,YAAI,OAAO,KAAK,wEAAmE;AACnF;AAAA,MACF;AAEA,WAAK,UAAU,IAAI,eAAe;AAAA,QAChC;AAAA,QACA,eAAe,KAAK,QAAQ;AAAA,MAC9B,CAAC;AACD,UAAI,gBAAgB,WAAW,KAAK,OAAO;AAE3C,UAAI,KAAK,QAAQ,YAAY,OAAO;AAClC,YAAI,OAAO,KAAK,4DAA4D;AAC5E;AAAA,MACF;AAEA,YAAM,KAAK,uBAAuB,KAAK,OAAO;AAC9C,UAAI,OAAO,OAAO,uBAAuB,YAAY;AACnD,eAAO,mBAAmB,IAAI,EAAE,QAAQ,IAAI,CAAC;AAC7C,YAAI,OAAO,KAAK,wDAAwD;AAAA,MAC1E,OAAO;AACL,YAAI,OAAO,KAAK,uFAAkF;AAAA,MACpG;AAGA,UAAI;AACF,aAAK,cAAc,IAAI,mBAAmB;AAAA,UACxC;AAAA,UACA,SAAS,KAAK;AAAA,UACd,QAAQ,IAAI;AAAA,QACd,CAAC;AACD,YAAI,gBAAgB,gBAAgB,KAAK,WAAW;AAEpD,YAAI,OAAO,OAAO,iBAAiB,cAAc,OAAO,OAAO,6BAA6B,YAAY;AACtG,gBAAM,QAAQ,MAAM,KAAK,YAAY,UAAU,EAAE,YAAY,KAAK,GAAG,EAAE,UAAU,KAAK,CAAQ;AAC9F,6BAAmB,MAAM;AACzB,wBAAc,QAAQ,KAAK,aAAa,OAAO,IAAI,MAAa;AAAA,QAClE,OAAO;AACL,cAAI,OAAO,KAAK,2FAAsF;AAAA,QACxG;AAAA,MACF,SAAS,KAAU;AACjB,YAAI,OAAO,KAAK,4DAA4D,EAAE,OAAO,KAAK,QAAQ,CAAC;AAAA,MACrG;AASA,UAAI;AACF,aAAK,cAAc,IAAI,iBAAiB,EAAE,OAAgC,CAAC;AAC3E,YAAI,gBAAgB,cAAc,KAAK,WAAW;AAElD,YAAI,KAAK,QAAQ,4BAA4B,OAAO;AAClD,cAAI,OAA2B;AAC/B,cAAI;AACF,mBAAO,IAAI,WAAwB,aAAa;AAAA,UAClD,QAAQ;AAAA,UAER;AACA,cAAI,MAAM;AACR,oCAAwB,MAAM,KAAK,aAAa,QAAyB;AAAA,cACvE,UAAU,KAAK,QAAQ;AAAA,YACzB,CAAC;AACD,gBAAI,OAAO;AAAA,cACT,yDACG,KAAK,QAAQ,qBAAqB;AAAA,YACvC;AAAA,UACF,OAAO;AACL,gBAAI,OAAO;AAAA,cACT;AAAA,YAEF;AAAA,UACF;AAAA,QACF;AAAA,MACF,SAAS,KAAU;AACjB,YAAI,OAAO,KAAK,0DAA0D,EAAE,OAAO,KAAK,QAAQ,CAAC;AAAA,MACnG;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAOO,SAAS,uBAAuB,SAA2C;AAChF,SAAO,eAAe,kBAAkB,KAAuB,MAA2B;AACxF,UAAM,KAAK,IAAI;AACf,UAAM,OAAO,IAAI;AAGjB,QAAI,OAAO,UAAU,OAAO,aAAa,OAAO,WAAW,OAAO,aAAa;AAC7E,YAAM,SAAS,MAAM,QAAQ,gBAAgB,IAAI,QAAQ,QAAQ,CAAC,CAAC;AACnE,UAAI,QAAQ;AACV,cAAM,MAAW,IAAI,OAAO,CAAC;AAC7B,YAAI,QAAQ,WAAW,IAAI,OAAO,MAAM;AACxC,YAAI,SAAS,WAAW,IAAI,QAAQ,MAAM;AAC1C,YAAI,MAAM;AAAA,MACZ;AACA,aAAO,KAAK;AAAA,IACd;AAGA,QAAI,OAAO,YAAY,OAAO,UAAU;AACtC,YAAM,OAAY,IAAI;AACtB,YAAM,UAAe,IAAI;AACzB,YAAM,KAAK,cAAc,MAAM,OAAO;AACtC,UAAI,MAAM,MAAM;AACd,cAAM,KAAK,MAAM,QAAQ,QAAQ,IAAI,QAAQ,OAAO,EAAE,GAAG,QAAQ,CAAC,CAAC;AACnE,YAAI,CAAC,IAAI;AACP,gBAAM,MAAW,IAAI;AAAA,YACnB,yCAAyC,EAAE,IAAI,IAAI,MAAM,IAAI,EAAE;AAAA,UACjE;AACA,cAAI,OAAO;AACX,cAAI,SAAS;AACb,gBAAM;AAAA,QACR;AAAA,MACF;AACA,aAAO,KAAK;AAAA,IACd;AAIA,WAAO,KAAK;AAAA,EACd;AACF;AAEA,SAAS,WAAW,UAAmB,UAA4B;AACjE,MAAI,YAAY,KAAM,QAAO;AAC7B,MAAI,YAAY,KAAM,QAAO;AAE7B,MACE,OAAO,aAAa,YAAY,aAAa,QAAQ,CAAC,MAAM,QAAQ,QAAQ,KAC5E,OAAO,aAAa,YAAY,aAAa,QAAQ,CAAC,MAAM,QAAQ,QAAQ,GAC5E;AACA,UAAM,KAAU;AAChB,QAAI,MAAM,QAAQ,GAAG,IAAI,GAAG;AAC1B,aAAO,EAAE,MAAM,CAAC,GAAG,GAAG,MAAM,QAAQ,EAAE;AAAA,IACxC;AAGA,WAAO,EAAE,MAAM,CAAC,UAAU,QAAQ,EAAE;AAAA,EACtC;AACA,SAAO,EAAE,MAAM,CAAC,UAAU,QAAQ,EAAE;AACtC;AAEA,SAAS,cAAc,MAAW,SAA2C;AAC3E,MAAI,QAAQ,OAAO,SAAS,YAAY,KAAK,MAAM,KAAM,QAAO,KAAK;AACrE,MAAI,WAAW,OAAO,YAAY,UAAU;AAC1C,QAAI,QAAQ,MAAM,KAAM,QAAO,QAAQ;AACvC,QAAI,QAAQ,SAAS,OAAO,QAAQ,UAAU,YAAY,QAAQ,MAAM,MAAM,MAAM;AAClF,aAAO,QAAQ,MAAM;AAAA,IACvB;AACA,QAAI,QAAQ,UAAU,OAAO,QAAQ,WAAW,YAAY,QAAQ,OAAO,MAAM,MAAM;AACrF,aAAO,QAAQ,OAAO;AAAA,IACxB;AAAA,EACF;AACA,SAAO;AACT;;;ARxMA,uBAAmC;","names":["import_security","import_identity","row","SYSTEM_CTX","SYSTEM_CTX","SYSTEM_CTX","SYSTEM_CTX","SYSTEM_CTX","SYSTEM_CTX"]}