{"version":3,"file":"register-ts-hook-Djjnj5R8.mjs","names":["fs","semverLt","fs","fs","stableStringify","CHUNK_SIZE","crypto","planServices","planServices","planServices","fs","fs","fs","CHUNK_SIZE","crypto","fs","isPlainObject","toPlatformKey","fs","fs","fs","fs","createWorkspace","createCommand","listCommand","nameArgs","getCommand","formatTime","setTimeout","getCommand","setTimeout","waitForExecution","listCommand","loadOptions","getCommand","loadOptions","listCommand","fs","generate","listCommand","getCommand","listCommand","deleteCommand","getCommand","listCommand","updateCommand","getCommand","listCommand","updateCommand","loadOptions","removeCommand","setTimeout","fs","mimeLookup","fs","fsPromises","fs","fsPromises","listCommand","waitForExecution","loadOptions","loadOptions","listCommand","loadOptions","loadOptions","loadOptions","loadOptions","loadOptions","loadOptions","loadOptions","TailorDBTypeSchema","parseSql"],"sources":["../src/cli/shared/args.ts","../src/cli/shared/command.ts","../src/parser/app-config/schema.ts","../src/parser/plugin-config/schema.ts","../src/cli/shared/token-store.ts","../src/cli/shared/context.ts","../src/cli/shared/env-secret-scan.ts","../src/cli/shared/mock.ts","../src/cli/shared/config-loader.ts","../src/cli/shared/readonly-guard.ts","../src/cli/commands/api/api-call.ts","../src/cli/shared/operator-context.ts","../src/cli/shared/prompt.ts","../src/cli/commands/deploy/change-set.ts","../src/cli/commands/deploy/compare.ts","../src/cli/commands/deploy/label.ts","../src/cli/commands/deploy/owned-resource.ts","../src/cli/commands/deploy/staticwebsite.ts","../src/cli/commands/deploy/aigateway.ts","../src/cli/commands/deploy/application.ts","../src/cli/commands/deploy/secrets-state.ts","../src/cli/commands/deploy/auth-connection.ts","../src/cli/commands/deploy/function-registry.ts","../src/cli/commands/deploy/grouped-display.ts","../src/cli/shared/publish-events.ts","../src/parser/service/idp/permission.ts","../src/cli/commands/deploy/idp.ts","../src/cli/commands/deploy/auth.ts","../src/cli/commands/deploy/invoker.ts","../src/cli/commands/deploy/executor.ts","../src/cli/commands/deploy/resolver.ts","../src/cli/commands/deploy/secret-manager.ts","../src/cli/commands/tailordb/migrate/snapshot-types.ts","../src/cli/commands/tailordb/migrate/nested-members.ts","../src/cli/commands/tailordb/migrate/diff-calculator.ts","../src/cli/commands/tailordb/migrate/migration-number.ts","../src/cli/commands/tailordb/migrate/snapshot-normalization.ts","../src/cli/commands/tailordb/migrate/field-type-change.ts","../src/cli/commands/tailordb/migrate/rename-detection.ts","../src/cli/commands/tailordb/migrate/snapshot-warnings.ts","../src/cli/commands/tailordb/migrate/snapshot-comparison.ts","../src/cli/commands/tailordb/migrate/types.ts","../src/cli/commands/tailordb/migrate/snapshot-schema.ts","../src/cli/commands/tailordb/migrate/snapshot-files.ts","../src/cli/commands/tailordb/migrate/snapshot-migrations.ts","../src/cli/commands/tailordb/migrate/snapshot-local.ts","../src/parser/service/tailordb/type-script.ts","../src/cli/commands/tailordb/migrate/snapshot-remote.ts","../src/cli/commands/tailordb/migrate/file-state.ts","../src/cli/commands/tailordb/migrate/config.ts","../src/cli/commands/tailordb/migrate/remote-state.ts","../src/cli/commands/tailordb/migrate/snapshot-script-compatibility.ts","../src/cli/commands/tailordb/migrate/snapshot-manifest.ts","../src/cli/commands/tailordb/migrate/bundler.ts","../src/cli/commands/tailordb/migrate/hints.ts","../src/cli/shared/spinner.ts","../src/cli/commands/deploy/tailordb/migration-workflow.ts","../src/cli/commands/deploy/tailordb/migration.ts","../src/cli/commands/tailordb/migrate/pre-migration-schema.ts","../src/cli/commands/deploy/tailordb/migration-execution.ts","../src/cli/commands/tailordb/migrate/schema-checks.ts","../src/cli/commands/deploy/tailordb/migration-validation.ts","../src/cli/commands/deploy/tailordb/apply.ts","../src/cli/commands/deploy/tailordb/display.ts","../src/cli/commands/deploy/tailordb/compare.ts","../src/cli/commands/deploy/tailordb/plan.ts","../src/cli/commands/deploy/workflow.ts","../src/cli/commands/deploy/workflow-execution-policy.ts","../src/cli/commands/deploy/apply-phases.ts","../src/cli/commands/deploy/bundled-scripts.ts","../src/cli/commands/deploy/confirm.ts","../src/cli/commands/deploy/dependency-records.ts","../src/cli/cache/types.ts","../src/cli/cache/store.ts","../src/cli/cache/manager.ts","../src/cli/shared/type-generator.ts","../src/cli/commands/deploy/config-id-injector.ts","../src/cli/commands/deploy/app-id-lock.ts","../src/cli/commands/deploy/deployment-target.ts","../src/cli/commands/deploy/visible-resources.ts","../src/cli/commands/deploy/event-subscriptions.ts","../src/cli/commands/deploy/managed-resources.ts","../src/cli/commands/deploy/metadata-lookup.ts","../src/cli/commands/deploy/plan-report.ts","../src/cli/commands/deploy/validate-plan.ts","../src/cli/shared/parse-options.ts","../src/cli/shared/profile-name.ts","../src/cli/shared/workspace-name.ts","../src/cli/commands/workspace/age.ts","../src/cli/commands/workspace/expiry.ts","../src/cli/shared/format.ts","../src/cli/commands/workspace/transform.ts","../src/cli/commands/workspace/create.ts","../src/cli/commands/workspace/list.ts","../src/cli/commands/deploy/workspace-context.ts","../src/cli/commands/deploy/workspace.ts","../src/cli/commands/deploy/deploy.ts","../src/cli/commands/executor/status.ts","../src/cli/commands/executor/transform.ts","../src/cli/commands/executor/get.ts","../src/cli/shared/function-execution.ts","../src/cli/shared/wait-error.ts","../src/cli/commands/workflow/args.ts","../src/cli/commands/workflow/status.ts","../src/cli/commands/workflow/transform.ts","../src/cli/commands/workflow/waiter.ts","../src/cli/commands/workflow/executions.ts","../src/cli/commands/workflow/get.ts","../src/cli/commands/workflow/start.ts","../src/cli/commands/executor/jobs.ts","../src/cli/commands/executor/list.ts","../src/cli/commands/executor/trigger.ts","../src/cli/commands/executor/webhook.ts","../src/cli/commands/function/transform.ts","../src/cli/commands/function/get.ts","../src/cli/commands/function/list.ts","../src/cli/shared/script-executor.ts","../src/cli/shared/config.ts","../src/cli/shared/tailordb-namespaces.ts","../src/plugin/get-plugin-config.ts","../src/cli/shared/auth-input.ts","../src/cli/shared/error-json.ts","../src/cli/commands/generate/service.ts","../src/cli/commands/machineuser/list.ts","../src/cli/commands/machineuser/token.ts","../src/cli/commands/oauth2client/transform.ts","../src/cli/commands/oauth2client/get.ts","../src/cli/commands/oauth2client/list.ts","../src/cli/commands/organization/transform.ts","../src/cli/commands/organization/folder/create.ts","../src/cli/commands/organization/folder/delete.ts","../src/cli/commands/organization/folder/get.ts","../src/cli/commands/organization/folder/list.ts","../src/cli/commands/organization/folder/update.ts","../src/cli/commands/organization/get.ts","../src/cli/commands/organization/list.ts","../src/cli/commands/organization/tree.ts","../src/cli/commands/organization/update.ts","../src/cli/commands/remove.ts","../src/cli/commands/show.ts","../src/cli/shared/progress.ts","../src/cli/commands/staticwebsite/deploy.ts","../src/cli/shared/beta.ts","../src/cli/shared/editor.ts","../src/cli/commands/tailordb/migrate/expand-contract.ts","../src/cli/commands/tailordb/migrate/db-types-generator.ts","../src/cli/commands/tailordb/migrate/pglite-schema-generator.ts","../src/cli/commands/tailordb/migrate/template-generator.ts","../src/cli/commands/tailordb/migrate/script.ts","../src/cli/commands/tailordb/migrate/generate.ts","../src/cli/commands/generate/seed/bundler.ts","../src/cli/shared/seed-chunker.ts","../src/plugin/builtin/seed/seed-type-processor.ts","../src/cli/shared/seed-context.ts","../src/cli/shared/tailordb-namespace.ts","../src/cli/commands/tailordb/truncate.ts","../src/cli/commands/workflow/list.ts","../src/cli/commands/workflow/resume.ts","../src/cli/commands/workflow/wait.ts","../src/cli/commands/workspace/app/transform.ts","../src/cli/commands/workspace/app/health.ts","../src/cli/commands/workspace/app/list.ts","../src/cli/commands/workspace/profile-cleanup.ts","../src/cli/commands/workspace/delete.ts","../src/cli/commands/workspace/get.ts","../src/cli/commands/workspace/restore.ts","../src/cli/commands/workspace/user/transform.ts","../src/cli/commands/workspace/user/invite.ts","../src/cli/commands/workspace/user/list.ts","../src/cli/commands/workspace/user/remove.ts","../src/cli/commands/workspace/user/update.ts","../src/cli/bundler/query/query-bundler.ts","../src/cli/query/errors.ts","../src/cli/query/graphql-repl.ts","../src/cli/query/sql-repl.ts","../src/cli/query/sql-type-extractor.ts","../src/cli/query/type-field-order.ts","../src/cli/query/types.ts","../src/cli/query/index.ts","../src/cli/shared/github-actions.ts","../src/cli/shared/runtime.ts","../src/cli/shared/register-ts-hook.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport { parseEnv } from \"node:util\";\nimport { arg } from \"@politty/zod\";\nimport { PageDirection } from \"@tailor-platform/tailor-proto/resource_pb\";\nimport * as path from \"pathe\";\nimport { z } from \"zod\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { logger } from \"./logger\";\n\ntype ArgsShape = Record<string, z.ZodType>;\nexport type MachineUserInputSource = \"option\" | \"env\";\ntype ResolveMachineUserInputSourceOptions = {\n  valueIsExplicit?: boolean;\n};\n\n// ============================================================================\n// Validators\n// ============================================================================\n\nconst durationUnits = [\"ms\", \"s\", \"m\"] as const;\ntype DurationUnit = (typeof durationUnits)[number];\n\nconst unitToMs: Record<DurationUnit, number> = {\n  ms: 1,\n  s: 1000,\n  m: 60 * 1000,\n};\n\nconst durationPattern = /^(\\d+)(ms|s|m)$/;\n\n/**\n * Schema for duration string validation (e.g., \"3s\", \"500ms\", \"1m\")\n * Only validates format; use parseDuration() to convert to milliseconds\n */\nexport const durationArg = z\n  .string()\n  .refine((val) => durationPattern.test(val), {\n    message: \"Invalid duration format. Expected format: '3s', '500ms', '1m'\",\n  })\n  .refine(\n    (val) => {\n      const match = val.match(durationPattern);\n      if (!match) return false;\n      const digits = match[1];\n      return digits !== undefined && parseInt(digits, 10) > 0;\n    },\n    { message: \"Duration must be greater than 0\" },\n  );\n\n/**\n * Parse a validated duration string into milliseconds\n * @param duration - Duration string (e.g., \"3s\", \"500ms\", \"1m\")\n * @returns Duration in milliseconds\n */\nexport function parseDuration(duration: string): number {\n  const match = assertDefined(\n    duration.match(durationPattern),\n    `invalid duration format: ${duration}`,\n  );\n  const value = parseInt(assertDefined(match[1], \"duration digits group missing\"), 10);\n  const unit = assertDefined(match[2], \"duration unit group missing\") as DurationUnit;\n  return value * unitToMs[unit];\n}\n\n/**\n * Schema for positive integer validation (from string input)\n * Transforms the string to a number\n */\nexport const positiveIntArg = z.coerce.number().int().positive();\n\n/**\n * Schema for non-negative integer validation (from string input).\n * Accepts 0 (used for `--limit 0` to disable the limit).\n */\nexport const nonNegativeIntArg = z.coerce.number().int().nonnegative();\n\n/**\n * Schema for sort order (`asc` or `desc`).\n */\nexport const orderArg = z.enum([\"asc\", \"desc\"]);\n\nexport type Order = z.infer<typeof orderArg>;\n\n/**\n * Translate a CLI `--order` value into the proto `PageDirection` enum.\n * Returns `undefined` when the user did not specify an order so that\n * callers can omit the field and fall back to the server default.\n * @param order - Order string from CLI args (`\"asc\"` | `\"desc\"` | undefined)\n * @returns PageDirection, or undefined when `order` is undefined\n */\nexport function toPageDirection(order: Order | undefined): PageDirection | undefined {\n  if (order === undefined) return undefined;\n  return order === \"asc\" ? PageDirection.ASC : PageDirection.DESC;\n}\n\nfunction hasMachineUserFlag(argv: readonly string[]): boolean {\n  const optionArgs = argv.slice(0, argv.indexOf(\"--\") === -1 ? argv.length : argv.indexOf(\"--\"));\n  return optionArgs.some(\n    (token) =>\n      token === \"-m\" ||\n      token.startsWith(\"-m=\") ||\n      token === \"--machine-user\" ||\n      token.startsWith(\"--machine-user=\") ||\n      token === \"--machineUser\" ||\n      token.startsWith(\"--machineUser=\") ||\n      token === \"--machineuser\" ||\n      token.startsWith(\"--machineuser=\"),\n  );\n}\n\n/**\n * Resolve whether a parsed machine user value came from an explicit CLI option or env fallback.\n * @param machineUser - Parsed machine user value\n * @param argv - Raw CLI argv, excluding the executable and script path\n * @param options - Source resolution options\n * @returns Machine user input source, or undefined when no value was parsed\n */\nexport function resolveMachineUserInputSource(\n  machineUser: string | undefined,\n  argv: readonly string[] = process.argv.slice(2),\n  options: ResolveMachineUserInputSourceOptions = {},\n): MachineUserInputSource | undefined {\n  if (machineUser === undefined) return undefined;\n  if (options.valueIsExplicit) return \"option\";\n  if (hasMachineUserFlag(argv)) return \"option\";\n  return process.env.TAILOR_PLATFORM_MACHINE_USER_NAME === machineUser ? \"env\" : \"option\";\n}\n\n// ============================================================================\n// Env File Helpers\n// ============================================================================\n\ntype EnvFileArg = string | string[] | undefined;\n\n/**\n * Load env files from parsed arguments.\n * Processes --env-file first, then --env-file-if-exists.\n *\n * Follows Node.js --env-file behavior:\n * - Variables already set in the environment are NOT overwritten\n * - Variables from later files override those from earlier files\n * @param envFiles - Required env file path(s) that must exist\n * @param envFilesIfExists - Optional env file path(s) that are loaded if they exist\n */\nexport function loadEnvFiles(envFiles: EnvFileArg, envFilesIfExists: EnvFileArg): void {\n  // Snapshot of originally set environment variables (before loading any files)\n  const originalEnvKeys = new Set(Object.keys(process.env));\n\n  const load = (files: EnvFileArg, required: boolean) => {\n    for (const file of [files ?? []].flat()) {\n      const envPath = path.resolve(process.cwd(), file);\n      if (!fs.existsSync(envPath)) {\n        if (required) {\n          throw new Error(`Environment file not found: ${envPath}`);\n        }\n        continue;\n      }\n      const content = fs.readFileSync(envPath, \"utf-8\");\n      const parsed = parseEnv(content);\n      for (const [key, value] of Object.entries(parsed)) {\n        // Skip if the variable was originally set in the environment\n        if (originalEnvKeys.has(key)) {\n          continue;\n        }\n        // Allow overwriting between env files\n        process.env[key] = value;\n      }\n    }\n  };\n\n  load(envFiles, true);\n  load(envFilesIfExists, false);\n}\n\n// ============================================================================\n// Argument Definitions\n// ============================================================================\n\ninterface CommonArgsOptions {\n  /** Extra short alias for `--verbose` (e.g. `\"v\"`), for plugins that need one */\n  verboseAlias?: string;\n}\n\n/**\n * Build the common arguments for all CLI commands. CLI plugins call this so\n * their forwarded global flags parse identically to the host Tailor CLI and\n * feed the same logger state.\n *\n * NOTE: --env-file and --env-file-if-exists collide with Node.js flags due to a bug\n * (https://github.com/nodejs/node/issues/54232). Node.js parses these even after the\n * script path, causing warnings (twice due to tsx loader).\n * @param options - Per-plugin adjustments to the shared arguments\n * @returns Argument shape suitable for spreading into a command schema\n */\nexport function createCommonArgs(options: CommonArgsOptions = {}) {\n  return {\n    \"env-file\": arg(z.string().optional(), {\n      alias: \"e\",\n      description: \"Path to the environment file (error if not found)\",\n      completion: { type: \"file\", matcher: [\".env.*\", \".env\"] },\n    }),\n    \"env-file-if-exists\": arg(z.string().optional(), {\n      description: \"Path to the environment file (ignored if not found)\",\n      completion: { type: \"file\", matcher: [\".env.*\", \".env\"] },\n      effect: (_value, { args }) => {\n        loadEnvFiles(\n          args[\"env-file\"] as string | undefined,\n          args[\"env-file-if-exists\"] as string | undefined,\n        );\n      },\n    }),\n    verbose: arg(z.boolean().default(false), {\n      ...(options.verboseAlias === undefined ? {} : { alias: options.verboseAlias }),\n      description: \"Enable verbose logging\",\n      effect: (value) => {\n        logger.verbose = value;\n      },\n    }),\n    json: arg(z.boolean().default(false), {\n      alias: \"j\",\n      description: \"Output as JSON\",\n      effect: (value) => {\n        logger.jsonMode = value;\n      },\n    }),\n  } satisfies ArgsShape;\n}\n\n/**\n * Common arguments for all CLI commands\n */\nexport const commonArgs = createCommonArgs();\n\n/**\n * Arguments for commands that require workspace context\n */\nexport const workspaceArgs = {\n  \"workspace-id\": arg(z.string().optional(), {\n    alias: \"w\",\n    description: \"Workspace ID\",\n    env: \"TAILOR_PLATFORM_WORKSPACE_ID\",\n    completion: { type: \"none\" },\n  }),\n  profile: arg(z.string().optional(), {\n    alias: \"p\",\n    description: \"Workspace profile\",\n    env: \"TAILOR_PLATFORM_PROFILE\",\n    completion: { type: \"none\" },\n  }),\n} satisfies ArgsShape;\n\n/**\n * Default config file path used when --config is not passed\n */\nexport const DEFAULT_CONFIG_PATH = \"tailor.config.ts\";\n\n/**\n * Format the --config argument for remediation command hints so they target\n * the same config the current run used. The `--config=<value>` form keeps a\n * leading-hyphen path bound as the option value.\n * @param {string} [configPath] - Config path the current run used, if any\n * @returns {string | undefined} `--config=<path>` argument, or undefined when the default config is in use\n */\nexport function formatConfigArg(configPath?: string): string | undefined {\n  if (!configPath) return undefined;\n  const relativeConfigPath = path.relative(process.cwd(), configPath);\n  if (relativeConfigPath === DEFAULT_CONFIG_PATH) return undefined;\n  return `--config=${relativeConfigPath}`;\n}\n\n/** Profile and workspace selection the current run used. */\nexport interface RecoveryContext {\n  profile?: string | undefined;\n  workspaceId?: string | undefined;\n}\n\n/**\n * Arguments that make a hinted follow-up command select the same profile and\n * workspace as the current run. The `--option=<value>` form keeps a\n * leading-hyphen value bound as the option value.\n * @param {RecoveryContext} context - Profile and workspace id the current run used\n * @returns {readonly string[]} Arguments to append to the hinted command\n */\nexport function recoveryContextArgs(context: RecoveryContext): readonly string[] {\n  return [\n    ...(context.workspaceId ? [`--workspace-id=${context.workspaceId}`] : []),\n    ...(context.profile ? [`--profile=${context.profile}`] : []),\n  ];\n}\n\n/**\n * Shared config arg for commands that accept a config file path\n */\nexport const configArg = {\n  config: arg(z.string().default(DEFAULT_CONFIG_PATH), {\n    alias: \"c\",\n    description: \"Path to Tailor config file\",\n    env: \"TAILOR_CONFIG_PATH\",\n    completion: { type: \"file\", extensions: [\"ts\"] },\n  }),\n} satisfies ArgsShape;\n\n/**\n * Shared config arg for commands that accept one or more comma-separated config file paths\n */\nexport const multiConfigArg = {\n  config: arg(z.string().default(DEFAULT_CONFIG_PATH), {\n    alias: \"c\",\n    description:\n      \"Path to SDK config file. Use comma-separated paths to deploy multiple apps together.\",\n    env: \"TAILOR_PLATFORM_SDK_CONFIG_PATH\",\n    completion: { type: \"file\", extensions: [\"ts\"] },\n  }),\n} satisfies ArgsShape;\n\n/**\n * Arguments for commands that interact with deployed resources (includes config)\n */\nexport const deploymentArgs = {\n  ...workspaceArgs,\n  ...configArg,\n} satisfies ArgsShape;\n\n/**\n * Arguments for commands that require confirmation\n */\nexport const confirmationArgs = {\n  yes: arg(z.boolean().default(false), {\n    alias: \"y\",\n    description: \"Skip confirmation prompts\",\n  }),\n} satisfies ArgsShape;\n\n/**\n * Arguments for commands that require organization context\n */\nexport const organizationArgs = {\n  \"organization-id\": arg(z.string(), {\n    alias: \"o\",\n    description: \"Organization ID\",\n    env: \"TAILOR_PLATFORM_ORGANIZATION_ID\",\n    completion: { type: \"none\" },\n  }),\n} satisfies ArgsShape;\n\n/**\n * Arguments for list commands that accept `--order` / `--limit`. Sort\n * order defaults to `desc` (newest first) because most callers want the\n * latest items; pass `--order asc` to opt in to ascending order. The\n * limit is unbounded by default so existing invocations keep returning\n * every item; pass `--limit N` to cap the result size.\n * @param defaultOrder - Default value for `--order` (defaults to `\"desc\"`)\n * @returns Argument shape suitable for spreading into a command schema\n */\nexport const paginationArgs = (defaultOrder: Order = \"desc\") =>\n  ({\n    order: arg(orderArg.default(defaultOrder), {\n      description: \"Sort order (asc or desc)\",\n    }),\n    limit: arg(nonNegativeIntArg.optional(), {\n      alias: \"l\",\n      description: \"Maximum number of items to return (0 or omit: unlimited)\",\n    }),\n  }) satisfies ArgsShape;\n\n/**\n * Arguments for time-series log list commands. Defaults to newest-first\n * (`desc`) and a 50-item cap so that listing stays responsive on busy\n * workspaces. Pass `--limit 0` to disable the cap and fetch all entries.\n */\nexport const pagedLogArgs = {\n  order: arg(orderArg.default(\"desc\"), {\n    description: \"Sort order (asc or desc)\",\n  }),\n  limit: arg(nonNegativeIntArg.default(50), {\n    alias: \"l\",\n    description: \"Maximum number of items to return (0: unlimited)\",\n  }),\n} satisfies ArgsShape;\n\n/**\n * Arguments for commands that require folder context\n */\nexport const folderArgs = {\n  \"folder-id\": arg(z.string(), {\n    alias: \"f\",\n    description: \"Folder ID\",\n    env: \"TAILOR_PLATFORM_FOLDER_ID\",\n    completion: { type: \"none\" },\n  }),\n} satisfies ArgsShape;\n\nexport type CommonArgsType = z.infer<z.ZodObject<typeof commonArgs>>;\n","import { type AnyCommand, createDefineCommand, runCommand } from \"@politty/zod\";\nimport type { CommonArgsType } from \"./args\";\n\n/**\n * defineCommand with global args type (CommonArgsType).\n * Use this for leaf commands with `run` to get type-safe access to global args.\n * Parent commands with only `subCommands` can use `defineCommand` from politty directly.\n */\n// The explicit annotation keeps the emitted declaration expressible: the\n// inferred overload type names politty internals that its package does not export.\nexport const defineAppCommand: ReturnType<typeof createDefineCommand<CommonArgsType>> =\n  createDefineCommand<CommonArgsType>();\n\n/**\n * Run a parent command's default subcommand, propagating its failure.\n * `runCommand` reports failures through its result instead of throwing, so\n * without this the parent shortcut exits 0 on a failed delegation.\n * @param command - Subcommand to delegate to\n * @param argv - Arguments forwarded to the subcommand\n */\nexport async function runDefaultSubCommand(\n  command: AnyCommand,\n  argv: string[] = [],\n): Promise<void> {\n  const result = await runCommand(command, argv);\n  if (!result.success) {\n    throw result.error;\n  }\n}\n","import { z } from \"zod\";\nimport { LOG_LEVELS } from \"./log-level\";\n\nconst envValueSchema = z.union([z.string(), z.number(), z.boolean()]);\n\n// A boolean is never detected as a credential, so it cannot need an allowance.\nconst allowedSecretValueSchema = z.union([z.string(), z.number()]);\n\nconst envEntrySchema = z.union([\n  envValueSchema,\n  z.strictObject({\n    value: allowedSecretValueSchema,\n    allowSecretReason: z.string().min(1, {\n      message: \"'allowSecretReason' must state why the value is safe to keep in 'env'.\",\n    }),\n  }),\n]);\n\nexport const LogLevelSchema = z.enum(LOG_LEVELS);\n\nconst METADATA_KEY_PATTERN = /^[a-z][a-z0-9_-]{0,62}$/;\nconst METADATA_VALUE_PATTERN = /^$|^[a-z][a-z0-9_-]{0,62}$/;\nconst RESERVED_METADATA_KEY_PREFIX = \"sdk-\";\n// The platform stores at most 20 labels per resource; deploy writes three of its own.\nconst MAX_METADATA_ENTRIES = 17;\n\nconst metadataValueSchema = z.string().regex(METADATA_VALUE_PATTERN, {\n  message: `'metadata' values must match ${METADATA_VALUE_PATTERN.source}.`,\n});\n\n// A key schema on `z.record` reports a generic \"Invalid key in record\", so the\n// keys are checked here to name the offending key and the constraint.\nconst metadataSchema = z.record(z.string(), metadataValueSchema).superRefine((metadata, ctx) => {\n  const keys = Object.keys(metadata);\n  if (keys.length > MAX_METADATA_ENTRIES) {\n    ctx.addIssue({\n      code: \"custom\",\n      message: `'metadata' can hold at most ${MAX_METADATA_ENTRIES} entries.`,\n    });\n  }\n  for (const key of keys) {\n    if (!METADATA_KEY_PATTERN.test(key)) {\n      ctx.addIssue({\n        code: \"custom\",\n        path: [key],\n        message: `'metadata' keys must match ${METADATA_KEY_PATTERN.source}.`,\n      });\n    } else if (key.startsWith(RESERVED_METADATA_KEY_PREFIX)) {\n      ctx.addIssue({\n        code: \"custom\",\n        path: [key],\n        message: `'metadata' keys starting with '${RESERVED_METADATA_KEY_PREFIX}' are reserved for the SDK.`,\n      });\n    }\n  }\n});\n\nconst logLevelSchema = z\n  .string()\n  .refine((value) => LogLevelSchema.safeParse(value.trim().toUpperCase()).success, {\n    message: `'logLevel' must be one of: ${LOG_LEVELS.join(\", \")}.`,\n  });\n\n/**\n * Structural validation schema for `defineConfig({...})`. Validates only\n * top-level fields with platform-side constraints (notably `id`); fields\n * that carry SDK builder objects (`auth`, `idp`, `db`, ...) are accepted\n * as opaque values, since their internal shapes are validated by their\n * own factory functions and parser-level schemas.\n *\n * The `id` is auto-managed by `deploy` and stored as a plain UUID. A\n * label-compatible prefix is added at the metadata boundary, so user-facing\n * configs only need to carry a UUID.\n */\nexport const AppConfigSchema = z.strictObject({\n  id: z.uuid({ message: \"'id' must be a UUID.\" }).optional(),\n  name: z.string().min(1, { message: \"'name' must be a non-empty string.\" }),\n  env: z.record(z.string(), envEntrySchema).optional(),\n  cors: z.array(z.string()).optional(),\n  allowedIpAddresses: z.array(z.string()).optional(),\n  disableIntrospection: z.boolean().optional(),\n  inlineSourcemap: z.boolean().optional(),\n  logLevel: logLevelSchema.optional(),\n  metadata: metadataSchema.optional(),\n  db: z.unknown().optional(),\n  resolver: z.unknown().optional(),\n  idp: z.unknown().optional(),\n  auth: z.unknown().optional(),\n  executor: z.unknown().optional(),\n  workflow: z.unknown().optional(),\n  httpAdapter: z.unknown().optional(),\n  staticWebsites: z.unknown().optional(),\n  aiGateways: z.unknown().optional(),\n  secrets: z.unknown().optional(),\n});\n","import { z } from \"zod\";\nimport { functionSchema } from \"#/parser/service/common\";\nimport type { Plugin } from \"#/plugin/types\";\n\n// Custom plugin schema (object form)\n// Using passthrough() to preserve additional properties on Plugin instances\nexport const PluginConfigSchema = z\n  .looseObject({\n    id: z.string(),\n    description: z.string(),\n    importPath: z.string().optional(),\n    pluginConfig: z.unknown().optional(),\n    tableConfigRequired: z.union([z.boolean(), functionSchema]).optional(),\n    // Definition-time hooks\n    onTableLoaded: functionSchema.optional(),\n    onNamespaceLoaded: functionSchema.optional(),\n    // Generation-time hooks\n    onTailorDBReady: functionSchema.optional(),\n    onResolverReady: functionSchema.optional(),\n    onExecutorReady: functionSchema.optional(),\n  })\n  .refine(\n    (p) => {\n      // importPath is required when plugin has definition-time hooks\n      const hasDefineHooks = p.onTableLoaded || p.onNamespaceLoaded;\n      return !hasDefineHooks || !!p.importPath;\n    },\n    {\n      message:\n        \"importPath is required when plugin has definition-time hooks (onTableLoaded/onNamespaceLoaded)\",\n    },\n  )\n  .transform(\n    (plugin) =>\n      plugin as Plugin<\n        unknown,\n        unknown,\n        // zinfer emits an unqualified, import-less reference for a named type\n        // import used here, so this stays an inline import() type query so the\n        // generated src/types/plugin-config.generated.ts resolves correctly.\n        // oxlint-disable-next-line consistent-type-imports\n        Record<string, import(\"#/configure/services/tailordb/types\").TailorAnyDBField>\n      >,\n  );\n","import { logger } from \"./logger\";\n\nconst SERVICE_NAME = \"tailor-platform-cli\";\n\ntype TokenData = {\n  accessToken: string;\n  refreshToken?: string;\n};\n\ntype EntryLike = {\n  setPassword(password: string): void;\n  getPassword(): string | null;\n  deletePassword(): void;\n};\n\ntype EntryConstructor = new (service: string, account: string) => EntryLike;\n\nlet entryClass: EntryConstructor | false | undefined;\n\nasync function getEntryClass(): Promise<EntryConstructor | false> {\n  if (entryClass !== undefined) return entryClass;\n\n  try {\n    const mod = await import(\"@napi-rs/keyring\");\n    entryClass = mod.Entry;\n  } catch {\n    logger.warn(\n      \"System keyring is not available. Tokens will be stored in the config file. Set TAILOR_PLATFORM_TOKEN environment variable for CI environments.\",\n    );\n    entryClass = false;\n  }\n\n  return entryClass;\n}\n\n/**\n * Check whether the native keyring library can be loaded.\n * @returns true if the library is available; individual operations may still fail\n */\nexport async function isKeyringAvailable(): Promise<boolean> {\n  return (await getEntryClass()) !== false;\n}\n\n/**\n * Load tokens from the OS keyring for a given account.\n * @param account - User identifier (e.g. email or client ID)\n * @returns Token data or undefined if not found or the stored JSON is invalid\n * @throws If the keyring library is unavailable or the keyring cannot be read\n */\nexport async function loadKeyringTokens(account: string): Promise<TokenData | undefined> {\n  const Entry = await getEntryClass();\n  if (!Entry) throw new Error(\"System keyring is not available.\");\n\n  const entry = new Entry(SERVICE_NAME, account);\n  const raw = entry.getPassword();\n  if (raw === null) return undefined;\n  try {\n    return JSON.parse(raw) as TokenData;\n  } catch {\n    return undefined;\n  }\n}\n\n/**\n * Save tokens to the OS keyring for a given account.\n * @param account - User identifier (e.g. email or client ID)\n * @param tokens - Token data to store\n */\nexport async function saveKeyringTokens(account: string, tokens: TokenData): Promise<void> {\n  const Entry = await getEntryClass();\n  if (!Entry) throw new Error(\"System keyring is not available.\");\n\n  const entry = new Entry(SERVICE_NAME, account);\n  entry.setPassword(JSON.stringify(tokens));\n}\n\n/**\n * Delete tokens from the OS keyring for a given account.\n * @param account - User identifier (e.g. email or client ID)\n */\nexport async function deleteKeyringTokens(account: string): Promise<void> {\n  const Entry = await getEntryClass();\n  if (!Entry) return;\n\n  try {\n    const entry = new Entry(SERVICE_NAME, account);\n    entry.deletePassword();\n  } catch {\n    // Ignore \"not found\" errors\n  }\n}\n\n/**\n * Reset the cached keyring state. Used for testing.\n */\nexport function resetKeyringState(): void {\n  entryClass = undefined;\n}\n\nexport type { TokenData };\n","import * as fs from \"node:fs\";\nimport { parseYAML, stringifyYAML } from \"confbox\";\nimport { findUpSync } from \"find-up-simple\";\nimport * as path from \"pathe\";\nimport { lt as semverLt } from \"semver\";\nimport { xdgConfig } from \"xdg-basedir\";\nimport { z } from \"zod\";\nimport { assertDefined } from \"#/utils/assert\";\nimport ml from \"#/utils/multiline\";\nimport { type MachineUserInputSource, recoveryContextArgs } from \"./args\";\nimport {\n  defaultPlatformBaseUrl,\n  fetchUserInfo,\n  getConsoleBaseUrl,\n  getPlatformBaseUrl,\n  initOAuth2Client,\n  normalizeBaseUrl,\n  rememberPlatformConfigForToken,\n  type PlatformClientConfig,\n} from \"./client\";\nimport { CLIError } from \"./errors\";\nimport { logger } from \"./logger\";\nimport { readPackageJson } from \"./package-json\";\nimport { tightenSecretFilePermissions, writeSecretFile } from \"./secret-file\";\nimport {\n  isKeyringAvailable,\n  loadKeyringTokens,\n  saveKeyringTokens,\n  deleteKeyringTokens,\n} from \"./token-store\";\n\n// strip unknown keys\nconst pfProfileSchema = z.object({\n  user: z.string(),\n  workspace_id: z.string(),\n  readonly: z.boolean().optional(),\n  machine_user: z.string().optional(),\n  machine_user_override: z.enum([\"allow\", \"deny\"]).optional(),\n  platform_url: z.url().optional(),\n  oauth2_client_id: z.string().optional(),\n  console_url: z.url().optional(),\n});\n\n// strip unknown keys\nconst pfUserSchemaV1 = z.object({\n  access_token: z.string(),\n  refresh_token: z.string().optional(),\n  token_expires_at: z.string(),\n});\n\n// strip unknown keys\nconst pfUserKeyringSchema = z.object({\n  storage: z.literal(\"keyring\"),\n  token_expires_at: z.string(),\n});\n\n// strip unknown keys\nconst pfUserFileSchema = z.object({\n  storage: z.literal(\"file\"),\n  token_expires_at: z.string(),\n  access_token: z.string(),\n  refresh_token: z.string().optional(),\n});\n\nconst pfUserSchemaV2 = z.discriminatedUnion(\"storage\", [pfUserKeyringSchema, pfUserFileSchema]);\n\nconst pfUserKeyringSchemaV3 = pfUserKeyringSchema.extend({\n  email: z.string().optional(),\n});\n\nconst pfUserFileSchemaV3 = pfUserFileSchema.extend({\n  email: z.string().optional(),\n});\n\nconst pfUserSchemaV3 = z.discriminatedUnion(\"storage\", [pfUserKeyringSchemaV3, pfUserFileSchemaV3]);\n\n// strip unknown keys\nconst pfConfigSchemaV1 = z.object({\n  version: z.literal(1),\n  users: z.partialRecord(z.string(), pfUserSchemaV1),\n  profiles: z.partialRecord(z.string(), pfProfileSchema),\n  current_user: z.string().nullable(),\n});\n\nconst V2_CONFIG_VERSION = 2;\nconst LATEST_CONFIG_VERSION = 3;\nconst V2_MIN_SDK_VERSION = \"1.29.0\";\nconst V3_MIN_SDK_VERSION = \"2.0.0\";\n\nconst semverSchema = z.templateLiteral([\n  z.number().int(),\n  \".\",\n  z.number().int(),\n  \".\",\n  z.number().int(),\n]);\n\n// strip unknown keys\nconst pfConfigSchemaV2 = z.object({\n  version: z.literal(V2_CONFIG_VERSION),\n  min_sdk_version: semverSchema,\n  latest_version: z.number().int().optional(),\n  latest_min_sdk_version: semverSchema.optional(),\n  users: z.partialRecord(z.string(), pfUserSchemaV2),\n  profiles: z.partialRecord(z.string(), pfProfileSchema),\n  current_user: z.string().nullable(),\n});\n\n// strip unknown keys\nconst pfConfigSchemaV3 = z.object({\n  version: z.literal(LATEST_CONFIG_VERSION),\n  min_sdk_version: semverSchema,\n  latest_version: z.number().int().optional(),\n  latest_min_sdk_version: semverSchema.optional(),\n  users: z.partialRecord(z.string(), pfUserSchemaV3),\n  profiles: z.partialRecord(z.string(), pfProfileSchema),\n  current_user: z.string().nullable(),\n});\n\ntype PfConfigV1 = z.output<typeof pfConfigSchemaV1>;\ntype PfConfigV2 = z.output<typeof pfConfigSchemaV2>;\ntype PfConfig = z.output<typeof pfConfigSchemaV3>;\ntype PfUser = z.output<typeof pfUserSchemaV3>;\ntype UserTokens = { accessToken: string; refreshToken?: string };\ntype PfConfigV3 = PfConfig;\ntype LoadWorkspaceIdOptions = {\n  workspaceId?: string;\n  profile?: string;\n};\ntype LoadAccessTokenOptions = {\n  profile?: string;\n};\ntype LoadPlatformClientConfigOptions = {\n  profile?: string;\n  allowMissingProfile?: boolean;\n};\ntype LoadConsoleBaseUrlOptions = {\n  profile?: string;\n  allowMissingProfile?: boolean;\n};\ntype LoadMachineUserNameOptions = {\n  machineUser?: string;\n  machineUserSource?: MachineUserInputSource;\n  profile?: string;\n};\ntype ExplicitMachineUser = {\n  source: MachineUserInputSource;\n  value: string;\n};\n\nexport type AuthStatus = {\n  authenticated: boolean;\n  identity: string | null;\n  identitySource: \"environment\" | \"profile\" | \"default\" | \"none\";\n  profile: string | null;\n  workspaceId: string | null;\n  permission: \"read\" | \"write\";\n  platformUrl: string;\n  tokenStatus: \"environment\" | \"valid\" | \"refreshable\" | \"expired\" | \"missing\";\n};\n\nfunction platformConfigPath() {\n  if (!xdgConfig) {\n    throw new Error(\"User home directory not found\");\n  }\n  return path.join(xdgConfig, \"tailor-platform\", \"config.yaml\");\n}\n\ntype ProfilePlatformSettings = {\n  platform_url?: string;\n  oauth2_client_id?: string;\n  console_url?: string;\n};\n\n/**\n * Convert stored profile platform fields to platform client settings.\n * @param profile - Profile platform settings\n * @returns Platform client settings\n */\nexport function platformConfigFromProfile(\n  profile: ProfilePlatformSettings | undefined,\n): PlatformClientConfig | undefined {\n  const config = {\n    ...(profile?.platform_url ? { platformUrl: profile.platform_url } : {}),\n    ...(profile?.oauth2_client_id ? { oauth2ClientId: profile.oauth2_client_id } : {}),\n    ...(profile?.console_url ? { consoleUrl: profile.console_url } : {}),\n  };\n  return Object.keys(config).length > 0 ? config : undefined;\n}\n\nfunction platformUserKey(user: string, config?: PlatformClientConfig): string {\n  const platformUrl = getPlatformBaseUrl(config);\n  if (platformUrl === normalizeBaseUrl(defaultPlatformBaseUrl)) {\n    return user;\n  }\n  return `${platformUrl}|${user}`;\n}\n\nfunction userFromPlatformUserKey(userKey: string, config?: PlatformClientConfig): string {\n  const platformPrefix = `${getPlatformBaseUrl(config)}|`;\n  return userKey.startsWith(platformPrefix) ? userKey.slice(platformPrefix.length) : userKey;\n}\n\nfunction canUseLegacyUserKey(platformUrl: string): boolean {\n  try {\n    return getPlatformBaseUrl() === platformUrl;\n  } catch {\n    return false;\n  }\n}\n\ntype UserEntryLookupOptions = {\n  allowLegacyUserKey?: boolean;\n};\n\nfunction findUserByEmail(\n  users: PfConfig[\"users\"],\n  email: string,\n  platformConfig?: PlatformClientConfig,\n) {\n  const platformUrl = getPlatformBaseUrl(platformConfig);\n  const platformPrefix = `${platformUrl}|`;\n  const defaultPlatform = platformUrl === normalizeBaseUrl(defaultPlatformBaseUrl);\n  return Object.entries(users).find(([key, entry]) => {\n    if (entry?.email !== email) return false;\n    return defaultPlatform ? !key.includes(\"|\") : key.startsWith(platformPrefix);\n  });\n}\n\nfunction findUserEntry(\n  config: PfConfig,\n  user: string,\n  platformConfig?: PlatformClientConfig,\n  opts: UserEntryLookupOptions = {},\n) {\n  const userKey = platformUserKey(user, platformConfig);\n  const userEntry = config.users[userKey];\n  if (userEntry) {\n    return { userKey, userEntry };\n  }\n  const emailMatch = findUserByEmail(config.users, user, platformConfig);\n  if (emailMatch?.[1]) {\n    return { userKey: emailMatch[0], userEntry: emailMatch[1] };\n  }\n  const platformUrl = getPlatformBaseUrl(platformConfig);\n  if (\n    userKey !== user &&\n    (opts.allowLegacyUserKey === false || !canUseLegacyUserKey(platformUrl))\n  ) {\n    return { userKey, userEntry };\n  }\n  const legacyEntry = config.users[user];\n  return legacyEntry ? { userKey: user, userEntry: legacyEntry } : { userKey, userEntry };\n}\n\n/**\n * Resolve the config user key that would be used for a user on the selected platform.\n * @param config - Platform config\n * @param user - User name\n * @param platformConfig - Optional platform connection settings\n * @param opts - Token lookup options\n * @returns Resolved config user key\n */\nexport function resolveUserTokenKey(\n  config: PfConfig,\n  user: string,\n  platformConfig?: PlatformClientConfig,\n  opts?: UserEntryLookupOptions,\n): string {\n  return findUserEntry(config, user, platformConfig, opts).userKey;\n}\n\nexport function resolveConfigUser(\n  config: PfConfig,\n  user: string,\n  platformConfig?: PlatformClientConfig,\n  opts?: UserEntryLookupOptions,\n): string | undefined {\n  const { userKey, userEntry } = findUserEntry(config, user, platformConfig, opts);\n  return userEntry ? userFromPlatformUserKey(userKey, platformConfig) : undefined;\n}\n\n/**\n * Check whether tokens are registered for a user on the selected platform.\n * @param config - Platform config\n * @param user - User name\n * @param platformConfig - Optional platform connection settings\n * @param opts - Token lookup options\n * @returns True when the user has a registered token entry\n */\nexport function hasUserTokenEntry(\n  config: PfConfig,\n  user: string,\n  platformConfig?: PlatformClientConfig,\n  opts?: UserEntryLookupOptions,\n): boolean {\n  return findUserEntry(config, user, platformConfig, opts).userEntry !== undefined;\n}\n\nfunction hasUserKeyForName(users: Record<string, unknown>, user: string): boolean {\n  return users[user] !== undefined || Object.keys(users).some((key) => key.endsWith(`|${user}`));\n}\n\nfunction hasUserEmailEntry(users: PfConfig[\"users\"], user: string): boolean {\n  return Object.values(users).some((entry) => entry?.email === user);\n}\n\n/**\n * Check whether any platform has tokens registered for a user.\n * @param config - Platform config\n * @param user - User name\n * @returns True when the user has a token entry for any platform\n */\nexport function hasAnyUserTokenEntry(config: Pick<PfConfig, \"users\">, user: string): boolean {\n  return hasUserKeyForName(config.users, user) || hasUserEmailEntry(config.users, user);\n}\n\nfunction hasCurrentUserEntry(users: PfConfigV1[\"users\"], currentUser: string): boolean {\n  return hasUserKeyForName(users, currentUser);\n}\n\n/**\n * Migrate a v1 config to v2.\n * Tokens are kept in the config file (storage: \"file\") during migration.\n * They will be moved to the OS keyring on next login or token refresh.\n * @param v1Config - v1 configuration to migrate\n * @returns Migrated v2 configuration\n */\nfunction migrateV1ToV2(v1Config: PfConfigV1): PfConfigV2 {\n  const users: PfConfigV2[\"users\"] = {};\n\n  for (const [name, v1User] of Object.entries(v1Config.users)) {\n    if (!v1User) continue;\n\n    users[name] = {\n      access_token: v1User.access_token,\n      refresh_token: v1User.refresh_token,\n      token_expires_at: v1User.token_expires_at,\n      storage: \"file\",\n    };\n  }\n\n  return {\n    version: V2_CONFIG_VERSION,\n    min_sdk_version: V2_MIN_SDK_VERSION,\n    users,\n    profiles: v1Config.profiles,\n    current_user: v1Config.current_user,\n  };\n}\n\nfunction inferEmailFromUserId(user: string): string | undefined {\n  return z.email().safeParse(user).success ? user : undefined;\n}\n\nfunction migrateV2ToV3(v2Config: PfConfigV2): PfConfig {\n  const users: PfConfig[\"users\"] = {};\n\n  for (const [user, entry] of Object.entries(v2Config.users)) {\n    if (!entry) continue;\n    const email = inferEmailFromUserId(user);\n    users[user] = {\n      ...entry,\n      ...(email ? { email } : {}),\n    };\n  }\n\n  return {\n    version: LATEST_CONFIG_VERSION,\n    min_sdk_version: V3_MIN_SDK_VERSION,\n    users,\n    profiles: v2Config.profiles,\n    current_user: v2Config.current_user,\n  };\n}\n\nfunction migrateV1ToV3(v1Config: PfConfigV1): PfConfig {\n  return migrateV2ToV3(migrateV1ToV2(v1Config));\n}\n\nfunction formatUnknownError(error: unknown): string {\n  return error instanceof Error ? error.message : String(error);\n}\n\nasync function trySaveTokensInKeyring(user: string, tokens: UserTokens): Promise<boolean> {\n  if (!(await isKeyringAvailable())) return false;\n  try {\n    await saveKeyringTokens(user, tokens);\n    return true;\n  } catch (error) {\n    logger.warn(\n      `System keyring failed to store credentials. Tokens will be stored in the config file. ${formatUnknownError(error)}`,\n    );\n    return false;\n  }\n}\n\nasync function warnIfNewerConfigAvailable(config: {\n  latest_version?: number;\n  latest_min_sdk_version?: string;\n}) {\n  if (!config.latest_min_sdk_version) return;\n  const packageJson = await readPackageJson();\n  const sdkVersion = packageJson.version ?? \"0.0.0\";\n  if (semverLt(sdkVersion, config.latest_min_sdk_version)) {\n    logger.warn(ml`\n      A newer config version (${String(config.latest_version)}) is available.\n      Please update your SDK to >= ${config.latest_min_sdk_version}: pnpm update @tailor-platform/sdk\n    `);\n  }\n}\n\n/**\n * Read Tailor Platform CLI configuration, migrating from v1 if necessary.\n * @returns Parsed platform configuration\n */\nexport async function readPlatformConfig(): Promise<PfConfig> {\n  const configPath = platformConfigPath();\n\n  if (!fs.existsSync(configPath)) {\n    const config: PfConfig = {\n      version: LATEST_CONFIG_VERSION,\n      min_sdk_version: V3_MIN_SDK_VERSION,\n      users: {},\n      profiles: {},\n      current_user: null,\n    };\n    writePlatformConfig(config);\n    return config;\n  }\n\n  const rawConfig = parseYAML(fs.readFileSync(configPath, \"utf-8\"));\n\n  // Legacy installs may have left the config world-readable (umask default\n  // 0o644). Tighten it here so users who only run read-only commands still\n  // get the secret-file permissions applied without waiting for a write.\n  tightenSecretFilePermissions(configPath);\n\n  // Check for unsupported future versions\n  const version =\n    rawConfig != null && typeof rawConfig === \"object\" && \"version\" in rawConfig\n      ? rawConfig.version\n      : undefined;\n  if (typeof version === \"number\" && version > LATEST_CONFIG_VERSION) {\n    const minSdk =\n      \"min_sdk_version\" in (rawConfig as object)\n        ? String((rawConfig as { min_sdk_version: unknown }).min_sdk_version)\n        : undefined;\n    const updateHint = minSdk\n      ? `Please update your SDK to >= ${minSdk}: pnpm update @tailor-platform/sdk`\n      : \"Please update your SDK: pnpm update @tailor-platform/sdk\";\n    throw new Error(ml`\n      Config file uses version ${String(version)}, but this SDK only supports up to version ${String(LATEST_CONFIG_VERSION)}.\n      ${updateHint}\n    `);\n  }\n\n  // Try v3 first\n  const v3Result = pfConfigSchemaV3.safeParse(rawConfig);\n  if (v3Result.success) {\n    await warnIfNewerConfigAvailable(v3Result.data);\n    return v3Result.data;\n  }\n\n  // Try v2 next\n  const v2Result = pfConfigSchemaV2.safeParse(rawConfig);\n  if (v2Result.success) {\n    await warnIfNewerConfigAvailable(v2Result.data);\n    return migrateV2ToV3(v2Result.data);\n  }\n\n  // Fall back to v1 (convert to v3 in memory, but don't rewrite disk)\n  const v1Result = pfConfigSchemaV1.safeParse(rawConfig);\n  if (v1Result.success) {\n    return migrateV1ToV3(v1Result.data);\n  }\n\n  // Neither v1, v2, nor v3\n  throw new Error(ml`\n    Failed to parse config file at ${configPath}.\n    The file may be corrupted or created by an incompatible SDK version.\n  `);\n}\n\nfunction toV1ForDisk(config: PfConfigV2): PfConfigV1 {\n  const users: PfConfigV1[\"users\"] = {};\n  for (const [name, entry] of Object.entries(config.users)) {\n    if (!entry || entry.storage === \"keyring\") continue;\n    users[name] = {\n      access_token: entry.access_token,\n      refresh_token: entry.refresh_token,\n      token_expires_at: entry.token_expires_at,\n    };\n  }\n  const currentUser =\n    config.current_user && hasCurrentUserEntry(users, config.current_user)\n      ? config.current_user\n      : null;\n  return {\n    version: 1,\n    users,\n    profiles: config.profiles,\n    current_user: currentUser,\n  };\n}\n\nfunction hasProfilePlatformSettings(config: Pick<PfConfig | PfConfigV1, \"profiles\">): boolean {\n  return Object.values(config.profiles).some(\n    (profile) =>\n      profile?.platform_url !== undefined ||\n      profile?.oauth2_client_id !== undefined ||\n      profile?.console_url !== undefined,\n  );\n}\n\nfunction hasScopedUserKeys(config: Pick<PfConfig | PfConfigV1, \"users\">): boolean {\n  return Object.keys(config.users).some((userKey) => userKey.includes(\"|\"));\n}\n\nfunction hasUserEmailMetadata(config: Pick<PfConfig | PfConfigV1, \"users\">): boolean {\n  return Object.values(config.users).some(\n    (user) => user != null && \"email\" in user && user.email !== undefined,\n  );\n}\n\nfunction toLatestForDisk(config: PfConfig | PfConfigV2 | PfConfigV1): PfConfigV3 {\n  const latestInput = config.version === 1 ? migrateV1ToV2(config) : config;\n  return {\n    ...latestInput,\n    version: LATEST_CONFIG_VERSION,\n    min_sdk_version: V3_MIN_SDK_VERSION,\n  };\n}\n\n/**\n * Write Tailor Platform CLI configuration to disk.\n * By default, file-backed configs without newer fields are converted to V1 for\n * backward compatibility, so an older SDK can still read the file. Configs\n * containing a keyring user are kept in V2 or later because the keyring storage\n * variant is not representable in V1. Configs containing profile-level Platform\n * settings, platform-scoped user tokens, canonical user IDs, or email metadata\n * are written in the latest min-SDK-gated format because older SDKs would\n * silently drop or misread those settings.\n *\n * The config file may contain access/refresh tokens when the OS keyring is\n * unavailable, so it is written via {@link writeSecretFile} so other users\n * on the host cannot read it.\n * @param config - Platform configuration to write\n */\nexport function writePlatformConfig(config: PfConfig | PfConfigV2 | PfConfigV1) {\n  const configPath = platformConfigPath();\n  const hasKeyringUser =\n    config.version !== 1 && Object.values(config.users).some((u) => u?.storage === \"keyring\");\n  const diskConfig =\n    config.version === LATEST_CONFIG_VERSION ||\n    hasProfilePlatformSettings(config) ||\n    hasScopedUserKeys(config) ||\n    hasUserEmailMetadata(config)\n      ? toLatestForDisk(config)\n      : config.version === V2_CONFIG_VERSION && !hasKeyringUser\n        ? toV1ForDisk(config)\n        : config;\n  writeSecretFile(configPath, stringifyYAML(diskConfig));\n}\n\nfunction validateUUID(value: string, source: string): string {\n  const result = z.uuid().safeParse(value);\n  if (!result.success) {\n    throw new Error(`Invalid value from ${source}: must be a valid UUID`);\n  }\n  return result.data;\n}\n\n/**\n * Load workspace ID from command options, environment variables, or platform config.\n * In CLI context, env fallback is also handled by politty's arg env option.\n * Priority: opts/workspaceId > env/workspaceId > opts/profile > error\n * @param opts - Workspace and profile options\n * @returns Resolved workspace ID\n */\nexport async function loadWorkspaceId(opts?: LoadWorkspaceIdOptions): Promise<string> {\n  const workspaceId = await tryLoadWorkspaceId(opts);\n  if (workspaceId) return workspaceId;\n\n  throw new Error(ml`\n    Workspace ID not found.\n    Please specify workspace ID via --workspace-id option or TAILOR_PLATFORM_WORKSPACE_ID environment variable.\n  `);\n}\n\n/**\n * Load a workspace ID when one is explicitly configured.\n * @param opts - Workspace and profile options\n * @returns Resolved workspace ID, or undefined when no source is configured\n */\nexport async function tryLoadWorkspaceId(\n  opts?: LoadWorkspaceIdOptions,\n): Promise<string | undefined> {\n  const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;\n\n  if (opts?.workspaceId !== undefined) {\n    return validateUUID(opts.workspaceId, \"--workspace-id option\");\n  }\n\n  if (process.env.TAILOR_PLATFORM_WORKSPACE_ID) {\n    return validateUUID(\n      process.env.TAILOR_PLATFORM_WORKSPACE_ID,\n      \"TAILOR_PLATFORM_WORKSPACE_ID environment variable\",\n    );\n  }\n\n  if (profile) {\n    const pfConfig = await readPlatformConfig();\n    const profileEntry = pfConfig.profiles[profile];\n    const wsId = profileEntry?.workspace_id;\n    if (!wsId) {\n      throw new Error(`Profile \"${profile}\" not found`);\n    }\n    return validateUUID(wsId, `profile \"${profile}\"`);\n  }\n\n  return undefined;\n}\n\n/**\n * Load machine user name from command options, environment variables, or platform config.\n * In CLI context, env fallback is also handled by politty's arg env option.\n * Priority: opts/machineUser > env/TAILOR_PLATFORM_MACHINE_USER_NAME > opts/profile (profile default) > undefined.\n * An explicitly empty `opts.machineUser` is rejected with a CLIError (`MACHINE_USER_NAME_EMPTY`) rather than falling back to the env var or profile default.\n * When the active profile has `machine_user_override: \"deny\"`, an explicit value that differs from the profile's machine user throws a CLIError with code `PROFILE_MACHINE_USER_OVERRIDE_DENIED`.\n * @param opts - Machine user and profile options\n * @returns Resolved machine user name, or undefined if not set\n */\nexport async function loadMachineUserName(\n  opts?: LoadMachineUserNameOptions,\n): Promise<string | undefined> {\n  if (opts?.machineUser === \"\") {\n    throw CLIError({\n      code: \"MACHINE_USER_NAME_EMPTY\",\n      message: \"Machine user name cannot be empty.\",\n      suggestion:\n        \"Pass a non-empty machine user name, or omit the option to use the environment variable or profile default.\",\n    });\n  }\n\n  const envMachineUser = process.env.TAILOR_PLATFORM_MACHINE_USER_NAME || undefined;\n  const explicitMachineUser: ExplicitMachineUser | undefined = opts?.machineUser\n    ? {\n        source: opts.machineUserSource ?? \"option\",\n        value: opts.machineUser,\n      }\n    : envMachineUser\n      ? { source: \"env\", value: envMachineUser }\n      : undefined;\n  const explicit = explicitMachineUser?.value;\n\n  const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;\n  if (!profile) return explicit;\n\n  const pfConfig = await readPlatformConfig();\n  const entry = pfConfig.profiles[profile];\n  if (!entry) {\n    if (explicit) return explicit;\n    throw new Error(`Profile \"${profile}\" not found`);\n  }\n\n  if (entry.machine_user && entry.machine_user_override === \"deny\") {\n    if (explicit && explicit !== entry.machine_user) {\n      const details =\n        explicitMachineUser.source === \"env\"\n          ? `The machine user is being set to \"${explicit}\" via the TAILOR_PLATFORM_MACHINE_USER_NAME environment variable, which conflicts with this profile's pinned machine user \"${entry.machine_user}\".`\n          : `This profile fixes the machine user to \"${entry.machine_user}\" for application-data commands.`;\n      throw CLIError({\n        code: \"PROFILE_MACHINE_USER_OVERRIDE_DENIED\",\n        message: `Profile \"${profile}\" denies overriding the machine user.`,\n        details,\n        suggestion: `Omit the machine user option, unset TAILOR_PLATFORM_MACHINE_USER_NAME, or run 'tailor profile update ${profile} --machine-user-override allow'.`,\n      });\n    }\n    return entry.machine_user;\n  }\n\n  return explicit || entry.machine_user;\n}\n\n/**\n * Load access token from environment variables, command options, or platform config.\n * In CLI context, profile env fallback is also handled by politty's arg env option.\n * Priority: env/TAILOR_PLATFORM_TOKEN > env/TAILOR_TOKEN (deprecated) > opts/profile > env/profile > config/currentUser > error\n * @param opts - Profile options\n * @returns Resolved access token\n */\nexport async function loadAccessToken(opts?: LoadAccessTokenOptions) {\n  const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;\n  const envToken = process.env.TAILOR_PLATFORM_TOKEN ?? process.env.TAILOR_TOKEN;\n  if (envToken && !process.env.TAILOR_PLATFORM_TOKEN) {\n    logger.warn(\"TAILOR_TOKEN is deprecated. Please use TAILOR_PLATFORM_TOKEN instead.\");\n  }\n\n  if (envToken) {\n    logger.registerSecret(envToken);\n    const platformConfig = await loadPlatformClientConfig({ profile, allowMissingProfile: true });\n    rememberPlatformConfigForToken(envToken, platformConfig);\n    return envToken;\n  }\n\n  const pfConfig = await readPlatformConfig();\n  const profileEntry = profile ? pfConfig.profiles[profile] : undefined;\n  if (profile && !profileEntry) {\n    throw new Error(`Profile \"${profile}\" not found`);\n  }\n  const user = profileEntry?.user ?? pfConfig.current_user;\n  if (!user) {\n    throw CLIError({\n      code: \"AUTH_TOKEN_NOT_FOUND\",\n      message: \"Tailor Platform token not found.\",\n      suggestion: \"Set TAILOR_PLATFORM_TOKEN or log in using the selected profile.\",\n      next: { command: \"tailor\", args: [\"login\", ...recoveryContextArgs({ profile })] },\n      context: { profile: profile ?? null },\n    });\n  }\n  const fromProfile = profileEntry ? platformConfigFromProfile(profileEntry) : undefined;\n  return (await fetchLatestToken(pfConfig, user, fromProfile, profile)).accessToken;\n}\n\n/**\n * Resolve authentication metadata without returning token values.\n * @param opts - Profile options\n * @returns Authentication status for the active environment and profile\n */\nexport async function loadAuthStatus(opts?: LoadAccessTokenOptions): Promise<AuthStatus> {\n  const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;\n  const envToken = process.env.TAILOR_PLATFORM_TOKEN ?? process.env.TAILOR_TOKEN;\n  if (envToken && !process.env.TAILOR_PLATFORM_TOKEN) {\n    logger.warn(\"TAILOR_TOKEN is deprecated. Please use TAILOR_PLATFORM_TOKEN instead.\");\n  }\n\n  if (envToken) {\n    logger.registerSecret(envToken);\n    const config = await readPlatformConfig().catch(() => undefined);\n    const profileEntry = profile ? config?.profiles[profile] : undefined;\n    const platformConfig = profileEntry ? platformConfigFromProfile(profileEntry) : undefined;\n    return {\n      authenticated: true,\n      identity: null,\n      identitySource: \"environment\",\n      profile: profile ?? null,\n      workspaceId: process.env.TAILOR_PLATFORM_WORKSPACE_ID ?? profileEntry?.workspace_id ?? null,\n      permission: profileEntry?.readonly === true ? \"read\" : \"write\",\n      platformUrl: getPlatformBaseUrl(platformConfig),\n      tokenStatus: \"environment\",\n    };\n  }\n\n  const config = await readPlatformConfig();\n  const profileEntry = profile ? config.profiles[profile] : undefined;\n  if (profile && !profileEntry) {\n    throw new Error(`Profile \"${profile}\" not found`);\n  }\n\n  const platformConfig = profileEntry ? platformConfigFromProfile(profileEntry) : undefined;\n  const platformUrl = getPlatformBaseUrl(platformConfig);\n  const workspaceId =\n    process.env.TAILOR_PLATFORM_WORKSPACE_ID ?? profileEntry?.workspace_id ?? null;\n\n  const identity = profileEntry?.user ?? config.current_user;\n  const identitySource = profileEntry?.user ? \"profile\" : identity ? \"default\" : \"none\";\n  let tokenStatus: AuthStatus[\"tokenStatus\"] = \"missing\";\n  if (identity) {\n    const { userKey, userEntry } = findUserEntry(config, identity, platformConfig);\n    if (userEntry) {\n      const tokens = await resolveTokens(userEntry, userKey, identity).catch(() => undefined);\n      if (tokens) {\n        const expired = new Date(userEntry.token_expires_at) <= new Date();\n        if (!expired) {\n          tokenStatus = \"valid\";\n        } else {\n          tokenStatus = tokens.refreshToken ? \"refreshable\" : \"expired\";\n        }\n      }\n    }\n  }\n\n  return {\n    authenticated: tokenStatus === \"valid\" || tokenStatus === \"refreshable\",\n    identity: identity ?? null,\n    identitySource,\n    profile: profile ?? null,\n    workspaceId,\n    permission: profileEntry?.readonly === true ? \"read\" : \"write\",\n    platformUrl,\n    tokenStatus,\n  };\n}\n\n/**\n * Load platform connection settings from the active profile.\n * @param opts - Profile options\n * @returns Resolved platform connection settings, or undefined for the default environment\n */\nexport async function loadPlatformClientConfig(\n  opts?: LoadPlatformClientConfigOptions,\n): Promise<PlatformClientConfig | undefined> {\n  const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;\n  if (!profile) {\n    return undefined;\n  }\n\n  let pfConfig: PfConfig;\n  try {\n    pfConfig = await readPlatformConfig();\n  } catch (error) {\n    if (opts?.allowMissingProfile) {\n      return undefined;\n    }\n    throw error;\n  }\n  const profileEntry = pfConfig.profiles[profile];\n  if (!profileEntry) {\n    if (opts?.allowMissingProfile) {\n      return undefined;\n    }\n    throw new Error(`Profile \"${profile}\" not found`);\n  }\n  return platformConfigFromProfile(profileEntry);\n}\n\n/**\n * Load the Tailor Platform Console base URL from environment variables or the active profile.\n * @param opts - Profile options\n * @returns Resolved Console base URL\n */\nexport async function loadConsoleBaseUrl(opts?: LoadConsoleBaseUrlOptions): Promise<string> {\n  const platformConfig = await loadPlatformClientConfig(opts);\n  return getConsoleBaseUrl(platformConfig);\n}\n\n/**\n * Registers a token pair's values with the logger so they are redacted from diagnostic\n * log output, wherever they later flow (retries, error messages, etc.). Call this as soon\n * as a token is obtained, not just before it is persisted — code between the two points\n * (e.g. an intervening API call) can still fail or log diagnostically.\n * @param tokens - Access token and optional refresh token\n */\nexport function registerTokenSecrets(tokens: UserTokens): void {\n  logger.registerSecret(tokens.accessToken);\n  if (tokens.refreshToken) logger.registerSecret(tokens.refreshToken);\n}\n\n/**\n * Resolve the actual token values for a user, reading from keyring or config as appropriate.\n * @param userEntry - User entry from the config\n * @param user - User identifier\n * @param label - User-facing identifier used in error messages\n * @returns Access token and optional refresh token\n */\nexport async function resolveTokens(\n  userEntry: PfUser,\n  user: string,\n  label = user,\n): Promise<{ accessToken: string; refreshToken?: string }> {\n  if (userEntry.storage === \"keyring\") {\n    let tokens: UserTokens | undefined;\n    try {\n      tokens = await loadKeyringTokens(user);\n    } catch (error) {\n      throw new Error(\n        ml`\n          Failed to read credentials from OS keyring for \"${label}\". ${formatUnknownError(error)}\n          Restore access to the OS keyring and try again, or run 'tailor login' in this environment to authenticate again.\n          For non-interactive environments, set TAILOR_PLATFORM_TOKEN.\n        `,\n        { cause: error },\n      );\n    }\n    if (!tokens) {\n      throw new Error(ml`\n        Credentials not found in OS keyring for \"${label}\".\n        Credentials may be missing or inaccessible from this environment (for example, due to sandbox restrictions).\n        Restore access to the OS keyring and try again, or run 'tailor login' in this environment to authenticate again.\n        For non-interactive environments, set TAILOR_PLATFORM_TOKEN.\n      `);\n    }\n    registerTokenSecrets(tokens);\n    return tokens;\n  }\n\n  const tokens = {\n    accessToken: userEntry.access_token,\n    refreshToken: userEntry.refresh_token,\n  };\n  registerTokenSecrets(tokens);\n  return tokens;\n}\n\n/**\n * Save tokens for a user, writing to keyring by default when available.\n * @param config - Platform config\n * @param user - User identifier\n * @param tokens - Token data to save\n * @param tokens.accessToken - Access token to save\n * @param tokens.refreshToken - Optional refresh token to save\n * @param expiresAt - Token expiration date\n * @param opts - Optional platform and user metadata\n */\nexport async function saveUserTokens(\n  config: PfConfig,\n  user: string,\n  tokens: UserTokens,\n  expiresAt: string,\n  opts: { platformConfig?: PlatformClientConfig; email?: string } = {},\n): Promise<void> {\n  registerTokenSecrets(tokens);\n  const userKey = platformUserKey(user, opts.platformConfig);\n  const email = opts.email ?? config.users[userKey]?.email;\n  if (await trySaveTokensInKeyring(userKey, tokens)) {\n    config.users[userKey] = {\n      token_expires_at: expiresAt,\n      storage: \"keyring\",\n      ...(email ? { email } : {}),\n    };\n  } else {\n    if (config.users[userKey]?.storage === \"keyring\") {\n      await deleteKeyringTokens(userKey);\n    }\n    config.users[userKey] = {\n      access_token: tokens.accessToken,\n      refresh_token: tokens.refreshToken,\n      token_expires_at: expiresAt,\n      storage: \"file\",\n      ...(email ? { email } : {}),\n    };\n  }\n}\n\n/**\n * Delete tokens for a user from keyring if applicable.\n * @param config - Platform config\n * @param user - User identifier\n * @param platformConfig - Optional platform connection settings\n * @param opts - Token lookup options\n */\nexport async function deleteUserTokens(\n  config: PfConfig,\n  user: string,\n  platformConfig?: PlatformClientConfig,\n  opts?: UserEntryLookupOptions,\n): Promise<void> {\n  const { userKey, userEntry } = findUserEntry(config, user, platformConfig, opts);\n  if (userEntry?.storage === \"keyring\") {\n    await deleteKeyringTokens(userKey);\n  }\n  delete config.users[userKey];\n}\n\n/**\n * Resolve stored tokens for a user on the selected platform.\n * @param config - Platform config\n * @param user - User name\n * @param platformConfig - Optional platform connection settings\n * @param opts - Token lookup options\n * @returns Stored user entry and token values, or undefined when the user is not logged in\n */\nexport async function loadStoredUserTokens(\n  config: PfConfig,\n  user: string,\n  platformConfig?: PlatformClientConfig,\n  opts?: UserEntryLookupOptions,\n): Promise<\n  | {\n      userEntry: PfUser;\n      accessToken: string;\n      refreshToken?: string;\n    }\n  | undefined\n> {\n  const { userKey, userEntry } = findUserEntry(config, user, platformConfig, opts);\n  if (!userEntry) return undefined;\n  const tokens = await resolveTokens(userEntry, userKey, user);\n  return { userEntry, ...tokens };\n}\n\nfunction updateUserReferences(config: PfConfig, fromUser: string, toUser: string) {\n  if (fromUser === toUser) return;\n  if (config.current_user === fromUser) {\n    config.current_user = toUser;\n  }\n  for (const profile of Object.values(config.profiles)) {\n    if (profile?.user === fromUser) {\n      profile.user = toUser;\n    }\n  }\n}\n\n/**\n * Remove a legacy alias after a canonical user ID has been written.\n * @param config - Platform config\n * @param legacyUser - Previous user key\n * @param canonicalUser - Canonical user key\n * @param platformConfig - Platform settings for scoped token storage\n */\nexport async function removeLegacyUserAlias(\n  config: PfConfig,\n  legacyUser: string,\n  canonicalUser: string,\n  platformConfig?: PlatformClientConfig,\n): Promise<void> {\n  if (legacyUser === canonicalUser) return;\n  updateUserReferences(config, legacyUser, canonicalUser);\n  const canonicalKey = platformUserKey(canonicalUser, platformConfig);\n  const legacyKeys = new Set([legacyUser, platformUserKey(legacyUser, platformConfig)]);\n  for (const legacyKey of legacyKeys) {\n    if (legacyKey === canonicalKey) continue;\n    const entry = config.users[legacyKey];\n    if (entry?.storage === \"keyring\") {\n      await deleteKeyringTokens(legacyKey);\n    }\n    delete config.users[legacyKey];\n  }\n}\n\nfunction shouldResolveSubjectOnRefresh(user: string, userEntry: PfUser): boolean {\n  return Boolean(userEntry.email || inferEmailFromUserId(user));\n}\n\n/**\n * Fetch the latest access token, refreshing if necessary.\n * @param config - Platform config\n * @param user - User identifier\n * @param platformConfig - Optional platform connection settings\n * @param profile - Selected profile for login recovery\n * @returns Latest access token and the canonical user ID it is stored under\n *   (the resolved subject when a legacy email key was migrated during refresh,\n *   otherwise the matching config user)\n */\nexport async function fetchLatestToken(\n  config: PfConfig,\n  user: string,\n  platformConfig?: PlatformClientConfig,\n  profile?: string,\n): Promise<{ accessToken: string; user: string }> {\n  const loginArgs = profile ? [\"--profile\", profile] : [];\n  const loginFailure = (code: string, message: string, suggestion: string) =>\n    CLIError({\n      code,\n      message,\n      suggestion,\n      next: { command: \"tailor\", args: [\"login\", ...loginArgs, \"--help\"] },\n      context: { profile: profile ?? null },\n    });\n  const { userKey: storedUser, userEntry } = findUserEntry(config, user, platformConfig);\n  if (!userEntry) {\n    throw loginFailure(\n      \"AUTH_USER_NOT_FOUND\",\n      `User \"${user}\" not found.`,\n      \"Verify the selected user and use the original login method (browser or --machine-user) on the same platform.\",\n    );\n  }\n\n  const storedConfigUser = userFromPlatformUserKey(storedUser, platformConfig);\n  const tokens = await resolveTokens(userEntry, storedUser, user);\n\n  if (new Date(userEntry.token_expires_at) > new Date()) {\n    rememberPlatformConfigForToken(tokens.accessToken, platformConfig);\n    return { accessToken: tokens.accessToken, user: storedConfigUser };\n  }\n\n  if (!tokens.refreshToken) {\n    throw loginFailure(\n      \"AUTH_TOKEN_EXPIRED\",\n      \"Token expired.\",\n      \"Use the original login method (browser or --machine-user) to authenticate again on the same platform.\",\n    );\n  }\n\n  const client = initOAuth2Client(platformConfig);\n  let resp;\n  try {\n    resp = await client.refreshToken({\n      accessToken: tokens.accessToken,\n      refreshToken: tokens.refreshToken,\n      expiresAt: Date.parse(userEntry.token_expires_at),\n    });\n  } catch {\n    throw loginFailure(\n      \"AUTH_TOKEN_REFRESH_FAILED\",\n      \"Failed to refresh token. Your session may have expired.\",\n      \"Check network connectivity and platform availability, then use the original login method (browser or --machine-user) on the same platform if needed.\",\n    );\n  }\n  registerTokenSecrets({\n    accessToken: resp.accessToken,\n    refreshToken: resp.refreshToken ?? undefined,\n  });\n\n  const newExpiresAt = new Date(\n    assertDefined(resp.expiresAt, \"token refresh response missing expiresAt\"),\n  ).toISOString();\n\n  let resolvedUser = storedConfigUser;\n  const previousEmail =\n    userEntry.email ?? inferEmailFromUserId(user) ?? inferEmailFromUserId(storedConfigUser);\n  let email = previousEmail;\n  if (\n    shouldResolveSubjectOnRefresh(user, userEntry) ||\n    shouldResolveSubjectOnRefresh(storedConfigUser, userEntry)\n  ) {\n    try {\n      const userInfo = await fetchUserInfo(resp.accessToken, platformConfig);\n      resolvedUser = userInfo.sub;\n      email = userInfo.email;\n    } catch (error) {\n      logger.debug(`Failed to resolve refreshed token user info: ${String(error)}`);\n    }\n  }\n\n  await saveUserTokens(\n    config,\n    resolvedUser,\n    {\n      accessToken: resp.accessToken,\n      refreshToken: resp.refreshToken ?? tokens.refreshToken,\n    },\n    newExpiresAt,\n    { platformConfig, email },\n  );\n  await removeLegacyUserAlias(config, user, resolvedUser, platformConfig);\n  const canonicalKey = platformUserKey(resolvedUser, platformConfig);\n  if (storedUser !== canonicalKey) {\n    const entry = config.users[storedUser];\n    if (entry?.storage === \"keyring\") {\n      await deleteKeyringTokens(storedUser);\n    }\n    delete config.users[storedUser];\n  }\n  if (previousEmail && email && previousEmail !== email) {\n    logger.info(`Updated local user email from \"${previousEmail}\" to \"${email}\".`);\n  }\n  writePlatformConfig(config);\n  rememberPlatformConfigForToken(resp.accessToken, platformConfig);\n  return { accessToken: resp.accessToken, user: resolvedUser };\n}\n\nconst DEFAULT_CONFIG_FILENAME = \"tailor.config.ts\";\n\n/**\n * Load config path from command options, environment variables, or search parent directories.\n * In CLI context, env fallback is also handled by politty's arg env option.\n * Priority: opts/config > env/config > search parent directories\n * @param configPath - Optional explicit config path\n * @returns Resolved config path or undefined\n */\nexport function loadConfigPath(configPath?: string): string | undefined {\n  if (configPath) {\n    return configPath;\n  }\n  if (process.env.TAILOR_CONFIG_PATH) {\n    return process.env.TAILOR_CONFIG_PATH;\n  }\n\n  // Search for config file in current directory and parent directories\n  return findUpSync(DEFAULT_CONFIG_FILENAME);\n}\n","import { createHash } from \"node:crypto\";\nimport { logger, styles } from \"./logger\";\nimport type { EnvEntry, EnvValue } from \"#/configure/config/types\";\n\nconst AWS_RULE_ID = \"@secretlint/secretlint-rule-aws\";\nconst RULE_ID_PREFIX = \"@secretlint/secretlint-rule-\";\n/**\n * Honors `secretlint-disable` comments found in the scanned text. `env` values\n * are author-controlled text, so leaving this rule in let a value act as a\n * directive and suppress the findings of the entries after it — defeating the\n * check without the explicit allowance.\n *\n * Matched by id on purpose: the rule declares itself a `scanner`, so it cannot\n * be told apart by `meta.type`, and the preset's `disabled` option has no\n * effect on it.\n */\nconst COMMENT_DIRECTIVE_RULE_ID = \"@secretlint/secretlint-rule-filter-comments\";\nconst HIGH_ENTROPY_DETECTOR = \"high-entropy\";\n\n/**\n * The scanned document is assembled in memory, so the path only labels the\n * source for the scanner and never reaches the filesystem.\n */\nconst VIRTUAL_SOURCE_PATH = \"/tailor-config-env\";\n\nconst ENTROPY_MIN_LENGTH = 20;\n/**\n * Bits per character. Above 4.0 no hex-only string can reach the threshold,\n * which keeps commit hashes, UUIDs and slugs out of the heuristic while still\n * catching base64/base62 credentials.\n */\nconst ENTROPY_MIN_BITS_PER_CHAR = 4.2;\nconst TOKEN_LIKE_VALUE = /^[A-Za-z0-9+/=_.-]+$/;\n\n/**\n * A single command can load the same config repeatedly — `setup generate`\n * derives five separate answers, each through its own `loadConfig` — so results\n * are memoized on the entries scanned. Without this the scanner would run, and\n * warnings would print, once per load.\n *\n * Keys are digests rather than the serialized entries, so the cache does not\n * hold the values it was asked to judge for the life of the process.\n */\nconst scans = new Map<string, Promise<void>>();\n\ninterface EnvSecretFinding {\n  /** `env` key holding the value. */\n  readonly key: string;\n  /** Short name of what matched, e.g. `slack`, `aws`, `high-entropy`. */\n  readonly detector: string;\n  /**\n   * Which of the detector's patterns matched, e.g. `AWSAccountID`. A detector\n   * can recognize several credential shapes — `aws` alone covers an account id,\n   * an access key id and a secret access key — and knowing which one fired is\n   * what tells the reader whether the value is actually sensitive.\n   */\n  readonly rule?: string;\n  /** Where the matched pattern is documented. */\n  readonly docsUrl?: string;\n  /** `error` for provider-specific matches, `warning` for the entropy heuristic. */\n  readonly severity: \"error\" | \"warning\";\n}\n\ninterface EnvSecretScanInput {\n  /** `env` entries as written in the config, before `{ value, allowSecretReason }` wrappers are resolved. */\n  readonly env?: Readonly<Record<string, EnvEntry>>;\n  /** Config file the entries came from, named in the failure so multi-config projects can tell which one. */\n  readonly configPath?: string;\n}\n\ntype ScannedEntry = readonly [key: string, value: EnvValue];\n\ntype EntryRange = {\n  readonly key: string;\n  readonly start: number;\n  readonly end: number;\n};\n\n/**\n * Resolve an `env` entry to the value that gets deployed.\n * @param entry - Entry as written in the config\n * @returns The entry's value, unwrapped when it carries an `allowSecretReason`\n */\nexport function resolveEnvValue(entry: EnvEntry): EnvValue {\n  return isAllowedSecret(entry) ? entry.value : entry;\n}\n\n/**\n * Scan `env` values for credentials.\n *\n * Entries wrapped as `{ value, allowSecretReason }` are skipped.\n * Provider-specific matches are reported as errors; values that merely look\n * randomly generated are reported as warnings.\n * @param input - `env` entries as written in the config\n * @returns Provider matches first, then entropy warnings; empty when nothing matched\n */\nexport async function scanEnvForSecrets(input: EnvSecretScanInput): Promise<EnvSecretFinding[]> {\n  const entries: ScannedEntry[] = Object.entries(input.env ?? {})\n    .filter(([, entry]) => !isAllowedSecret(entry))\n    .map(([key, entry]) => [key, resolveEnvValue(entry)]);\n  if (entries.length === 0) {\n    return [];\n  }\n\n  const findings = await scanWithProviderRules(entries);\n  const alreadyFound = new Set(findings.map((finding) => finding.key));\n\n  for (const [key, value] of entries) {\n    if (alreadyFound.has(key) || typeof value !== \"string\") continue;\n    if (looksRandomlyGenerated(value)) {\n      findings.push({ key, detector: HIGH_ENTROPY_DETECTOR, severity: \"warning\" });\n    }\n  }\n\n  return findings;\n}\n\n/**\n * Report secret-looking `env` values, failing when a credential is identified.\n *\n * Warnings are logged and do not fail the command. Repeated calls for the same\n * entries reuse the first result.\n * @param input - `env` entries as written in the config\n * @returns Promise that resolves when the entries carry no credential\n * @throws When a value is identified as a credential\n */\nexport async function assertEnvHasNoSecrets(input: EnvSecretScanInput): Promise<void> {\n  const key = createHash(\"sha256\")\n    .update(JSON.stringify([input.configPath ?? \"\", input.env ?? {}]))\n    .digest(\"hex\");\n  const pending = scans.get(key);\n  if (pending) {\n    return pending;\n  }\n\n  const scan = reportEnvSecrets(input);\n  scans.set(key, scan);\n  return scan;\n}\n\n/**\n * Log warnings and throw on credentials found in `env`.\n * @param input - `env` entries as written in the config\n * @throws When a value is identified as a credential\n */\nasync function reportEnvSecrets(input: EnvSecretScanInput): Promise<void> {\n  const findings = await scanEnvForSecrets(input);\n\n  for (const finding of findings) {\n    if (finding.severity !== \"warning\") continue;\n    logger.warn(\n      `env.${finding.key} looks like a randomly generated credential. ` +\n        `If it is one, move it to Secret Manager; otherwise allow it with ${styles.bold(\"allowSecretReason\")}.`,\n    );\n  }\n\n  const errors = findings.filter((finding) => finding.severity === \"error\");\n  if (errors.length === 0) {\n    return;\n  }\n\n  const location = input.configPath ? ` in ${input.configPath}` : \"\";\n  const list = errors\n    .map((error) => {\n      const matched = error.rule ? `${error.detector}: ${error.rule}` : error.detector;\n      const reference = error.docsUrl ? `\\n    ${error.docsUrl}` : \"\";\n      return `  - env.${error.key} (matched ${matched})${reference}`;\n    })\n    .join(\"\\n\");\n  const example = errors[0]?.key ?? \"KEY\";\n  throw new Error(\n    `Secret detected in 'env'${location}:\\n${list}\\n` +\n      \"'env' values are deployed as plaintext and are readable by anyone who can read the application's configuration. \" +\n      \"Define these with defineSecretManager() instead, and read them through Secret Manager at runtime.\\n\" +\n      \"If a value is genuinely safe to keep in 'env', allow it where it is defined: \" +\n      `${example}: { value: ..., allowSecretReason: \"<why this is safe>\" }`,\n  );\n}\n\n/**\n * Run the provider rule set over all entries at once.\n *\n * Entries are scanned as one `KEY=value` document because some rules only match\n * when the key name accompanies the value (`AWS_SECRET_ACCESS_KEY`, database\n * connection strings). Each finding is mapped back to its key through the\n * character range the entry occupies, which stays correct for multi-line values.\n * @param entries - `env` entries to scan\n * @returns Error-severity findings, deduplicated per key and rule\n */\nasync function scanWithProviderRules(\n  entries: ReadonlyArray<ScannedEntry>,\n): Promise<EnvSecretFinding[]> {\n  const [{ lintSource }, { rules }] = await Promise.all([\n    import(\"@secretlint/core\"),\n    import(\"@secretlint/secretlint-rule-preset-recommend\"),\n  ]);\n\n  const ranges: EntryRange[] = [];\n  let content = \"\";\n  for (const [key, value] of entries) {\n    const line = `${key}=${String(value)}`;\n    ranges.push({ key, start: content.length, end: content.length + line.length });\n    content += `${line}\\n`;\n  }\n\n  const result = await lintSource({\n    source: { filePath: VIRTUAL_SOURCE_PATH, content, contentType: \"text\" },\n    options: {\n      // Messages embed the matched value, so mask them: nothing this scan\n      // produces should be able to print a credential.\n      maskSecrets: true,\n      noPhysicFilePath: true,\n      config: {\n        // Registered individually rather than through the preset so the\n        // comment-directive rule can be left out (see its id above).\n        rules: rules\n          .filter((rule) => rule.meta.id !== COMMENT_DIRECTIVE_RULE_ID)\n          .map((rule) => ({\n            id: rule.meta.id,\n            rule,\n            // Off by default, and the only way to catch a bare access key id.\n            ...(rule.meta.id === AWS_RULE_ID ? { options: { enableIDScanRule: true } } : {}),\n          })),\n      },\n    },\n  });\n\n  const findings: EnvSecretFinding[] = [];\n  const seen = new Set<string>();\n  for (const message of result.messages) {\n    const entry = ranges.find(\n      (range) => message.range[0] >= range.start && message.range[0] < range.end,\n    );\n    if (!entry) continue;\n\n    const detector = message.ruleId.startsWith(RULE_ID_PREFIX)\n      ? message.ruleId.slice(RULE_ID_PREFIX.length)\n      : message.ruleId;\n    const dedupeKey = JSON.stringify([entry.key, detector, message.messageId]);\n    if (seen.has(dedupeKey)) continue;\n    seen.add(dedupeKey);\n\n    // The message text embeds the matched value; the identifiers do not.\n    findings.push({\n      key: entry.key,\n      detector,\n      rule: message.messageId,\n      ...(message.docsUrl ? { docsUrl: message.docsUrl } : {}),\n      severity: \"error\",\n    });\n  }\n\n  return findings;\n}\n\n/**\n * Decide whether an entry carries its own allowance.\n * @param entry - Entry as written in the config\n * @returns True when the entry is the `{ value, allowSecretReason }` form\n */\nfunction isAllowedSecret(entry: EnvEntry): entry is Exclude<EnvEntry, EnvValue> {\n  return typeof entry === \"object\";\n}\n\n/**\n * Decide whether a value carries enough randomness to look generated rather\n * than authored.\n * @param value - `env` value to inspect\n * @returns True when the value is long, token-shaped and high-entropy\n */\nfunction looksRandomlyGenerated(value: string): boolean {\n  if (value.length < ENTROPY_MIN_LENGTH || !TOKEN_LIKE_VALUE.test(value)) {\n    return false;\n  }\n  return shannonEntropyPerChar(value) >= ENTROPY_MIN_BITS_PER_CHAR;\n}\n\n/**\n * Compute Shannon entropy of a string in bits per character.\n * @param value - String to measure\n * @returns Bits per character\n */\nfunction shannonEntropyPerChar(value: string): number {\n  const occurrences = new Map<string, number>();\n  for (const char of value) {\n    occurrences.set(char, (occurrences.get(char) ?? 0) + 1);\n  }\n\n  let entropy = 0;\n  for (const count of occurrences.values()) {\n    const probability = count / value.length;\n    entropy -= probability * Math.log2(probability);\n  }\n  return entropy;\n}\n","/**\n * Install a stub `globalThis.tailordb` so that user code loaded by the CLI\n * (e.g. via `createGetDB` in `@tailor-platform/sdk/kysely`) can reference\n * `tailordb.Client` without hitting a `ReferenceError`. The CLI never\n * actually executes the user code paths that issue queries, so a no-op\n * client suffices.\n *\n * Exposed as a function (rather than a top-level statement) so that\n * `package.json#sideEffects` can keep the file marked side-effect-free\n * without bundlers eliminating the install step.\n */\nexport function installCliTailordbStub(): void {\n  (\n    globalThis as unknown as {\n      tailordb: {\n        Client: typeof tailordb.Client;\n      };\n    }\n  ).tailordb = {\n    Client: class {\n      constructor(_config: { namespace: string }) {}\n      async connect(): Promise<void> {}\n      async end(): Promise<void> {}\n      async queryObject<O>(): Promise<tailordb.QueryResult<O>> {\n        return {} as Promise<tailordb.QueryResult<O>>;\n      }\n    },\n  };\n}\n","import * as fs from \"node:fs\";\nimport { pathToFileURL } from \"node:url\";\nimport * as path from \"pathe\";\nimport { AppConfigSchema } from \"#/parser/app-config/schema\";\nimport { PluginConfigSchema } from \"#/parser/plugin-config/index\";\nimport { pickPluginArrays } from \"#/plugin/guards\";\nimport { loadConfigPath } from \"./context\";\nimport { assertEnvHasNoSecrets, resolveEnvValue } from \"./env-secret-scan\";\nimport { getErrorDiagnostics, withErrorDiagnostics } from \"./error-diagnostics\";\nimport { installCliTailordbStub } from \"./mock\";\nimport { currentImportNonce, IMPORT_NONCE_PARAM } from \"./user-modules\";\nimport type { AppConfig, EnvValue } from \"#/configure/config/types\";\nimport type { Plugin } from \"#/plugin/types\";\n\n/**\n * App config whose `env` entries have been resolved to the values that get\n * deployed: the `{ value, allowSecretReason }` form accepted in `defineConfig`\n * is unwrapped during loading, so nothing downstream can deploy a wrapper\n * object or the reason string alongside the value.\n */\nexport type ResolvedEnvAppConfig = Omit<AppConfig, \"env\"> & {\n  env?: Record<string, EnvValue>;\n};\n\n/** Loaded configuration with resolved path. */\nexport type LoadedConfig = ResolvedEnvAppConfig & { path: string };\n\nexport interface LoadConfigOptions {\n  /** Import cache-busting value for callers that reload the config module after a rebuild. */\n  importNonce?: string;\n}\n\n/**\n * Load Tailor configuration file and associated plugins.\n * @param configPath - Optional explicit config path\n * @param options - Optional module import behavior.\n * @returns Loaded config, plugins, and config path\n */\nexport async function loadConfig(\n  configPath?: string,\n  options: LoadConfigOptions = {},\n): Promise<{ config: LoadedConfig; plugins: Plugin[] }> {\n  installCliTailordbStub();\n  const foundPath = loadConfigPath(configPath);\n  if (!foundPath) {\n    throw new Error(\n      \"Configuration file not found: tailor.config.ts not found in current or parent directories\",\n    );\n  }\n  const resolvedPath = path.resolve(process.cwd(), foundPath);\n\n  if (!fs.existsSync(resolvedPath)) {\n    throw new Error(`Configuration file not found: ${configPath}`);\n  }\n\n  const configUrl = pathToFileURL(resolvedPath);\n  const importNonce = options.importNonce ?? currentImportNonce();\n  if (importNonce) {\n    configUrl.searchParams.set(IMPORT_NONCE_PARAM, importNonce);\n  }\n  let configModule: unknown;\n  try {\n    configModule = await import(configUrl.href);\n  } catch (error) {\n    throw atConfigSource(error, resolvedPath);\n  }\n  if (\n    typeof configModule !== \"object\" ||\n    configModule === null ||\n    !(\"default\" in configModule) ||\n    !configModule.default\n  ) {\n    throw atConfigFile(\n      new Error(\"Invalid Tailor config module: default export not found\"),\n      resolvedPath,\n    );\n  }\n\n  const validated = AppConfigSchema.safeParse(configModule.default);\n  if (!validated.success) {\n    const issues = validated.error.issues\n      .map((i) => `  - ${i.path.join(\".\") || \"(root)\"}: ${i.message}`)\n      .join(\"\\n\");\n    throw atConfigFile(\n      new Error(`Invalid Tailor config in ${resolvedPath}:\\n${issues}`),\n      resolvedPath,\n    );\n  }\n\n  const appConfig = configModule.default as AppConfig;\n  try {\n    await assertEnvHasNoSecrets({ env: appConfig.env, configPath: resolvedPath });\n  } catch (error) {\n    throw error instanceof Error ? atConfigFile(error, resolvedPath) : error;\n  }\n  const env = appConfig.env\n    ? Object.fromEntries(\n        Object.entries(appConfig.env).map(([key, entry]) => [key, resolveEnvValue(entry)]),\n      )\n    : undefined;\n\n  // Collect all plugin exports (plugins, plugins2, etc.); an array with an\n  // item the schema rejects is left out as a whole.\n  const allPlugins: Plugin[] = [];\n  for (const items of pickPluginArrays(configModule)) {\n    const parsed = items.map((item) => PluginConfigSchema.safeParse(item));\n    if (parsed.every((result) => result.success)) {\n      allPlugins.push(...parsed.map((result) => result.data));\n    }\n  }\n\n  return {\n    config: {\n      ...appConfig,\n      ...(env ? { env } : {}),\n      path: resolvedPath,\n    } as LoadedConfig,\n    plugins: allPlugins,\n  };\n}\n\n/**\n * Point a config rejection at the file it came from.\n * @param error - Failure raised while loading the config\n * @param resolvedPath - Absolute path to the config file\n * @returns The same error, carrying the config file as its source location\n */\nfunction atConfigFile<T extends Error>(error: T, resolvedPath: string): T {\n  return withErrorDiagnostics(error, { location: { file: resolvedPath } });\n}\n\n/**\n * Diagnostic the TypeScript transform throws for source it cannot parse.\n *\n * It arrives as a plain object rather than an Error, so a failure to parse the\n * config would otherwise reach the caller as `[object Object]`.\n */\ninterface SyntaxDiagnostic {\n  code: \"InvalidSyntax\";\n  message: string;\n  filename: string;\n  startLine?: number;\n}\n\nfunction isSyntaxDiagnostic(value: unknown): value is SyntaxDiagnostic {\n  if (typeof value !== \"object\" || value === null || value instanceof Error) return false;\n  const { code, message, filename, startLine } = value as Record<string, unknown>;\n  return (\n    code === \"InvalidSyntax\" &&\n    typeof message === \"string\" &&\n    typeof filename === \"string\" &&\n    (startLine === undefined || typeof startLine === \"number\")\n  );\n}\n\n/**\n * Point a failure raised while importing the config at the source it came from.\n *\n * Unparsable source names the file it was found in, which is the imported\n * module rather than the config when the config imports it. Anything else is\n * attributed to the config file, the one location loading it establishes, and\n * a failure that already names its own source keeps it.\n * @param error - Value thrown while importing the config\n * @param resolvedPath - Absolute path to the config file\n * @returns An Error carrying the source location the failure points at\n */\nexport function atConfigSource(error: unknown, resolvedPath: string): unknown {\n  if (isSyntaxDiagnostic(error)) {\n    return withErrorDiagnostics(new SyntaxError(error.message, { cause: error }), {\n      location: {\n        file: error.filename,\n        ...(error.startLine === undefined ? {} : { line: error.startLine }),\n      },\n    });\n  }\n  if (!(error instanceof Error)) return error;\n  return getErrorDiagnostics(error).location ? error : atConfigFile(error, resolvedPath);\n}\n","import { readPlatformConfig } from \"./context\";\nimport { CLIError } from \"./errors\";\n\ninterface AssertWritableOptions {\n  /** Explicit profile name from command args. Falls back to TAILOR_PLATFORM_PROFILE. */\n  profile?: string;\n}\n\n/**\n * Throw a CLIError if the active profile has `readonly: true`.\n *\n * Resolves the active profile in this order:\n * 1. `opts.profile` (CLI flag)\n * 2. `process.env.TAILOR_PLATFORM_PROFILE`\n *\n * If neither is set, no profile is in scope so the call is allowed. This is\n * intentional: `TAILOR_PLATFORM_TOKEN` direct access (CI / machine user) and\n * `--workspace-id` without a profile are out-of-band paths whose authorization\n * is governed by the bearer token itself, not by the local profile flag.\n *\n * If the resolved profile cannot be found in the config, this function returns\n * silently and lets downstream loaders surface the not-found error.\n * @param opts - Options\n * @param opts.profile - Optional explicit profile name from command args\n */\nexport async function assertWritable(opts?: AssertWritableOptions): Promise<void> {\n  // Truthy fallback (||, not ??) so an empty `--profile \"\"` flag falls\n  // through to TAILOR_PLATFORM_PROFILE, matching loadAccessToken /\n  // loadWorkspaceId. Otherwise the loaders would still resolve a readonly\n  // profile from the env var while this guard returns silently.\n  const profileName = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;\n  if (!profileName) return;\n  const config = await readPlatformConfig();\n  const profile = config.profiles[profileName];\n  if (!profile || profile.readonly !== true) return;\n  throw CLIError({\n    code: \"PROFILE_READONLY\",\n    message: `Profile \"${profileName}\" is read-only.`,\n    details:\n      \"This profile blocks platform-state mutations (apply, create/update/delete, deploy, etc.). Application-data operations remain available because their permissions are governed by the machine user.\",\n    suggestion: `Use a different profile, unset TAILOR_PLATFORM_PROFILE, or run 'tailor profile update ${profileName} --permission write'.`,\n  });\n}\n","import { getPlatformBaseUrl, userAgent, type PlatformClientConfig } from \"#/cli/shared/client\";\nimport { loadAccessToken, loadPlatformClientConfig } from \"#/cli/shared/context\";\nimport { CLIError } from \"#/cli/shared/errors\";\n\nexport interface ApiCallOptions {\n  profile?: string;\n  endpoint: string;\n  body?: string;\n}\n\nexport interface ApiCallResult {\n  status: number;\n  data: unknown;\n}\n\nfunction hasEnvAccessToken(): boolean {\n  const envToken = process.env.TAILOR_PLATFORM_TOKEN ?? process.env.TAILOR_TOKEN;\n  return Boolean(envToken);\n}\n\n/**\n * Call Tailor Platform API endpoints directly.\n * If the endpoint doesn't contain \"/\", it defaults to `tailor.v1.OperatorService/{endpoint}`.\n * @param options - API call options (profile, endpoint, body)\n * @returns Response status and data\n */\nexport async function apiCall(options: ApiCallOptions): Promise<ApiCallResult> {\n  const accessToken = await loadAccessToken({\n    profile: options.profile,\n  });\n  let platformConfig: PlatformClientConfig | undefined;\n  try {\n    platformConfig = await loadPlatformClientConfig({\n      profile: options.profile,\n    });\n  } catch (error) {\n    if (!hasEnvAccessToken()) throw error;\n  }\n\n  let endpointPath: string;\n  if (options.endpoint.includes(\"/\")) {\n    endpointPath = options.endpoint;\n  } else {\n    endpointPath = `tailor.v1.OperatorService/${options.endpoint}`;\n  }\n\n  const url = new URL(endpointPath, getPlatformBaseUrl(platformConfig));\n\n  const response = await fetch(url.toString(), {\n    method: \"POST\",\n    headers: {\n      \"Content-Type\": \"application/json\",\n      Authorization: `Bearer ${accessToken}`,\n      \"User-Agent\": await userAgent(),\n    },\n    body: options.body ?? \"{}\",\n  });\n\n  const data: unknown = await response.json();\n\n  if (!response.ok) {\n    throw CLIError({\n      code: \"API_REQUEST_FAILED\",\n      message: `API call failed (${response.status}): ${JSON.stringify(data)}`,\n      context: { status: response.status },\n    });\n  }\n\n  return {\n    status: response.status,\n    data,\n  };\n}\n","import { initOperatorClient } from \"./client\";\nimport { loadAccessToken, loadWorkspaceId } from \"./context\";\n\ntype LoadOperatorWorkspaceContextOptions = {\n  profile?: string;\n  workspaceId?: string;\n};\n\nexport async function loadOperatorWorkspaceContext(options: LoadOperatorWorkspaceContextOptions) {\n  const accessToken = await loadAccessToken({ profile: options.profile });\n  const client = await initOperatorClient(accessToken);\n  const workspaceId = await loadWorkspaceId({\n    profile: options.profile,\n    workspaceId: options.workspaceId,\n  });\n  return { client, workspaceId };\n}\n","import { ExitPromptError } from \"@inquirer/core\";\nimport { confirm, input, password, select } from \"@inquirer/prompts\";\nimport { isCI } from \"std-env\";\nimport { CIPromptError, logger } from \"./logger\";\n\nexport function canPrompt(): boolean {\n  return !isCI && process.stdin.isTTY === true && process.stdout.isTTY === true && !logger.jsonMode;\n}\n\n/**\n * Wraps a prompt function with CI guard and cancellation handling.\n * @param fn - A prompt function from `@inquirer/prompts`\n * @param unavailableMessage - Message used when interactive input is unavailable\n * @returns A wrapped function that throws in CI and exits on cancel\n */\nfunction withGuard<Config, R>(\n  fn: (config: Config) => Promise<R>,\n  unavailableMessage?: string,\n): (config: Config) => Promise<R> {\n  return async (config: Config): Promise<R> => {\n    if (!canPrompt()) throw new CIPromptError(unavailableMessage);\n    try {\n      return await fn(config);\n    } catch (error) {\n      if (error instanceof ExitPromptError) process.exit(130);\n      throw error;\n    }\n  };\n}\n\n/** Options accepted by {@link prompt.confirm}. */\nexport interface ConfirmConfig {\n  message: string;\n  default?: boolean;\n}\n\n/** Options accepted by {@link prompt.text}. */\nexport interface TextConfig {\n  message: string;\n  default?: string;\n  required?: boolean;\n  validate?: (value: string) => boolean | string | Promise<boolean | string>;\n}\n\n/** Options accepted by {@link prompt.password}. */\nexport interface PasswordConfig {\n  message: string;\n  mask?: boolean | string;\n  validate?: (value: string) => boolean | string | Promise<boolean | string>;\n}\n\n/** A selectable entry of {@link SelectConfig.choices}. */\nexport interface SelectChoice<Value> {\n  value: Value;\n  name?: string;\n  description?: string;\n  short?: string;\n  disabled?: boolean | string;\n}\n\n/** Options accepted by {@link prompt.select}. */\nexport interface SelectConfig<Value> {\n  message: string;\n  choices: readonly SelectChoice<Value>[];\n  default?: NoInfer<Value>;\n  pageSize?: number;\n  loop?: boolean;\n}\n\n/**\n * Interactive prompts that fail with an actionable message instead of hanging\n * when stdin is not a TTY (CI, piped input), and exit with 130 on Ctrl-C.\n *\n * The config types are declared here rather than inferred from\n * `@inquirer/prompts`: inference pulls `@inquirer/*` internals (`Context`,\n * `Keybinding`, `PartialDeep`) into this public type, and those cannot be\n * named portably from the published declarations (TS2883). They cover the\n * options this CLI uses — widen them here when a call site needs more.\n */\nexport const prompt = {\n  confirm: withGuard<ConfirmConfig, boolean>(\n    confirm,\n    \"Interactive confirmations are not available in this environment. Use --yes to skip confirmation prompts, or provide the required options explicitly.\",\n  ),\n  text: withGuard<TextConfig, string>(input),\n  password: withGuard<PasswordConfig, string>(password),\n  select: <const Value>(config: SelectConfig<Value>): Promise<Value> =>\n    withGuard<SelectConfig<Value>, Value>(select)(config),\n};\n","import { styles, symbols } from \"#/cli/shared/logger\";\n\nexport interface HasName {\n  name: string;\n  /**\n   * Optional pre-formatted lines rendered indented beneath the item by\n   * `ChangeSet.lines()` (e.g. per-sub-resource diffs embedded in a single\n   * resource).\n   */\n  details?: readonly string[];\n}\n\nexport type ChangeSet<\n  C extends HasName,\n  U extends HasName,\n  D extends HasName,\n  R extends HasName = never,\n  Un extends HasName = HasName,\n> = {\n  readonly title: string;\n  readonly creates: C[];\n  readonly updates: U[];\n  readonly deletes: D[];\n  readonly replaces: R[];\n  readonly unchanged: Un[];\n  isEmpty: () => boolean;\n  lines: () => string[];\n};\n\nexport interface PlanSummary {\n  create: number;\n  update: number;\n  delete: number;\n  replace: number;\n}\n\n/**\n * Create a new ChangeSet for tracking resource changes.\n * @param title - Title for the change set\n * @returns Empty ChangeSet instance with isEmpty() and lines() methods\n */\nexport function createChangeSet<\n  C extends HasName,\n  U extends HasName,\n  D extends HasName,\n  R extends HasName = never,\n  Un extends HasName = HasName,\n>(title: string): ChangeSet<C, U, D, R, Un> {\n  const creates: C[] = [];\n  const updates: U[] = [];\n  const deletes: D[] = [];\n  const replaces: R[] = [];\n  const unchanged: Un[] = [];\n\n  const isEmpty = (): boolean =>\n    creates.length === 0 && updates.length === 0 && deletes.length === 0 && replaces.length === 0;\n\n  return {\n    title,\n    creates,\n    updates,\n    deletes,\n    replaces,\n    unchanged,\n    isEmpty,\n    lines: () => {\n      if (isEmpty()) return [];\n      const itemLines = (symbol: string) => (item: HasName) => [\n        `  ${symbol} ${item.name}`,\n        ...(item.details ?? []).map((d) => `    ${d}`),\n      ];\n      return [\n        styles.bold(`${title}:`),\n        ...creates.flatMap(itemLines(symbols.create)),\n        ...deletes.flatMap(itemLines(symbols.delete)),\n        ...updates.flatMap(itemLines(symbols.update)),\n        ...replaces.flatMap(itemLines(symbols.replace)),\n      ];\n    },\n  };\n}\n\n/**\n * Summarize resource counts across multiple change sets.\n * @param changeSets - Change sets to aggregate\n * @returns Aggregated plan counts by action\n */\nexport function summarizeChangeSets(\n  changeSets: Array<\n    Pick<\n      ChangeSet<HasName, HasName, HasName, HasName>,\n      \"creates\" | \"updates\" | \"deletes\" | \"replaces\"\n    >\n  >,\n): PlanSummary {\n  const summary: PlanSummary = { create: 0, update: 0, delete: 0, replace: 0 };\n\n  for (const changeSet of changeSets) {\n    summary.create += changeSet.creates.length;\n    summary.update += changeSet.updates.length;\n    summary.delete += changeSet.deletes.length;\n    summary.replace += changeSet.replaces.length;\n  }\n\n  return summary;\n}\n\n/**\n * Format an aggregated plan summary for CLI output.\n * @param summary - Aggregated plan counts\n * @returns Human-readable plan summary line\n */\nexport function formatPlanSummary(summary: PlanSummary): string {\n  const parts = [\n    `${summary.create} to create`,\n    `${summary.update} to update`,\n    `${summary.delete} to delete`,\n  ];\n\n  if (summary.replace > 0) {\n    parts.push(`${summary.replace} to replace`);\n  }\n\n  return `Plan: ${parts.join(\", \")}`;\n}\n","import { create, toJson, type DescMessage, type MessageInitShape } from \"@bufbuild/protobuf\";\n\n/**\n * Canonicalize a proto message (or init shape) into proto JSON for comparison.\n *\n * Deserialized messages materialize implicit proto3 fields with their zero\n * values while locally built init shapes omit them, so comparing the raw\n * objects reports a diff for every field the SDK does not set — including\n * fields newly added to the proto. Proto JSON omits implicit zero values on\n * both sides, which matches wire semantics (unset == zero value).\n * @param schema - Message schema describing the value\n * @param value - Message or init shape to canonicalize\n * @returns Proto JSON representation of the value\n */\nexport function toComparableProtoJson<Desc extends DescMessage>(\n  schema: Desc,\n  value: MessageInitShape<Desc>,\n): unknown {\n  return toJson(schema, create(schema, value));\n}\n\n/**\n * Stable JSON-like serialization that sorts object keys and ignores proto runtime metadata.\n * @param value - Value to serialize\n * @returns Stable serialized string\n */\nexport function stableStringify(value: unknown): string {\n  if (Array.isArray(value)) {\n    return `[${value.map((item) => (item === undefined ? \"null\" : stableStringify(item))).join(\",\")}]`;\n  }\n  if (value && typeof value === \"object\") {\n    const entries = Object.entries(value as Record<string, unknown>)\n      .filter(([key, entryValue]) => key !== \"$typeName\" && entryValue !== undefined)\n      .toSorted(([left], [right]) => left.localeCompare(right));\n    return `{${entries.map(([key, entryValue]) => `${JSON.stringify(key)}:${stableStringify(entryValue)}`).join(\",\")}}`;\n  }\n  if (typeof value === \"bigint\") {\n    return JSON.stringify(value.toString());\n  }\n  return JSON.stringify(value);\n}\n\n/**\n * Normalize a proto-ish object into a plain JSON-compatible structure for comparison.\n * @param value - Value to normalize\n * @returns Normalized value\n */\nexport function normalizeProtoConfig<T>(value: T): T {\n  if (value === undefined || value === null) {\n    return value;\n  }\n  return JSON.parse(stableStringify(value)) as T;\n}\n\n/**\n * Sort a string array for order-insensitive comparison.\n * @param values - Values to sort\n * @returns Sorted values\n */\nexport function normalizeStringArray(values: readonly string[] | undefined): string[] {\n  return (values ?? []).toSorted();\n}\n\n/**\n * Compare two values after proto normalization.\n * @param left - Left value\n * @param right - Right value\n * @returns True when normalized values are equal\n */\nexport function areNormalizedEqual(left: unknown, right: unknown): boolean {\n  return (\n    stableStringify(normalizeProtoConfig(left)) === stableStringify(normalizeProtoConfig(right))\n  );\n}\n","import { stripVTControlCharacters } from \"node:util\";\nimport { getOrNull } from \"#/cli/shared/client\";\nimport { withErrorDiagnostics } from \"#/cli/shared/error-diagnostics\";\nimport { CLIError, isCLIError, toError } from \"#/cli/shared/errors\";\nimport { readPackageJson } from \"#/cli/shared/package-json\";\nimport type { MessageInitShape } from \"@bufbuild/protobuf\";\nimport type {\n  BulkSetMetadataRequestSchema,\n  SetMetadataRequestSchema,\n} from \"@tailor-platform/tailor-proto/metadata_pb\";\n\nexport type WithLabel<T> = Partial<\n  Record<\n    string,\n    {\n      resource: T;\n      label: string | undefined;\n      allLabels?: Record<string, string>;\n    }\n  >\n>;\n\n/**\n * Build TRN prefix for a workspace.\n * @param workspaceId - Workspace ID\n * @returns TRN prefix string\n */\nfunction trnPrefix(workspaceId: string): string {\n  return `trn:v1:workspace:${workspaceId}`;\n}\n\n/**\n * Resource kind segment used in a TRN (`trn:v1:workspace:<id>:<kind>:<name>`).\n */\nexport type ResourceKind =\n  | \"application\"\n  | \"function_registry\"\n  | \"pipeline\"\n  | \"idp\"\n  | \"auth\"\n  | \"auth_connection\"\n  | \"executor\"\n  | \"workflow\"\n  | \"workflow_job_function\"\n  | \"workflow_job_function_execution_policy\"\n  | \"staticwebsite\"\n  | \"aigateway\"\n  | \"tailordb\"\n  | \"vault\";\n\n/**\n * Build the TRN for a workspace resource.\n * @param workspaceId - Workspace ID\n * @param kind - Resource kind segment\n * @param name - Resource name\n * @returns Fully-qualified TRN string\n */\nexport function resourceTrn(workspaceId: string, kind: ResourceKind, name: string): string {\n  return `${trnPrefix(workspaceId)}:${kind}:${name}`;\n}\n\n/**\n * Build the TRN for a resource nested inside another.\n *\n * The platform reads everything after the workspace id as alternating key/value\n * pairs and matches the pair list against one resource type, so a nested\n * resource is the parent's pair followed by its own. A TailorDB table is\n * `tailordb:<namespace>:type:<name>`, distinct from the namespace's own\n * `tailordb:<namespace>`.\n * @param workspaceId - Workspace ID\n * @param parent - Parent kind and name, e.g. the namespace holding the resource\n * @param child - Nested key and name, e.g. `[\"type\", \"Order\"]`\n * @returns Fully-qualified TRN string\n */\nfunction nestedResourceTrn(\n  workspaceId: string,\n  parent: readonly [ResourceKind, string],\n  child: readonly [NestedResourceKey, string],\n): string {\n  return `${trnPrefix(workspaceId)}:${parent[0]}:${parent[1]}:${child[0]}:${child[1]}`;\n}\n\n/** Key naming a resource nested inside a namespace in a TRN. */\ntype NestedResourceKey = \"type\" | \"resolver\";\n\n/**\n * Build the TRN for one TailorDB table.\n * @param workspaceId - Workspace ID\n * @param namespace - TailorDB namespace holding the table\n * @param typeName - Table name\n * @returns Fully-qualified TRN string\n */\nexport function tailorDBTypeTrn(workspaceId: string, namespace: string, typeName: string): string {\n  return nestedResourceTrn(workspaceId, [\"tailordb\", namespace], [\"type\", typeName]);\n}\n\n/**\n * Build the TRN for one resolver.\n * @param workspaceId - Workspace ID\n * @param namespace - Resolver namespace holding the resolver\n * @param resolverName - Resolver name\n * @returns Fully-qualified TRN string\n */\nexport function resolverTrn(workspaceId: string, namespace: string, resolverName: string): string {\n  return nestedResourceTrn(workspaceId, [\"pipeline\", namespace], [\"resolver\", resolverName]);\n}\n\n/** The platform rejects a `SetMetadata` write holding more labels than this. */\nexport const MAX_RESOURCE_LABELS = 20;\n\nexport const sdkNameLabelKey = \"sdk-name\";\nexport const sdkVersionLabelKey = \"sdk-version\";\nexport const sdkAppIdLabelKey = \"sdk-app-id\";\n\n// The metadata label value regex requires a leading lowercase letter, while\n// the auto-generated app id is a plain UUID (which may start with a digit).\n// The `app-` prefix is added at the metadata boundary so the user-facing id\n// in `tailor.config.ts` can stay a plain UUID.\nconst appIdLabelPrefix = \"app-\";\n\nexport function sdkAppIdLabelValue(appId: string): string {\n  return `${appIdLabelPrefix}${appId}`;\n}\n\n/**\n * Check whether existing metadata was produced by the current SDK version.\n * @param existingLabels - Labels currently stored on the remote resource\n * @param desiredLabels - Labels that will be written by the current apply run\n * @returns True when sdk-version matches\n */\nexport function hasMatchingSdkVersion(\n  existingLabels: Record<string, string> | undefined,\n  desiredLabels: Record<string, string> | undefined,\n): boolean {\n  return existingLabels?.[sdkVersionLabelKey] === desiredLabels?.[sdkVersionLabelKey];\n}\n\n/**\n * Determine whether a remote resource is owned by the given application.\n * When the resource carries an `sdk-app-id`, ownership is decided strictly\n * by id match — a resource explicitly tagged with another app's id is\n * NOT ours even if the legacy sdk-name happens to match. Resources without\n * `sdk-app-id` (legacy) fall back to sdk-name comparison.\n * @param labels - Labels currently stored on the remote resource\n * @param appName - Application name from the local config\n * @param appId - Stable application id from the local config (when present)\n * @returns True when the resource is owned by the application\n */\nexport function isOwnedByApp(\n  labels: Record<string, string> | undefined,\n  appName: string,\n  appId: string | undefined,\n): boolean {\n  if (!labels) return false;\n  const labelAppId = labels[sdkAppIdLabelKey];\n  if (labelAppId) {\n    return appId !== undefined && labelAppId === sdkAppIdLabelValue(appId);\n  }\n  return labels[sdkNameLabelKey] === appName;\n}\n\n// Records that another config must take part in the same deploy, because this\n// application's resources are applied differently when it does. The dependent\n// application's id goes in the key so several can be recorded at once — a label\n// value cannot hold a delimited list (values are `^$|^[a-z][a-z0-9_-]{0,62}$`).\nconst dependedByAppLabelPrefix = \"sdk-depended-by-app-\";\n\n// A workflow carries two independent values: its own publishExecutionEvents and\n// the one its jobs get. Different trigger kinds drive them, so their records need\n// separate namespaces on the one TRN — collapsing them lets a subscriber of one\n// suppress the confirmation for the other.\nconst jobDependedByAppLabelPrefix = \"sdk-job-depended-by-app-\";\n\n/** Which of a resource's values a dependency record concerns. */\nexport type DependencyScope = \"resource\" | \"jobs\";\n\nfunction prefixFor(scope: DependencyScope): string {\n  return scope === \"jobs\" ? jobDependedByAppLabelPrefix : dependedByAppLabelPrefix;\n}\n\n/** Why a dependent config has to take part in the same deploy. */\nexport type DeployDependencyReason = \"publish-events\";\n\n// Label keys are `^[a-z][a-z0-9_-]{0,62}$`, so an id that is not a lowercase\n// UUID cannot be recorded. `ensureConfigIdForDeploy` writes canonical UUIDs;\n// this guards a hand-edited value rather than silently building an invalid key.\nconst RECORDABLE_APP_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;\n\n/**\n * Build the label key recording that an application depends on this deploy.\n * @param appId - Stable id of the dependent application\n * @param scope - Which of the resource's values the record concerns\n * @returns Label key, or undefined when the id cannot form a valid key\n */\nexport function dependedByAppLabelKey(\n  appId: string,\n  scope: DependencyScope = \"resource\",\n): string | undefined {\n  return RECORDABLE_APP_ID.test(appId) ? `${prefixFor(scope)}${appId}` : undefined;\n}\n\n/** An application recorded as depending on this deploy. */\nexport type RecordedDependency = {\n  /** Stable id of the dependent application. */\n  appId: string;\n  /** Why it has to take part in the same deploy. */\n  reason: string;\n};\n\n/**\n * Read the dependent applications recorded on a resource.\n *\n * Only keys {@link dependedByAppLabelKey} could have written are read back, so a\n * label the SDK could not have produced cannot raise a confirmation prompt that\n * naming no config in the run makes unanswerable.\n * @param labels - Labels currently stored on the remote resource\n * @param scope - Which of the resource's values to read records for\n * @returns Recorded dependencies, in label-key order\n */\nexport function recordedDependencies(\n  labels: Record<string, string> | undefined,\n  scope: DependencyScope = \"resource\",\n): RecordedDependency[] {\n  if (!labels) return [];\n  const prefix = prefixFor(scope);\n  return Object.entries(labels)\n    .toSorted(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n    .flatMap(([key, reason]) => {\n      if (!key.startsWith(prefix)) return [];\n      const appId = key.slice(prefix.length);\n      return RECORDABLE_APP_ID.test(appId) ? [{ appId, reason }] : [];\n    });\n}\n\n/**\n * Key one event-publishing resource for the dependency records.\n *\n * Planners rebuild the same string from the resource they are applying, so the\n * shape is the TRN's tail rather than anything new to keep in step.\n */\nexport const eventSourceKey = {\n  tailorDBType: (namespace: string, typeName: string) => `tailordb:${namespace}:type:${typeName}`,\n  resolver: (namespace: string, resolverName: string) =>\n    `pipeline:${namespace}:resolver:${resolverName}`,\n  idp: (name: string) => `idp:${name}`,\n  workflow: (name: string) => `workflow:${name}`,\n  // A workflowJobExecution trigger names a workflow, but drives the jobs' value\n  // rather than the workflow's own, so it aggregates separately.\n  workflowJobs: (name: string) => `workflow:${name}:jobs`,\n} as const;\n\n/**\n * Dependent application ids and reasons, keyed by the resource that carries them.\n * The key is the TRN's tail, e.g. `tailordb:db:type:Order` or `workflow:nightly`.\n */\nexport type DependentAppsByResource = ReadonlyMap<\n  string,\n  ReadonlyMap<string, DeployDependencyReason>\n>;\n\n/** Inputs deciding which dependency records a deploy writes and drops. */\nexport type DependencyLabelParams = {\n  /** Labels currently stored on the resource. */\n  existingLabels: Record<string, string> | undefined;\n  /** Applications this run found depending on the resource being planned. */\n  dependentApps: ReadonlyMap<string, DeployDependencyReason> | undefined;\n  /** Stable ids of every application taking part in the run. */\n  runAppIds: ReadonlySet<string> | undefined;\n  /**\n   * Whether the resource declares `publishEvents`. A declared value is not\n   * recomputed, so no absent config can change it.\n   */\n  pinned: boolean;\n  /** Which of the resource's values these records concern. */\n  scope?: DependencyScope;\n};\n\n/**\n * Split the dependency records into the ones to write and the ones to drop.\n *\n * A record for an application outside the run appears in neither list, so\n * {@link writeMetadataLabels} keeps it: it was written when both took part, and\n * dropping it would lose the only signal that this partial deploy is about to\n * change how the resource is applied. A record for an application that does take\n * part is rewritten or dropped, so a dependency that no longer exists disappears\n * on the next deploy including both.\n *\n * A resource that declares `publishEvents` drops every record instead. Nothing\n * about it depends on which configs the run covers, so a record could only\n * produce a prompt about a change that cannot happen — and one the owner could\n * never clear on its own, since clearing needs the dependent to take part.\n * @param params - Existing labels and the run's dependency inputs\n * @returns Labels to set and label keys to delete\n */\nexport function dependencyLabelWrite(\n  params: DependencyLabelParams,\n): Required<Pick<MetadataLabelWrite, \"labels\" | \"remove\">> {\n  const { existingLabels, dependentApps, runAppIds, pinned, scope = \"resource\" } = params;\n  if (pinned) {\n    return {\n      labels: {},\n      remove: recordedDependencies(existingLabels, scope).flatMap(\n        ({ appId }) => dependedByAppLabelKey(appId, scope) ?? [],\n      ),\n    };\n  }\n  const dependents = dependentApps ?? new Map<string, DeployDependencyReason>();\n  const inRun = runAppIds ?? new Set<string>();\n\n  const labels: Record<string, string> = {};\n  for (const [appId, reason] of dependents) {\n    const key = dependedByAppLabelKey(appId, scope);\n    if (!key) {\n      throw CLIError({\n        code: \"APP_ID_INVALID\",\n        message: `Application id \"${appId}\" cannot be recorded as a dependency of this deploy.`,\n        suggestion:\n          'Ids are written by deploy as lowercase UUIDs; restore the generated value in the config\\'s \"id\".',\n      });\n    }\n    labels[key] = reason;\n  }\n\n  const remove = recordedDependencies(existingLabels, scope).flatMap(({ appId }) => {\n    if (!inRun.has(appId) || dependents.has(appId)) return [];\n    const key = dependedByAppLabelKey(appId, scope);\n    return key ? [key] : [];\n  });\n\n  return { labels, remove };\n}\n\nexport interface BuildMetaRequestParams {\n  trn: string;\n  appName: string;\n  appId?: string;\n  /** Labels from `defineConfig({ metadata })`, written alongside the SDK's own. */\n  metadata?: Record<string, string>;\n}\n\n/**\n * Build metadata request with SDK labels.\n *\n * Sets only the SDK's own labels and the config's `metadata`;\n * {@link writeMetadataLabels} keeps the rest from the labels it reads at write\n * time. The SDK's labels win over a same-named `metadata` entry.\n *\n * Without an app id the id label is removed rather than merely left unset,\n * because {@link isOwnedByApp} decides ownership by that label alone: one left\n * over from an earlier deploy would keep reading as another app's, and every\n * later deploy would ask to re-tag the same resources again.\n * @param params - Parameters for building the metadata request\n * @param params.trn - Target TRN\n * @param params.appName - Application name label\n * @param params.appId - Stable application id label (when managed by SDK)\n * @param params.metadata - Labels from the config's `metadata`\n * @returns Metadata request\n */\nexport async function buildMetaRequest(\n  params: BuildMetaRequestParams,\n): Promise<MetadataLabelWrite> {\n  const { trn, appName, appId, metadata } = params;\n  const packageJson = await readPackageJson();\n  // Format version to be suitable for label value\n  const sdkVersion = packageJson.version\n    ? `v${packageJson.version.replace(/\\./g, \"-\")}`\n    : \"unknown\";\n\n  return {\n    trn,\n    labels: {\n      ...metadata,\n      [sdkNameLabelKey]: appName,\n      [sdkVersionLabelKey]: sdkVersion,\n      ...(appId ? { [sdkAppIdLabelKey]: sdkAppIdLabelValue(appId) } : {}),\n    },\n    remove: appId ? undefined : [sdkAppIdLabelKey],\n  };\n}\n\n/** What a planner knows about the resource it is recording dependencies for. */\nexport type ResourceDependencyParams = {\n  /** Key identifying the resource, e.g. `workflow:nightly`. */\n  key: string;\n  /** Dependents the run resolved, keyed by resource. */\n  dependentApps: DependentAppsByResource | undefined;\n  /** Stable ids of every application taking part in the run. */\n  runAppIds: ReadonlySet<string> | undefined;\n  /** Whether the resource declares `publishEvents`. */\n  pinned: boolean;\n  /** Which of the resource's values these records concern. */\n  scope?: DependencyScope;\n};\n\n/**\n * Fold a resource's dependency records into the write already planned for it.\n *\n * The reconciliation is attached rather than computed, so it runs against the\n * labels read at write time. Whatever {@link buildMetaRequest} asked for —\n * dropping a stale `sdk-app-id`, for instance — still happens alongside it.\n * @param write - The resource's planned metadata write, mutated in place\n * @param params - The resource's key and the run's inputs\n * @returns The same write, for use as an expression\n */\nexport function addDependencyRecords(\n  write: MetadataLabelWrite,\n  params: ResourceDependencyParams,\n): MetadataLabelWrite {\n  const { key, dependentApps, runAppIds, pinned, scope } = params;\n  write.dependencies = [\n    ...(write.dependencies ?? []),\n    { dependentApps: dependentApps?.get(key), runAppIds, pinned, scope },\n  ];\n  return write;\n}\n\n/**\n * The client surface {@link writeMetadataLabels} needs. Narrower than the full\n * operator client so tests can pass a stub and the module stays decoupled.\n */\nexport interface MetadataLabelClient {\n  getMetadata(request: { trn: string }): Promise<{ metadata?: { labels: Record<string, string> } }>;\n  setMetadata(request: MessageInitShape<typeof SetMetadataRequestSchema>): Promise<unknown>;\n}\n\nexport interface MetadataLabelBulkClient extends MetadataLabelClient {\n  bulkSetMetadata(request: MessageInitShape<typeof BulkSetMetadataRequestSchema>): Promise<unknown>;\n}\n\n/** A metadata label write, expressed as a change rather than a whole map. */\nexport interface MetadataLabelWrite {\n  /** Target TRN. */\n  trn: string;\n  /** Labels to set. Keys absent here keep whatever the resource already has. */\n  labels?: Record<string, string>;\n  /** Label keys to delete. Absent keys are ignored. */\n  remove?: ReadonlyArray<string>;\n  /**\n   * Dependency records to reconcile against the labels found at write time.\n   *\n   * Which records to drop depends on what is already there, and\n   * {@link writeMetadataLabels} reads that anyway — resolving it here rather than\n   * while planning saves every planner a second read of the same resource.\n   */\n  dependencies?: ReadonlyArray<PendingDependencyRecords>;\n}\n\n/** A dependency-record reconciliation waiting on the resource's current labels. */\ntype PendingDependencyRecords = Omit<DependencyLabelParams, \"existingLabels\">;\n\nconst metadataWriteBatch = Symbol(\"metadataWriteBatch\");\nconst metadataWriteBatchSize = 100;\nconst metadataReadWaveSize = 100;\n\ninterface MetadataWriteBatchClient extends MetadataLabelClient {\n  [metadataWriteBatch]?: MetadataWriteBatch;\n}\n\nclass MetadataWriteBatch {\n  readonly #client: MetadataLabelBulkClient;\n  readonly #writesByTrn = new Map<string, MetadataLabelWrite[]>();\n  #flushPromise: Promise<void> | undefined;\n\n  constructor(client: MetadataLabelBulkClient) {\n    this.#client = client;\n  }\n\n  async enqueue(write: MetadataLabelWrite): Promise<void> {\n    if (this.#flushPromise) {\n      // The wrapper reports a flush failure; a late apply sibling must still attempt its write.\n      await this.#flushPromise.catch(() => undefined);\n      await writeMetadataLabelsDirect(this.#client, write);\n      return;\n    }\n    const writes = this.#writesByTrn.get(write.trn) ?? [];\n    writes.push(write);\n    this.#writesByTrn.set(write.trn, writes);\n  }\n\n  flush(): Promise<void> {\n    this.#flushPromise ??= this.#flushQueued();\n    return this.#flushPromise;\n  }\n\n  async #flushQueued(): Promise<void> {\n    const queued = [...this.#writesByTrn].toSorted(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));\n    const readRequest = async ([trn, writes]: (typeof queued)[number]) => {\n      const current = await getOrNull(() => this.#client.getMetadata({ trn }));\n      const currentLabels = current?.metadata?.labels ?? {};\n      const labels = writes.reduce(applyMetadataLabelWrite, currentLabels);\n      return areSameLabels(currentLabels, labels) ? undefined : { trn, labels };\n    };\n    const candidates: (typeof queued)[number][] = [];\n    let cursor = 0;\n\n    while (cursor < queued.length || candidates.length > 0) {\n      let freshRequests: MessageInitShape<typeof SetMetadataRequestSchema>[] | undefined =\n        candidates.length === 0 ? [] : undefined;\n      while (cursor < queued.length && candidates.length < metadataWriteBatchSize) {\n        // Fixed-width waves keep a nearly full batch from serializing a long no-op tail.\n        if (candidates.length > 0) freshRequests = undefined;\n        const entries = queued.slice(cursor, cursor + metadataReadWaveSize);\n        cursor += entries.length;\n        const changed = await Promise.all(\n          entries.map(async (entry) => {\n            const request = await readRequest(entry);\n            return request ? { entry, request } : undefined;\n          }),\n        );\n        for (const candidate of changed) {\n          if (!candidate) continue;\n          candidates.push(candidate.entry);\n          freshRequests?.push(candidate.request);\n        }\n      }\n\n      const batchEntries = candidates.splice(0, metadataWriteBatchSize);\n      // Candidates spanning waves or carried past a bulk need one shared freshness barrier.\n      const latestRequests =\n        freshRequests ??\n        (await Promise.all(batchEntries.map((entry) => readRequest(entry)))).filter(\n          (request) => request !== undefined,\n        );\n      if (latestRequests.length > 0) {\n        await this.#client.bulkSetMetadata({ requests: latestRequests });\n      }\n    }\n  }\n}\n\nfunction hasMetadataLabelChange(write: MetadataLabelWrite): boolean {\n  return Boolean(\n    Object.keys(write.labels ?? {}).length || write.remove?.length || write.dependencies?.length,\n  );\n}\n\nfunction applyMetadataLabelWrite(\n  currentLabels: Record<string, string>,\n  write: MetadataLabelWrite,\n): Record<string, string> {\n  const { labels, remove, dependencies } = write;\n  const resolved = (dependencies ?? []).map((pending) =>\n    dependencyLabelWrite({ ...pending, existingLabels: currentLabels }),\n  );\n  const merged: Record<string, string> = {\n    ...currentLabels,\n    ...labels,\n    ...Object.assign({}, ...resolved.map((records) => records.labels)),\n  };\n  for (const key of [...(remove ?? []), ...resolved.flatMap((records) => records.remove)]) {\n    delete merged[key];\n  }\n  return merged;\n}\n\nfunction metadataRecoveryError(applyError: unknown, flushError: unknown): AggregateError {\n  const describeCause = (error: unknown) =>\n    isCLIError(error) ? stripVTControlCharacters(error.format()) : toError(error).message;\n  return withErrorDiagnostics(\n    new AggregateError(\n      [applyError, flushError],\n      `Resource apply failed: ${describeCause(applyError)}\\nQueued metadata recovery failed: ${describeCause(flushError)}`,\n      { cause: flushError },\n    ),\n    {\n      code: \"DEPLOY_METADATA_RECOVERY_FAILED\",\n      suggestion:\n        \"Some resources may already have changed and deployment metadata could not be saved. Inspect the current resources and resolve both failures before deploying again.\",\n      causes: { apply: applyError, recovery: flushError },\n    },\n  );\n}\n\n/**\n * Collect metadata label changes and write the final maps in batches.\n * @template TClient, T\n * @param client - Operator client instance\n * @param apply - Resource apply callback using the batch-aware client\n * @returns The apply callback result\n */\nexport async function withMetadataWriteBatch<TClient extends MetadataLabelBulkClient, T>(\n  client: TClient,\n  apply: (client: TClient) => Promise<T>,\n): Promise<T> {\n  const batch = new MetadataWriteBatch(client);\n  const batchClient = new Proxy(client, {\n    get(target, property, receiver) {\n      return property === metadataWriteBatch ? batch : Reflect.get(target, property, receiver);\n    },\n  });\n  let result: T;\n  try {\n    result = await apply(batchClient);\n  } catch (applyError) {\n    try {\n      await batch.flush();\n    } catch (flushError) {\n      throw metadataRecoveryError(applyError, flushError);\n    }\n    throw applyError;\n  }\n  await batch.flush();\n  return result;\n}\n\n/**\n * Write metadata labels as a change against the resource's current labels.\n *\n * `SetMetadata` replaces the whole label map, so a request built from labels\n * read earlier deletes anything written in between. This applies `labels` and\n * `remove` to the latest labels this helper reads before writing, which is why\n * every label write in the SDK goes through it.\n *\n * Concurrent writers are still not safe in the strict sense — that needs\n * server-side conditional writes — but a write can no longer be built from\n * state this process read at an unrelated point in time.\n *\n * A write that changes nothing does nothing — whether the caller requested no\n * change or the change turns out to already hold. Writing back what was just\n * read would still overwrite whatever landed in between, for no gain, and the\n * labels the SDK sets are unchanged on most deploys.\n * @param client - Operator client instance\n * @param write - TRN, labels to set, and label keys to delete\n * @returns Promise that resolves when the change is queued for a batch or written directly\n */\nexport async function writeMetadataLabels(\n  client: MetadataLabelClient,\n  write: MetadataLabelWrite,\n): Promise<void> {\n  if (!hasMetadataLabelChange(write)) return;\n  const batch = (client as MetadataWriteBatchClient)[metadataWriteBatch];\n  if (batch) {\n    await batch.enqueue(write);\n    return;\n  }\n  await writeMetadataLabelsDirect(client, write);\n}\n\n/**\n * Write one metadata change immediately, bypassing deploy resource batching.\n * This is reserved for migration checkpoints whose callers continue only\n * after the label is durable.\n * @param client - Operator client instance\n * @param write - TRN, labels to set, and label keys to delete\n */\nexport async function writeMetadataLabelsDirect(\n  client: MetadataLabelClient,\n  write: MetadataLabelWrite,\n): Promise<void> {\n  if (!hasMetadataLabelChange(write)) return;\n  const { trn } = write;\n  const current = await getOrNull(() => client.getMetadata({ trn }));\n  const currentLabels = current?.metadata?.labels ?? {};\n  const merged = applyMetadataLabelWrite(currentLabels, write);\n  if (areSameLabels(currentLabels, merged)) return;\n  await client.setMetadata({ trn, labels: merged });\n}\n\nfunction areSameLabels(a: Record<string, string>, b: Record<string, string>): boolean {\n  const keys = Object.keys(a);\n  return keys.length === Object.keys(b).length && keys.every((key) => a[key] === b[key]);\n}\n","import { fetchAllTolerant, type OperatorClient } from \"#/cli/shared/client\";\nimport { isOwnedByApp, sdkNameLabelKey, type WithLabel } from \"./label\";\nimport type { OwnerConflict, UnmanagedResource } from \"./confirm\";\n\ntype ResourcePageFetcher<T> = (pageToken: string, maxPageSize: number) => Promise<[T[], string]>;\n\nexport interface FetchExistingResourcesWithLabelsParams<T> {\n  client: OperatorClient;\n  fetchPage: ResourcePageFetcher<T>;\n  getName: (resource: T) => string | undefined;\n  getTrn: (name: string) => string;\n}\n\n/**\n * Fetch a workspace-scoped resource list and attach SDK ownership metadata.\n * @template T\n * @param params - Resource fetch parameters\n * @param params.client - Operator client instance\n * @param params.fetchPage - Function that fetches one resource page\n * @param params.getName - Function that extracts the resource name\n * @param params.getTrn - Function that builds the resource TRN\n * @returns Existing resources keyed by resource name, with SDK labels attached\n */\nexport async function fetchExistingResourcesWithLabels<T>(\n  params: FetchExistingResourcesWithLabelsParams<T>,\n): Promise<WithLabel<T>> {\n  const { client, fetchPage, getName, getTrn } = params;\n  const withoutLabel = await fetchAllTolerant(fetchPage);\n  const existingResources: WithLabel<T> = {};\n  await Promise.all(\n    withoutLabel.map(async (resource) => {\n      const name = getName(resource);\n      if (!name) {\n        return;\n      }\n      const { metadata } = await client.getMetadata({\n        trn: getTrn(name),\n      });\n      existingResources[name] = {\n        resource,\n        label: metadata?.labels[sdkNameLabelKey],\n        allLabels: metadata?.labels,\n      };\n    }),\n  );\n  return existingResources;\n}\n\nexport interface TrackDesiredResourceOwnershipParams {\n  labels: Record<string, string> | undefined;\n  ownerLabel: string | undefined;\n  appName: string;\n  appId: string | undefined;\n  resourceType: string;\n  resourceName: string;\n  conflicts: OwnerConflict[];\n  unmanaged: UnmanagedResource[];\n}\n\n/**\n * Determine whether a same-named existing resource is managed by this app.\n * Records the user-facing confirmation data when ownership does not match.\n * @param params - Ownership classification inputs\n * @param params.labels - Existing resource labels\n * @param params.ownerLabel - Existing `sdk-name` label, when present\n * @param params.appName - Current application name\n * @param params.appId - Current application id, when present\n * @param params.resourceType - Resource kind for confirmation messages\n * @param params.resourceName - Resource name for confirmation messages\n * @param params.conflicts - Conflict accumulator\n * @param params.unmanaged - Unmanaged-resource accumulator\n * @returns True when the resource is owned by the current app\n */\nexport function trackDesiredResourceOwnership(\n  params: TrackDesiredResourceOwnershipParams,\n): boolean {\n  const { labels, ownerLabel, appName, appId, resourceType, resourceName, conflicts, unmanaged } =\n    params;\n  const owned = isOwnedByApp(labels, appName, appId);\n  if (!owned) {\n    if (!ownerLabel) {\n      unmanaged.push({ resourceType, resourceName });\n    } else {\n      conflicts.push({\n        resourceType,\n        resourceName,\n        currentOwner: ownerLabel,\n      });\n    }\n  }\n  return owned;\n}\n\nexport interface TrackRemainingResourceOwnerParams {\n  labels: Record<string, string> | undefined;\n  ownerLabel: string | undefined;\n  appName: string;\n  appId: string | undefined;\n  resourceOwners: Set<string>;\n}\n\n/**\n * Determine whether a remote-only resource is still owned by this app.\n * Also records other SDK owners so renamed-empty applications can be handled.\n * @param params - Ownership classification inputs\n * @param params.labels - Existing resource labels\n * @param params.ownerLabel - Existing `sdk-name` label, when present\n * @param params.appName - Current application name\n * @param params.appId - Current application id, when present\n * @param params.resourceOwners - Other-owner accumulator\n * @returns True when the resource is owned by the current app\n */\nexport function trackRemainingResourceOwner(params: TrackRemainingResourceOwnerParams): boolean {\n  const { labels, ownerLabel, appName, appId, resourceOwners } = params;\n  const owned = isOwnedByApp(labels, appName, appId);\n  if (ownerLabel && !owned) {\n    resourceOwners.add(ownerLabel);\n  }\n  return owned;\n}\n","import { type MessageInitShape } from \"@bufbuild/protobuf\";\nimport {\n  type AddCustomDomainRequestSchema,\n  type CreateStaticWebsiteRequestSchema,\n  type DeleteStaticWebsiteRequestSchema,\n  type RemoveCustomDomainRequestSchema,\n  type UpdateStaticWebsiteRequestSchema,\n} from \"@tailor-platform/tailor-proto/staticwebsite_pb\";\nimport { getOrNull, type OperatorClient } from \"#/cli/shared/client\";\nimport { createChangeSet } from \"./change-set\";\nimport { areNormalizedEqual } from \"./compare\";\nimport {\n  buildMetaRequest,\n  hasMatchingSdkVersion,\n  isOwnedByApp,\n  type MetadataLabelWrite,\n  resourceTrn,\n  writeMetadataLabels,\n} from \"./label\";\nimport {\n  fetchExistingResourcesWithLabels,\n  trackDesiredResourceOwnership,\n  trackRemainingResourceOwner,\n} from \"./owned-resource\";\nimport type { ApplyPhase, PlanContext } from \"#/cli/commands/deploy/types\";\nimport type { OwnerConflict, UnmanagedResource } from \"./confirm\";\nimport type { StaticWebsite as ProtoStaticWebsite } from \"@tailor-platform/tailor-proto/staticwebsite_resource_pb\";\n\n/**\n * Apply static website changes for the given phase.\n * @param client - Operator client instance\n * @param result - Planned static website changes\n * @param phase - Apply phase\n * @returns Promise that resolves when static websites are applied\n */\nexport async function applyStaticWebsite(\n  client: OperatorClient,\n  result: Awaited<ReturnType<typeof planStaticWebsite>>,\n  phase: Extract<ApplyPhase, \"create-update\" | \"delete\"> = \"create-update\",\n) {\n  const { changeSet, customDomainChangeSet } = result;\n  if (phase === \"create-update\") {\n    // StaticWebsites\n    await Promise.all([\n      ...changeSet.creates.map(async (create) => {\n        await client.createStaticWebsite(create.request);\n        await writeMetadataLabels(client, create.metaRequest);\n      }),\n      ...changeSet.updates.map(async (update) => {\n        await client.updateStaticWebsite(update.request);\n        await writeMetadataLabels(client, update.metaRequest);\n      }),\n    ]);\n    // Custom domains\n    await Promise.all([\n      ...customDomainChangeSet.creates.map(async (add) => {\n        await client.addCustomDomain(add.request);\n        await writeMetadataLabels(client, add.metaRequest);\n      }),\n      ...customDomainChangeSet.deletes.map((del) => client.removeCustomDomain(del.request)),\n    ]);\n  } else {\n    // Delete in reverse order of dependencies\n    // StaticWebsites\n    await Promise.all(changeSet.deletes.map((del) => client.deleteStaticWebsite(del.request)));\n  }\n}\n\ntype CreateStaticWebsite = {\n  name: string;\n  request: MessageInitShape<typeof CreateStaticWebsiteRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype UpdateStaticWebsite = {\n  name: string;\n  request: MessageInitShape<typeof UpdateStaticWebsiteRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype DeleteStaticWebsite = {\n  name: string;\n  request: MessageInitShape<typeof DeleteStaticWebsiteRequestSchema>;\n};\n\ntype AddCustomDomainEntry = {\n  name: string;\n  request: MessageInitShape<typeof AddCustomDomainRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype RemoveCustomDomainEntry = {\n  name: string;\n  request: MessageInitShape<typeof RemoveCustomDomainRequestSchema>;\n};\n\ntype ComparableStaticWebsite = {\n  description: string;\n  allowedIpAddresses: string[];\n};\n\ntype ComparableStaticWebsiteInput = {\n  description?: string;\n  allowedIpAddresses?: readonly string[];\n};\n\nfunction customDomainTrn(workspaceId: string, websiteName: string, domain: string) {\n  return `trn:v1:workspace:${workspaceId}:staticwebsite:${websiteName}:custom_domain:${domain}`;\n}\n\nfunction normalizeComparableStaticWebsiteShape(\n  input: Pick<ComparableStaticWebsite, \"description\" | \"allowedIpAddresses\">,\n): ComparableStaticWebsite {\n  return {\n    description: input.description,\n    allowedIpAddresses: input.allowedIpAddresses.toSorted(),\n  };\n}\n\nfunction normalizeComparableStaticWebsite(\n  input: ComparableStaticWebsiteInput,\n): ComparableStaticWebsite {\n  return normalizeComparableStaticWebsiteShape({\n    description: input.description || \"\",\n    allowedIpAddresses: [...(input.allowedIpAddresses || [])],\n  });\n}\n\nfunction areStaticWebsitesEqual(\n  existing: ProtoStaticWebsite,\n  desired: ComparableStaticWebsiteInput,\n): boolean {\n  return areNormalizedEqual(\n    normalizeComparableStaticWebsite(existing),\n    normalizeComparableStaticWebsite(desired),\n  );\n}\n\n/**\n * Static website names expected to exist after this deploy run.\n * @param context - Planning context\n * @returns Names from the deploy-run scope when set, otherwise the application's own websites\n */\nexport function expectedLocalStaticWebsiteNames(context: PlanContext): ReadonlySet<string> {\n  return (\n    context.expectedLocalStaticWebsiteNames ??\n    new Set(context.application.staticWebsiteServices.map((website) => website.name))\n  );\n}\n\n/**\n * Plan static website changes based on current and desired state.\n * @param context - Planning context\n * @returns Planned changes\n */\nexport async function planStaticWebsite(context: PlanContext) {\n  const { client, workspaceId, application, forRemoval } = context;\n  const changeSet = createChangeSet<CreateStaticWebsite, UpdateStaticWebsite, DeleteStaticWebsite>(\n    \"StaticWebsites\",\n  );\n  const customDomainChangeSet = createChangeSet<\n    AddCustomDomainEntry,\n    never,\n    RemoveCustomDomainEntry\n  >(\"CustomDomains\");\n  const conflicts: OwnerConflict[] = [];\n  const unmanaged: UnmanagedResource[] = [];\n  const resourceOwners = new Set<string>();\n\n  const existingWebsites = await fetchExistingResourcesWithLabels({\n    client,\n    fetchPage: async (pageToken, pageSize) => {\n      const { staticwebsites, nextPageToken } = await client.listStaticWebsites({\n        workspaceId,\n        pageToken,\n        pageSize,\n      });\n      return [staticwebsites, nextPageToken];\n    },\n    getName: (resource) => resource.name,\n    getTrn: (name) => resourceTrn(workspaceId, \"staticwebsite\", name),\n  });\n\n  // Track owned website names to plan custom domains afterward\n  const ownedWebsiteNames = new Set<string>();\n\n  const staticWebsiteServices = forRemoval ? [] : application.staticWebsiteServices;\n  for (const websiteService of staticWebsiteServices) {\n    const config = websiteService;\n    const name = websiteService.name;\n    const existing = existingWebsites[name];\n    const metaRequest = await buildMetaRequest({\n      trn: resourceTrn(workspaceId, \"staticwebsite\", name),\n      appName: application.name,\n      appId: application.id,\n    });\n    const desired = normalizeComparableStaticWebsite(config);\n    const request = {\n      workspaceId,\n      staticwebsite: {\n        name,\n        description: config.description || \"\",\n        allowedIpAddresses: config.allowedIpAddresses || [],\n      },\n    };\n\n    if (existing) {\n      const owned = trackDesiredResourceOwnership({\n        labels: existing.allLabels,\n        ownerLabel: existing.label,\n        appName: application.name,\n        appId: application.id,\n        resourceType: \"StaticWebsite\",\n        resourceName: name,\n        conflicts,\n        unmanaged,\n      });\n\n      if (\n        owned &&\n        hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) &&\n        areStaticWebsitesEqual(existing.resource, desired)\n      ) {\n        changeSet.unchanged.push({ name });\n      } else {\n        changeSet.updates.push({\n          name,\n          request,\n          metaRequest,\n        });\n      }\n\n      if (owned) {\n        ownedWebsiteNames.add(name);\n      }\n      delete existingWebsites[name];\n    } else {\n      changeSet.creates.push({\n        name,\n        request,\n        metaRequest,\n      });\n      // New websites are owned by this app\n      ownedWebsiteNames.add(name);\n    }\n  }\n  Object.entries(existingWebsites).forEach(([name]) => {\n    const entry = existingWebsites[name];\n    const label = entry?.label;\n    const owned = trackRemainingResourceOwner({\n      labels: entry?.allLabels,\n      ownerLabel: label,\n      appName: application.name,\n      appId: application.id,\n      resourceOwners,\n    });\n    if (owned) {\n      changeSet.deletes.push({\n        name,\n        request: {\n          workspaceId,\n          name,\n        },\n      });\n    }\n  });\n\n  // Plan custom domain changes for owned websites\n  const desiredDomainsByWebsite = new Map<string, readonly string[]>();\n  for (const service of staticWebsiteServices) {\n    if (service.customDomains !== undefined && ownedWebsiteNames.has(service.name)) {\n      desiredDomainsByWebsite.set(service.name, service.customDomains);\n    }\n  }\n\n  // Fetch existing custom domains and their labels for owned websites that already exist\n  type ExistingDomainInfo = { domain: string; allLabels: Record<string, string> | undefined };\n  const existingDomainsByWebsite = new Map<string, ExistingDomainInfo[]>();\n  const websitesToFetchDomains = [...ownedWebsiteNames].filter(\n    (name) => !changeSet.creates.some((c) => c.name === name),\n  );\n  await Promise.all(\n    websitesToFetchDomains.map(async (name) => {\n      const domainsWithLabels = await getOrNull(async () => {\n        const { customDomains } = await client.listCustomDomains({\n          workspaceId,\n          staticWebsiteName: name,\n        });\n        return await Promise.all(\n          customDomains.map(async (d) => {\n            const { metadata } = await client.getMetadata({\n              trn: customDomainTrn(workspaceId, name, d.domain),\n            });\n            return {\n              domain: d.domain,\n              allLabels: metadata?.labels,\n            };\n          }),\n        );\n      });\n      if (domainsWithLabels) {\n        existingDomainsByWebsite.set(name, domainsWithLabels);\n      }\n    }),\n  );\n\n  // Diff custom domains for each owned website\n  for (const name of ownedWebsiteNames) {\n    const desired = new Set(desiredDomainsByWebsite.get(name) ?? []);\n    const existingDomains = existingDomainsByWebsite.get(name) ?? [];\n    const existingSet = new Set(existingDomains.map((d) => d.domain));\n    const sdkOwnedDomains = new Set(\n      existingDomains\n        .filter((d) => isOwnedByApp(d.allLabels, application.name, application.id))\n        .map((d) => d.domain),\n    );\n\n    for (const domain of desired) {\n      if (!existingSet.has(domain)) {\n        const metaRequest = await buildMetaRequest({\n          trn: customDomainTrn(workspaceId, name, domain),\n          appName: application.name,\n          appId: application.id,\n        });\n        customDomainChangeSet.creates.push({\n          name: domain,\n          request: { workspaceId, staticWebsiteName: name, domain },\n          metaRequest,\n        });\n      } else {\n        customDomainChangeSet.unchanged.push({ name: domain });\n      }\n    }\n\n    // Only remove SDK-owned domains not in desired if customDomains is explicitly specified\n    if (desiredDomainsByWebsite.has(name)) {\n      for (const domain of sdkOwnedDomains) {\n        if (!desired.has(domain)) {\n          customDomainChangeSet.deletes.push({\n            name: domain,\n            request: { workspaceId, domain },\n          });\n        }\n      }\n    }\n  }\n\n  return { changeSet, customDomainChangeSet, conflicts, unmanaged, resourceOwners };\n}\n","import { type MessageInitShape } from \"@bufbuild/protobuf\";\nimport {\n  type CreateAIGatewayRequestSchema,\n  type DeleteAIGatewayRequestSchema,\n  type UpdateAIGatewayRequestSchema,\n} from \"@tailor-platform/tailor-proto/aigateway_pb\";\nimport { resolveStaticWebsiteUrls, type OperatorClient } from \"#/cli/shared/client\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { createChangeSet } from \"./change-set\";\nimport { areNormalizedEqual } from \"./compare\";\nimport {\n  buildMetaRequest,\n  hasMatchingSdkVersion,\n  type MetadataLabelWrite,\n  resourceTrn,\n  writeMetadataLabels,\n} from \"./label\";\nimport {\n  fetchExistingResourcesWithLabels,\n  trackDesiredResourceOwnership,\n  trackRemainingResourceOwner,\n} from \"./owned-resource\";\nimport { expectedLocalStaticWebsiteNames } from \"./staticwebsite\";\nimport type { ApplyPhase, PlanContext } from \"#/cli/commands/deploy/types\";\nimport type { OwnerConflict, UnmanagedResource } from \"./confirm\";\nimport type { AIGateway as ProtoAIGateway } from \"@tailor-platform/tailor-proto/aigateway_resource_pb\";\n\n/**\n * Apply AI Gateway changes for the given phase.\n * @param client - Operator client instance\n * @param result - Planned AI Gateway changes\n * @param phase - Apply phase\n * @returns Promise that resolves when AI Gateways are applied\n */\nexport async function applyAIGateway(\n  client: OperatorClient,\n  result: Awaited<ReturnType<typeof planAIGateway>>,\n  phase: Extract<ApplyPhase, \"create-update\" | \"delete\"> = \"create-update\",\n) {\n  const { changeSet } = result;\n  if (phase === \"create-update\") {\n    await Promise.all([\n      ...changeSet.creates.map(async (create) => {\n        create.request.cors = await resolveStaticWebsiteUrls(\n          client,\n          assertDefined(create.request.workspaceId, \"request missing workspaceId\"),\n          create.request.cors,\n          \"AIGateway CORS\",\n        );\n        await client.createAIGateway(create.request);\n        await writeMetadataLabels(client, create.metaRequest);\n      }),\n      ...changeSet.updates.map(async (update) => {\n        update.request.cors = await resolveStaticWebsiteUrls(\n          client,\n          assertDefined(update.request.workspaceId, \"request missing workspaceId\"),\n          update.request.cors,\n          \"AIGateway CORS\",\n        );\n        await client.updateAIGateway(update.request);\n        await writeMetadataLabels(client, update.metaRequest);\n      }),\n    ]);\n  } else {\n    await Promise.all(changeSet.deletes.map((del) => client.deleteAIGateway(del.request)));\n  }\n}\n\ntype CreateAIGateway = {\n  name: string;\n  request: MessageInitShape<typeof CreateAIGatewayRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype UpdateAIGateway = {\n  name: string;\n  request: MessageInitShape<typeof UpdateAIGatewayRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype DeleteAIGateway = {\n  name: string;\n  request: MessageInitShape<typeof DeleteAIGatewayRequestSchema>;\n};\n\ntype ComparableAIGateway = {\n  authNamespace: string;\n  cors: string[];\n};\n\ntype ComparableAIGatewayInput = {\n  authNamespace?: string;\n  cors?: readonly string[];\n};\n\nfunction normalizeComparableAIGatewayShape(\n  input: Pick<ComparableAIGateway, \"authNamespace\" | \"cors\">,\n): ComparableAIGateway {\n  return {\n    authNamespace: input.authNamespace,\n    cors: input.cors.toSorted(),\n  };\n}\n\nfunction normalizeComparableAIGateway(input: ComparableAIGatewayInput): ComparableAIGateway {\n  return normalizeComparableAIGatewayShape({\n    authNamespace: input.authNamespace || \"\",\n    cors: [...(input.cors || [])],\n  });\n}\n\nfunction areAIGatewaysEqual(existing: ProtoAIGateway, desired: ComparableAIGatewayInput): boolean {\n  return areNormalizedEqual(\n    normalizeComparableAIGateway(existing),\n    normalizeComparableAIGateway(desired),\n  );\n}\n\n/**\n * Plan AI Gateway changes based on current and desired state.\n * @param context - Planning context\n * @returns Planned changes\n */\nexport async function planAIGateway(context: PlanContext) {\n  const { client, workspaceId, application, forRemoval } = context;\n  const changeSet = createChangeSet<CreateAIGateway, UpdateAIGateway, DeleteAIGateway>(\n    \"AIGateways\",\n  );\n  const conflicts: OwnerConflict[] = [];\n  const unmanaged: UnmanagedResource[] = [];\n  const resourceOwners = new Set<string>();\n\n  const existingGateways = await fetchExistingResourcesWithLabels({\n    client,\n    fetchPage: async (pageToken, pageSize) => {\n      const { aigateways, nextPageToken } = await client.listAIGateways({\n        workspaceId,\n        pageToken,\n        pageSize,\n      });\n      return [aigateways, nextPageToken];\n    },\n    getName: (resource) => resource.name,\n    getTrn: (name) => resourceTrn(workspaceId, \"aigateway\", name),\n  });\n\n  const aiGatewayServices = forRemoval ? [] : application.aiGatewayServices;\n  const expectedLocalWebsites = expectedLocalStaticWebsiteNames(context);\n  for (const gatewayService of aiGatewayServices) {\n    const config = gatewayService;\n    const name = gatewayService.name;\n    const existing = existingGateways[name];\n    const metaRequest = await buildMetaRequest({\n      trn: resourceTrn(workspaceId, \"aigateway\", name),\n      appName: application.name,\n      appId: application.id,\n    });\n    const resolvedCors = await resolveStaticWebsiteUrls(\n      client,\n      workspaceId,\n      config.cors ? [...config.cors] : [],\n      \"AIGateway CORS\",\n      { expectedLocalNames: expectedLocalWebsites },\n    );\n    const desired = normalizeComparableAIGateway({ ...config, cors: resolvedCors });\n    const request = {\n      workspaceId,\n      aigatewayName: name,\n      authNamespace: config.authNamespace,\n      cors: config.cors ? [...config.cors] : [],\n    };\n\n    if (existing) {\n      const owned = trackDesiredResourceOwnership({\n        labels: existing.allLabels,\n        ownerLabel: existing.label,\n        appName: application.name,\n        appId: application.id,\n        resourceType: \"AIGateway\",\n        resourceName: name,\n        conflicts,\n        unmanaged,\n      });\n\n      if (\n        owned &&\n        hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) &&\n        areAIGatewaysEqual(existing.resource, desired)\n      ) {\n        changeSet.unchanged.push({ name });\n      } else {\n        changeSet.updates.push({\n          name,\n          request,\n          metaRequest,\n        });\n      }\n      delete existingGateways[name];\n    } else {\n      changeSet.creates.push({\n        name,\n        request,\n        metaRequest,\n      });\n    }\n  }\n  Object.entries(existingGateways).forEach(([name, entry]) => {\n    const label = entry?.label;\n    const owned = trackRemainingResourceOwner({\n      labels: entry?.allLabels,\n      ownerLabel: label,\n      appName: application.name,\n      appId: application.id,\n      resourceOwners,\n    });\n    if (owned) {\n      changeSet.deletes.push({\n        name,\n        request: {\n          workspaceId,\n          aigatewayName: name,\n        },\n      });\n    }\n  });\n\n  return { changeSet, conflicts, unmanaged, resourceOwners };\n}\n","import { type MessageInitShape } from \"@bufbuild/protobuf\";\nimport {\n  type Application as ProtoApplication,\n  Subgraph_ServiceType,\n  type SubgraphSchema,\n} from \"@tailor-platform/tailor-proto/application_resource_pb\";\nimport {\n  fetchAllTolerant,\n  getOrNull,\n  resolveStaticWebsiteUrls,\n  type OperatorClient,\n} from \"#/cli/shared/client\";\nimport { CLIError, internalError } from \"#/cli/shared/errors\";\nimport { symbols } from \"#/cli/shared/logger\";\nimport { HTTP_METHODS } from \"#/parser/service/http-adapter/index\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { createChangeSet } from \"./change-set\";\nimport { areNormalizedEqual } from \"./compare\";\nimport {\n  buildMetaRequest,\n  hasMatchingSdkVersion,\n  isOwnedByApp,\n  MAX_RESOURCE_LABELS,\n  type MetadataLabelWrite,\n  resourceTrn,\n  sdkNameLabelKey,\n  writeMetadataLabels,\n} from \"./label\";\nimport { trackDesiredResourceOwnership, trackRemainingResourceOwner } from \"./owned-resource\";\nimport { expectedLocalStaticWebsiteNames } from \"./staticwebsite\";\nimport type { ApplyPhase, PlanContext } from \"#/cli/commands/deploy/types\";\nimport type { Application } from \"#/cli/services/application\";\nimport type { HttpAdapterBundleResult } from \"#/cli/services/http-adapter/bundler\";\nimport type { OwnerConflict, UnmanagedResource } from \"./confirm\";\nimport type {\n  DeleteApplicationRequestSchema,\n  CreateApplicationRequestSchema,\n  UpdateApplicationRequestSchema,\n} from \"@tailor-platform/tailor-proto/application_pb\";\nimport type { HttpAdapterSchema } from \"@tailor-platform/tailor-proto/http_adapter_resource_pb\";\n\n/**\n * Apply application changes for the given phase.\n * @param client - Operator client instance\n * @param changeSet - Planned application changes\n * @param phase - Apply phase\n * @returns Promise that resolves when applications are applied\n */\nexport async function applyApplication(\n  client: OperatorClient,\n  changeSet: Awaited<ReturnType<typeof planApplication>>,\n  phase: Extract<ApplyPhase, \"create-update\" | \"delete\"> = \"create-update\",\n) {\n  if (phase === \"create-update\") {\n    // Re-issue updateApplication for unchanged apps too, so the platform\n    // re-composes the gateway schema synchronously on every deploy.\n    const updates = [...changeSet.updates, ...changeSet.unchanged];\n    await Promise.all([\n      ...changeSet.creates.map(async (create) => {\n        create.request.cors = await resolveStaticWebsiteUrls(\n          client,\n          assertDefined(create.request.workspaceId, \"request missing workspaceId\"),\n          create.request.cors,\n          \"CORS\",\n        );\n        await client.createApplication(create.request);\n        await writeMetadataLabels(client, create.metaRequest);\n      }),\n      ...updates.map(async (update) => {\n        update.request.cors = await resolveStaticWebsiteUrls(\n          client,\n          assertDefined(update.request.workspaceId, \"request missing workspaceId\"),\n          update.request.cors,\n          \"CORS\",\n        );\n        await client.updateApplication(update.request);\n        await writeMetadataLabels(client, update.metaRequest);\n      }),\n    ]);\n  } else {\n    // Delete in reverse order of dependencies\n    // Applications\n    await Promise.all(\n      changeSet.deletes.map(async (del) => {\n        await client.deleteApplication(del.request);\n      }),\n    );\n  }\n}\n\ntype CreateApplication = {\n  name: string;\n  request: MessageInitShape<typeof CreateApplicationRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n  /** Per-adapter diff lines shown indented beneath the application entry. */\n  details?: string[];\n};\n\ntype UpdateApplication = {\n  name: string;\n  request: MessageInitShape<typeof UpdateApplicationRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n  /** Per-adapter diff lines shown indented beneath the application entry. */\n  details?: string[];\n};\n\ntype DeleteApplication = {\n  name: string;\n  request: MessageInitShape<typeof DeleteApplicationRequestSchema>;\n};\n\ntype ComparableHttpAdapter = {\n  name: string;\n  pathPattern: string;\n  methods: string[];\n  inputScript: string;\n  outputScript: string;\n  enabled: boolean;\n  priority: number;\n};\n\ntype ComparableApplication = {\n  authNamespace: string;\n  authIdpConfigName: string;\n  cors: string[];\n  subgraphs: Array<{\n    serviceType: Subgraph_ServiceType;\n    serviceNamespace: string;\n  }>;\n  allowedIpAddresses: string[];\n  disableIntrospection: boolean;\n  disabled: boolean;\n  httpAdapters: ComparableHttpAdapter[];\n};\n\nfunction sortStrings(values: readonly string[] | undefined): string[] {\n  return (values ?? []).toSorted();\n}\n\nfunction normalizeSubgraphs(\n  subgraphs: ReadonlyArray<MessageInitShape<typeof SubgraphSchema>> | undefined,\n): ComparableApplication[\"subgraphs\"] {\n  return [...(subgraphs ?? [])]\n    .map((subgraph) => ({\n      serviceType: assertDefined(subgraph.serviceType, \"subgraph missing serviceType\"),\n      serviceNamespace: subgraph.serviceNamespace ?? \"\",\n    }))\n    .toSorted((left, right) => {\n      if (left.serviceType !== right.serviceType) {\n        return left.serviceType - right.serviceType;\n      }\n      return left.serviceNamespace.localeCompare(right.serviceNamespace);\n    });\n}\n\nfunction normalizeHttpAdapters(\n  httpAdapters:\n    | ReadonlyArray<{\n        name?: string;\n        pathPattern?: string;\n        methods?: string[];\n        inputScript?: string;\n        outputScript?: string;\n        enabled?: boolean;\n        priority?: number;\n      }>\n    | undefined,\n): ComparableHttpAdapter[] {\n  return [...(httpAdapters ?? [])]\n    .map((adapter) => ({\n      name: adapter.name ?? \"\",\n      pathPattern: adapter.pathPattern ?? \"\",\n      methods: sortStrings(adapter.methods),\n      inputScript: adapter.inputScript ?? \"\",\n      outputScript: adapter.outputScript ?? \"\",\n      // Fallbacks mirror the schema defaults; in practice both sides always\n      // carry explicit values (the SDK sets them and proto bools are present).\n      enabled: adapter.enabled ?? true,\n      priority: adapter.priority ?? 0,\n    }))\n    .toSorted((left, right) => left.name.localeCompare(right.name));\n}\n\nfunction toComparableApplication(\n  input: Pick<\n    ComparableApplication,\n    | \"authNamespace\"\n    | \"authIdpConfigName\"\n    | \"cors\"\n    | \"subgraphs\"\n    | \"allowedIpAddresses\"\n    | \"disableIntrospection\"\n    | \"disabled\"\n    | \"httpAdapters\"\n  >,\n): ComparableApplication {\n  return {\n    authNamespace: input.authNamespace,\n    authIdpConfigName: input.authIdpConfigName,\n    cors: sortStrings(input.cors),\n    subgraphs: [...input.subgraphs],\n    allowedIpAddresses: sortStrings(input.allowedIpAddresses),\n    disableIntrospection: input.disableIntrospection,\n    disabled: input.disabled,\n    httpAdapters: [...input.httpAdapters],\n  };\n}\n\nfunction normalizeComparableApplication(\n  application: Readonly<Application>,\n  authNamespace: string | undefined,\n  authIdpConfigName: string | undefined,\n  cors: string[],\n  httpAdapters: ReadonlyArray<MessageInitShape<typeof HttpAdapterSchema>>,\n): ComparableApplication {\n  return toComparableApplication({\n    authNamespace: authNamespace ?? \"\",\n    authIdpConfigName: authIdpConfigName ?? \"\",\n    cors,\n    subgraphs: normalizeSubgraphs(application.subgraphs.map((subgraph) => protoSubgraph(subgraph))),\n    allowedIpAddresses: application.config.allowedIpAddresses ?? [],\n    disableIntrospection: application.config.disableIntrospection ?? false,\n    disabled: false,\n    httpAdapters: normalizeHttpAdapters(httpAdapters),\n  });\n}\n\nfunction normalizeComparableExistingApplication(app: ProtoApplication): ComparableApplication {\n  return toComparableApplication({\n    authNamespace: app.authNamespace,\n    authIdpConfigName: app.authIdpConfigName,\n    cors: app.cors,\n    subgraphs: normalizeSubgraphs(app.subgraphs),\n    allowedIpAddresses: app.allowedIpAddresses,\n    disableIntrospection: app.disableIntrospection,\n    disabled: app.disabled,\n    httpAdapters: normalizeHttpAdapters(app.httpAdapters),\n  });\n}\n\nfunction areApplicationsEqual(existing: ProtoApplication, desired: ComparableApplication): boolean {\n  return areNormalizedEqual(normalizeComparableExistingApplication(existing), desired);\n}\n\n/**\n * Plan application changes based on current and desired state.\n * @param context - Planning context\n * @param httpAdapterBuildResult - Bundled HTTP adapter scripts to embed on the Application\n * @returns Planned changes\n */\nexport async function planApplication(\n  context: PlanContext,\n  httpAdapterBuildResult?: HttpAdapterBundleResult,\n) {\n  const { client, workspaceId, application, forRemoval } = context;\n  const conflicts: OwnerConflict[] = [];\n  const unmanaged: UnmanagedResource[] = [];\n  const resourceOwners = new Set<string>();\n  const changeSet = createChangeSet<\n    CreateApplication,\n    UpdateApplication,\n    DeleteApplication,\n    never,\n    UpdateApplication\n  >(\"Applications\");\n\n  const existingApplications = await fetchAllTolerant(async (pageToken, maxPageSize) => {\n    const { applications, nextPageToken } = await client.listApplications({\n      workspaceId,\n      pageToken,\n      pageSize: maxPageSize,\n    });\n    return [applications, nextPageToken];\n  });\n\n  if (forRemoval) {\n    // A same-named app in a shared workspace may belong to another user, so\n    // never delete by name alone. Without an id only the same-name app can be\n    // ours; with an id, scan all apps to also clean up renamed-away ones.\n    const candidates = application.id\n      ? existingApplications\n      : existingApplications.filter((app) => app.name === application.name);\n    const owned = await Promise.all(\n      candidates.map(async (app) => {\n        const labels = await fetchAppLabels(client, workspaceId, app.name);\n        return trackRemainingResourceOwner({\n          labels,\n          ownerLabel: labels?.[sdkNameLabelKey],\n          appName: application.name,\n          appId: application.id,\n          resourceOwners,\n        })\n          ? app.name\n          : null;\n      }),\n    );\n    for (const name of owned) {\n      if (name) {\n        changeSet.deletes.push({\n          name,\n          request: {\n            workspaceId,\n            applicationName: name,\n          },\n        });\n      }\n    }\n    return withOwnership(changeSet, conflicts, unmanaged, resourceOwners);\n  }\n\n  // Skip application create/update when there are no subgraphs\n  // (e.g. deploying only static web hosting)\n  if (application.subgraphs.length === 0) {\n    return withOwnership(changeSet, conflicts, unmanaged, resourceOwners);\n  }\n\n  let authNamespace: string | undefined;\n  let authIdpConfigName: string | undefined;\n  if (application.authService) {\n    authNamespace = application.authService.config.name;\n\n    const idProvider = application.authService.config.idProvider;\n    if (idProvider) {\n      authIdpConfigName = idProvider.name;\n    }\n  } else if (application.config.auth) {\n    // Prefer peer plans for same-run multi-config deploys; otherwise read remote state.\n    authNamespace = application.config.auth.name;\n    if (context.externalAuthIdpConfigNames?.has(authNamespace)) {\n      authIdpConfigName = context.externalAuthIdpConfigNames.get(authNamespace);\n    } else {\n      const idpConfigs = await fetchAllTolerant(async (pageToken, maxPageSize) => {\n        const { idpConfigs, nextPageToken } = await client.listAuthIDPConfigs({\n          workspaceId,\n          namespaceName: assertDefined(\n            authNamespace,\n            \"authNamespace must be set before listing IDP configs\",\n          ),\n          pageToken,\n          pageSize: maxPageSize,\n        });\n        return [idpConfigs, nextPageToken];\n      });\n      if (idpConfigs.length > 0) {\n        const [firstConfig] = idpConfigs;\n        if (firstConfig) {\n          authIdpConfigName = firstConfig.name;\n        }\n      }\n    }\n  }\n  const metaRequest = await buildMetaRequest({\n    trn: resourceTrn(workspaceId, \"application\", application.name),\n    appName: application.name,\n    appId: application.id,\n    metadata: application.config.metadata,\n  });\n  const existingLabels = await fetchAppLabels(client, workspaceId, application.name);\n  assertLabelBudget(application.name, existingLabels, metaRequest);\n  const metadataDetails = diffMetadataDisplay(existingLabels, application.config.metadata);\n  const expectedLocalWebsites = expectedLocalStaticWebsiteNames(context);\n  const resolvedCors = await resolveStaticWebsiteUrls(\n    client,\n    workspaceId,\n    application.config.cors,\n    \"CORS\",\n    { expectedLocalNames: expectedLocalWebsites },\n  );\n  const httpAdapters = buildHttpAdapters(application, httpAdapterBuildResult);\n  const desired = normalizeComparableApplication(\n    application,\n    authNamespace,\n    authIdpConfigName,\n    resolvedCors,\n    httpAdapters,\n  );\n  const request = {\n    workspaceId,\n    applicationName: application.name,\n    authNamespace,\n    authIdpConfigName,\n    cors: application.config.cors,\n    subgraphs: application.subgraphs.map((subgraph) => protoSubgraph(subgraph)),\n    allowedIpAddresses: application.config.allowedIpAddresses,\n    disableIntrospection: application.config.disableIntrospection,\n    httpAdapters,\n  };\n  const existing = existingApplications.find((app) => app.name === application.name);\n\n  // Detect renames: other apps owned by our id should be deleted before\n  // creating/updating the current name (so the old name is freed up).\n  if (application.id) {\n    const otherApps = existingApplications.filter((app) => app.name !== application.name);\n    const renamedAway = await Promise.all(\n      otherApps.map(async (app) => {\n        const labels = await fetchAppLabels(client, workspaceId, app.name);\n        return isOwnedByApp(labels, application.name, application.id) ? app.name : null;\n      }),\n    );\n    for (const name of renamedAway) {\n      if (name) {\n        changeSet.deletes.push({\n          name,\n          request: {\n            workspaceId,\n            applicationName: name,\n          },\n        });\n      }\n    }\n  }\n\n  if (existing) {\n    const owned = trackDesiredResourceOwnership({\n      labels: existingLabels,\n      ownerLabel: existingLabels?.[sdkNameLabelKey],\n      appName: application.name,\n      appId: application.id,\n      resourceType: \"Application\",\n      resourceName: application.name,\n      conflicts,\n      unmanaged,\n    });\n    const update: UpdateApplication = {\n      name: application.name,\n      request,\n      metaRequest,\n    };\n    if (\n      owned &&\n      hasMatchingSdkVersion(existingLabels, metaRequest.labels) &&\n      areApplicationsEqual(existing, desired) &&\n      metadataDetails.length === 0\n    ) {\n      // Plan display shows this as unchanged, but apply still re-issues it.\n      changeSet.unchanged.push(update);\n    } else {\n      const details = [\n        ...diffHttpAdapterDisplay(existing.httpAdapters, httpAdapters),\n        ...metadataDetails,\n      ];\n      if (details.length > 0) {\n        update.details = details;\n      }\n      changeSet.updates.push(update);\n    }\n  } else {\n    const details = [...diffHttpAdapterDisplay(undefined, httpAdapters), ...metadataDetails];\n    changeSet.creates.push({\n      name: application.name,\n      request,\n      metaRequest,\n      details: details.length > 0 ? details : undefined,\n    });\n  }\n\n  return withOwnership(changeSet, conflicts, unmanaged, resourceOwners);\n}\n\n/**\n * Attach the ownership-tracking fields to the plan's change set.\n *\n * The other resource plans return `{ changeSet, conflicts, ... }`; this one\n * returns the change set itself, so the fields are attached to it. Without\n * them the application is the one managed resource that never reaches\n * `confirmOwnerConflict`, which would let a deploy re-tag — or a `remove`\n * silently skip — an application this config does not own.\n * @param changeSet - The application change set\n * @param conflicts - Resources owned by another application\n * @param unmanaged - Resources carrying no SDK label\n * @param resourceOwners - Owners of the resources that were skipped\n * @returns The change set, with the ownership-tracking fields attached\n */\nfunction withOwnership<T extends object>(\n  changeSet: T,\n  conflicts: OwnerConflict[],\n  unmanaged: UnmanagedResource[],\n  resourceOwners: Set<string>,\n): T & { conflicts: OwnerConflict[]; unmanaged: UnmanagedResource[]; resourceOwners: Set<string> } {\n  return Object.assign(changeSet, { conflicts, unmanaged, resourceOwners });\n}\n\nasync function fetchAppLabels(\n  client: OperatorClient,\n  workspaceId: string,\n  appName: string,\n): Promise<Record<string, string> | undefined> {\n  const response = await getOrNull(async () => {\n    const { metadata } = await client.getMetadata({\n      trn: resourceTrn(workspaceId, \"application\", appName),\n    });\n    return metadata;\n  });\n  return response?.labels;\n}\n\n/**\n * Build per-adapter diff lines for the application plan display. The platform\n * models HTTP adapters as an embedded Application field (no dedicated RPC), so\n * adapter changes surface as an Application update; these lines show which\n * adapter actually changed instead of just `~ <app>`.\n * @param existingAdapters - HTTP adapters currently deployed on the application\n * @param desiredAdapters - HTTP adapters built from the local config\n * @returns Indented diff lines (`+`/`~`/`-` per adapter), sorted by name\n */\nexport function diffHttpAdapterDisplay(\n  existingAdapters: ReadonlyArray<MessageInitShape<typeof HttpAdapterSchema>> | undefined,\n  desiredAdapters: ReadonlyArray<MessageInitShape<typeof HttpAdapterSchema>>,\n): string[] {\n  const existingByName = new Map((existingAdapters ?? []).map((a) => [a.name ?? \"\", a]));\n  const desiredByName = new Map(desiredAdapters.map((a) => [a.name ?? \"\", a]));\n  const entries: Array<{ name: string; symbol: string }> = [];\n  for (const [name, desired] of desiredByName) {\n    const existing = existingByName.get(name);\n    if (!existing) {\n      entries.push({ name, symbol: symbols.create });\n    } else if (\n      !areNormalizedEqual(normalizeHttpAdapters([existing])[0], normalizeHttpAdapters([desired])[0])\n    ) {\n      entries.push({ name, symbol: symbols.update });\n    }\n  }\n  for (const name of existingByName.keys()) {\n    if (!desiredByName.has(name)) {\n      entries.push({ name, symbol: symbols.delete });\n    }\n  }\n  return entries\n    .toSorted((left, right) => left.name.localeCompare(right.name))\n    .map((entry) => `${entry.symbol} ${entry.name} (httpAdapter)`);\n}\n\n/**\n * Fail the plan when the labels this deploy would leave behind exceed the\n * platform's per-resource limit.\n *\n * The `metadata` cap alone cannot catch this: a write keeps every stored label\n * it does not name, so labels from another tool or an earlier config push are\n * merged on top of the entries being written. Reporting it here fails the run\n * before the application is created or updated, rather than leaving a bare\n * `SetMetadata` rejection after the resource has already changed.\n * @param appName - Application the labels belong to\n * @param existingLabels - Labels currently stored on the application\n * @param write - The metadata write planned for the application\n */\nfunction assertLabelBudget(\n  appName: string,\n  existingLabels: Record<string, string> | undefined,\n  write: MetadataLabelWrite,\n): void {\n  const merged = new Set([\n    ...Object.keys(existingLabels ?? {}),\n    ...Object.keys(write.labels ?? {}),\n  ]);\n  for (const key of write.remove ?? []) {\n    merged.delete(key);\n  }\n  if (merged.size <= MAX_RESOURCE_LABELS) return;\n  const named = new Set(Object.keys(write.labels ?? {}));\n  const retained = [...merged].filter((key) => !named.has(key)).toSorted();\n  throw CLIError({\n    code: \"DEPLOY_LABEL_LIMIT_EXCEEDED\",\n    message: `Application '${appName}' would store ${merged.size} labels, over the platform's limit of ${MAX_RESOURCE_LABELS}.`,\n    details: `${named.size} come from this deploy and ${retained.length} are kept from earlier deploys or other tools${retained.length ? ` (${retained.join(\", \")})` : \"\"}.`,\n    suggestion:\n      \"Remove entries from 'metadata' in the config, or delete labels the application no longer needs.\",\n  });\n}\n\n/**\n * Build per-entry diff lines for the config's `metadata` labels. Labels the\n * config does not name are kept as they are, so they never appear here.\n * @param existingLabels - Labels currently stored on the application\n * @param metadata - `metadata` entries from the local config\n * @returns Indented diff lines (`+`/`~` per entry), sorted by key\n */\nfunction diffMetadataDisplay(\n  existingLabels: Record<string, string> | undefined,\n  metadata: Record<string, string> | undefined,\n): string[] {\n  const existing = existingLabels ?? {};\n  const isStored = (key: string) => Object.hasOwn(existing, key);\n  return Object.entries(metadata ?? {})\n    .filter(([key, value]) => !isStored(key) || existing[key] !== value)\n    .toSorted(([left], [right]) => left.localeCompare(right))\n    .map(([key]) => `${isStored(key) ? symbols.update : symbols.create} ${key} (metadata)`);\n}\n\nfunction buildHttpAdapters(\n  application: Readonly<Application>,\n  httpAdapterBuildResult: HttpAdapterBundleResult | undefined,\n): MessageInitShape<typeof HttpAdapterSchema>[] {\n  const adapters = application.httpAdapterService?.adapters ?? [];\n  if (adapters.length === 0) {\n    return [];\n  }\n  return adapters.map((loaded) => {\n    const inputScript = httpAdapterBuildResult?.bundledInputs.get(loaded.adapter.name);\n    if (!inputScript) {\n      throw internalError(\n        `HTTP adapter \"${loaded.adapter.name}\" was loaded but no bundled input script is available`,\n      );\n    }\n    let outputScript = \"\";\n    if (loaded.hasOutput) {\n      const bundled = httpAdapterBuildResult?.bundledOutputs.get(loaded.adapter.name);\n      if (!bundled) {\n        throw internalError(\n          `HTTP adapter \"${loaded.adapter.name}\" declares an output handler but no bundled output script is available`,\n        );\n      }\n      outputScript = bundled;\n    }\n    return {\n      name: loaded.adapter.name,\n      pathPattern: loaded.adapter.pathPattern,\n      methods: loaded.methods.map((m) => HTTP_METHODS[m]),\n      inputScript,\n      outputScript,\n      // `enabled`/`priority` are always populated here because\n      // HttpAdapterConfigSchema applies their defaults during parse.\n      enabled: loaded.adapter.enabled,\n      priority: loaded.adapter.priority,\n    };\n  });\n}\n\nfunction protoSubgraph(\n  subgraph: Readonly<{ Type: string; Name: string }>,\n): MessageInitShape<typeof SubgraphSchema> {\n  // TODO(remiposo): Make it type-safe\n  let serviceType: Subgraph_ServiceType;\n  switch (subgraph.Type) {\n    case \"tailordb\":\n      serviceType = Subgraph_ServiceType.TAILORDB;\n      break;\n    case \"pipeline\":\n      serviceType = Subgraph_ServiceType.PIPELINE;\n      break;\n    case \"idp\":\n      serviceType = Subgraph_ServiceType.IDP;\n      break;\n    case \"auth\":\n      serviceType = Subgraph_ServiceType.AUTH;\n      break;\n    default:\n      throw internalError(`Unknown subgraph type: ${subgraph.Type}`);\n  }\n  return {\n    serviceType,\n    serviceNamespace: subgraph.Name,\n  };\n}\n","import { createHash, randomUUID } from \"node:crypto\";\nimport {\n  mkdirSync,\n  readFileSync,\n  renameSync,\n  rmSync,\n  statSync,\n  utimesSync,\n  writeFileSync,\n} from \"node:fs\";\nimport pLimit, { type LimitFunction } from \"p-limit\";\nimport * as path from \"pathe\";\nimport { z } from \"zod\";\nimport { getDistDir } from \"#/cli/shared/dist-dir\";\nimport { CLIError, internalError } from \"#/cli/shared/errors\";\nimport type { Timestamp } from \"@bufbuild/protobuf/wkt\";\n\n// strip unknown keys\nconst SecretsStateEntrySchema = z.object({\n  hash: z.string(),\n  updateTime: z.string().optional(),\n});\n\n// strip unknown keys\nconst SecretsStateSchema = z.object({\n  vaults: z.record(z.string(), z.record(z.string(), SecretsStateEntrySchema)),\n  connections: z.record(z.string(), z.string()).optional(),\n});\n\n// strip unknown keys\nconst PersistedSecretsStateSchema = z.object({\n  version: z.literal(2),\n  workspaceId: z.string(),\n  applicationKey: z.string(),\n  state: SecretsStateSchema,\n});\n\nexport type SecretsState = z.infer<typeof SecretsStateSchema>;\ntype PersistedSecretsState = z.infer<typeof PersistedSecretsStateSchema>;\n\nexport interface SecretsStateScope {\n  readonly workspaceId: string;\n  readonly applicationId: string | undefined;\n  readonly applicationName: string;\n}\n\n/**\n * Get the file path for one workspace and application's secrets state JSON.\n * @param scope - Workspace and application identity for the deployment\n * @returns Absolute path to the scoped state file\n */\nexport function getSecretsStatePath(scope: SecretsStateScope): string {\n  const scopeHash = hashValue(JSON.stringify([scope.workspaceId, applicationStateKey(scope)]));\n  return path.join(getDistDir(), \"secrets-state\", `${scopeHash}.json`);\n}\n\nfunction loadPersistedSecretsState(scope: SecretsStateScope): PersistedSecretsState | undefined {\n  try {\n    const raw = readFileSync(getSecretsStatePath(scope), \"utf-8\");\n    const persistedState = PersistedSecretsStateSchema.parse(JSON.parse(raw));\n    if (\n      persistedState.workspaceId !== scope.workspaceId ||\n      persistedState.applicationKey !== applicationStateKey(scope)\n    ) {\n      return undefined;\n    }\n    return persistedState;\n  } catch {\n    return undefined;\n  }\n}\n\nfunction applicationStateKey(scope: SecretsStateScope): string {\n  if (!scope.applicationId) {\n    throw internalError(\n      `Application \"${scope.applicationName}\" has no stable id for secrets state`,\n    );\n  }\n  return `id:${scope.applicationId}`;\n}\n\n/**\n * Load secrets hash state for one workspace and application from disk.\n * @param scope - Workspace and application identity for the deployment\n * @returns Persisted state, or empty state if the scope is missing or the file is invalid\n */\nexport function loadSecretsState(scope: SecretsStateScope): SecretsState {\n  if (!scope.applicationId) {\n    return { vaults: {} };\n  }\n  return loadPersistedSecretsState(scope)?.state ?? { vaults: {} };\n}\n\n/**\n * Save secrets hash state for one workspace and application to disk.\n * @param scope - Workspace and application identity for the deployment\n * @param state - The secrets state to persist\n */\nexport function saveSecretsState(scope: SecretsStateScope, state: SecretsState): void {\n  if (!scope.applicationId) {\n    return;\n  }\n  const filePath = getSecretsStatePath(scope);\n  const dir = path.dirname(filePath);\n  mkdirSync(dir, { recursive: true });\n  // Write via a temp file and rename so concurrent readers never see torn JSON.\n  const tempPath = `${filePath}.tmp-${randomUUID()}`;\n  writeFileSync(\n    tempPath,\n    JSON.stringify(\n      {\n        version: 2,\n        workspaceId: scope.workspaceId,\n        applicationKey: applicationStateKey(scope),\n        state,\n      } satisfies PersistedSecretsState,\n      null,\n      2,\n    ),\n    \"utf-8\",\n  );\n  renameSync(tempPath, filePath);\n}\n\n/**\n * Compute SHA-256 hex digest of a value.\n * @param value - The string to hash\n * @returns Hex-encoded SHA-256 hash\n */\nexport function hashValue(value: string): string {\n  return createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\n/**\n * Serialize a platform timestamp into the string stored as update evidence.\n * @param updateTime - Timestamp from a Secret Manager list or mutation response\n * @returns Serialized timestamp, or undefined when the platform sent none\n */\nexport function serializeUpdateTime(updateTime: Timestamp | undefined): string | undefined {\n  return updateTime === undefined ? undefined : `${updateTime.seconds}.${updateTime.nanos}`;\n}\n\nconst LOCK_POLL_INTERVAL_MS = 100;\nconst LOCK_ACQUIRE_TIMEOUT_MS = 5 * 60 * 1000;\n// A holder refreshes the lock directory mtime while working, so a lock whose\n// mtime is older than the lease can only belong to a crashed or stopped\n// process and is safe to steal.\nconst LOCK_HEARTBEAT_INTERVAL_MS = 10 * 1000;\nconst LOCK_LEASE_MS = 60 * 1000;\n\nconst lockQueues = new Map<string, LimitFunction>();\n\n/**\n * Run a remote-update/state-save sequence exclusively for one target's secrets state.\n *\n * Serializes concurrent deploys to the same workspace and application (across\n * processes sharing the same output directory) so the persisted hash state\n * always reflects the last remote write.\n * @param scope - Workspace and application identity for the deployment\n * @param fn - Critical section performing remote updates and the state save\n * @returns The value returned by fn\n */\nexport async function withSecretsStateLock<T>(\n  scope: SecretsStateScope,\n  fn: () => Promise<T>,\n): Promise<T> {\n  if (!scope.applicationId) {\n    return fn();\n  }\n  const lockPath = `${getSecretsStatePath(scope)}.lock`;\n  let queue = lockQueues.get(lockPath);\n  if (!queue) {\n    queue = pLimit(1);\n    lockQueues.set(lockPath, queue);\n  }\n  return queue(async () => {\n    const token = await acquireFileLock(lockPath);\n    const heartbeat = setInterval(() => refreshLock(lockPath, token), LOCK_HEARTBEAT_INTERVAL_MS);\n    heartbeat.unref();\n    try {\n      return await fn();\n    } finally {\n      clearInterval(heartbeat);\n      releaseFileLock(lockPath, token);\n    }\n  });\n}\n\nasync function acquireFileLock(lockPath: string): Promise<string> {\n  mkdirSync(path.dirname(lockPath), { recursive: true });\n  const token = randomUUID();\n  const deadline = Date.now() + LOCK_ACQUIRE_TIMEOUT_MS;\n  for (;;) {\n    let created = true;\n    try {\n      mkdirSync(lockPath);\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") {\n        throw error;\n      }\n      created = false;\n    }\n    if (created) {\n      try {\n        writeFileSync(\n          path.join(lockPath, \"owner.json\"),\n          JSON.stringify({ pid: process.pid, token }),\n        );\n      } catch (error) {\n        rmSync(lockPath, { recursive: true, force: true });\n        throw error;\n      }\n      return token;\n    }\n    if (isLockExpired(lockPath) && stealLock(lockPath)) {\n      continue;\n    }\n    if (Date.now() >= deadline) {\n      throw CLIError({\n        code: \"DEPLOY_LOCK_TIMEOUT\",\n        message:\n          \"Timed out waiting for another deploy to the same workspace and application to finish.\",\n        suggestion:\n          \"Wait for it to complete and retry; an interrupted deploy recovers automatically within a minute.\",\n      });\n    }\n    await new Promise((resolve) => setTimeout(resolve, LOCK_POLL_INTERVAL_MS));\n  }\n}\n\nfunction isLockExpired(lockPath: string): boolean {\n  try {\n    return Date.now() - statSync(lockPath).mtimeMs > LOCK_LEASE_MS;\n  } catch {\n    return false;\n  }\n}\n\nfunction readLockToken(lockPath: string): unknown {\n  try {\n    return (\n      JSON.parse(readFileSync(path.join(lockPath, \"owner.json\"), \"utf-8\")) as { token?: unknown }\n    ).token;\n  } catch {\n    return undefined;\n  }\n}\n\nfunction refreshLock(lockPath: string, token: string): void {\n  if (readLockToken(lockPath) !== token) {\n    return;\n  }\n  const now = new Date();\n  try {\n    utimesSync(lockPath, now, now);\n  } catch {\n    // The lock disappeared or was stolen; the release path handles ownership.\n  }\n}\n\nfunction releaseFileLock(lockPath: string, token: string): void {\n  // Only remove a lock this process still owns, so a holder whose lease\n  // expired cannot delete the current holder's lock.\n  if (readLockToken(lockPath) !== token) {\n    return;\n  }\n  rmSync(lockPath, { recursive: true, force: true });\n}\n\nfunction stealLock(lockPath: string): boolean {\n  // Rename first so concurrent stealers cannot remove a lock that another\n  // contender has just re-acquired.\n  const trash = `${lockPath}.stale-${process.pid}-${Date.now()}`;\n  try {\n    renameSync(lockPath, trash);\n  } catch {\n    return false;\n  }\n  if (isLockExpired(trash)) {\n    rmSync(trash, { recursive: true, force: true });\n    return true;\n  }\n  // A live holder re-acquired or refreshed the lock between the expiry check\n  // and the rename; hand it back.\n  try {\n    renameSync(trash, lockPath);\n  } catch {\n    rmSync(trash, { recursive: true, force: true });\n  }\n  return false;\n}\n","import { type MessageInitShape } from \"@bufbuild/protobuf\";\nimport {\n  AuthConnection_Status,\n  AuthConnection_Type,\n} from \"@tailor-platform/tailor-proto/auth_resource_pb\";\nimport { type AuthService } from \"#/cli/services/auth/service\";\nimport { fetchAllTolerant, type OperatorClient } from \"#/cli/shared/client\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { createChangeSet } from \"./change-set\";\nimport {\n  buildMetaRequest,\n  type MetadataLabelWrite,\n  resourceTrn,\n  sdkNameLabelKey,\n  type WithLabel,\n  writeMetadataLabels,\n} from \"./label\";\nimport { trackDesiredResourceOwnership, trackRemainingResourceOwner } from \"./owned-resource\";\nimport {\n  hashValue,\n  loadSecretsState,\n  saveSecretsState,\n  withSecretsStateLock,\n} from \"./secrets-state\";\nimport type { AuthConnectionConfig } from \"#/types/auth-connection.generated\";\nimport type { OwnerConflict, UnmanagedResource } from \"./confirm\";\nimport type { ApplyPhase } from \"./phase\";\nimport type {\n  CreateAuthConnectionRequestSchema,\n  DeleteAuthConnectionRequestSchema,\n  UpdateAuthConnectionRequestSchema,\n} from \"@tailor-platform/tailor-proto/auth_pb\";\nimport type { AuthConnection } from \"@tailor-platform/tailor-proto/auth_resource_pb\";\n\ntype CreateConnection = {\n  name: string;\n  request: MessageInitShape<typeof CreateAuthConnectionRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype UpdateConnection = {\n  name: string;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype MaskedUpdateConnection = {\n  name: string;\n  updateRequest: MessageInitShape<typeof UpdateAuthConnectionRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype DeleteConnection = {\n  name: string;\n  request: MessageInitShape<typeof DeleteAuthConnectionRequestSchema>;\n};\n\nfunction buildConnectionRequest(\n  workspaceId: string,\n  name: string,\n  config: AuthConnectionConfig,\n): MessageInitShape<typeof CreateAuthConnectionRequestSchema> {\n  return {\n    workspaceId,\n    connection: {\n      name,\n      type: AuthConnection_Type.OAUTH2,\n      config: {\n        case: \"oauth2\",\n        value: {\n          providerUrl: config.providerUrl,\n          issuerUrl: config.issuerUrl,\n          clientId: config.clientId,\n          clientSecret: config.clientSecret,\n          authUrl: config.authUrl ?? \"\",\n          tokenUrl: config.tokenUrl ?? \"\",\n        },\n      },\n    },\n  };\n}\n\nfunction buildUpdateMask(\n  existing: AuthConnection,\n  desired: AuthConnectionConfig,\n  secretChanged: boolean,\n): { paths: string[] } {\n  if (existing.config.case !== \"oauth2\") {\n    const paths = [\n      \"type\",\n      \"oauth2.provider_url\",\n      \"oauth2.issuer_url\",\n      \"oauth2.client_id\",\n      \"oauth2.auth_url\",\n      \"oauth2.token_url\",\n    ];\n    if (desired.clientSecret) paths.push(\"oauth2.client_secret\");\n    return { paths };\n  }\n  // The SDK only creates OAUTH2 connections, so no type change is possible here.\n  const paths: string[] = [];\n  const v = existing.config.value;\n  if (v.providerUrl !== desired.providerUrl) paths.push(\"oauth2.provider_url\");\n  if (v.issuerUrl !== desired.issuerUrl) paths.push(\"oauth2.issuer_url\");\n  if (v.clientId !== desired.clientId) paths.push(\"oauth2.client_id\");\n  if (v.authUrl !== (desired.authUrl ?? \"\")) paths.push(\"oauth2.auth_url\");\n  if (v.tokenUrl !== (desired.tokenUrl ?? \"\")) paths.push(\"oauth2.token_url\");\n  if (secretChanged && desired.clientSecret) paths.push(\"oauth2.client_secret\");\n  return { paths };\n}\n\n/**\n * Plan auth connection changes based on current and desired state.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param appName - Application name for ownership\n * @param appId - Stable application id (when managed by SDK)\n * @param auths - Auth services with connection configs\n * @returns Planned changes for auth connections\n */\nexport async function planAuthConnections(\n  client: OperatorClient,\n  workspaceId: string,\n  appName: string,\n  appId: string | undefined,\n  auths: ReadonlyArray<Readonly<AuthService>>,\n) {\n  const stateScope = {\n    workspaceId,\n    applicationId: appId,\n    applicationName: appName,\n  };\n  const changeSet = createChangeSet<\n    CreateConnection,\n    UpdateConnection,\n    DeleteConnection,\n    MaskedUpdateConnection\n  >(\"Auth connections\");\n  const conflicts: OwnerConflict[] = [];\n  const unmanaged: UnmanagedResource[] = [];\n  const resourceOwners = new Set<string>();\n\n  const desiredConnections: Record<string, AuthConnectionConfig> = {};\n  for (const auth of auths) {\n    for (const [name, config] of Object.entries(auth.connections)) {\n      desiredConnections[name] = config;\n      logger.registerSecret(config.clientSecret);\n    }\n  }\n\n  const existingList = await fetchAllTolerant(async (pageToken, maxPageSize) => {\n    const { connections, nextPageToken } = await client.listAuthConnections({\n      workspaceId,\n      pageToken,\n      pageSize: maxPageSize,\n    });\n    return [connections, nextPageToken];\n  });\n\n  const existingConnections: WithLabel<AuthConnection> = {};\n  await Promise.all(\n    existingList.map(async (resource) => {\n      const { metadata } = await client.getMetadata({\n        trn: resourceTrn(workspaceId, \"auth_connection\", resource.name),\n      });\n      existingConnections[resource.name] = {\n        resource,\n        label: metadata?.labels[sdkNameLabelKey],\n        allLabels: metadata?.labels,\n      };\n    }),\n  );\n\n  const state = loadSecretsState(stateScope);\n\n  for (const [name, config] of Object.entries(desiredConnections)) {\n    const existing = existingConnections[name];\n    const metaRequest = await buildMetaRequest({\n      trn: resourceTrn(workspaceId, \"auth_connection\", name),\n      appName,\n      appId,\n    });\n\n    if (existing) {\n      const owned = trackDesiredResourceOwnership({\n        labels: existing.allLabels,\n        ownerLabel: existing.label,\n        appName,\n        appId,\n        resourceType: \"Auth connection\",\n        resourceName: name,\n        conflicts,\n        unmanaged,\n      });\n\n      const currentHash = hashValue(config.clientSecret);\n      const storedHash = state.connections?.[name];\n      const secretChanged = currentHash !== storedHash;\n      const updateMask = buildUpdateMask(existing.resource, config, secretChanged);\n\n      if (updateMask.paths.length > 0) {\n        changeSet.replaces.push({\n          name,\n          updateRequest: {\n            ...buildConnectionRequest(workspaceId, name, config),\n            updateMask,\n          } as MessageInitShape<typeof UpdateAuthConnectionRequestSchema>,\n          metaRequest,\n        });\n      } else if (!owned) {\n        // The connection itself is unchanged, but this application does not own\n        // it yet: it carries no SDK label (just adopted, or created by an SDK\n        // that predates ownership labels), or it carries an id this config does\n        // not match. Either way the labels have to be written, or the take-over\n        // the user just confirmed would not happen and the next deploy would ask\n        // the same question again.\n        changeSet.updates.push({ name, metaRequest });\n      } else {\n        changeSet.unchanged.push({ name });\n      }\n      delete existingConnections[name];\n    } else {\n      changeSet.creates.push({\n        name,\n        request: buildConnectionRequest(workspaceId, name, config),\n        metaRequest,\n      });\n    }\n  }\n\n  for (const [name, entry] of Object.entries(existingConnections)) {\n    if (!entry) continue;\n    const owned = trackRemainingResourceOwner({\n      labels: entry.allLabels,\n      ownerLabel: entry.label,\n      appName,\n      appId,\n      resourceOwners,\n    });\n    // Only delete connections we own. Connections without our label are\n    // treated as unowned and left untouched, even if the local secrets-state\n    // happens to track them.\n    if (owned) {\n      changeSet.deletes.push({\n        name,\n        request: { workspaceId, connectionName: name },\n      });\n    }\n  }\n\n  return { changeSet, conflicts, unmanaged, resourceOwners, stateScope };\n}\n\ntype AuthConnectionApplyResult = Pick<\n  Awaited<ReturnType<typeof planAuthConnections>>,\n  \"changeSet\" | \"stateScope\"\n>;\n\n/**\n * Apply auth connection changes for the given phase.\n * @param client - Operator client instance\n * @param result - Planned auth connection changes\n * @param phase - Apply phase\n */\nexport async function applyAuthConnections(\n  client: OperatorClient,\n  result: AuthConnectionApplyResult,\n  phase: Exclude<ApplyPhase, \"delete-services\">,\n) {\n  const { changeSet, stateScope } = result;\n\n  if (phase === \"create-update\") {\n    if (changeSet.creates.length > 0 || changeSet.replaces.length > 0) {\n      await withSecretsStateLock(stateScope, async () => {\n        await Promise.all(\n          changeSet.creates.map(async (create) => {\n            await client.createAuthConnection(create.request);\n            await writeMetadataLabels(client, create.metaRequest);\n            logger.info(\n              `Connection \"${create.name}\" was created. Authorize it with:\\n` +\n                `  tailor authconnection authorize --name ${create.name}\\n` +\n                `Or via the Console: tailor authconnection open`,\n            );\n          }),\n        );\n\n        for (const replace of changeSet.replaces) {\n          const resp = await client.updateAuthConnection(replace.updateRequest);\n          if (resp.connection?.status === AuthConnection_Status.UNAUTHORIZED) {\n            logger.warn(\n              `Connection \"${replace.name}\" requires re-authorization. Authorize with:\\n` +\n                `  tailor authconnection authorize --name ${replace.name}\\n` +\n                `Or via the Console: tailor authconnection open`,\n            );\n          }\n          await writeMetadataLabels(client, replace.metaRequest);\n        }\n\n        const secretReplaces = changeSet.replaces.filter((replace) =>\n          replace.updateRequest.updateMask?.paths?.includes(\"oauth2.client_secret\"),\n        );\n        if (changeSet.creates.length > 0 || secretReplaces.length > 0) {\n          const state = loadSecretsState(stateScope);\n          if (!state.connections) {\n            state.connections = {};\n          }\n          for (const create of changeSet.creates) {\n            const conn = create.request.connection;\n            if (conn?.config?.case === \"oauth2\") {\n              state.connections[create.name] = hashValue(conn.config.value.clientSecret ?? \"\");\n            }\n          }\n          for (const replace of secretReplaces) {\n            const conn = replace.updateRequest.connection;\n            if (conn?.config?.case === \"oauth2\") {\n              state.connections[replace.name] = hashValue(conn.config.value.clientSecret ?? \"\");\n            }\n          }\n          saveSecretsState(stateScope, state);\n        }\n      });\n    }\n\n    // Metadata-only updates: backfill the SDK ownership label on connections\n    // whose configuration is otherwise unchanged.\n    await Promise.all(\n      changeSet.updates.map(async (update) => {\n        await writeMetadataLabels(client, update.metaRequest);\n      }),\n    );\n  } else if (changeSet.deletes.length > 0) {\n    await withSecretsStateLock(stateScope, async () => {\n      await Promise.all(\n        changeSet.deletes.map(async (del) => {\n          await client.deleteAuthConnection(del.request);\n        }),\n      );\n\n      const state = loadSecretsState(stateScope);\n      if (state.connections) {\n        for (const del of changeSet.deletes) {\n          delete state.connections[del.name];\n        }\n        saveSecretsState(stateScope, state);\n      }\n    });\n  }\n}\n","import * as crypto from \"node:crypto\";\nimport { createApplyLimiter } from \"#/cli/shared/apply-concurrency\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { resolverBundleKey } from \"#/cli/shared/resolver-bundle-key\";\nimport { createChangeSet, type ChangeSet, type HasName } from \"./change-set\";\nimport {\n  buildMetaRequest,\n  hasMatchingSdkVersion,\n  type MetadataLabelWrite,\n  resourceTrn,\n  writeMetadataLabels,\n} from \"./label\";\nimport {\n  fetchExistingResourcesWithLabels,\n  trackDesiredResourceOwnership,\n  trackRemainingResourceOwner,\n} from \"./owned-resource\";\nimport type { Application } from \"#/cli/services/application\";\nimport type { CollectedJob } from \"#/cli/services/workflow/service\";\nimport type { OperatorClient } from \"#/cli/shared/client\";\nimport type { OwnerConflict, UnmanagedResource } from \"./confirm\";\nimport type { BundledScripts, FunctionEntry } from \"./function-registry-types\";\nimport type { ApplyPhase } from \"./phase\";\nimport type { MessageInitShape } from \"@bufbuild/protobuf\";\nimport type {\n  CreateFunctionRegistryRequestSchema,\n  UpdateFunctionRegistryRequestSchema,\n} from \"@tailor-platform/tailor-proto/function_registry_pb\";\n\nexport type { BundledScripts, FunctionEntry } from \"./function-registry-types\";\n\nconst CHUNK_SIZE = 64 * 1024; // 64KB\n\ntype CreateFunction = {\n  name: string;\n  entry: FunctionEntry;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype UpdateFunction = {\n  name: string;\n  entry: FunctionEntry;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype DeleteFunction = {\n  name: string;\n  workspaceId: string;\n};\n\ntype FunctionRegistryChangeSet = ChangeSet<CreateFunction, UpdateFunction, DeleteFunction>;\n\n/**\n * Compute SHA-256 content hash for a script string.\n * @param content - Script content to hash\n * @returns Hex-encoded SHA-256 hash\n */\nfunction computeContentHash(content: string): string {\n  return crypto.createHash(\"sha256\").update(content, \"utf-8\").digest(\"hex\");\n}\n\nexport const RESOLVER_PREFIX = \"resolver--\";\nexport const EXECUTOR_PREFIX = \"executor--\";\nexport const WORKFLOW_PREFIX = \"workflow--\";\nexport const AUTH_HOOK_PREFIX = \"auth-hook--\";\n\n/**\n * Build a function registry name for a resolver.\n * @param namespace - Resolver namespace\n * @param resolverName - Resolver name\n * @returns Function registry name\n */\nexport function resolverFunctionName(namespace: string, resolverName: string): string {\n  return `${RESOLVER_PREFIX}${namespace}--${resolverName}`;\n}\n\n/**\n * Build a function registry name for an executor.\n * @param executorName - Executor name\n * @returns Function registry name\n */\nexport function executorFunctionName(executorName: string): string {\n  return `${EXECUTOR_PREFIX}${executorName}`;\n}\n\n/**\n * Build a function registry name for a workflow job.\n * @param jobName - Workflow job name\n * @returns Function registry name\n */\nexport function workflowJobFunctionName(jobName: string): string {\n  return `${WORKFLOW_PREFIX}${jobName}`;\n}\n\n/**\n * Split function registry changes into grouped buckets by resource-name prefix.\n * @param changeSet - Function registry change set\n * @returns Grouped function registry changes by resource kind\n */\nexport function splitFunctionRegistryChanges<\n  C extends HasName,\n  U extends HasName,\n  D extends HasName,\n  R extends HasName,\n>(changeSet: ChangeSet<C, U, D, R>) {\n  type Buckets<T> = {\n    workflowJob: T[];\n    resolver: T[];\n    executor: T[];\n    authHook: T[];\n    other: T[];\n  };\n\n  function partition<T extends HasName>(items: ReadonlyArray<T>): Buckets<T> {\n    const buckets: Buckets<T> = {\n      workflowJob: [],\n      resolver: [],\n      executor: [],\n      authHook: [],\n      other: [],\n    };\n    for (const item of items) {\n      if (item.name.startsWith(WORKFLOW_PREFIX)) buckets.workflowJob.push(item);\n      else if (item.name.startsWith(RESOLVER_PREFIX)) buckets.resolver.push(item);\n      else if (item.name.startsWith(EXECUTOR_PREFIX)) buckets.executor.push(item);\n      else if (item.name.startsWith(AUTH_HOOK_PREFIX)) buckets.authHook.push(item);\n      else buckets.other.push(item);\n    }\n    return buckets;\n  }\n\n  const creates = partition(changeSet.creates);\n  const updates = partition(changeSet.updates);\n  const deletes = partition(changeSet.deletes);\n  const replaces = partition(changeSet.replaces);\n  const unchanged = partition(changeSet.unchanged);\n\n  function collect<K extends keyof Buckets<unknown>>(key: K) {\n    return {\n      creates: creates[key],\n      updates: updates[key],\n      deletes: deletes[key],\n      replaces: replaces[key],\n      unchanged: unchanged[key],\n    };\n  }\n\n  return {\n    workflowJobChanges: collect(\"workflowJob\"),\n    resolverFunctionChanges: collect(\"resolver\"),\n    executorFunctionChanges: collect(\"executor\"),\n    authHookFunctionChanges: collect(\"authHook\"),\n    otherChanges: collect(\"other\"),\n  };\n}\n\n/**\n * Build a function registry name for an auth hook.\n * @param authName - Auth namespace name\n * @param hookPoint - Hook point identifier (e.g. \"before-login\")\n * @returns Function registry name\n */\nexport function authHookFunctionName(authName: string, hookPoint: string): string {\n  return `auth-hook--${authName}--${hookPoint}`;\n}\n\n/**\n * Collect all function entries from in-memory bundled scripts for all services.\n * @param application - Application definition\n * @param workflowJobs - Collected workflow jobs from config\n * @param bundledScripts - In-memory bundled code organized by kind\n * @returns Array of function entries to register\n */\nexport function collectFunctionEntries(\n  application: Readonly<Application>,\n  workflowJobs: CollectedJob[],\n  bundledScripts: BundledScripts,\n): FunctionEntry[] {\n  const entries: FunctionEntry[] = [];\n\n  // Resolvers\n  for (const app of application.applications) {\n    for (const pipeline of app.resolverServices) {\n      for (const resolver of Object.values(pipeline.resolvers)) {\n        const content = bundledScripts.resolvers.get(\n          resolverBundleKey(pipeline.namespace, resolver.name),\n        );\n        if (!content) {\n          logger.warn(\n            `Bundled code not found for resolver: ${pipeline.namespace}/${resolver.name}`,\n          );\n          continue;\n        }\n        entries.push({\n          name: resolverFunctionName(pipeline.namespace, resolver.name),\n          scriptContent: content,\n          contentHash: computeContentHash(content),\n          description: `Resolver: ${pipeline.namespace}/${resolver.name}`,\n        });\n      }\n    }\n  }\n\n  // Executors\n  if (application.executorService) {\n    const executors = application.executorService.executors;\n    for (const executor of Object.values(executors)) {\n      if (executor.operation.kind === \"function\" || executor.operation.kind === \"jobFunction\") {\n        const content = bundledScripts.executors.get(executor.name);\n        if (!content) {\n          logger.warn(`Bundled code not found for executor: ${executor.name}`);\n          continue;\n        }\n        entries.push({\n          name: executorFunctionName(executor.name),\n          scriptContent: content,\n          contentHash: computeContentHash(content),\n          description: `Executor: ${executor.name}`,\n        });\n      }\n    }\n  }\n\n  // Workflow jobs\n  for (const job of workflowJobs) {\n    const content = bundledScripts.workflowJobs.get(job.name);\n    if (!content) {\n      logger.warn(`Bundled code not found for workflow job: ${job.name}`);\n      continue;\n    }\n    entries.push({\n      name: workflowJobFunctionName(job.name),\n      scriptContent: content,\n      contentHash: computeContentHash(content),\n      description: `Workflow job: ${job.name}`,\n    });\n  }\n\n  // Auth hooks\n  for (const app of application.applications) {\n    if (app.authService?.config.hooks?.beforeLogin) {\n      const authName = app.authService.config.name;\n      const funcName = authHookFunctionName(authName, \"before-login\");\n      const content = bundledScripts.authHooks.get(funcName);\n      if (!content) {\n        logger.warn(`Bundled code not found for auth hook: ${funcName}`);\n        continue;\n      }\n      entries.push({\n        name: funcName,\n        scriptContent: content,\n        contentHash: computeContentHash(content),\n        description: `Auth hook: ${authName}/before-login`,\n      });\n    }\n  }\n\n  return entries;\n}\n\n/**\n * Filter collected workflow jobs down to the ones actually bundled.\n * @param jobs - All collected workflow jobs\n * @param usedJobNames - Job names that were bundled\n * @returns Bundled workflow jobs only\n */\nexport function filterBundledWorkflowJobs(\n  jobs: CollectedJob[],\n  usedJobNames: readonly string[],\n): CollectedJob[] {\n  const used = new Set(usedJobNames);\n  return jobs.filter((job) => used.has(job.name));\n}\n\ntype ExistingFunction = {\n  name: string;\n  contentHash: string;\n};\n\n/**\n * Plan function registry changes based on current and desired state.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param appName - Application name\n * @param appId - Stable application id (when managed by SDK)\n * @param entries - Desired function entries\n * @returns Planned changes\n */\nexport async function planFunctionRegistry(\n  client: OperatorClient,\n  workspaceId: string,\n  appName: string,\n  appId: string | undefined,\n  entries: FunctionEntry[],\n) {\n  const changeSet: FunctionRegistryChangeSet = createChangeSet<\n    CreateFunction,\n    UpdateFunction,\n    DeleteFunction\n  >(\"Function registry\");\n  const conflicts: OwnerConflict[] = [];\n  const unmanaged: UnmanagedResource[] = [];\n  const resourceOwners = new Set<string>();\n\n  const existingMap = await fetchExistingResourcesWithLabels({\n    client,\n    fetchPage: async (pageToken, maxPageSize) => {\n      const response = await client.listFunctionRegistries({\n        workspaceId,\n        pageToken,\n        pageSize: maxPageSize,\n      });\n      return [\n        response.functions.map((f): ExistingFunction => ({\n          name: f.name,\n          contentHash: f.contentHash,\n        })),\n        response.nextPageToken,\n      ];\n    },\n    getName: (func) => func.name,\n    getTrn: (name) => resourceTrn(workspaceId, \"function_registry\", name),\n  });\n\n  // Process desired entries\n  for (const entry of entries) {\n    const existing = existingMap[entry.name];\n    const metaRequest = await buildMetaRequest({\n      trn: resourceTrn(workspaceId, \"function_registry\", entry.name),\n      appName,\n      appId,\n    });\n\n    if (existing) {\n      const owned = trackDesiredResourceOwnership({\n        labels: existing.allLabels,\n        ownerLabel: existing.label,\n        appName,\n        appId,\n        resourceType: \"Function registry\",\n        resourceName: entry.name,\n        conflicts,\n        unmanaged,\n      });\n\n      if (\n        existing.resource.contentHash === entry.contentHash &&\n        owned &&\n        hasMatchingSdkVersion(existing.allLabels, metaRequest.labels)\n      ) {\n        changeSet.unchanged.push({\n          name: entry.name,\n        });\n      } else {\n        changeSet.updates.push({\n          name: entry.name,\n          entry,\n          metaRequest,\n        });\n      }\n      delete existingMap[entry.name];\n    } else {\n      changeSet.creates.push({\n        name: entry.name,\n        entry,\n        metaRequest,\n      });\n    }\n  }\n\n  // Remaining entries in existingMap are candidates for deletion\n  for (const [name, existing] of Object.entries(existingMap)) {\n    if (!existing) continue;\n    const owned = trackRemainingResourceOwner({\n      labels: existing.allLabels,\n      ownerLabel: existing.label,\n      appName,\n      appId,\n      resourceOwners,\n    });\n    if (owned) {\n      changeSet.deletes.push({\n        name,\n        workspaceId,\n      });\n    }\n  }\n\n  const {\n    workflowJobChanges,\n    resolverFunctionChanges,\n    executorFunctionChanges,\n    authHookFunctionChanges,\n  } = splitFunctionRegistryChanges(changeSet);\n  return {\n    changeSet,\n    workflowJobChanges,\n    resolverFunctionChanges,\n    executorFunctionChanges,\n    authHookFunctionChanges,\n    conflicts,\n    unmanaged,\n    resourceOwners,\n  };\n}\n\n/**\n * Upload a function script to the function registry using client streaming.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param entry - Function entry to upload\n * @param isCreate - Whether this is a create (true) or update (false)\n */\nasync function uploadFunctionScript(\n  client: OperatorClient,\n  workspaceId: string,\n  entry: FunctionEntry,\n  isCreate: boolean,\n) {\n  const buffer = Buffer.from(entry.scriptContent, \"utf-8\");\n\n  const info = {\n    workspaceId,\n    name: entry.name,\n    description: entry.description,\n    sizeBytes: BigInt(buffer.length),\n    contentHash: entry.contentHash,\n  };\n\n  if (isCreate) {\n    /** @yields {MessageInitShape<typeof CreateFunctionRegistryRequestSchema>} Create request messages (info header followed by content chunks) */\n    async function* createStream(): AsyncIterable<\n      MessageInitShape<typeof CreateFunctionRegistryRequestSchema>\n    > {\n      yield { payload: { case: \"info\" as const, value: info } };\n      for (let i = 0; i < buffer.length; i += CHUNK_SIZE) {\n        yield {\n          payload: {\n            case: \"chunk\" as const,\n            value: buffer.subarray(i, Math.min(i + CHUNK_SIZE, buffer.length)),\n          },\n        };\n      }\n    }\n    await client.createFunctionRegistry(createStream());\n  } else {\n    /** @yields {MessageInitShape<typeof UpdateFunctionRegistryRequestSchema>} Update request messages (info header followed by content chunks) */\n    async function* updateStream(): AsyncIterable<\n      MessageInitShape<typeof UpdateFunctionRegistryRequestSchema>\n    > {\n      yield { payload: { case: \"info\" as const, value: info } };\n      for (let i = 0; i < buffer.length; i += CHUNK_SIZE) {\n        yield {\n          payload: {\n            case: \"chunk\" as const,\n            value: buffer.subarray(i, Math.min(i + CHUNK_SIZE, buffer.length)),\n          },\n        };\n      }\n    }\n    await client.updateFunctionRegistry(updateStream());\n  }\n}\n\n/**\n * Apply function registry changes for the given phase.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param result - Planned function registry changes\n * @param phase - Apply phase\n */\nexport async function applyFunctionRegistry(\n  client: OperatorClient,\n  workspaceId: string,\n  result: Awaited<ReturnType<typeof planFunctionRegistry>>,\n  phase: Extract<ApplyPhase, \"create-update\" | \"delete\"> = \"create-update\",\n) {\n  const { changeSet } = result;\n  if (phase === \"create-update\") {\n    // Streaming uploads bypass the client's unary concurrency cap, so bound\n    // each upload + metadata pair here with the same apply-concurrency budget.\n    const limitFunction = createApplyLimiter();\n\n    await Promise.all([\n      ...changeSet.creates.map((create) =>\n        limitFunction(async () => {\n          await uploadFunctionScript(client, workspaceId, create.entry, true);\n          await writeMetadataLabels(client, create.metaRequest);\n        }),\n      ),\n      ...changeSet.updates.map((update) =>\n        limitFunction(async () => {\n          await uploadFunctionScript(client, workspaceId, update.entry, false);\n          await writeMetadataLabels(client, update.metaRequest);\n        }),\n      ),\n    ]);\n  } else {\n    await Promise.all(\n      changeSet.deletes.map((del) =>\n        client.deleteFunctionRegistry({\n          workspaceId: del.workspaceId,\n          name: del.name,\n        }),\n      ),\n    );\n  }\n}\n","import { styles, symbols } from \"#/cli/shared/logger\";\nimport { assertDefined } from \"#/utils/assert\";\nimport {\n  AUTH_HOOK_PREFIX,\n  EXECUTOR_PREFIX,\n  RESOLVER_PREFIX,\n  WORKFLOW_PREFIX,\n} from \"./function-registry\";\nimport type { ChangeSet, HasName } from \"./change-set\";\n\nexport type DisplayAction = \"create\" | \"update\" | \"delete\" | \"replace\";\n\nexport type GroupedDisplayEntry = {\n  action: DisplayAction;\n  symbol: string;\n  name: string;\n  labels: string[];\n  namespace?: string;\n};\n\nexport type RelatedFunctionRegistryChanges = {\n  creates: ReadonlyArray<HasName>;\n  updates: ReadonlyArray<HasName>;\n  deletes: ReadonlyArray<HasName>;\n  replaces: ReadonlyArray<HasName>;\n};\n\ntype RelatedFunctionRegistryNameSets = {\n  creates: Set<string>;\n  updates: Set<string>;\n  deletes: Set<string>;\n  replaces: Set<string>;\n};\n\n/**\n * Convert grouped function registry changes into mutable name sets.\n * @param changes - Grouped function registry changes\n * @returns Mutable name sets keyed by action\n */\nfunction createRelatedFunctionRegistryNameSets(\n  changes?: RelatedFunctionRegistryChanges,\n): RelatedFunctionRegistryNameSets {\n  return {\n    creates: new Set(changes?.creates.map((item) => item.name) ?? []),\n    updates: new Set(changes?.updates.map((item) => item.name) ?? []),\n    deletes: new Set(changes?.deletes.map((item) => item.name) ?? []),\n    replaces: new Set(changes?.replaces.map((item) => item.name) ?? []),\n  };\n}\n\nexport const ACTION_SYMBOLS = {\n  create: symbols.create,\n  update: symbols.update,\n  delete: symbols.delete,\n  replace: symbols.replace,\n} as const satisfies Record<DisplayAction, string>;\n\n/**\n * Convert a plain change set into grouped display entries.\n * @param changeSet - Change set to convert\n * @param labels - Labels to attach to each entry\n * @param getNamespace - Optional callback to extract namespace from an item\n * @returns Display entries in CLI print order\n */\nexport function formatChangeSetEntries(\n  changeSet: Pick<\n    ChangeSet<HasName, HasName, HasName, HasName>,\n    \"creates\" | \"updates\" | \"deletes\" | \"replaces\"\n  >,\n  labels: string[] = [],\n  getNamespace?: (item: HasName) => string | undefined,\n): GroupedDisplayEntry[] {\n  function toEntry(action: DisplayAction, item: HasName): GroupedDisplayEntry {\n    return {\n      action,\n      symbol: ACTION_SYMBOLS[action],\n      name: item.name,\n      labels: [...labels],\n      namespace: getNamespace?.(item),\n    };\n  }\n  return [\n    ...changeSet.creates.map((item) => toEntry(\"create\", item)),\n    ...changeSet.deletes.map((item) => toEntry(\"delete\", item)),\n    ...changeSet.updates.map((item) => toEntry(\"update\", item)),\n    ...changeSet.replaces.map((item) => toEntry(\"replace\", item)),\n  ];\n}\n\nfunction formatGroupedDisplayLine(entry: GroupedDisplayEntry) {\n  return entry.labels.length > 0\n    ? `${entry.symbol} ${entry.name} (${entry.labels.join(\", \")})`\n    : `${entry.symbol} ${entry.name}`;\n}\n\nfunction parseFunctionRegistryName(name: string): { displayName: string; namespace?: string } {\n  if (name.startsWith(RESOLVER_PREFIX)) {\n    const [, namespace, resolverName] = name.split(\"--\");\n    if (namespace && resolverName) {\n      return { displayName: resolverName, namespace };\n    }\n  }\n\n  if (name.startsWith(WORKFLOW_PREFIX)) {\n    return { displayName: name.slice(WORKFLOW_PREFIX.length) };\n  }\n\n  if (name.startsWith(EXECUTOR_PREFIX)) {\n    return { displayName: name.slice(EXECUTOR_PREFIX.length) };\n  }\n\n  if (name.startsWith(AUTH_HOOK_PREFIX)) {\n    const [, namespace, hookPoint] = name.split(\"--\");\n    if (namespace && hookPoint) {\n      return { displayName: hookPoint, namespace };\n    }\n  }\n\n  return { displayName: name };\n}\n\n/**\n * Build function-registry-only entries that were not grouped with a parent resource.\n * @param names - Related function registry names keyed by action\n * @param consumed - Function registry names already grouped with parent resources\n * @returns Display entries for ungrouped function registry changes\n */\nfunction buildRemainingFunctionRegistryEntries(\n  names: RelatedFunctionRegistryNameSets,\n  consumed: RelatedFunctionRegistryNameSets = createRelatedFunctionRegistryNameSets(),\n): GroupedDisplayEntry[] {\n  const actions = [\n    [\"create\", names.creates, consumed.creates],\n    [\"delete\", names.deletes, consumed.deletes],\n    [\"update\", names.updates, consumed.updates],\n    [\"replace\", names.replaces, consumed.replaces],\n  ] as const;\n\n  return actions.flatMap(([action, nameSet, consumedSet]) =>\n    [...nameSet]\n      .filter((name) => !consumedSet.has(name))\n      .map((name) => {\n        const { displayName, namespace } = parseFunctionRegistryName(name);\n        return {\n          action,\n          symbol: ACTION_SYMBOLS[action],\n          name: displayName,\n          labels: [\"function\"],\n          namespace,\n        };\n      }),\n  );\n}\n\n/**\n * Format change set entries with function registry grouping.\n *\n * For each item in creates/updates/deletes, calls `getFunctionRegistryNames` to\n * derive zero or more function registry names. When a matching function registry\n * change exists for the same action, the item is displayed with both the resource\n * label and \"functionRegistry\". Ungrouped function registry changes are appended.\n * @param resourceLabel - Label for the resource kind (e.g. \"executor\", \"resolver\")\n * @param changeSet - Resource change set with creates/updates/deletes/replaces\n * @param changeSet.creates - Created resources\n * @param changeSet.updates - Updated resources\n * @param changeSet.deletes - Deleted resources\n * @param changeSet.replaces - Replaced resources\n * @param functionRegistryChanges - Related function registry changes\n * @param getFunctionRegistryNames - Derives function registry names from a resource item\n * @param options - Optional display callbacks\n * @param options.getNamespace - Extract namespace from an item for nested display\n * @param options.getDisplayName - Override display name for an item\n * @returns Display entries for CLI output\n */\nexport function formatChangeEntriesWithFunctionRegistry<\n  C extends HasName,\n  U extends HasName,\n  D extends HasName,\n>(\n  resourceLabel: string,\n  changeSet: {\n    creates: ReadonlyArray<C>;\n    updates: ReadonlyArray<U>;\n    deletes: ReadonlyArray<D>;\n    replaces: ReadonlyArray<HasName>;\n  },\n  functionRegistryChanges: RelatedFunctionRegistryChanges | undefined,\n  getFunctionRegistryNames: (item: C | U | D, action: DisplayAction) => string[],\n  options?: {\n    getNamespace?: (item: C | U | D) => string | undefined;\n    getDisplayName?: (item: C | U | D) => string;\n  },\n): GroupedDisplayEntry[] {\n  const { getNamespace, getDisplayName } = options ?? {};\n  const functionNames = createRelatedFunctionRegistryNameSets(functionRegistryChanges);\n  const consumed: RelatedFunctionRegistryNameSets = createRelatedFunctionRegistryNameSets();\n\n  function processItems(\n    items: ReadonlyArray<C | U | D>,\n    action: DisplayAction,\n    fnNameSet: Set<string>,\n    consumedSet: Set<string>,\n  ): GroupedDisplayEntry[] {\n    return items.map((item) => {\n      const names = getFunctionRegistryNames(item, action);\n      const hasMatch = names.some((name) => fnNameSet.has(name));\n      if (hasMatch) {\n        for (const name of names) {\n          if (fnNameSet.has(name)) {\n            consumedSet.add(name);\n          }\n        }\n      }\n      return {\n        action,\n        symbol: ACTION_SYMBOLS[action],\n        name: getDisplayName?.(item) ?? item.name,\n        labels: hasMatch ? [resourceLabel, \"function\"] : [resourceLabel],\n        namespace: getNamespace?.(item),\n      };\n    });\n  }\n\n  return [\n    ...processItems(changeSet.creates, \"create\", functionNames.creates, consumed.creates),\n    ...processItems(changeSet.deletes, \"delete\", functionNames.deletes, consumed.deletes),\n    ...processItems(changeSet.updates, \"update\", functionNames.updates, consumed.updates),\n    ...changeSet.replaces.map((item) => ({\n      action: \"replace\" as const,\n      symbol: ACTION_SYMBOLS[\"replace\"],\n      name: getDisplayName?.(item as C | U | D) ?? item.name,\n      labels: [resourceLabel],\n      namespace: getNamespace?.(item as C | U | D),\n    })),\n    ...buildRemainingFunctionRegistryEntries(functionNames, consumed),\n  ];\n}\n\nexport type NamespaceAction = {\n  name: string;\n  action: DisplayAction;\n};\n\n/**\n * Extract service-level actions from a change set for namespace header display.\n * @param changeSet - Service change set\n * @returns Array of namespace actions\n */\nexport function extractServiceActions(\n  changeSet: Pick<\n    ChangeSet<HasName, HasName, HasName, HasName>,\n    \"creates\" | \"updates\" | \"deletes\" | \"replaces\"\n  >,\n): NamespaceAction[] {\n  return [\n    ...changeSet.creates.map((item) => ({ name: item.name, action: \"create\" as const })),\n    ...changeSet.deletes.map((item) => ({ name: item.name, action: \"delete\" as const })),\n    ...changeSet.updates.map((item) => ({ name: item.name, action: \"update\" as const })),\n    ...changeSet.replaces.map((item) => ({ name: item.name, action: \"replace\" as const })),\n  ];\n}\n\n/**\n * Build display lines for a titled section of grouped entries, nesting by namespace.\n * Service-level changes are shown as the namespace header symbol.\n * Services without child entries are shown as flat entries.\n * @param title - Section title\n * @param entries - Entries to render (should NOT include service entries)\n * @param serviceActions - Optional service-level actions to merge into namespace headers\n * @returns Lines ready for output; empty array when there is nothing to show\n */\nexport function buildGroupedDisplayLines(\n  title: string,\n  entries: ReadonlyArray<GroupedDisplayEntry>,\n  serviceActions?: ReadonlyArray<NamespaceAction>,\n): string[] {\n  const serviceMap = new Map<string, DisplayAction>();\n  if (serviceActions) {\n    for (const sa of serviceActions) {\n      serviceMap.set(sa.name, sa.action);\n    }\n  }\n\n  if (entries.length === 0 && serviceMap.size === 0) {\n    return [];\n  }\n\n  const out: string[] = [styles.bold(`${title}:`)];\n\n  // Group entries by namespace while preserving order\n  const namespaceOrder: (string | undefined)[] = [];\n  const byNamespace = new Map<string | undefined, GroupedDisplayEntry[]>();\n  for (const entry of entries) {\n    const ns = entry.namespace;\n    if (!byNamespace.has(ns)) {\n      namespaceOrder.push(ns);\n      byNamespace.set(ns, []);\n    }\n    assertDefined(byNamespace.get(ns), \"namespace group missing\").push(entry);\n  }\n\n  // Track which services have child entries\n  const printedServices = new Set<string>();\n\n  for (const ns of namespaceOrder) {\n    const group = assertDefined(byNamespace.get(ns), \"namespace group missing\");\n    if (ns) {\n      const svcAction = serviceMap.get(ns);\n      const prefix = svcAction ? `${ACTION_SYMBOLS[svcAction]} ` : \"\";\n      out.push(`  ${prefix}${styles.bold(`${ns}:`)}`);\n      printedServices.add(ns);\n      for (const entry of group) {\n        out.push(`    ${formatGroupedDisplayLine(entry)}`);\n      }\n    } else {\n      for (const entry of group) {\n        out.push(`  ${formatGroupedDisplayLine(entry)}`);\n      }\n    }\n  }\n\n  // Append services without child entries as flat entries\n  for (const [name, action] of serviceMap) {\n    if (!printedServices.has(name)) {\n      out.push(`  ${ACTION_SYMBOLS[action]} ${name}`);\n    }\n  }\n\n  return out;\n}\n","/** Resource and trigger named in a `publishEvents` opt-out conflict error. */\nexport type PublishEventsConflict = {\n  /** Resource named in the error, e.g. `TailorDB table \"Order\"`. */\n  resource: string;\n  /** Executor trigger family named in the error, e.g. `record`. */\n  trigger: string;\n  /** What the subscribing executors subscribe to. Defaults to `\"it\"`. */\n  subscribesTo?: string;\n};\n\n/**\n * How each event-publishing resource is named in user-facing messages.\n *\n * Every message naming one of these reads from here, so a conflict error and the\n * confirmation that lists the same resource cannot drift apart.\n */\nexport const eventSourceLabel = {\n  tailorDBType: (name: string) => `TailorDB table \"${name}\"`,\n  resolver: (name: string) => `Resolver \"${name}\"`,\n  idpService: (name: string) => `IdP service \"${name}\"`,\n  workflow: (name: string) => `Workflow \"${name}\"`,\n  workflowJob: (name: string) => `Job \"${name}\"`,\n  workflowJobs: (workflowName: string) => `Jobs of workflow \"${workflowName}\"`,\n} as const;\n\n/** Opt-out conflict details per event-publishing resource. */\nexport const publishEventsConflict = {\n  tailorDBType: (name: string): PublishEventsConflict => ({\n    resource: eventSourceLabel.tailorDBType(name),\n    trigger: \"record\",\n  }),\n  resolver: (name: string): PublishEventsConflict => ({\n    resource: eventSourceLabel.resolver(name),\n    trigger: \"resolverExecuted\",\n  }),\n  idpService: (name: string): PublishEventsConflict => ({\n    resource: eventSourceLabel.idpService(name),\n    trigger: \"idpUser\",\n  }),\n  workflow: (name: string): PublishEventsConflict => ({\n    resource: eventSourceLabel.workflow(name),\n    trigger: \"workflowExecution\",\n  }),\n  workflowJob: (name: string): PublishEventsConflict => ({\n    resource: eventSourceLabel.workflowJob(name),\n    trigger: \"workflowJobExecution\",\n    subscribesTo: \"a workflow that runs it\",\n  }),\n} as const;\n\n/**\n * Build the error raised when a resource opts out of publishing that a\n * subscribing executor needs.\n * @param conflict - Resource, trigger, and subscription target named in the error\n * @returns Error message\n */\nfunction publishEventsConflictError(conflict: PublishEventsConflict): string {\n  const { resource, trigger, subscribesTo = \"it\" } = conflict;\n  return (\n    `${resource} has \"publishEvents: false\", but executors with ${trigger} triggers subscribe to ${subscribesTo}. ` +\n    `Either remove \"publishEvents: false\" or remove the matching executor triggers.`\n  );\n}\n\n/** The part of an executor that decides whether its triggers need events. */\nexport type EventSubscribingExecutor = {\n  /** Whether the executor is disabled, i.e. deployed but never run. */\n  disabled?: boolean | undefined;\n};\n\n/**\n * Whether an executor's triggers count toward the resources it subscribes to.\n *\n * A disabled executor never runs, so it needs no events: counting one would keep\n * publishing enabled on the resource its trigger names, and would reject an\n * explicit `publishEvents: false` that nothing actually contradicts.\n * @param executor - Executor declared by the subscribing config\n * @returns Whether the executor's triggers subscribe to anything\n */\nexport function subscribesToEvents(executor: EventSubscribingExecutor): boolean {\n  return !executor.disabled;\n}\n\n/** Inputs deciding whether a resource publishes events. */\nexport type ResolvePublishEventsParams = {\n  /** `publishEvents` declared on the resource, or undefined when unset. */\n  explicit: boolean | undefined;\n  /** Whether an executor taking part in the same run subscribes to it. */\n  subscribed: boolean;\n  /** Resource and trigger named when an opt-out conflicts with a subscriber. */\n  conflict: PublishEventsConflict;\n};\n\n/**\n * Reject an opt-out that a subscribing executor contradicts.\n *\n * Separate from {@link resolvePublishEvents} so a planner can reject the whole\n * config before issuing any request, rather than partway through.\n * @param params - Declared value, subscriber presence, and conflict error details\n */\nexport function assertNoPublishEventsConflict(params: ResolvePublishEventsParams): void {\n  const { explicit, subscribed, conflict } = params;\n  if (explicit === false && subscribed) {\n    throw new Error(publishEventsConflictError(conflict));\n  }\n}\n\n/**\n * Resolve whether a resource publishes events.\n *\n * An unset value is recomputed from the executors taking part in the run, so\n * removing the last subscribing trigger turns publishing back off. A `deploy`\n * covering several configs counts a subscriber in any of them, so a resource\n * shared across configs needs `publishEvents: true` on the resource itself only\n * to keep publishing when the subscribing config is deployed on its own.\n * @param params - Declared value, subscriber presence, and conflict error details\n * @returns Whether the resource publishes events\n */\nexport function resolvePublishEvents(params: ResolvePublishEventsParams): boolean {\n  assertNoPublishEventsConflict(params);\n  return params.explicit ?? params.subscribed;\n}\n","import { createPermissionNormalizer, hasOmittedPermit } from \"#/parser/service/permission\";\nimport type { IdPPermission as RawIdPPermission } from \"#/types/idp.generated\";\nimport type {\n  StandardIdPPermission,\n  StandardIdPActionPermission,\n  StandardIdPPermissionCondition,\n} from \"./types\";\n\ntype PermissionOperator = \"=\" | \"!=\" | \"in\" | \"not in\";\n\nconst { normalizeActionPermission } = createPermissionNormalizer<\n  PermissionOperator,\n  StandardIdPPermissionCondition\n>({\n  \"=\": \"eq\",\n  \"!=\": \"ne\",\n  in: \"in\",\n  \"not in\": \"nin\",\n});\n\n/**\n * Normalize a single IdP action permission into the standard format.\n * @param permission - Raw permission definition\n * @returns Normalized action permission\n */\nexport function normalizeIdPActionPermission(permission: unknown): StandardIdPActionPermission {\n  return normalizeActionPermission(permission);\n}\n\n/**\n * Normalize raw IdP permission into standard form.\n * @param permission - Raw IdP permission from user config\n * @returns Normalized IdP permission\n */\nexport function normalizeIdPPermission(permission: RawIdPPermission): StandardIdPPermission {\n  return {\n    create: permission.create.map((p) => normalizeIdPActionPermission(p)),\n    read: permission.read.map((p) => normalizeIdPActionPermission(p)),\n    update: permission.update.map((p) => normalizeIdPActionPermission(p)),\n    delete: permission.delete.map((p) => normalizeIdPActionPermission(p)),\n    sendPasswordResetEmail: (permission.sendPasswordResetEmail ?? []).map((p) =>\n      normalizeIdPActionPermission(p),\n    ),\n    unenrollMfa: (permission.unenrollMfa ?? []).map((p) => normalizeIdPActionPermission(p)),\n  } as StandardIdPPermission;\n}\n\n/**\n * Parse raw IdP permission, returning undefined if not set.\n * @param rawPermission - Raw permission from parsed config\n * @returns Normalized permission or undefined\n */\nexport function parseIdPPermission(\n  rawPermission: RawIdPPermission | undefined,\n): StandardIdPPermission | undefined {\n  if (!rawPermission) {\n    return undefined;\n  }\n  return normalizeIdPPermission(rawPermission);\n}\n\n/**\n * Find object-format IdP permission rules that omit `permit` (which defaults\n * to `deny` there, unlike the array shorthand), so the CLI can warn about them.\n * @param permission - Raw IdP permission from user config\n * @returns Locations of offending rules, e.g. `read[0]`\n */\nexport function findOmittedPermitRules(permission: RawIdPPermission | undefined): string[] {\n  if (!permission) {\n    return [];\n  }\n  const locations: string[] = [];\n  for (const action of Object.keys(permission) as Array<keyof typeof permission>) {\n    permission[action]?.forEach((rule: unknown, index: number) => {\n      if (hasOmittedPermit(rule)) {\n        locations.push(`${String(action)}[${index}]`);\n      }\n    });\n  }\n  return locations;\n}\n","import { fromJson, type MessageInitShape } from \"@bufbuild/protobuf\";\nimport { ValueSchema } from \"@bufbuild/protobuf/wkt\";\nimport {\n  type CreateIdPClientRequestSchema,\n  type CreateIdPServiceRequestSchema,\n  type DeleteIdPClientRequestSchema,\n  type DeleteIdPServiceRequestSchema,\n  type UpdateIdPServiceRequestSchema,\n} from \"@tailor-platform/tailor-proto/idp_pb\";\nimport {\n  IdPLang,\n  IdPPermissionOperator,\n  IdPPermissionPermit,\n  type IdPPermissionConditionSchema as ProtoIdPPermissionConditionSchema,\n  type IdPPermissionOperandSchema as ProtoIdPPermissionOperandSchema,\n  type IdPPermissionPolicySchema as ProtoIdPPermissionPolicySchema,\n  type IdPPermissionSchema as ProtoIdPPermissionSchema,\n  type IdPService as ProtoIdPService,\n} from \"@tailor-platform/tailor-proto/idp_resource_pb\";\nimport {\n  fetchAllTolerant,\n  getOrNull,\n  resolveStaticWebsiteUrls,\n  type OperatorClient,\n} from \"#/cli/shared/client\";\nimport { CLIError, internalError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { publishEventsConflict, resolvePublishEvents } from \"#/cli/shared/publish-events\";\nimport { ALL_EMAIL_DOMAINS, hasImplicitAllEmailDomains } from \"#/parser/service/idp/email-domains\";\nimport { findOmittedPermitRules, parseIdPPermission } from \"#/parser/service/idp/permission\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { createChangeSet } from \"./change-set\";\nimport { areNormalizedEqual } from \"./compare\";\nimport {\n  addDependencyRecords,\n  buildMetaRequest,\n  type DependentAppsByResource,\n  eventSourceKey,\n  hasMatchingSdkVersion,\n  type MetadataLabelWrite,\n  resourceTrn,\n  writeMetadataLabels,\n} from \"./label\";\nimport {\n  fetchExistingResourcesWithLabels,\n  trackDesiredResourceOwnership,\n  trackRemainingResourceOwner,\n} from \"./owned-resource\";\nimport { expectedLocalStaticWebsiteNames } from \"./staticwebsite\";\nimport type { ApplyPhase, PlanContext } from \"#/cli/commands/deploy/types\";\nimport type {\n  IdPPermissionOperand,\n  StandardIdPActionPermission,\n  StandardIdPPermission,\n  StandardIdPPermissionCondition,\n} from \"#/parser/service/idp/types\";\nimport type { IdP, IdPLang as IdPLangInput } from \"#/types/idp.generated\";\nimport type { OwnerConflict, UnmanagedResource } from \"./confirm\";\n\ntype IdPServiceMutationRequest = {\n  workspaceId?: string;\n  namespaceName?: string;\n  userAuthPolicy?: { allowedReturnOrigins?: string[] } | undefined;\n};\n\nasync function resolveServiceReturnOrigins(\n  client: OperatorClient,\n  request: IdPServiceMutationRequest,\n): Promise<void> {\n  const policy = request.userAuthPolicy;\n  const originals = policy?.allowedReturnOrigins;\n  if (!policy || !originals?.length) {\n    return;\n  }\n  const resolved = await resolveStaticWebsiteUrls(\n    client,\n    assertDefined(request.workspaceId, \"request missing workspaceId\"),\n    originals,\n    `IdP service \"${request.namespaceName ?? \"\"}\" allowedReturnOrigins`,\n  );\n  // resolveStaticWebsiteUrls warn-and-drops unresolvable entries, which is fine\n  // for CORS but would silently clear an authoritative field here (UpdateIdP is\n  // a full replacement, and `enable_mfa: true` requires ≥1 origin). Fail fast.\n  if (resolved.length !== originals.length) {\n    throw CLIError({\n      code: \"IDP_RETURN_ORIGIN_UNRESOLVED\",\n      message: `IdP service \"${request.namespaceName ?? \"\"}\" allowedReturnOrigins: ${originals.length - resolved.length} of ${originals.length} entries could not be resolved.`,\n      suggestion: 'Check that each \"<name>:url\" entry refers to a deployed static website.',\n    });\n  }\n  policy.allowedReturnOrigins = resolved;\n}\n\n/**\n * Build the vault name for an IdP client.\n * @param namespaceName - IdP namespace name\n * @param clientName - IdP client name\n * @returns Vault name\n */\nexport function idpClientVaultName(namespaceName: string, clientName: string) {\n  return `idp-${namespaceName}-${clientName}`;\n}\n\n/**\n * Build the secret name for an IdP client.\n * @param namespaceName - IdP namespace name\n * @param clientName - IdP client name\n * @returns Secret name\n */\nexport function idpClientSecretName(namespaceName: string, clientName: string) {\n  return `client-secret-${namespaceName}-${clientName}`;\n}\n\n/**\n * Apply IdP-related changes for the given phase.\n * @param client - Operator client instance\n * @param result - Planned IdP changes\n * @param phase - Apply phase\n * @returns Promise that resolves when IdP changes are applied\n */\nexport async function applyIdP(\n  client: OperatorClient,\n  result: Awaited<ReturnType<typeof planIdP>>,\n  phase: Exclude<ApplyPhase, \"delete\"> = \"create-update\",\n) {\n  const { changeSet } = result;\n  if (phase === \"create-update\") {\n    // Services. An unchanged service still gets its labels written, because its\n    // dependency records can change while its definition does not.\n    await Promise.all([\n      ...changeSet.service.creates.map(async (create) => {\n        await resolveServiceReturnOrigins(client, create.request);\n        await client.createIdPService(create.request);\n        await writeMetadataLabels(client, create.metaRequest);\n      }),\n      ...changeSet.service.updates.map(async (update) => {\n        await resolveServiceReturnOrigins(client, update.request);\n        await client.updateIdPService(update.request);\n        await writeMetadataLabels(client, update.metaRequest);\n      }),\n      ...changeSet.service.unchanged.flatMap((entry) =>\n        entry.metaRequest ? [writeMetadataLabels(client, entry.metaRequest)] : [],\n      ),\n    ]);\n\n    // Clients\n    await Promise.all([\n      ...changeSet.client.creates.map(async (create) => {\n        const resp = await client.createIdPClient(create.request);\n        if (resp.client?.clientSecret) logger.registerSecret(resp.client.clientSecret);\n\n        // Create the secret manager vault and secret\n        const vaultName = idpClientVaultName(\n          assertDefined(create.request.namespaceName, \"request missing namespaceName\"),\n          create.request.client?.name || \"\",\n        );\n        const secretName = idpClientSecretName(\n          assertDefined(create.request.namespaceName, \"request missing namespaceName\"),\n          create.request.client?.name || \"\",\n        );\n        await client.createSecretManagerVault({\n          workspaceId: create.request.workspaceId,\n          secretmanagerVaultName: vaultName,\n        });\n        await client.createSecretManagerSecret({\n          workspaceId: create.request.workspaceId,\n          secretmanagerVaultName: vaultName,\n          secretmanagerSecretName: secretName,\n          secretmanagerSecretValue: resp.client?.clientSecret,\n        });\n      }),\n      ...changeSet.client.updates.map(async (update) => {\n        // Ensure the vault and secret exist\n        const vaultName = idpClientVaultName(update.namespaceName, update.name);\n        const secretName = idpClientSecretName(update.namespaceName, update.name);\n        const vault = await getOrNull(async () => {\n          return await client.getSecretManagerVault({\n            workspaceId: update.workspaceId,\n            secretmanagerVaultName: vaultName,\n          });\n        });\n        if (vault) return;\n        await client.createSecretManagerVault({\n          workspaceId: update.workspaceId,\n          secretmanagerVaultName: vaultName,\n        });\n        await client.createSecretManagerSecret({\n          workspaceId: update.workspaceId,\n          secretmanagerVaultName: vaultName,\n          secretmanagerSecretName: secretName,\n          secretmanagerSecretValue: update.clientSecret,\n        });\n      }),\n    ]);\n  } else if (phase === \"delete-resources\") {\n    // Delete in reverse order of dependencies\n    // Clients\n    await Promise.all(\n      changeSet.client.deletes.map(async (del) => {\n        await client.deleteIdPClient(del.request);\n\n        // Delete the secret manager vault and secret\n        const vaultName = `idp-${del.request.namespaceName}-${del.request.name}`;\n        await client.deleteSecretManagerVault({\n          workspaceId: del.request.workspaceId,\n          secretmanagerVaultName: vaultName,\n        });\n      }),\n    );\n  } else {\n    // Services only\n    await Promise.all(changeSet.service.deletes.map((del) => client.deleteIdPService(del.request)));\n  }\n}\n\n/**\n * Plan IdP-related changes based on current and desired state.\n * @param context - Planning context\n * @returns Planned changes and metadata\n */\nexport async function planIdP(context: PlanContext) {\n  const {\n    client,\n    workspaceId,\n    application,\n    forRemoval,\n    forceApplyAll = false,\n    idpUserTriggerTargets,\n    dependentApps,\n    runAppIds,\n  } = context;\n  const idps = forRemoval ? [] : application.idpServices;\n  const expectedLocalWebsites = expectedLocalStaticWebsiteNames(context);\n  const {\n    changeSet: serviceChangeSet,\n    conflicts,\n    unmanaged,\n    resourceOwners,\n  } = await planServices(\n    client,\n    workspaceId,\n    application.name,\n    application.id,\n    idps,\n    idpUserTriggerTargets ?? new Set<string>(),\n    expectedLocalWebsites,\n    { dependentApps, runAppIds },\n  );\n  const deletedServices = serviceChangeSet.deletes.map((del) => del.name);\n  const clientChangeSet = await planClients(\n    client,\n    workspaceId,\n    idps,\n    deletedServices,\n    forceApplyAll,\n  );\n\n  return {\n    changeSet: {\n      service: serviceChangeSet,\n      client: clientChangeSet,\n    },\n    conflicts,\n    unmanaged,\n    resourceOwners,\n  };\n}\n\ntype CreateService = {\n  name: string;\n  request: MessageInitShape<typeof CreateIdPServiceRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype UpdateService = {\n  name: string;\n  request: MessageInitShape<typeof UpdateIdPServiceRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype DeleteService = {\n  name: string;\n  request: MessageInitShape<typeof DeleteIdPServiceRequestSchema>;\n};\n\n/**\n * An IdP service whose definition is unchanged but whose dependency records are\n * not. The plan shows it as unchanged; apply still writes its labels.\n */\ntype UnchangedService = {\n  name: string;\n  metaRequest?: MetadataLabelWrite;\n};\n\ntype ComparableIdPService = {\n  authorization: string | undefined;\n  lang: IdPLang;\n  userAuthPolicy: Record<string, unknown> | undefined;\n  publishEvents: boolean;\n  disableGqlOperations: Record<string, boolean> | undefined;\n  emailConfig: Record<string, string> | undefined;\n  permission: MessageInitShape<typeof ProtoIdPPermissionSchema> | undefined;\n};\n\nfunction normalizeComparableUserAuthPolicy(\n  policy: ProtoIdPService[\"userAuthPolicy\"] | IdP[\"userAuthPolicy\"] | undefined,\n): Record<string, unknown> | undefined {\n  return {\n    useNonEmailIdentifier: policy?.useNonEmailIdentifier ?? false,\n    allowSelfPasswordReset: policy?.allowSelfPasswordReset ?? false,\n    passwordRequireUppercase: policy?.passwordRequireUppercase ?? false,\n    passwordRequireLowercase: policy?.passwordRequireLowercase ?? false,\n    passwordRequireNonAlphanumeric: policy?.passwordRequireNonAlphanumeric ?? false,\n    passwordRequireNumeric: policy?.passwordRequireNumeric ?? false,\n    // The platform fills an omitted policy with password_min_length 6 and\n    // password_max_length 4096 and echoes those back; it also coerces an\n    // explicit 0 to the same defaults, which is why these use || (not ??) —\n    // every falsy local value must compare equal to the stored defaults.\n    passwordMinLength: policy?.passwordMinLength || 6,\n    passwordMaxLength: policy?.passwordMaxLength || 4096,\n    // The platform lowercases and deduplicates domains before storing and echoes\n    // the normalized list back, so comparing the raw local list would report a\n    // permanent diff for an entry written in mixed case.\n    allowedEmailDomains: [\n      ...new Set((policy?.allowedEmailDomains ?? []).map((domain) => domain.toLowerCase())),\n    ].toSorted(),\n    allowGoogleOauth: policy?.allowGoogleOauth ?? false,\n    disablePasswordAuth: policy?.disablePasswordAuth ?? false,\n    allowMicrosoftOauth: policy?.allowMicrosoftOauth ?? false,\n    enableMfa: policy?.enableMfa ?? false,\n    requireMfa: policy?.requireMfa ?? false,\n    allowedReturnOrigins: (policy?.allowedReturnOrigins ?? []).toSorted(),\n    mfaIssuer: policy?.mfaIssuer ?? \"\",\n  };\n}\n\nfunction normalizeComparableDisableGqlOperations(\n  value: ProtoIdPService[\"disableGqlOperations\"] | Record<string, boolean> | undefined,\n): Record<string, boolean> | undefined {\n  return {\n    create: value?.create ?? false,\n    update: value?.update ?? false,\n    delete: value?.delete ?? false,\n    read: value?.read ?? false,\n    sendPasswordResetEmail: value?.sendPasswordResetEmail ?? false,\n    requestMfaSettingsUrl: value?.requestMfaSettingsUrl ?? false,\n    unenrollMfa: value?.unenrollMfa ?? false,\n  };\n}\n\nfunction normalizeComparableEmailConfig(\n  value: ProtoIdPService[\"emailConfig\"] | Record<string, string> | undefined,\n): Record<string, string> | undefined {\n  return {\n    fromName: value?.fromName ?? \"\",\n    passwordResetSubject: value?.passwordResetSubject ?? \"\",\n  };\n}\n\nfunction normalizeComparableIdPService(\n  input: Pick<\n    ComparableIdPService,\n    | \"authorization\"\n    | \"lang\"\n    | \"userAuthPolicy\"\n    | \"publishEvents\"\n    | \"disableGqlOperations\"\n    | \"emailConfig\"\n    | \"permission\"\n  >,\n): ComparableIdPService {\n  return {\n    authorization: input.authorization || undefined,\n    lang: input.lang === IdPLang.UNSPECIFIED ? IdPLang.EN : input.lang,\n    userAuthPolicy: input.userAuthPolicy,\n    publishEvents: input.publishEvents,\n    disableGqlOperations: input.disableGqlOperations,\n    emailConfig: input.emailConfig,\n    permission: input.permission,\n  };\n}\n\nfunction normalizeComparablePermission(\n  permission: ProtoIdPService[\"permission\"],\n): MessageInitShape<typeof ProtoIdPPermissionSchema> | undefined {\n  if (!permission) {\n    return undefined;\n  }\n  if (\n    permission.create.length === 0 &&\n    permission.read.length === 0 &&\n    permission.update.length === 0 &&\n    permission.delete.length === 0 &&\n    permission.sendPasswordResetEmail.length === 0 &&\n    permission.unenrollMfa.length === 0\n  ) {\n    return undefined;\n  }\n  const normalizePolicy = (policy: (typeof permission.create)[number]) => ({\n    conditions: policy.conditions.map((c) => ({\n      left: c.left ? { kind: c.left.kind } : undefined,\n      operator: c.operator,\n      right: c.right ? { kind: c.right.kind } : undefined,\n    })),\n    permit: policy.permit,\n    // Platform returns an empty string for an unset description; treat it the same as omitted.\n    description: policy.description || undefined,\n  });\n  return {\n    create: permission.create.map(normalizePolicy),\n    read: permission.read.map(normalizePolicy),\n    update: permission.update.map(normalizePolicy),\n    delete: permission.delete.map(normalizePolicy),\n    sendPasswordResetEmail: permission.sendPasswordResetEmail.map(normalizePolicy),\n    unenrollMfa: permission.unenrollMfa.map(normalizePolicy),\n  };\n}\n\nfunction areIdPServicesEqual(existing: ProtoIdPService, desired: ComparableIdPService): boolean {\n  return areNormalizedEqual(\n    normalizeComparableIdPService({\n      authorization: existing.authorization,\n      lang: existing.lang,\n      userAuthPolicy: normalizeComparableUserAuthPolicy(existing.userAuthPolicy),\n      publishEvents: existing.publishUserEvents,\n      disableGqlOperations: normalizeComparableDisableGqlOperations(existing.disableGqlOperations),\n      emailConfig: normalizeComparableEmailConfig(existing.emailConfig),\n      permission: normalizeComparablePermission(existing.permission),\n    }),\n    desired,\n  );\n}\n\nasync function planServices(\n  client: OperatorClient,\n  workspaceId: string,\n  appName: string,\n  appId: string | undefined,\n  idps: ReadonlyArray<IdP>,\n  idpUserTriggerTargets: ReadonlySet<string>,\n  expectedLocalWebsites: ReadonlySet<string>,\n  records: {\n    dependentApps: DependentAppsByResource | undefined;\n    runAppIds: ReadonlySet<string> | undefined;\n  },\n) {\n  const changeSet = createChangeSet<\n    CreateService,\n    UpdateService,\n    DeleteService,\n    never,\n    UnchangedService\n  >(\"IdP services\");\n  const conflicts: OwnerConflict[] = [];\n  const unmanaged: UnmanagedResource[] = [];\n  const resourceOwners = new Set<string>();\n\n  const existingServices = await fetchExistingResourcesWithLabels({\n    client,\n    fetchPage: async (pageToken, maxPageSize) => {\n      const { idpServices, nextPageToken } = await client.listIdPServices({\n        workspaceId,\n        pageToken,\n        pageSize: maxPageSize,\n      });\n      return [idpServices, nextPageToken];\n    },\n    getName: (resource) => resource.namespace?.name,\n    getTrn: (name) => resourceTrn(workspaceId, \"idp\", name),\n  });\n\n  for (const idp of idps) {\n    const namespaceName = idp.name;\n    const existing = existingServices[namespaceName];\n    const metaRequest = addDependencyRecords(\n      await buildMetaRequest({\n        trn: resourceTrn(workspaceId, \"idp\", namespaceName),\n        appName,\n        appId,\n      }),\n      {\n        key: eventSourceKey.idp(namespaceName),\n        dependentApps: records.dependentApps,\n        runAppIds: records.runAppIds,\n        pinned: idp.publishEvents !== undefined,\n      },\n    );\n    let authorization: string | undefined;\n    switch (idp.authorization) {\n      case \"insecure\":\n        authorization = \"true==true\";\n        break;\n      case \"loggedIn\":\n        authorization = \"user != null && size(user.id) > 0\";\n        break;\n      case undefined:\n        authorization = undefined;\n        break;\n      default:\n        authorization = idp.authorization.cel;\n        break;\n    }\n\n    const lang = convertLang(idp.lang);\n    const userAuthPolicy = idp.userAuthPolicy;\n    const publishEvents = resolvePublishEvents({\n      explicit: idp.publishEvents,\n      subscribed: idpUserTriggerTargets.has(namespaceName),\n      conflict: publishEventsConflict.idpService(namespaceName),\n    });\n    const emailConfig = idp.emailConfig;\n    if (!idp.permission) {\n      logger.warn(`IdP service \"${namespaceName}\" has no permission configured.`);\n    }\n    const omittedPermitLocations = findOmittedPermitRules(idp.permission);\n    if (omittedPermitLocations.length > 0) {\n      logger.warn(\n        `IdP service \"${namespaceName}\" has permission rule(s) ${omittedPermitLocations.join(\", \")} in object form without an explicit \"permit\"; they default to \"deny\". Set permit: true (allow) or permit: false (deny) to silence this warning.`,\n      );\n    }\n    if (hasImplicitAllEmailDomains(userAuthPolicy)) {\n      logger.warn(\n        `IdP service \"${namespaceName}\" leaves userAuthPolicy.allowedEmailDomains empty, which currently allows every email domain. The platform will stop treating an empty list as \"allow every domain\", so set allowedEmailDomains: [\"${ALL_EMAIL_DOMAINS}\"] to keep that behavior, or list the domains you accept.`,\n      );\n    }\n    const parsedPermission = parseIdPPermission(idp.permission);\n    const protoPermission = parsedPermission ? protoIdPPermission(parsedPermission) : undefined;\n    const resolvedReturnOrigins = await resolveStaticWebsiteUrls(\n      client,\n      workspaceId,\n      userAuthPolicy?.allowedReturnOrigins ? [...userAuthPolicy.allowedReturnOrigins] : [],\n      `IdP service \"${namespaceName}\" allowedReturnOrigins`,\n      { expectedLocalNames: expectedLocalWebsites },\n    );\n    const userAuthPolicyForCompare = userAuthPolicy\n      ? { ...userAuthPolicy, allowedReturnOrigins: resolvedReturnOrigins }\n      : userAuthPolicy;\n    const desired = normalizeComparableIdPService({\n      authorization,\n      lang,\n      userAuthPolicy: normalizeComparableUserAuthPolicy(userAuthPolicyForCompare),\n      publishEvents,\n      disableGqlOperations: normalizeComparableDisableGqlOperations(\n        convertGqlOperationsToDisable(idp.gqlOperations),\n      ),\n      emailConfig: normalizeComparableEmailConfig(emailConfig),\n      permission: protoPermission,\n    });\n    const request = {\n      workspaceId,\n      namespaceName,\n      authorization,\n      lang,\n      userAuthPolicy,\n      publishUserEvents: publishEvents,\n      disableGqlOperations: convertGqlOperationsToDisable(idp.gqlOperations),\n      emailConfig,\n      permission: protoPermission,\n    };\n\n    if (existing) {\n      const owned = trackDesiredResourceOwnership({\n        labels: existing.allLabels,\n        ownerLabel: existing.label,\n        appName,\n        appId,\n        resourceType: \"IdP service\",\n        resourceName: idp.name,\n        conflicts,\n        unmanaged,\n      });\n      if (\n        owned &&\n        hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) &&\n        areIdPServicesEqual(existing.resource, desired)\n      ) {\n        changeSet.unchanged.push({ name: namespaceName, metaRequest });\n      } else {\n        changeSet.updates.push({\n          name: namespaceName,\n          request,\n          metaRequest,\n        });\n      }\n      delete existingServices[namespaceName];\n    } else {\n      changeSet.creates.push({\n        name: namespaceName,\n        request,\n        metaRequest,\n      });\n    }\n  }\n  Object.entries(existingServices).forEach(([namespaceName]) => {\n    const entry = existingServices[namespaceName];\n    const owned = trackRemainingResourceOwner({\n      labels: entry?.allLabels,\n      ownerLabel: entry?.label,\n      appName,\n      appId,\n      resourceOwners,\n    });\n    if (owned) {\n      changeSet.deletes.push({\n        name: namespaceName,\n        request: {\n          workspaceId,\n          namespaceName,\n        },\n      });\n    }\n  });\n\n  return { changeSet, conflicts, unmanaged, resourceOwners };\n}\n\ntype CreateClient = {\n  name: string;\n  request: MessageInitShape<typeof CreateIdPClientRequestSchema>;\n};\n\ntype UpdateClient = {\n  name: string;\n  workspaceId: string;\n  namespaceName: string;\n  clientSecret: string;\n};\n\ntype DeleteClient = {\n  name: string;\n  request: MessageInitShape<typeof DeleteIdPClientRequestSchema>;\n};\n\nasync function planClients(\n  client: OperatorClient,\n  workspaceId: string,\n  idps: ReadonlyArray<IdP>,\n  deletedServices: string[],\n  forceApplyAll = false,\n) {\n  const changeSet = createChangeSet<CreateClient, UpdateClient, DeleteClient>(\"IdP clients\");\n\n  const fetchClients = (namespaceName: string) => {\n    return fetchAllTolerant(async (pageToken, maxPageSize) => {\n      const { clients, nextPageToken } = await client.listIdPClients({\n        workspaceId,\n        namespaceName,\n        pageToken,\n        pageSize: maxPageSize,\n      });\n      return [clients, nextPageToken];\n    });\n  };\n\n  const clientsByIdp = await Promise.all(idps.map((idp) => fetchClients(idp.name)));\n  for (const [i, idp] of idps.entries()) {\n    const namespaceName = idp.name;\n    const existingClients = assertDefined(\n      clientsByIdp[i],\n      \"clientsByIdp missing entry for idp index\",\n    );\n    const existingNameMap = new Map<string, string>();\n    existingClients.forEach((client) => {\n      existingNameMap.set(client.name, client.clientSecret);\n      logger.registerSecret(client.clientSecret);\n    });\n    for (const name of idp.clients) {\n      if (existingNameMap.has(name)) {\n        if (forceApplyAll) {\n          changeSet.updates.push({\n            name,\n            workspaceId,\n            namespaceName,\n            clientSecret: existingNameMap.get(name) ?? \"\",\n          });\n        } else {\n          changeSet.unchanged.push({\n            name,\n          });\n        }\n        existingNameMap.delete(name);\n      } else {\n        changeSet.creates.push({\n          name,\n          request: {\n            workspaceId,\n            namespaceName,\n            client: {\n              name,\n            },\n          },\n        });\n      }\n    }\n    existingNameMap.forEach((_clientSecret, name) => {\n      changeSet.deletes.push({\n        name,\n        request: {\n          workspaceId,\n          namespaceName,\n          name,\n        },\n      });\n    });\n  }\n\n  const deletedClientsByService = await Promise.all(\n    deletedServices.map((namespaceName) => fetchClients(namespaceName)),\n  );\n  for (const [i, namespaceName] of deletedServices.entries()) {\n    assertDefined(\n      deletedClientsByService[i],\n      \"deletedClientsByService missing entry for service index\",\n    ).forEach((client) => {\n      logger.registerSecret(client.clientSecret);\n      changeSet.deletes.push({\n        name: client.name,\n        request: {\n          workspaceId,\n          namespaceName,\n          name: client.name,\n        },\n      });\n    });\n  }\n  return changeSet;\n}\n\nfunction convertLang(lang: IdPLangInput | undefined): IdPLang {\n  switch (lang) {\n    case \"en\":\n      return IdPLang.EN;\n    case \"ja\":\n      return IdPLang.JA;\n    default:\n      return IdPLang.UNSPECIFIED;\n  }\n}\n\n// Converts gqlOperations (enabled semantics, default true) to\n// disableGqlOperations (disabled semantics) for the Platform API.\n// Undefined fields are treated as true (enabled), matching TailorDB behavior.\nfunction convertGqlOperationsToDisable(\n  gqlOperations: IdP[\"gqlOperations\"],\n): Record<string, boolean> | undefined {\n  if (!gqlOperations) {\n    return undefined;\n  }\n  return {\n    create: gqlOperations.create === false,\n    update: gqlOperations.update === false,\n    delete: gqlOperations.delete === false,\n    read: gqlOperations.read === false,\n    sendPasswordResetEmail: gqlOperations.sendPasswordResetEmail === false,\n    requestMfaSettingsUrl: gqlOperations.requestMfaSettingsUrl === false,\n    unenrollMfa: gqlOperations.unenrollMfa === false,\n  };\n}\n\nfunction protoIdPPermission(\n  permission: StandardIdPPermission,\n): MessageInitShape<typeof ProtoIdPPermissionSchema> {\n  return {\n    create: permission.create.map((p) => protoIdPPolicy(p)),\n    read: permission.read.map((p) => protoIdPPolicy(p)),\n    update: permission.update.map((p) => protoIdPPolicy(p)),\n    delete: permission.delete.map((p) => protoIdPPolicy(p)),\n    sendPasswordResetEmail: permission.sendPasswordResetEmail.map((p) => protoIdPPolicy(p)),\n    unenrollMfa: permission.unenrollMfa.map((p) => protoIdPPolicy(p)),\n  };\n}\n\nfunction protoIdPPolicy(\n  policy: StandardIdPActionPermission,\n): MessageInitShape<typeof ProtoIdPPermissionPolicySchema> {\n  let permit: IdPPermissionPermit;\n  switch (policy.permit) {\n    case \"allow\":\n      permit = IdPPermissionPermit.ALLOW;\n      break;\n    case \"deny\":\n      permit = IdPPermissionPermit.DENY;\n      break;\n    default:\n      throw internalError(`Unknown permission: ${policy.permit satisfies never}`);\n  }\n  return {\n    conditions: policy.conditions.map((cond) => protoIdPCondition(cond)),\n    permit,\n    description: policy.description,\n  };\n}\n\nfunction protoIdPCondition(\n  condition: StandardIdPPermissionCondition,\n): MessageInitShape<typeof ProtoIdPPermissionConditionSchema> {\n  const [left, operator, right] = condition;\n\n  const l = protoIdPOperand(left);\n  const r = protoIdPOperand(right);\n  let op: IdPPermissionOperator;\n  switch (operator) {\n    case \"eq\":\n      op = IdPPermissionOperator.EQ;\n      break;\n    case \"ne\":\n      op = IdPPermissionOperator.NE;\n      break;\n    case \"in\":\n      op = IdPPermissionOperator.IN;\n      break;\n    case \"nin\":\n      op = IdPPermissionOperator.NIN;\n      break;\n    default:\n      throw internalError(`Unknown operator: ${operator satisfies never}`);\n  }\n  return {\n    left: l,\n    operator: op,\n    right: r,\n  };\n}\n\nfunction protoIdPOperand(\n  operand: IdPPermissionOperand,\n): MessageInitShape<typeof ProtoIdPPermissionOperandSchema> {\n  if (typeof operand === \"object\" && !Array.isArray(operand)) {\n    if (\"user\" in operand) {\n      return { kind: { case: \"userField\", value: operand.user } };\n    } else if (\"idpUser\" in operand) {\n      return { kind: { case: \"idpUserField\", value: operand.idpUser } };\n    } else if (\"newIdpUser\" in operand) {\n      return { kind: { case: \"newIdpUserField\", value: operand.newIdpUser } };\n    } else if (\"oldIdpUser\" in operand) {\n      return { kind: { case: \"oldIdpUserField\", value: operand.oldIdpUser } };\n    } else {\n      throw internalError(`Unknown operand: ${JSON.stringify(operand)}`);\n    }\n  }\n\n  return {\n    kind: {\n      case: \"value\",\n      value: fromJson(ValueSchema, operand),\n    },\n  };\n}\n","import { fromJson, type MessageInitShape } from \"@bufbuild/protobuf\";\nimport { ValueSchema } from \"@bufbuild/protobuf/wkt\";\nimport {\n  AuthHookPoint,\n  AuthIDPConfig_AuthType,\n  AuthOAuth2Client_ClientType,\n  AuthOAuth2Client_GrantType,\n  AuthSCIMAttribute_Mutability,\n  AuthSCIMAttribute_Type,\n  AuthSCIMAttribute_Uniqueness,\n  AuthSCIMConfig_AuthorizationType,\n  type AuthIDPConfig_ConfigSchema,\n  TenantProviderConfig_TenantProviderType,\n  UserProfileProviderConfig_UserProfileProviderType,\n  AuthIDPConfigSchema,\n  type AuthOAuth2ClientSchema,\n  type AuthSCIMAttributeSchema,\n  type AuthSCIMConfigSchema,\n  type AuthSCIMResourceSchema,\n  TenantProviderConfigSchema,\n  UserProfileProviderConfigSchema,\n} from \"@tailor-platform/tailor-proto/auth_resource_pb\";\nimport { type AuthService } from \"#/cli/services/auth/service\";\nimport {\n  fetchAllTolerant,\n  getOrNull,\n  resolveStaticWebsiteUrls,\n  type OperatorClient,\n} from \"#/cli/shared/client\";\nimport { CLIError, internalError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { applyAuthConnections, planAuthConnections } from \"./auth-connection\";\nimport { createChangeSet, type ChangeSet, type HasName } from \"./change-set\";\nimport {\n  areNormalizedEqual,\n  normalizeProtoConfig,\n  normalizeStringArray,\n  toComparableProtoJson,\n} from \"./compare\";\nimport { authHookFunctionName } from \"./function-registry\";\nimport {\n  formatChangeEntriesWithFunctionRegistry,\n  type GroupedDisplayEntry,\n  type RelatedFunctionRegistryChanges,\n} from \"./grouped-display\";\nimport { idpClientSecretName, idpClientVaultName } from \"./idp\";\nimport {\n  buildMetaRequest,\n  type MetadataLabelWrite,\n  resourceTrn,\n  writeMetadataLabels,\n} from \"./label\";\nimport {\n  fetchExistingResourcesWithLabels,\n  trackDesiredResourceOwnership,\n  trackRemainingResourceOwner,\n} from \"./owned-resource\";\nimport { expectedLocalStaticWebsiteNames } from \"./staticwebsite\";\nimport type { ApplyPhase, PlanContext } from \"#/cli/commands/deploy/types\";\nimport type { AuthAttributeValue } from \"#/configure/services/auth/types\";\nimport type {\n  BuiltinIdP,\n  IdProvider as IdProviderConfig,\n  OAuth2Client,\n  SCIMAttribute,\n  SCIMConfig,\n  SCIMResource,\n  TenantProvider as TenantProviderConfig,\n} from \"#/types/auth.generated\";\nimport type { OwnerConflict, UnmanagedResource } from \"./confirm\";\nimport type {\n  CreateAuthHookRequestSchema,\n  CreateAuthIDPConfigRequestSchema,\n  CreateAuthMachineUserRequestSchema,\n  CreateAuthOAuth2ClientRequestSchema,\n  CreateAuthSCIMConfigRequestSchema,\n  CreateAuthSCIMResourceRequestSchema,\n  CreateAuthServiceRequestSchema,\n  CreateTenantConfigRequestSchema,\n  CreateUserProfileConfigRequestSchema,\n  DeleteAuthHookRequestSchema,\n  DeleteAuthIDPConfigRequestSchema,\n  DeleteAuthMachineUserRequestSchema,\n  DeleteAuthOAuth2ClientRequestSchema,\n  DeleteAuthSCIMConfigRequestSchema,\n  DeleteAuthSCIMResourceRequestSchema,\n  DeleteAuthServiceRequestSchema,\n  DeleteTenantConfigRequestSchema,\n  DeleteUserProfileConfigRequestSchema,\n  UpdateAuthHookRequestSchema,\n  UpdateAuthIDPConfigRequestSchema,\n  UpdateAuthMachineUserRequestSchema,\n  UpdateAuthOAuth2ClientRequestSchema,\n  UpdateAuthSCIMConfigRequestSchema,\n  UpdateAuthSCIMResourceRequestSchema,\n  UpdateAuthServiceRequestSchema,\n  UpdateTenantConfigRequestSchema,\n  UpdateUserProfileConfigRequestSchema,\n} from \"@tailor-platform/tailor-proto/auth_pb\";\n\ntype AuthApplyPhase =\n  | Exclude<ApplyPhase, \"delete\">\n  | \"create-update-prerequisites\"\n  | \"create-update-dependents\";\n\n/**\n * Apply auth-related changes for the given phase.\n * @param client - Operator client instance\n * @param result - Planned auth changes\n * @param phase - Apply phase (defaults to \"create-update\")\n * @returns Promise that resolves when auth changes are applied\n */\nexport async function applyAuth(\n  client: OperatorClient,\n  result: Awaited<ReturnType<typeof planAuth>>,\n  phase: AuthApplyPhase = \"create-update\",\n) {\n  const { changeSet } = result;\n  const applyServices = async () => {\n    await Promise.all([\n      ...changeSet.service.creates.map(async (create) => {\n        await client.createAuthService(create.request);\n        await writeMetadataLabels(client, create.metaRequest);\n      }),\n      ...changeSet.service.updates.map(async (update) => {\n        await client.updateAuthService(update.request);\n        await writeMetadataLabels(client, update.metaRequest);\n      }),\n    ]);\n  };\n\n  const applyMachineUsers = async () => {\n    await Promise.all([\n      ...changeSet.machineUser.creates.map(async (create) => {\n        const created = await client.createAuthMachineUser(create.request);\n        if (created.machineUser?.clientSecret) {\n          logger.registerSecret(created.machineUser.clientSecret);\n        }\n        return created;\n      }),\n      ...changeSet.machineUser.updates.map(async (update) => {\n        const updated = await client.updateAuthMachineUser(update.request);\n        if (updated.machineUser?.clientSecret) {\n          logger.registerSecret(updated.machineUser.clientSecret);\n        }\n        return updated;\n      }),\n    ]);\n  };\n\n  const applyUserProfileDeletes = async () => {\n    await Promise.all(\n      changeSet.userProfileConfig.deletes.map((del) => client.deleteUserProfileConfig(del.request)),\n    );\n  };\n\n  const applyCreateUpdateDependents = async () => {\n    await applyAuthConnections(\n      client,\n      {\n        changeSet: changeSet.connection,\n        stateScope: result.connectionStateScope,\n      },\n      \"create-update\",\n    );\n\n    await Promise.all([\n      ...changeSet.idpConfig.creates.map(async (create) => {\n        if (create.idpConfig.kind === \"BuiltInIdP\") {\n          assertDefined(create.request.idpConfig, \"request missing idpConfig\").config =\n            await protoBuiltinIdPConfig(\n              client,\n              assertDefined(create.request.workspaceId, \"request missing workspaceId\"),\n              create.idpConfig,\n            );\n        }\n        return client.createAuthIDPConfig(create.request);\n      }),\n      ...changeSet.idpConfig.updates.map(async (update) => {\n        if (update.idpConfig.kind === \"BuiltInIdP\") {\n          assertDefined(update.request.idpConfig, \"request missing idpConfig\").config =\n            await protoBuiltinIdPConfig(\n              client,\n              assertDefined(update.request.workspaceId, \"request missing workspaceId\"),\n              update.idpConfig,\n            );\n        }\n        return client.updateAuthIDPConfig(update.request);\n      }),\n    ]);\n\n    await Promise.all([\n      ...changeSet.userProfileConfig.creates.map((create) =>\n        client.createUserProfileConfig(create.request),\n      ),\n      ...changeSet.userProfileConfig.updates.map((update) =>\n        client.updateUserProfileConfig(update.request),\n      ),\n    ]);\n\n    await Promise.all([\n      ...changeSet.tenantConfig.creates.map((create) => client.createTenantConfig(create.request)),\n      ...changeSet.tenantConfig.updates.map((update) => client.updateTenantConfig(update.request)),\n    ]);\n\n    await Promise.all([\n      ...changeSet.authHook.creates.map((create) => client.createAuthHook(create.request)),\n      ...changeSet.authHook.updates.map((update) => client.updateAuthHook(update.request)),\n    ]);\n\n    await Promise.all([\n      ...changeSet.oauth2Client.creates.map(async (create) => {\n        const oauth2Client = assertDefined(\n          create.request.oauth2Client,\n          \"request missing oauth2Client\",\n        );\n        oauth2Client.redirectUris = await resolveStaticWebsiteUrls(\n          client,\n          assertDefined(create.request.workspaceId, \"request missing workspaceId\"),\n          oauth2Client.redirectUris,\n          \"OAuth2 redirect URIs\",\n        );\n        const created = await client.createAuthOAuth2Client(create.request);\n        if (created.oauth2Client?.clientSecret) {\n          logger.registerSecret(created.oauth2Client.clientSecret);\n        }\n        return created;\n      }),\n      ...changeSet.oauth2Client.updates.map(async (update) => {\n        const oauth2Client = assertDefined(\n          update.request.oauth2Client,\n          \"request missing oauth2Client\",\n        );\n        oauth2Client.redirectUris = await resolveStaticWebsiteUrls(\n          client,\n          assertDefined(update.request.workspaceId, \"request missing workspaceId\"),\n          oauth2Client.redirectUris,\n          \"OAuth2 redirect URIs\",\n        );\n        const updated = await client.updateAuthOAuth2Client(update.request);\n        if (updated.oauth2Client?.clientSecret) {\n          logger.registerSecret(updated.oauth2Client.clientSecret);\n        }\n        return updated;\n      }),\n    ]);\n\n    for (const replace of changeSet.oauth2Client.replaces) {\n      await client.deleteAuthOAuth2Client(replace.deleteRequest);\n      const replaceOauth2Client = assertDefined(\n        replace.createRequest.oauth2Client,\n        \"createRequest missing oauth2Client\",\n      );\n      replaceOauth2Client.redirectUris = await resolveStaticWebsiteUrls(\n        client,\n        assertDefined(replace.createRequest.workspaceId, \"createRequest missing workspaceId\"),\n        replaceOauth2Client.redirectUris,\n        \"OAuth2 redirect URIs\",\n      );\n      const replaced = await client.createAuthOAuth2Client(replace.createRequest);\n      if (replaced.oauth2Client?.clientSecret) {\n        logger.registerSecret(replaced.oauth2Client.clientSecret);\n      }\n    }\n\n    await Promise.all([\n      ...changeSet.scim.creates.map((create) => client.createAuthSCIMConfig(create.request)),\n      ...changeSet.scim.updates.map((update) => client.updateAuthSCIMConfig(update.request)),\n    ]);\n\n    await Promise.all([\n      ...changeSet.scimResource.creates.map((create) =>\n        client.createAuthSCIMResource(create.request),\n      ),\n      ...changeSet.scimResource.updates.map((update) =>\n        client.updateAuthSCIMResource(update.request),\n      ),\n    ]);\n  };\n\n  if (phase === \"create-update-prerequisites\" || phase === \"create-update\") {\n    await applyServices();\n    await applyMachineUsers();\n  }\n  if (phase === \"create-update-dependents\" || phase === \"create-update\") {\n    await applyCreateUpdateDependents();\n  }\n  if (phase === \"delete-resources\") {\n    // Delete in reverse order of dependencies\n    // SCIMResources\n    await Promise.all(\n      changeSet.scimResource.deletes.map((del) => client.deleteAuthSCIMResource(del.request)),\n    );\n\n    // SCIMConfigs\n    await Promise.all(\n      changeSet.scim.deletes.map((del) => client.deleteAuthSCIMConfig(del.request)),\n    );\n\n    // OAuth2Clients\n    await Promise.all(\n      changeSet.oauth2Client.deletes.map((del) => client.deleteAuthOAuth2Client(del.request)),\n    );\n\n    // AuthHooks (before machine users, since hooks reference invokers)\n    await Promise.all(changeSet.authHook.deletes.map((del) => client.deleteAuthHook(del.request)));\n\n    // MachineUsers\n    await Promise.all(\n      changeSet.machineUser.deletes.map((del) => client.deleteAuthMachineUser(del.request)),\n    );\n\n    // TenantConfigs\n    await Promise.all(\n      changeSet.tenantConfig.deletes.map((del) => client.deleteTenantConfig(del.request)),\n    );\n\n    // UserProfileConfigs\n    await applyUserProfileDeletes();\n\n    // IdPConfigs\n    await Promise.all(\n      changeSet.idpConfig.deletes.map((del) => client.deleteAuthIDPConfig(del.request)),\n    );\n\n    // Auth Connections\n    await applyAuthConnections(\n      client,\n      {\n        changeSet: changeSet.connection,\n        stateScope: result.connectionStateScope,\n      },\n      \"delete-resources\",\n    );\n  } else if (phase === \"delete-services\") {\n    // Services only\n    await Promise.all(\n      changeSet.service.deletes.map((del) => client.deleteAuthService(del.request)),\n    );\n  }\n}\n\n/**\n * Plan auth-related changes based on current and desired state.\n * @param context - Planning context\n * @returns Planned auth changes and metadata\n */\nexport async function planAuth(context: PlanContext) {\n  const { client, workspaceId, application, forRemoval, forceApplyAll = false } = context;\n  const auths: Readonly<AuthService>[] = [];\n  if (!forRemoval && application.authService) {\n    await application.authService.resolveNamespaces();\n    auths.push(application.authService);\n  }\n  const {\n    changeSet: serviceChangeSet,\n    conflicts,\n    unmanaged,\n    resourceOwners,\n  } = await planServices(\n    client,\n    workspaceId,\n    application.name,\n    application.id,\n    auths,\n    forceApplyAll,\n  );\n  const deletedServices = serviceChangeSet.deletes.map((del) => del.name);\n  const expectedLocalWebsites = expectedLocalStaticWebsiteNames(context);\n  const [\n    idpConfigChangeSet,\n    userProfileConfigChangeSet,\n    tenantConfigChangeSet,\n    machineUserChangeSet,\n    authHookChangeSet,\n    oauth2ClientChangeSet,\n    scimChangeSet,\n    scimResourceChangeSet,\n    connectionResult,\n  ] = await Promise.all([\n    planIdPConfigs(client, workspaceId, auths, deletedServices, forceApplyAll),\n    planUserProfileConfigs(client, workspaceId, auths, deletedServices, forceApplyAll),\n    planTenantConfigs(client, workspaceId, auths, deletedServices, forceApplyAll),\n    planMachineUsers(client, workspaceId, auths, deletedServices, forceApplyAll),\n    planAuthHooks(client, workspaceId, auths, deletedServices, forceApplyAll),\n    planOAuth2Clients(\n      client,\n      workspaceId,\n      auths,\n      deletedServices,\n      expectedLocalWebsites,\n      forceApplyAll,\n    ),\n    planSCIMConfigs(client, workspaceId, auths, deletedServices),\n    planSCIMResources(client, workspaceId, auths, deletedServices),\n    planAuthConnections(client, workspaceId, application.name, application.id, auths),\n  ]);\n  return {\n    changeSet: {\n      service: serviceChangeSet,\n      idpConfig: idpConfigChangeSet,\n      userProfileConfig: userProfileConfigChangeSet,\n      tenantConfig: tenantConfigChangeSet,\n      machineUser: machineUserChangeSet,\n      authHook: authHookChangeSet,\n      oauth2Client: oauth2ClientChangeSet,\n      scim: scimChangeSet,\n      scimResource: scimResourceChangeSet,\n      connection: connectionResult.changeSet,\n    },\n    conflicts: [...conflicts, ...connectionResult.conflicts],\n    unmanaged: [...unmanaged, ...connectionResult.unmanaged],\n    resourceOwners: new Set([...resourceOwners, ...connectionResult.resourceOwners]),\n    connectionStateScope: connectionResult.stateScope,\n  };\n}\n\ntype CreateService = {\n  name: string;\n  request: MessageInitShape<typeof CreateAuthServiceRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype UpdateService = {\n  name: string;\n  request: MessageInitShape<typeof UpdateAuthServiceRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype DeleteService = {\n  name: string;\n  request: MessageInitShape<typeof DeleteAuthServiceRequestSchema>;\n};\n\nasync function planServices(\n  client: OperatorClient,\n  workspaceId: string,\n  appName: string,\n  appId: string | undefined,\n  auths: ReadonlyArray<Readonly<AuthService>>,\n  forceApplyAll = false,\n) {\n  const changeSet = createChangeSet<CreateService, UpdateService, DeleteService>(\"Auth services\");\n  const conflicts: OwnerConflict[] = [];\n  const unmanaged: UnmanagedResource[] = [];\n  const resourceOwners = new Set<string>();\n\n  const existingServices = await fetchExistingResourcesWithLabels({\n    client,\n    fetchPage: async (pageToken, maxPageSize) => {\n      const { authServices, nextPageToken } = await client.listAuthServices({\n        workspaceId,\n        pageToken,\n        pageSize: maxPageSize,\n      });\n      return [authServices, nextPageToken];\n    },\n    getName: (resource) => resource.namespace?.name,\n    getTrn: (name) => resourceTrn(workspaceId, \"auth\", name),\n  });\n\n  for (const auth of auths) {\n    const { config } = auth;\n    const existing = existingServices[config.name];\n    const metaRequest = await buildMetaRequest({\n      trn: resourceTrn(workspaceId, \"auth\", config.name),\n      appName,\n      appId,\n    });\n    const request = {\n      workspaceId,\n      namespaceName: config.name,\n      publishSessionEvents: config.publishSessionEvents,\n    };\n    if (existing) {\n      const owned = trackDesiredResourceOwnership({\n        labels: existing.allLabels,\n        ownerLabel: existing.label,\n        appName,\n        appId,\n        resourceType: \"Auth service\",\n        resourceName: config.name,\n        conflicts,\n        unmanaged,\n      });\n\n      if (\n        !forceApplyAll &&\n        existing.resource.publishSessionEvents === (config.publishSessionEvents ?? false) &&\n        owned\n      ) {\n        changeSet.unchanged.push({ name: config.name });\n      } else {\n        changeSet.updates.push({\n          name: config.name,\n          request,\n          metaRequest,\n        });\n      }\n      delete existingServices[config.name];\n    } else {\n      changeSet.creates.push({\n        name: config.name,\n        request,\n        metaRequest,\n      });\n    }\n  }\n  Object.entries(existingServices).forEach(([namespaceName]) => {\n    const entry = existingServices[namespaceName];\n    const owned = trackRemainingResourceOwner({\n      labels: entry?.allLabels,\n      ownerLabel: entry?.label,\n      appName,\n      appId,\n      resourceOwners,\n    });\n    if (owned) {\n      changeSet.deletes.push({\n        name: namespaceName,\n        request: {\n          workspaceId,\n          namespaceName,\n        },\n      });\n    }\n  });\n\n  return { changeSet, conflicts, unmanaged, resourceOwners };\n}\n\ntype CreateIdPConfig = {\n  name: string;\n  idpConfig: Readonly<IdProviderConfig>;\n  request: MessageInitShape<typeof CreateAuthIDPConfigRequestSchema>;\n};\n\ntype UpdateIdPConfig = {\n  name: string;\n  idpConfig: Readonly<IdProviderConfig>;\n  request: MessageInitShape<typeof UpdateAuthIDPConfigRequestSchema>;\n};\n\ntype DeleteIdPConfig = {\n  name: string;\n  request: MessageInitShape<typeof DeleteAuthIDPConfigRequestSchema>;\n};\n\nasync function planIdPConfigs(\n  client: OperatorClient,\n  workspaceId: string,\n  auths: ReadonlyArray<Readonly<AuthService>>,\n  deletedServices: ReadonlyArray<string>,\n  forceApplyAll = false,\n) {\n  const changeSet = createChangeSet<CreateIdPConfig, UpdateIdPConfig, DeleteIdPConfig>(\n    \"Auth idpConfigs\",\n  );\n\n  const fetchIdPConfigs = (namespaceName: string) => {\n    return fetchAllTolerant(async (pageToken, maxPageSize) => {\n      const { idpConfigs, nextPageToken } = await client.listAuthIDPConfigs({\n        workspaceId,\n        namespaceName,\n        pageToken,\n        pageSize: maxPageSize,\n      });\n      return [idpConfigs, nextPageToken];\n    });\n  };\n\n  for (const authService of auths) {\n    const { config } = authService;\n    const existingIdPConfigs = await fetchIdPConfigs(config.name);\n    const existingMap = new Map<string, (typeof existingIdPConfigs)[number]>();\n    existingIdPConfigs.forEach((idpConfig) => {\n      existingMap.set(idpConfig.name, idpConfig);\n    });\n    const idpConfig = config.idProvider;\n    if (idpConfig) {\n      const desired = protoIdPConfig(idpConfig);\n      const existing = existingMap.get(idpConfig.name);\n      if (existing) {\n        const desiredComparable = await protoIdPConfigForComparison(\n          client,\n          workspaceId,\n          idpConfig,\n          desired,\n        );\n        if (!desiredComparable) {\n          changeSet.updates.push({\n            name: idpConfig.name,\n            idpConfig,\n            request: {\n              workspaceId,\n              namespaceName: config.name,\n              idpConfig: desired,\n            },\n          });\n          existingMap.delete(idpConfig.name);\n          continue;\n        }\n        if (!forceApplyAll && areAuthIdPConfigsEqual(existing, desiredComparable)) {\n          changeSet.unchanged.push({ name: idpConfig.name });\n        } else {\n          changeSet.updates.push({\n            name: idpConfig.name,\n            idpConfig,\n            request: {\n              workspaceId,\n              namespaceName: config.name,\n              idpConfig: desired,\n            },\n          });\n        }\n        existingMap.delete(idpConfig.name);\n      } else {\n        changeSet.creates.push({\n          name: idpConfig.name,\n          idpConfig,\n          request: {\n            workspaceId,\n            namespaceName: config.name,\n            idpConfig: desired,\n          },\n        });\n      }\n    }\n    existingMap.forEach((_, name) => {\n      changeSet.deletes.push({\n        name,\n        request: {\n          workspaceId,\n          namespaceName: config.name,\n          name,\n        },\n      });\n    });\n  }\n\n  for (const namespaceName of deletedServices) {\n    const existingIdPConfigs = await fetchIdPConfigs(namespaceName);\n    existingIdPConfigs.forEach((idpConfig) => {\n      changeSet.deletes.push({\n        name: idpConfig.name,\n        request: {\n          workspaceId,\n          namespaceName,\n          name: idpConfig.name,\n        },\n      });\n    });\n  }\n  return changeSet;\n}\n\nasync function protoIdPConfigForComparison(\n  client: OperatorClient,\n  workspaceId: string,\n  idpConfig: Readonly<IdProviderConfig>,\n  desired: MessageInitShape<typeof AuthIDPConfigSchema>,\n): Promise<MessageInitShape<typeof AuthIDPConfigSchema> | undefined> {\n  if (idpConfig.kind !== \"BuiltInIdP\") {\n    return desired;\n  }\n\n  const config = await tryProtoBuiltinIdPConfig(client, workspaceId, idpConfig);\n  return config\n    ? {\n        name: desired.name,\n        authType: desired.authType,\n        config,\n      }\n    : undefined;\n}\n\nfunction normalizeComparableAuthIdPConfig(idpConfig: MessageInitShape<typeof AuthIDPConfigSchema>) {\n  return toComparableProtoJson(AuthIDPConfigSchema, idpConfig);\n}\n\nfunction areAuthIdPConfigsEqual(\n  existing: MessageInitShape<typeof AuthIDPConfigSchema>,\n  desired: MessageInitShape<typeof AuthIDPConfigSchema>,\n) {\n  return areNormalizedEqual(\n    normalizeComparableAuthIdPConfig(existing),\n    normalizeComparableAuthIdPConfig(desired),\n  );\n}\n\nfunction protoIdPConfig(idpConfig: IdProviderConfig): MessageInitShape<typeof AuthIDPConfigSchema> {\n  switch (idpConfig.kind) {\n    case \"IDToken\":\n      return {\n        name: idpConfig.name,\n        authType: AuthIDPConfig_AuthType.ID_TOKEN,\n        config: {\n          config: {\n            case: \"idToken\",\n            value: {\n              providerUrl: idpConfig.providerURL,\n              clientId: idpConfig.clientID,\n              issuerUrl: idpConfig.issuerURL,\n              usernameClaim: idpConfig.usernameClaim,\n            },\n          },\n        },\n      };\n    case \"SAML\":\n      return {\n        name: idpConfig.name,\n        authType: AuthIDPConfig_AuthType.SAML,\n        config: {\n          config: {\n            case: \"saml\",\n            value: {\n              ...(idpConfig.metadataURL !== undefined\n                ? { metadataUrl: idpConfig.metadataURL }\n                : {\n                    rawMetadata: assertDefined(\n                      idpConfig.rawMetadata,\n                      \"SAML config missing rawMetadata\",\n                    ),\n                  }),\n              enableSignRequest: idpConfig.enableSignRequest,\n              defaultRedirectUrl: idpConfig.defaultRedirectURL,\n            },\n          },\n        },\n      };\n    case \"OIDC\":\n      return {\n        name: idpConfig.name,\n        authType: AuthIDPConfig_AuthType.OIDC,\n        config: {\n          config: {\n            case: \"oidc\",\n            value: {\n              clientIdKey: idpConfig.clientID,\n              clientSecretKey: {\n                vaultName: idpConfig.clientSecret.vaultName,\n                secretKey: idpConfig.clientSecret.secretKey,\n              },\n              providerUrl: idpConfig.providerURL,\n              issuerUrl: idpConfig.issuerURL,\n              usernameClaim: idpConfig.usernameClaim,\n            },\n          },\n        },\n      };\n    case \"BuiltInIdP\":\n      return {\n        name: idpConfig.name,\n        authType: AuthIDPConfig_AuthType.OIDC,\n        // config is set at apply time\n        config: {},\n      };\n    default:\n      throw internalError(`Unexpected idp kind: ${idpConfig satisfies never}`);\n  }\n}\n\nasync function protoBuiltinIdPConfig(\n  client: OperatorClient,\n  workspaceId: string,\n  builtinIdPConfig: BuiltinIdP,\n): Promise<MessageInitShape<typeof AuthIDPConfig_ConfigSchema>> {\n  const config = await tryProtoBuiltinIdPConfig(client, workspaceId, builtinIdPConfig);\n  if (!config) {\n    throw CLIError({\n      code: \"IDP_NOT_FOUND\",\n      message: `Built-in IdP \"${builtinIdPConfig.namespace}\" not found.`,\n      suggestion: \"Ensure that idp is configured correctly.\",\n    });\n  }\n  return config;\n}\n\nasync function tryProtoBuiltinIdPConfig(\n  client: OperatorClient,\n  workspaceId: string,\n  builtinIdPConfig: BuiltinIdP,\n): Promise<MessageInitShape<typeof AuthIDPConfig_ConfigSchema> | undefined> {\n  const idpService = await getOrNull(async () => {\n    return await client.getIdPService({\n      workspaceId,\n      namespaceName: builtinIdPConfig.namespace,\n    });\n  });\n  if (!idpService) return undefined;\n\n  const idpClient = await getOrNull(async () => {\n    return await client.getIdPClient({\n      workspaceId,\n      namespaceName: builtinIdPConfig.namespace,\n      name: builtinIdPConfig.clientName,\n    });\n  });\n  if (!idpClient) return undefined;\n\n  const vaultName = idpClientVaultName(builtinIdPConfig.namespace, builtinIdPConfig.clientName);\n  const secretKey = idpClientSecretName(builtinIdPConfig.namespace, builtinIdPConfig.clientName);\n  return {\n    config: {\n      case: \"oidc\",\n      value: {\n        clientIdKey: idpClient.client?.clientId,\n        clientSecretKey: {\n          vaultName,\n          secretKey,\n        },\n        providerUrl: idpService.idpService?.providerUrl,\n        usernameClaim: \"name\",\n      },\n    },\n  };\n}\n\ntype CreateUserProfileConfig = {\n  name: string;\n  request: MessageInitShape<typeof CreateUserProfileConfigRequestSchema>;\n};\n\ntype UpdateUserProfileConfig = {\n  name: string;\n  request: MessageInitShape<typeof UpdateUserProfileConfigRequestSchema>;\n};\n\ntype DeleteUserProfileConfig = {\n  name: string;\n  request: MessageInitShape<typeof DeleteUserProfileConfigRequestSchema>;\n};\n\nasync function planUserProfileConfigs(\n  client: OperatorClient,\n  workspaceId: string,\n  auths: ReadonlyArray<Readonly<AuthService>>,\n  deletedServices: ReadonlyArray<string>,\n  forceApplyAll = false,\n) {\n  const changeSet = createChangeSet<\n    CreateUserProfileConfig,\n    UpdateUserProfileConfig,\n    DeleteUserProfileConfig\n  >(\"Auth userProfileConfigs\");\n\n  for (const auth of auths) {\n    const { config } = auth;\n    const name = `${config.name}-user-profile-config`;\n    const existing = await getOrNull(async () => {\n      return await client.getUserProfileConfig({\n        workspaceId,\n        namespaceName: config.name,\n      });\n    });\n    if (!existing) {\n      const userProfileForUpdate = auth.userProfile;\n      if (userProfileForUpdate) {\n        changeSet.creates.push({\n          name,\n          request: {\n            workspaceId,\n            namespaceName: config.name,\n            userProfileProviderConfig: protoUserProfileConfig(userProfileForUpdate),\n          },\n        });\n      }\n      continue;\n    }\n\n    const userProfileForUpdate = auth.userProfile;\n    if (userProfileForUpdate) {\n      const desired = protoUserProfileConfig(userProfileForUpdate);\n      if (\n        !forceApplyAll &&\n        areUserProfileConfigsEqual(existing.userProfileProviderConfig ?? {}, desired)\n      ) {\n        changeSet.unchanged.push({ name });\n      } else {\n        changeSet.updates.push({\n          name,\n          request: {\n            workspaceId,\n            namespaceName: config.name,\n            userProfileProviderConfig: desired,\n          },\n        });\n      }\n    } else {\n      changeSet.deletes.push({\n        name,\n        request: {\n          workspaceId,\n          namespaceName: config.name,\n        },\n      });\n    }\n  }\n\n  for (const namespaceName of deletedServices) {\n    const existing = await getOrNull(async () => {\n      return await client.getUserProfileConfig({\n        workspaceId,\n        namespaceName,\n      });\n    });\n    if (!existing) continue;\n    changeSet.deletes.push({\n      name: `${namespaceName}-user-profile-config`,\n      request: {\n        workspaceId,\n        namespaceName,\n      },\n    });\n  }\n  return changeSet;\n}\n\nfunction protoUserProfileConfig(\n  userProfile: NonNullable<AuthService[\"userProfile\"]>,\n): MessageInitShape<typeof UserProfileProviderConfigSchema> {\n  // Convert attributes from { key: true } to { key: \"key\" }\n  const attributeMap = userProfile.attributes\n    ? Object.fromEntries(Object.keys(userProfile.attributes).map((key) => [key, key]))\n    : undefined;\n\n  return {\n    providerType: UserProfileProviderConfig_UserProfileProviderType.TAILORDB,\n    config: {\n      config: {\n        case: \"tailordb\",\n        value: {\n          namespace: userProfile.namespace,\n          type: userProfile.type.name,\n          usernameField: userProfile.usernameField,\n          tenantIdField: undefined,\n          attributesFields: userProfile.attributeList,\n          attributeMap,\n        },\n      },\n    },\n  };\n}\n\ntype CreateTenantConfig = {\n  name: string;\n  request: MessageInitShape<typeof CreateTenantConfigRequestSchema>;\n};\n\ntype UpdateTenantConfig = {\n  name: string;\n  request: MessageInitShape<typeof UpdateTenantConfigRequestSchema>;\n};\n\ntype DeleteTenantConfig = {\n  name: string;\n  request: MessageInitShape<typeof DeleteTenantConfigRequestSchema>;\n};\n\nasync function planTenantConfigs(\n  client: OperatorClient,\n  workspaceId: string,\n  auths: ReadonlyArray<Readonly<AuthService>>,\n  deletedServices: ReadonlyArray<string>,\n  forceApplyAll = false,\n) {\n  const changeSet = createChangeSet<CreateTenantConfig, UpdateTenantConfig, DeleteTenantConfig>(\n    \"Auth tenantConfigs\",\n  );\n\n  for (const auth of auths) {\n    const { config } = auth;\n    const name = `${config.name}-tenant-config`;\n    const existing = await getOrNull(async () => {\n      return await client.getTenantConfig({\n        workspaceId,\n        namespaceName: config.name,\n      });\n    });\n    if (!existing) {\n      if (config.tenantProvider) {\n        changeSet.creates.push({\n          name,\n          request: {\n            workspaceId,\n            namespaceName: config.name,\n            tenantProviderConfig: protoTenantConfig(config.tenantProvider),\n          },\n        });\n      }\n      continue;\n    }\n\n    if (config.tenantProvider) {\n      const desired = protoTenantConfig(config.tenantProvider);\n      if (!forceApplyAll && areTenantProviderConfigsEqual(existing.tenantProviderConfig, desired)) {\n        changeSet.unchanged.push({ name });\n      } else {\n        changeSet.updates.push({\n          name,\n          request: {\n            workspaceId,\n            namespaceName: config.name,\n            tenantProviderConfig: desired,\n          },\n        });\n      }\n    } else {\n      changeSet.deletes.push({\n        name,\n        request: {\n          workspaceId,\n          namespaceName: config.name,\n        },\n      });\n    }\n  }\n\n  for (const namespaceName of deletedServices) {\n    const existing = await getOrNull(async () => {\n      return await client.getTenantConfig({\n        workspaceId,\n        namespaceName,\n      });\n    });\n    if (!existing) continue;\n    changeSet.deletes.push({\n      name: `${namespaceName}-tenant-config`,\n      request: {\n        workspaceId,\n        namespaceName,\n      },\n    });\n  }\n  return changeSet;\n}\n\nfunction protoTenantConfig(\n  tenantConfig: TenantProviderConfig,\n): MessageInitShape<typeof TenantProviderConfigSchema> {\n  return {\n    providerType: TenantProviderConfig_TenantProviderType.TAILORDB,\n    config: {\n      config: {\n        case: \"tailordb\",\n        value: {\n          namespace: tenantConfig.namespace,\n          type: tenantConfig.type,\n          signatureField: tenantConfig.signatureField,\n        },\n      },\n    },\n  };\n}\n\ntype CreateMachineUser = {\n  name: string;\n  request: MessageInitShape<typeof CreateAuthMachineUserRequestSchema>;\n};\n\ntype UpdateMachineUser = {\n  name: string;\n  request: MessageInitShape<typeof UpdateAuthMachineUserRequestSchema>;\n};\n\ntype DeleteMachineUser = {\n  name: string;\n  request: MessageInitShape<typeof DeleteAuthMachineUserRequestSchema>;\n};\n\nasync function planMachineUsers(\n  client: OperatorClient,\n  workspaceId: string,\n  auths: ReadonlyArray<Readonly<AuthService>>,\n  deletedServices: ReadonlyArray<string>,\n  forceApplyAll = false,\n) {\n  const changeSet = createChangeSet<CreateMachineUser, UpdateMachineUser, DeleteMachineUser>(\n    \"Auth machineUsers\",\n  );\n\n  const fetchMachineUsers = (authNamespace: string) => {\n    return fetchAllTolerant(async (pageToken, maxPageSize) => {\n      const { machineUsers, nextPageToken } = await client.listAuthMachineUsers({\n        workspaceId,\n        authNamespace,\n        pageToken,\n        pageSize: maxPageSize,\n      });\n      return [machineUsers, nextPageToken];\n    });\n  };\n\n  for (const auth of auths) {\n    const { config } = auth;\n    const existingMachineUsers = await fetchMachineUsers(config.name);\n    const existingMap = new Map<string, (typeof existingMachineUsers)[number]>();\n    existingMachineUsers.forEach((machineUser) => {\n      existingMap.set(machineUser.name, machineUser);\n      logger.registerSecret(machineUser.clientSecret);\n    });\n    for (const machineUsername of Object.keys(config.machineUsers ?? {})) {\n      const machineUser = config.machineUsers?.[machineUsername];\n      if (!machineUser) {\n        continue;\n      }\n      const desiredMachineUser = {\n        attributes: machineUser.attributeList,\n        attributeMap: machineUser.attributes\n          ? protoMachineUserAttributeMap(machineUser.attributes)\n          : undefined,\n      };\n      const existing = existingMap.get(machineUsername);\n      if (existing) {\n        if (!forceApplyAll && areMachineUsersEqual(existing, desiredMachineUser)) {\n          changeSet.unchanged.push({ name: machineUsername });\n        } else {\n          changeSet.updates.push({\n            name: machineUsername,\n            request: {\n              workspaceId,\n              authNamespace: config.name,\n              name: machineUsername,\n              attributes: machineUser.attributeList,\n              attributeMap: desiredMachineUser.attributeMap,\n            },\n          });\n        }\n        existingMap.delete(machineUsername);\n      } else {\n        changeSet.creates.push({\n          name: machineUsername,\n          request: {\n            workspaceId,\n            authNamespace: config.name,\n            name: machineUsername,\n            attributes: machineUser.attributeList,\n            attributeMap: desiredMachineUser.attributeMap,\n          },\n        });\n      }\n    }\n    existingMap.forEach((_, name) => {\n      changeSet.deletes.push({\n        name,\n        request: {\n          workspaceId,\n          authNamespace: config.name,\n          name,\n        },\n      });\n    });\n  }\n\n  for (const namespaceName of deletedServices) {\n    const existingMachineUsers = await fetchMachineUsers(namespaceName);\n    existingMachineUsers.forEach((machineUser) => {\n      logger.registerSecret(machineUser.clientSecret);\n      changeSet.deletes.push({\n        name: machineUser.name,\n        request: {\n          workspaceId,\n          authNamespace: namespaceName,\n          name: machineUser.name,\n        },\n      });\n    });\n  }\n  return changeSet;\n}\n\nfunction protoMachineUserAttributeMap(\n  attributeMap: Record<string, AuthAttributeValue>,\n): Record<string, MessageInitShape<typeof ValueSchema>> {\n  const ret: Record<string, MessageInitShape<typeof ValueSchema>> = {};\n  for (const [key, value] of Object.entries(attributeMap)) {\n    ret[key] = fromJson(ValueSchema, value ?? null);\n  }\n  return ret;\n}\n\nfunction normalizeComparableUserProfileConfig(\n  config: MessageInitShape<typeof UserProfileProviderConfigSchema>,\n) {\n  const comparableConfig = config.config?.config;\n  const tailorDBConfig = comparableConfig?.case === \"tailordb\" ? comparableConfig.value : undefined;\n\n  return toComparableProtoJson(UserProfileProviderConfigSchema, {\n    providerType: config.providerType,\n    config: tailorDBConfig\n      ? {\n          config: {\n            case: \"tailordb\",\n            value: {\n              ...tailorDBConfig,\n              tenantIdField: tailorDBConfig.tenantIdField || \"\",\n              attributesFields: normalizeStringArray(tailorDBConfig.attributesFields),\n              attributeMap: normalizeProtoConfig(tailorDBConfig.attributeMap ?? {}),\n            },\n          },\n        }\n      : undefined,\n  });\n}\n\nfunction areUserProfileConfigsEqual(\n  existing: MessageInitShape<typeof UserProfileProviderConfigSchema>,\n  desired: MessageInitShape<typeof UserProfileProviderConfigSchema>,\n) {\n  return areNormalizedEqual(\n    normalizeComparableUserProfileConfig(existing),\n    normalizeComparableUserProfileConfig(desired),\n  );\n}\n\nfunction normalizeComparableTenantProviderConfig(\n  config: MessageInitShape<typeof TenantProviderConfigSchema> | undefined,\n) {\n  return toComparableProtoJson(TenantProviderConfigSchema, config ?? {});\n}\n\nfunction areTenantProviderConfigsEqual(\n  existing: MessageInitShape<typeof TenantProviderConfigSchema> | undefined,\n  desired: MessageInitShape<typeof TenantProviderConfigSchema>,\n) {\n  return areNormalizedEqual(\n    normalizeComparableTenantProviderConfig(existing),\n    normalizeComparableTenantProviderConfig(desired),\n  );\n}\n\nfunction normalizeComparableMachineUser(input: {\n  attributes?: readonly string[];\n  attributeMap?: Record<string, MessageInitShape<typeof ValueSchema>>;\n}) {\n  return normalizeProtoConfig({\n    attributes: normalizeStringArray(input.attributes),\n    attributeMap: normalizeProtoConfig(input.attributeMap ?? {}),\n  });\n}\n\nfunction areMachineUsersEqual(\n  existing: {\n    attributes?: readonly string[];\n    attributeMap?: Record<string, MessageInitShape<typeof ValueSchema>>;\n  },\n  desired: {\n    attributes?: readonly string[];\n    attributeMap?: Record<string, MessageInitShape<typeof ValueSchema>>;\n  },\n) {\n  return areNormalizedEqual(\n    normalizeComparableMachineUser(existing),\n    normalizeComparableMachineUser(desired),\n  );\n}\n\nfunction normalizeComparableOAuth2Client(\n  client:\n    | MessageInitShape<typeof AuthOAuth2ClientSchema>\n    | {\n        name?: string;\n        description?: string;\n        grantTypes?: readonly AuthOAuth2Client_GrantType[];\n        redirectUris?: readonly string[];\n        clientType?: AuthOAuth2Client_ClientType;\n        accessTokenLifetime?: number;\n        refreshTokenLifetime?: number;\n        requireDpop?: boolean;\n      },\n) {\n  const accessTokenLifetime = oauth2LifetimeToSeconds(client.accessTokenLifetime);\n  const refreshTokenLifetime = oauth2LifetimeToSeconds(client.refreshTokenLifetime);\n\n  return normalizeProtoConfig({\n    ...client,\n    // Platform returns an empty string for an unset description; treat it the same as omitted.\n    description: client.description || undefined,\n    redirectUris: normalizeStringArray(client.redirectUris),\n    grantTypes: (client.grantTypes ?? []).toSorted((left, right) => left - right),\n    accessTokenLifetime: accessTokenLifetime ?? 86400,\n    refreshTokenLifetime: refreshTokenLifetime ?? 604800,\n    requireDpop: client.requireDpop ?? false,\n  });\n}\n\nfunction oauth2LifetimeToSeconds(\n  lifetime:\n    | number\n    | {\n        seconds?: bigint;\n      }\n    | undefined,\n) {\n  if (typeof lifetime === \"number\") {\n    return lifetime;\n  }\n\n  if (lifetime?.seconds != null) {\n    return Number(lifetime.seconds);\n  }\n\n  return undefined;\n}\n\nfunction areOAuth2ClientsEqual(\n  existing: {\n    name: string;\n    description?: string;\n    grantTypes?: readonly AuthOAuth2Client_GrantType[];\n    redirectUris?: readonly string[];\n    clientType?: AuthOAuth2Client_ClientType;\n    accessTokenLifetime?: number;\n    refreshTokenLifetime?: number;\n    requireDpop?: boolean;\n  },\n  desired:\n    | MessageInitShape<typeof AuthOAuth2ClientSchema>\n    | {\n        name?: string;\n        description?: string;\n        grantTypes?: readonly AuthOAuth2Client_GrantType[];\n        redirectUris?: readonly string[];\n        clientType?: AuthOAuth2Client_ClientType;\n        accessTokenLifetime?: number;\n        refreshTokenLifetime?: number;\n        requireDpop?: boolean;\n      },\n) {\n  return areNormalizedEqual(\n    normalizeComparableOAuth2Client(existing),\n    normalizeComparableOAuth2Client(desired),\n  );\n}\n\ntype CreateOAuth2Clients = {\n  name: string;\n  request: MessageInitShape<typeof CreateAuthOAuth2ClientRequestSchema>;\n};\n\ntype UpdateOAuth2Client = {\n  name: string;\n  request: MessageInitShape<typeof UpdateAuthOAuth2ClientRequestSchema>;\n};\n\ntype DeleteOAuth2Client = {\n  name: string;\n  request: MessageInitShape<typeof DeleteAuthOAuth2ClientRequestSchema>;\n};\n\ntype ReplaceOAuth2Client = {\n  name: string;\n  deleteRequest: MessageInitShape<typeof DeleteAuthOAuth2ClientRequestSchema>;\n  createRequest: MessageInitShape<typeof CreateAuthOAuth2ClientRequestSchema>;\n};\n\nasync function planOAuth2Clients(\n  client: OperatorClient,\n  workspaceId: string,\n  auths: ReadonlyArray<Readonly<AuthService>>,\n  deletedServices: ReadonlyArray<string>,\n  expectedLocalWebsites: ReadonlySet<string>,\n  forceApplyAll = false,\n) {\n  const changeSet = createChangeSet<\n    CreateOAuth2Clients,\n    UpdateOAuth2Client,\n    DeleteOAuth2Client,\n    ReplaceOAuth2Client\n  >(\"Auth oauth2Clients\");\n\n  const fetchOAuth2Clients = (namespaceName: string) => {\n    return fetchAllTolerant(async (pageToken, maxPageSize) => {\n      const { oauth2Clients, nextPageToken } = await client.listAuthOAuth2Clients({\n        workspaceId,\n        namespaceName,\n        pageToken,\n        pageSize: maxPageSize,\n      });\n      return [oauth2Clients, nextPageToken];\n    });\n  };\n\n  for (const auth of auths) {\n    const { config } = auth;\n    const existingOAuth2Clients = await fetchOAuth2Clients(config.name);\n    const existingClientsMap = new Map<string, (typeof existingOAuth2Clients)[number]>();\n    existingOAuth2Clients.forEach((oauth2Client) => {\n      existingClientsMap.set(oauth2Client.name, oauth2Client);\n      logger.registerSecret(oauth2Client.clientSecret);\n    });\n    for (const oauth2ClientName of Object.keys(config.oauth2Clients ?? {})) {\n      const oauth2Client = config.oauth2Clients?.[oauth2ClientName];\n      if (!oauth2Client) {\n        continue;\n      }\n      const newOAuth2Client = protoOAuth2Client(oauth2ClientName, oauth2Client);\n      const resolvedRedirectUris = await resolveStaticWebsiteUrls(\n        client,\n        workspaceId,\n        newOAuth2Client.redirectUris ?? [],\n        \"OAuth2 redirect URIs\",\n        { expectedLocalNames: expectedLocalWebsites },\n      );\n      if (existingClientsMap.has(oauth2ClientName)) {\n        const existingClient = assertDefined(\n          existingClientsMap.get(oauth2ClientName),\n          \"existingClientsMap missing entry for oauth2ClientName\",\n        );\n        if (existingClient.clientType !== newOAuth2Client.clientType) {\n          // Client type changed: need to replace (delete then create)\n          changeSet.replaces.push({\n            name: oauth2ClientName,\n            deleteRequest: {\n              workspaceId,\n              namespaceName: config.name,\n              name: oauth2ClientName,\n            },\n            createRequest: {\n              workspaceId,\n              namespaceName: config.name,\n              oauth2Client: newOAuth2Client,\n            },\n          });\n        } else {\n          const desiredComparable = {\n            ...newOAuth2Client,\n            redirectUris: resolvedRedirectUris,\n            accessTokenLifetime: oauth2LifetimeToSeconds(newOAuth2Client.accessTokenLifetime),\n            refreshTokenLifetime: oauth2LifetimeToSeconds(newOAuth2Client.refreshTokenLifetime),\n          };\n          const existingComparable = {\n            name: existingClient.name,\n            description: existingClient.description,\n            grantTypes: existingClient.grantTypes,\n            redirectUris: existingClient.redirectUris,\n            clientType: existingClient.clientType,\n            accessTokenLifetime: oauth2LifetimeToSeconds(existingClient.accessTokenLifetime),\n            refreshTokenLifetime: oauth2LifetimeToSeconds(existingClient.refreshTokenLifetime),\n            requireDpop: existingClient.requireDpop,\n          };\n          if (!forceApplyAll && areOAuth2ClientsEqual(existingComparable, desiredComparable)) {\n            changeSet.unchanged.push({ name: oauth2ClientName });\n          } else {\n            changeSet.updates.push({\n              name: oauth2ClientName,\n              request: {\n                workspaceId,\n                namespaceName: config.name,\n                oauth2Client: newOAuth2Client,\n              },\n            });\n          }\n        }\n        existingClientsMap.delete(oauth2ClientName);\n      } else {\n        changeSet.creates.push({\n          name: oauth2ClientName,\n          request: {\n            workspaceId,\n            namespaceName: config.name,\n            oauth2Client: newOAuth2Client,\n          },\n        });\n      }\n    }\n    existingClientsMap.forEach((_, name) => {\n      changeSet.deletes.push({\n        name,\n        request: {\n          workspaceId,\n          namespaceName: config.name,\n          name,\n        },\n      });\n    });\n  }\n\n  for (const namespaceName of deletedServices) {\n    const existingOAuth2Clients = await fetchOAuth2Clients(namespaceName);\n    existingOAuth2Clients.forEach((oauth2Client) => {\n      logger.registerSecret(oauth2Client.clientSecret);\n      changeSet.deletes.push({\n        name: oauth2Client.name,\n        request: {\n          workspaceId,\n          namespaceName,\n          name: oauth2Client.name,\n        },\n      });\n    });\n  }\n\n  return changeSet;\n}\n\nfunction protoOAuth2Client(\n  oauth2ClientName: string,\n  oauth2Client: OAuth2Client,\n): MessageInitShape<typeof AuthOAuth2ClientSchema> {\n  // `oauth2Client` is already parsed output: AuthConfigSchema.parse (wired in\n  // application.ts) validated it and transformed the numeric token lifetimes\n  // into Duration ({ seconds, nanos }). Consume it directly instead of\n  // re-parsing, which would reject the already-transformed lifetimes.\n  return {\n    name: oauth2ClientName,\n    description: oauth2Client.description,\n    grantTypes: oauth2Client.grantTypes.map((grantType) => {\n      switch (grantType) {\n        case \"authorization_code\":\n          return AuthOAuth2Client_GrantType.AUTHORIZATION_CODE;\n        case \"refresh_token\":\n          return AuthOAuth2Client_GrantType.REFRESH_TOKEN;\n        default:\n          throw internalError(`Unknown OAuth2 client grant type: ${grantType satisfies never}`);\n      }\n    }),\n    redirectUris: oauth2Client.redirectURIs,\n    clientType: (\n      {\n        confidential: AuthOAuth2Client_ClientType.CONFIDENTIAL,\n        public: AuthOAuth2Client_ClientType.PUBLIC,\n        browser: AuthOAuth2Client_ClientType.BROWSER,\n      } satisfies Record<NonNullable<OAuth2Client[\"clientType\"]>, AuthOAuth2Client_ClientType>\n    )[oauth2Client.clientType ?? \"confidential\"],\n    accessTokenLifetime: oauth2Client.accessTokenLifetimeSeconds,\n    refreshTokenLifetime: oauth2Client.refreshTokenLifetimeSeconds,\n    requireDpop: oauth2Client.requireDpop,\n  };\n}\n\ntype CreateSCIMConfig = {\n  name: string;\n  request: MessageInitShape<typeof CreateAuthSCIMConfigRequestSchema>;\n};\n\ntype UpdateSCIMConfig = {\n  name: string;\n  request: MessageInitShape<typeof UpdateAuthSCIMConfigRequestSchema>;\n};\n\ntype DeleteSCIMConfig = {\n  name: string;\n  request: MessageInitShape<typeof DeleteAuthSCIMConfigRequestSchema>;\n};\n\nasync function planSCIMConfigs(\n  client: OperatorClient,\n  workspaceId: string,\n  auths: ReadonlyArray<Readonly<AuthService>>,\n  deletedServices: ReadonlyArray<string>,\n) {\n  const changeSet = createChangeSet<CreateSCIMConfig, UpdateSCIMConfig, DeleteSCIMConfig>(\n    \"Auth scimConfigs\",\n  );\n\n  for (const auth of auths) {\n    const { config } = auth;\n    const name = `${config.name}-scim-config`;\n    const existing = await getOrNull(async () => {\n      return await client.getAuthSCIMConfig({\n        workspaceId,\n        namespaceName: config.name,\n      });\n    });\n    if (!existing) {\n      if (config.scim) {\n        changeSet.creates.push({\n          name,\n          request: {\n            workspaceId,\n            namespaceName: config.name,\n            scimConfig: protoSCIMConfig(config.scim),\n          },\n        });\n      }\n    } else if (config.scim) {\n      changeSet.updates.push({\n        name,\n        request: {\n          workspaceId,\n          namespaceName: config.name,\n          scimConfig: protoSCIMConfig(config.scim),\n        },\n      });\n    } else {\n      changeSet.deletes.push({\n        name,\n        request: {\n          workspaceId,\n          namespaceName: config.name,\n        },\n      });\n    }\n  }\n\n  for (const namespaceName of deletedServices) {\n    const existing = await getOrNull(async () => {\n      return await client.getAuthSCIMConfig({\n        workspaceId,\n        namespaceName,\n      });\n    });\n    if (!existing) continue;\n    changeSet.deletes.push({\n      name: `${namespaceName}-scim-config`,\n      request: {\n        workspaceId,\n        namespaceName,\n      },\n    });\n  }\n  return changeSet;\n}\n\nfunction protoSCIMConfig(scimConfig: SCIMConfig): MessageInitShape<typeof AuthSCIMConfigSchema> {\n  let authorizationType;\n  switch (scimConfig.authorization.type) {\n    case \"bearer\":\n      authorizationType = AuthSCIMConfig_AuthorizationType.BEARER;\n      break;\n    case \"oauth2\":\n      authorizationType = AuthSCIMConfig_AuthorizationType.OAUTH2;\n      break;\n    default:\n      throw internalError(\n        `Unknown SCIM authorization type: ${scimConfig.authorization.type satisfies never}`,\n      );\n  }\n\n  return {\n    machineUserName: scimConfig.machineUserName,\n    authorizationType,\n    authorizationConfig: {\n      case: \"bearerSecret\",\n      value: {\n        vaultName: scimConfig.authorization.bearerSecret?.vaultName,\n        secretKey: scimConfig.authorization.bearerSecret?.secretKey,\n      },\n    },\n  };\n}\n\ntype CreateSCIMResource = {\n  name: string;\n  request: MessageInitShape<typeof CreateAuthSCIMResourceRequestSchema>;\n};\n\ntype UpdateSCIMResource = {\n  name: string;\n  request: MessageInitShape<typeof UpdateAuthSCIMResourceRequestSchema>;\n};\n\ntype DeleteSCIMResource = {\n  name: string;\n  request: MessageInitShape<typeof DeleteAuthSCIMResourceRequestSchema>;\n};\n\nasync function planSCIMResources(\n  client: OperatorClient,\n  workspaceId: string,\n  auths: ReadonlyArray<Readonly<AuthService>>,\n  deletedServices: ReadonlyArray<string>,\n) {\n  const changeSet = createChangeSet<CreateSCIMResource, UpdateSCIMResource, DeleteSCIMResource>(\n    \"Auth scimResources\",\n  );\n\n  const fetchSCIMResources = async (namespaceName: string) => {\n    const response = await getOrNull(async () => {\n      const { scimResources } = await client.getAuthSCIMResources({\n        workspaceId,\n        namespaceName,\n      });\n      return scimResources;\n    });\n    return response ?? [];\n  };\n\n  for (const auth of auths) {\n    const { config } = auth;\n    const existingSCIMResources = await fetchSCIMResources(config.name);\n    const existingNameSet = new Set<string>();\n    existingSCIMResources.forEach((scimResource) => {\n      existingNameSet.add(scimResource.name);\n    });\n    for (const scimResource of config.scim?.resources ?? []) {\n      if (existingNameSet.has(scimResource.name)) {\n        changeSet.updates.push({\n          name: scimResource.name,\n          request: {\n            workspaceId,\n            namespaceName: config.name,\n            scimResource: protoSCIMResource(scimResource),\n          },\n        });\n        existingNameSet.delete(scimResource.name);\n      } else {\n        changeSet.creates.push({\n          name: scimResource.name,\n          request: {\n            workspaceId,\n            namespaceName: config.name,\n            scimResource: protoSCIMResource(scimResource),\n          },\n        });\n      }\n    }\n    existingNameSet.forEach((name) => {\n      changeSet.deletes.push({\n        name,\n        request: {\n          workspaceId,\n          namespaceName: config.name,\n          name,\n        },\n      });\n    });\n  }\n\n  for (const namespaceName of deletedServices) {\n    const existingSCIMResources = await fetchSCIMResources(namespaceName);\n    existingSCIMResources.forEach((scimResource) => {\n      changeSet.deletes.push({\n        name: scimResource.name,\n        request: {\n          workspaceId,\n          namespaceName,\n          name: scimResource.name,\n        },\n      });\n    });\n  }\n  return changeSet;\n}\n\nfunction protoSCIMResource(\n  scimResource: SCIMResource,\n): MessageInitShape<typeof AuthSCIMResourceSchema> {\n  return {\n    name: scimResource.name,\n    tailorDbNamespace: scimResource.tailorDBNamespace,\n    tailorDbType: scimResource.tailorDBType,\n    coreSchema: {\n      name: scimResource.coreSchema.name,\n      attributes: scimResource.coreSchema.attributes.map((attr) => protoSCIMAttribute(attr)),\n    },\n    attributeMapping: scimResource.attributeMapping.map((attr) => ({\n      tailorDbField: attr.tailorDBField,\n      scimPath: attr.scimPath,\n    })),\n  };\n}\n\nfunction protoSCIMAttribute(attr: SCIMAttribute): MessageInitShape<typeof AuthSCIMAttributeSchema> {\n  let typ;\n  switch (attr.type) {\n    case \"string\":\n      typ = AuthSCIMAttribute_Type.STRING;\n      break;\n    case \"number\":\n      typ = AuthSCIMAttribute_Type.NUMBER;\n      break;\n    case \"boolean\":\n      typ = AuthSCIMAttribute_Type.BOOLEAN;\n      break;\n    case \"datetime\":\n      typ = AuthSCIMAttribute_Type.DATETIME;\n      break;\n    case \"complex\":\n      typ = AuthSCIMAttribute_Type.COMPLEX;\n      break;\n    default:\n      throw internalError(`Unknown SCIM attribute type: ${attr.type satisfies never}`);\n  }\n  let mutability;\n  if (attr.mutability) {\n    switch (attr.mutability) {\n      case \"readOnly\":\n        mutability = AuthSCIMAttribute_Mutability.READ_ONLY;\n        break;\n      case \"readWrite\":\n        mutability = AuthSCIMAttribute_Mutability.READ_WRITE;\n        break;\n      case \"writeOnly\":\n        mutability = AuthSCIMAttribute_Mutability.WRITE_ONLY;\n        break;\n      default:\n        throw internalError(\n          `Unknown SCIM attribute mutability: ${attr.mutability satisfies never}`,\n        );\n    }\n  }\n  let uniqueness;\n  if (attr.uniqueness) {\n    switch (attr.uniqueness) {\n      case \"none\":\n        uniqueness = AuthSCIMAttribute_Uniqueness.NONE;\n        break;\n      case \"server\":\n        uniqueness = AuthSCIMAttribute_Uniqueness.SERVER;\n        break;\n      case \"global\":\n        uniqueness = AuthSCIMAttribute_Uniqueness.GLOBAL;\n        break;\n      default:\n        throw internalError(\n          `Unknown SCIM attribute uniqueness: ${attr.uniqueness satisfies never}`,\n        );\n    }\n  }\n  return {\n    type: typ,\n    name: attr.name,\n    description: attr.description,\n    mutability,\n    required: attr.required,\n    multiValued: attr.multiValued,\n    uniqueness,\n    canonicalValues: attr.canonicalValues ?? undefined,\n    subAttributes: attr.subAttributes?.map((attr) => protoSCIMAttribute(attr)),\n  };\n}\n\ntype CreateAuthHook = {\n  name: string;\n  request: MessageInitShape<typeof CreateAuthHookRequestSchema>;\n};\n\ntype UpdateAuthHook = {\n  name: string;\n  request: MessageInitShape<typeof UpdateAuthHookRequestSchema>;\n};\n\ntype DeleteAuthHook = {\n  name: string;\n  request: MessageInitShape<typeof DeleteAuthHookRequestSchema>;\n};\n\nfunction areAuthHooksEqual(\n  existing: {\n    scriptRef?: string;\n    invoker?: {\n      namespace?: string;\n      machineUserName?: string;\n    };\n  },\n  desired: {\n    scriptRef?: string;\n    invoker?: {\n      namespace?: string;\n      machineUserName?: string;\n    };\n  },\n): boolean {\n  return areNormalizedEqual(\n    {\n      scriptRef: existing.scriptRef ?? \"\",\n      invoker: existing.invoker\n        ? {\n            namespace: existing.invoker.namespace ?? \"\",\n            machineUserName: existing.invoker.machineUserName ?? \"\",\n          }\n        : undefined,\n    },\n    {\n      scriptRef: desired.scriptRef ?? \"\",\n      invoker: desired.invoker\n        ? {\n            namespace: desired.invoker.namespace ?? \"\",\n            machineUserName: desired.invoker.machineUserName ?? \"\",\n          }\n        : undefined,\n    },\n  );\n}\n\n/**\n * Format auth hook changes for grouped dry-run display.\n * @param changeSet - Auth hook changes\n * @param functionRegistryAuthHookChanges - Related function registry changes for auth hooks\n * @returns Display entries for auth hook output\n */\nexport function formatAuthHookChangeEntries(\n  changeSet: Pick<\n    ChangeSet<HasName, HasName, HasName>,\n    \"creates\" | \"updates\" | \"deletes\" | \"replaces\"\n  >,\n  functionRegistryAuthHookChanges?: RelatedFunctionRegistryChanges,\n): GroupedDisplayEntry[] {\n  return formatChangeEntriesWithFunctionRegistry(\n    \"authHook\",\n    changeSet,\n    functionRegistryAuthHookChanges,\n    (item) => {\n      const [namespace, hookPoint] = item.name.split(\"/\");\n      return namespace && hookPoint ? [authHookFunctionName(namespace, hookPoint)] : [];\n    },\n    {\n      getNamespace: (item) => item.name.split(\"/\")[0],\n      getDisplayName: (item) => item.name.split(\"/\")[1] ?? item.name,\n    },\n  );\n}\n\nasync function planAuthHooks(\n  client: OperatorClient,\n  workspaceId: string,\n  auths: ReadonlyArray<Readonly<AuthService>>,\n  deletedServices: ReadonlyArray<string>,\n  forceApplyAll = false,\n) {\n  const changeSet = createChangeSet<CreateAuthHook, UpdateAuthHook, DeleteAuthHook>(\"Auth hooks\");\n\n  for (const auth of auths) {\n    const { config } = auth;\n    const beforeLogin = config.hooks?.beforeLogin;\n\n    const existingHook:\n      | {\n          scriptRef?: string;\n          invoker?: {\n            namespace?: string;\n            machineUserName?: string;\n          };\n        }\n      | undefined = await getOrNull(async () => {\n      const { hook } = await client.getAuthHook({\n        workspaceId,\n        namespaceName: config.name,\n        hookPoint: AuthHookPoint.BEFORE_LOGIN,\n      });\n      return hook;\n    });\n\n    if (beforeLogin) {\n      const hookRequest = {\n        workspaceId,\n        namespaceName: config.name,\n        hook: {\n          hookPoint: AuthHookPoint.BEFORE_LOGIN,\n          scriptRef: authHookFunctionName(config.name, \"before-login\"),\n          invoker: {\n            namespace: config.name,\n            machineUserName: beforeLogin.invoker,\n          },\n        },\n      };\n\n      if (existingHook) {\n        if (!forceApplyAll && areAuthHooksEqual(existingHook, hookRequest.hook)) {\n          changeSet.unchanged.push({\n            name: `${config.name}/before-login`,\n          });\n        } else {\n          changeSet.updates.push({\n            name: `${config.name}/before-login`,\n            request: hookRequest,\n          });\n        }\n      } else {\n        changeSet.creates.push({\n          name: `${config.name}/before-login`,\n          request: hookRequest,\n        });\n      }\n    } else if (existingHook) {\n      changeSet.deletes.push({\n        name: `${config.name}/before-login`,\n        request: {\n          workspaceId,\n          namespaceName: config.name,\n          hookPoint: AuthHookPoint.BEFORE_LOGIN,\n        },\n      });\n    }\n  }\n\n  for (const namespaceName of deletedServices) {\n    const existingHookResponse = await getOrNull(async () => {\n      return await client.getAuthHook({\n        workspaceId,\n        namespaceName,\n        hookPoint: AuthHookPoint.BEFORE_LOGIN,\n      });\n    });\n    if (existingHookResponse) {\n      changeSet.deletes.push({\n        name: `${namespaceName}/before-login`,\n        request: {\n          workspaceId,\n          namespaceName,\n          hookPoint: AuthHookPoint.BEFORE_LOGIN,\n        },\n      });\n    }\n  }\n\n  return changeSet;\n}\n","import { CLIError } from \"#/cli/shared/errors\";\nimport type { AuthInvoker } from \"#/types/auth.generated\";\n\n/**\n * Normalize an invoker value to the object form required by the proto payload.\n *\n * Accepts either:\n * - `undefined` — returns undefined\n * - a plain string (machine user name) — expands to `{ namespace, machineUserName }` using `authNamespace`\n * - an internal object `{ namespace, machineUserName }` — returned as-is\n * @param invoker - String machine user name or internal object form\n * @param authNamespace - Auth service namespace (required when invoker is a string)\n * @param context - Contextual label used in error messages (e.g. `resolver \"foo\"`)\n * @returns Object form of the invoker, or undefined\n */\nexport function normalizeInvoker(\n  invoker: string | AuthInvoker | undefined,\n  authNamespace: string | undefined,\n  context: string,\n): { namespace: string; machineUserName: string } | undefined {\n  if (invoker === undefined) return undefined;\n  if (typeof invoker === \"string\") {\n    if (!authNamespace) {\n      throw CLIError({\n        code: \"INVOKER_AUTH_REQUIRED\",\n        message: `${context} uses a string invoker (\"${invoker}\"), but no Auth service is configured.`,\n        suggestion: \"Configure an Auth service before using invoker.\",\n      });\n    }\n    return { namespace: authNamespace, machineUserName: invoker };\n  }\n  return invoker;\n}\n","import { type MessageInitShape } from \"@bufbuild/protobuf\";\nimport {\n  type CreateExecutorExecutorRequestSchema,\n  type DeleteExecutorExecutorRequestSchema,\n  type UpdateExecutorExecutorRequestSchema,\n} from \"@tailor-platform/tailor-proto/executor_pb\";\nimport {\n  ExecutorExecutorSchema,\n  type ExecutorTargetConfigSchema,\n  ExecutorTargetType,\n  type ExecutorTargetWebhookHeaderSchema,\n  type ExecutorTriggerConfigSchema,\n  type ExecutorTriggerEventConfigSchema,\n  ExecutorTriggerType,\n} from \"@tailor-platform/tailor-proto/executor_resource_pb\";\nimport {\n  getApplicationAuthNamespace,\n  requireApplicationAuthNamespace,\n} from \"#/cli/shared/auth-namespace\";\nimport { type OperatorClient } from \"#/cli/shared/client\";\nimport { CLIError, internalError } from \"#/cli/shared/errors\";\nimport { buildExecutorArgsExpr } from \"#/cli/shared/runtime-exprs\";\nimport { stringifyFunction } from \"#/parser/service/tailordb/index\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { createChangeSet, type ChangeSet } from \"./change-set\";\nimport { areNormalizedEqual, normalizeProtoConfig, toComparableProtoJson } from \"./compare\";\nimport { executorFunctionName } from \"./function-registry\";\nimport {\n  formatChangeEntriesWithFunctionRegistry,\n  type GroupedDisplayEntry,\n  type RelatedFunctionRegistryChanges,\n} from \"./grouped-display\";\nimport { normalizeInvoker } from \"./invoker\";\nimport {\n  buildMetaRequest,\n  hasMatchingSdkVersion,\n  type MetadataLabelWrite,\n  resourceTrn,\n  writeMetadataLabels,\n} from \"./label\";\nimport {\n  fetchExistingResourcesWithLabels,\n  trackDesiredResourceOwnership,\n  trackRemainingResourceOwner,\n} from \"./owned-resource\";\nimport type { ApplyPhase, PlanContext } from \"#/cli/commands/deploy/types\";\nimport type { Application } from \"#/cli/services/application\";\nimport type { Executor } from \"#/types/executor.generated\";\nimport type { OwnerConflict, UnmanagedResource } from \"./confirm\";\n\n/**\n * Apply executor-related changes for the given phase.\n * @param client - Operator client instance\n * @param result - Planned executor changes\n * @param phase - Apply phase (defaults to \"create-update\")\n * @returns Promise that resolves when executors are applied\n */\nexport async function applyExecutor(\n  client: OperatorClient,\n  result: Awaited<ReturnType<typeof planExecutor>>,\n  phase: Extract<ApplyPhase, \"create-update\" | \"delete\"> = \"create-update\",\n) {\n  const { changeSet } = result;\n  if (phase === \"create-update\") {\n    // Executors\n    await Promise.all([\n      ...changeSet.creates.map(async (create) => {\n        await client.createExecutorExecutor(create.request);\n        await writeMetadataLabels(client, create.metaRequest);\n      }),\n      ...changeSet.updates.map(async (update) => {\n        await client.updateExecutorExecutor(update.request);\n        await writeMetadataLabels(client, update.metaRequest);\n      }),\n    ]);\n  } else {\n    // Delete in reverse order of dependencies\n    // Executors\n    await Promise.all(changeSet.deletes.map((del) => client.deleteExecutorExecutor(del.request)));\n  }\n}\n\ntype CreateExecutor = {\n  name: string;\n  request: MessageInitShape<typeof CreateExecutorExecutorRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype UpdateExecutor = {\n  name: string;\n  request: MessageInitShape<typeof UpdateExecutorExecutorRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype DeleteExecutor = {\n  name: string;\n  request: MessageInitShape<typeof DeleteExecutorExecutorRequestSchema>;\n};\n\n/**\n * Plan executor-related changes based on current and desired state.\n * @param context - Planning context\n * @returns Planned changes\n */\nexport async function planExecutor(context: PlanContext) {\n  const { client, workspaceId, application, forRemoval } = context;\n  const changeSet = createChangeSet<CreateExecutor, UpdateExecutor, DeleteExecutor>(\"Executors\");\n  const conflicts: OwnerConflict[] = [];\n  const unmanaged: UnmanagedResource[] = [];\n  const resourceOwners = new Set<string>();\n\n  const existingExecutors = await fetchExistingResourcesWithLabels({\n    client,\n    fetchPage: async (pageToken, pageSize) => {\n      const { executors, nextPageToken } = await client.listExecutorExecutors({\n        workspaceId,\n        pageToken,\n        pageSize,\n      });\n      return [executors, nextPageToken];\n    },\n    getName: (resource) => resource.name,\n    getTrn: (name) => resourceTrn(workspaceId, \"executor\", name),\n  });\n\n  const executors = forRemoval ? {} : ((await application.executorService?.loadExecutors()) ?? {});\n  for (const executor of Object.values(executors)) {\n    const existing = existingExecutors[executor.name];\n    const metaRequest = await buildMetaRequest({\n      trn: resourceTrn(workspaceId, \"executor\", executor.name),\n      appName: application.name,\n      appId: application.id,\n    });\n    const desiredExecutor = protoExecutor(context, executor);\n    if (existing) {\n      const owned = trackDesiredResourceOwnership({\n        labels: existing.allLabels,\n        ownerLabel: existing.label,\n        appName: application.name,\n        appId: application.id,\n        resourceType: \"Executor\",\n        resourceName: executor.name,\n        conflicts,\n        unmanaged,\n      });\n\n      if (\n        owned &&\n        hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) &&\n        areExecutorsEqual(existing.resource, desiredExecutor)\n      ) {\n        changeSet.unchanged.push({ name: executor.name });\n      } else {\n        changeSet.updates.push({\n          name: executor.name,\n          request: {\n            workspaceId,\n            executor: desiredExecutor,\n          },\n          metaRequest,\n        });\n      }\n      delete existingExecutors[executor.name];\n    } else {\n      changeSet.creates.push({\n        name: executor.name,\n        request: {\n          workspaceId,\n          executor: desiredExecutor,\n        },\n        metaRequest,\n      });\n    }\n  }\n  Object.entries(existingExecutors).forEach(([name]) => {\n    const entry = existingExecutors[name];\n    const label = entry?.label;\n    const owned = trackRemainingResourceOwner({\n      labels: entry?.allLabels,\n      ownerLabel: label,\n      appName: application.name,\n      appId: application.id,\n      resourceOwners,\n    });\n    if (owned) {\n      changeSet.deletes.push({\n        name,\n        request: {\n          workspaceId,\n          name,\n        },\n      });\n    }\n  });\n\n  return { changeSet, conflicts, unmanaged, resourceOwners };\n}\n\ntype ExecutorDisplayEntry = GroupedDisplayEntry;\n\nfunction isFunctionBackedExecutor(\n  executor: MessageInitShape<typeof ExecutorExecutorSchema> | undefined,\n) {\n  return (\n    executor?.targetType === ExecutorTargetType.FUNCTION ||\n    executor?.targetType === ExecutorTargetType.JOB_FUNCTION\n  );\n}\n\n/**\n * Build desired executor configs keyed by executor name from create/update changes.\n * @param changeSet - Executor create/update changes\n * @returns Executor configs keyed by name\n */\nexport function buildPlannedExecutorsByName(\n  changeSet: Pick<ChangeSet<CreateExecutor, UpdateExecutor, DeleteExecutor>, \"creates\" | \"updates\">,\n): Record<string, MessageInitShape<typeof ExecutorExecutorSchema> | undefined> {\n  return Object.fromEntries(\n    [...changeSet.creates, ...changeSet.updates].map((item) => [item.name, item.request.executor]),\n  );\n}\n\n/**\n * Format executor changes for grouped dry-run display.\n * @param changeSet - Executor changes\n * @param executors - Desired executor configs keyed by name\n * @param functionRegistryExecutorChanges - Related function registry changes for executors\n * @returns Display entries for executor output\n */\nexport function formatExecutorChangeEntries(\n  changeSet: Pick<\n    ChangeSet<CreateExecutor, UpdateExecutor, DeleteExecutor>,\n    \"creates\" | \"updates\" | \"deletes\" | \"replaces\"\n  >,\n  executors: Record<string, MessageInitShape<typeof ExecutorExecutorSchema> | undefined>,\n  functionRegistryExecutorChanges?: RelatedFunctionRegistryChanges,\n): ExecutorDisplayEntry[] {\n  return formatChangeEntriesWithFunctionRegistry(\n    \"executor\",\n    changeSet,\n    functionRegistryExecutorChanges,\n    (item, action) => {\n      if (action === \"delete\") {\n        return [executorFunctionName(item.name)];\n      }\n      const executor = executors[item.name];\n      return executor && isFunctionBackedExecutor(executor)\n        ? [executorFunctionName(item.name)]\n        : [];\n    },\n  );\n}\n\nfunction normalizeComparableExecutor(executor: MessageInitShape<typeof ExecutorExecutorSchema>) {\n  const normalized = normalizeProtoConfig(executor);\n  const webhookHeaders =\n    normalized.targetConfig?.config?.case === \"webhook\"\n      ? (normalized.targetConfig.config.value.headers ?? []).toSorted((left, right) =>\n          (left.key ?? \"\").localeCompare(right.key ?? \"\"),\n        )\n      : undefined;\n  const triggerConfig =\n    normalized.triggerConfig?.config?.case === \"incomingWebhook\"\n      ? {\n          ...normalized.triggerConfig,\n          config: {\n            ...normalized.triggerConfig.config,\n            value: {\n              ...normalized.triggerConfig.config.value,\n              // secret is server-managed, so omit it from comparison\n              secret: undefined,\n            },\n          },\n        }\n      : normalized.triggerConfig?.config?.case === \"event\"\n        ? {\n            ...normalized.triggerConfig,\n            config: {\n              ...normalized.triggerConfig.config,\n              value: {\n                ...normalized.triggerConfig.config.value,\n                // The platform fills this field in responses even though the SDK never sets it.\n                eventType: undefined,\n              },\n            },\n          }\n        : normalized.triggerConfig;\n  const comparable = normalizeProtoConfig({\n    name: normalized.name,\n    description: normalized.description ?? \"\",\n    disabled: normalized.disabled ?? false,\n    triggerType: normalized.triggerType,\n    triggerConfig,\n    targetType: normalized.targetType,\n    targetConfig:\n      normalized.targetConfig?.config?.case === \"webhook\"\n        ? {\n            ...normalized.targetConfig,\n            config: {\n              ...normalized.targetConfig.config,\n              value: {\n                ...normalized.targetConfig.config.value,\n                headers: webhookHeaders,\n              },\n            },\n          }\n        : normalized.targetConfig?.config?.case === \"function\"\n          ? {\n              ...normalized.targetConfig,\n              config: {\n                ...normalized.targetConfig.config,\n                value: {\n                  ...normalized.targetConfig.config.value,\n                  script: undefined,\n                },\n              },\n            }\n          : normalized.targetConfig,\n  }) as MessageInitShape<typeof ExecutorExecutorSchema>;\n  return toComparableProtoJson(ExecutorExecutorSchema, comparable);\n}\n\nfunction areExecutorsEqual(\n  existing: MessageInitShape<typeof ExecutorExecutorSchema>,\n  desired: MessageInitShape<typeof ExecutorExecutorSchema>,\n): boolean {\n  return areNormalizedEqual(\n    normalizeComparableExecutor(existing),\n    normalizeComparableExecutor(desired),\n  );\n}\n\n/**\n * Resolve a resource's namespace from same-run peer configs, throwing when the\n * name is claimed by more than one namespace in the deploy run.\n * @param sameRunNamespaces - Namespaces keyed by resource name across the deploy run\n * @param resourceName - Resource name to resolve\n * @param resourceLabel - Resource label used in error messages\n * @returns The owning namespace, or undefined when the name is unknown\n */\nfunction resolveSameRunNamespace(\n  sameRunNamespaces: ReadonlyMap<string, string | undefined> | undefined,\n  resourceName: string,\n  resourceLabel: string,\n): string | undefined {\n  if (!sameRunNamespaces?.has(resourceName)) {\n    return undefined;\n  }\n  const namespace = sameRunNamespaces.get(resourceName);\n  if (!namespace) {\n    throw CLIError({\n      code: \"DEPLOY_RESOURCE_NAMESPACE_AMBIGUOUS\",\n      message:\n        `${resourceLabel} \"${resourceName}\" is defined in multiple namespaces in this deploy run. ` +\n        `Move the trigger to the application that owns it or use unique names.`,\n    });\n  }\n  return namespace;\n}\n\n/**\n * Find the local TailorDB namespace that declares the given table.\n * @param application - Loaded application\n * @param tableName - TailorDB table name to look up\n * @returns The declaring namespace, or undefined when no local service has it\n */\nfunction findTailorDBNamespace(\n  application: Readonly<Application>,\n  tableName: string,\n): string | undefined {\n  return application.tailorDBServices.find((service) => Object.hasOwn(service.types, tableName))\n    ?.namespace;\n}\n\n/**\n * Find the local resolver namespace that declares the given resolver.\n * @param application - Loaded application\n * @param resolverName - Resolver name to look up\n * @returns The declaring namespace, or undefined when no local service has it\n */\nexport function findResolverNamespace(\n  application: Readonly<Application>,\n  resolverName: string,\n): string | undefined {\n  return application.resolverServices.find((service) =>\n    Object.values(service.resolvers).some((resolver) => resolver.name === resolverName),\n  )?.namespace;\n}\n\nfunction resolveNamespace(params: {\n  resourceLabel: string;\n  resourceName: string;\n  localNamespaces: ReadonlyArray<string>;\n  findLocalNamespace: () => string | undefined;\n  sameRunNamespaces?: ReadonlyMap<string, string | undefined>;\n}): string {\n  const { resourceLabel, resourceName, localNamespaces, findLocalNamespace, sameRunNamespaces } =\n    params;\n  const localNamespace = findLocalNamespace();\n  if (localNamespace !== undefined) {\n    return localNamespace;\n  }\n  const sameRunNamespace = resolveSameRunNamespace(sameRunNamespaces, resourceName, resourceLabel);\n  if (sameRunNamespace !== undefined) {\n    return sameRunNamespace;\n  }\n  const sameRunAvailableNamespaces = sameRunNamespaces\n    ? [...new Set([...sameRunNamespaces.values()].filter((value) => value !== undefined))]\n    : [];\n  const availableNamespaces = [...localNamespaces, ...sameRunAvailableNamespaces];\n  throw CLIError({\n    code: \"DEPLOY_RESOURCE_NOT_FOUND\",\n    message: `${resourceLabel} \"${resourceName}\" not found in any namespace. Available namespaces: ${availableNamespaces.join(\", \")}`,\n  });\n}\n\nfunction resolveTailorDBNamespace(\n  application: Readonly<Application>,\n  typeName: string,\n  sameRunNamespaces?: ReadonlyMap<string, string | undefined>,\n): string {\n  return resolveNamespace({\n    resourceLabel: \"TailorDB table\",\n    resourceName: typeName,\n    localNamespaces: application.tailorDBServices.map((service) => service.namespace),\n    findLocalNamespace: () => findTailorDBNamespace(application, typeName),\n    sameRunNamespaces,\n  });\n}\n\nfunction resolveResolverNamespace(\n  application: Readonly<Application>,\n  resolverName: string,\n  sameRunNamespaces?: ReadonlyMap<string, string | undefined>,\n): string {\n  return resolveNamespace({\n    resourceLabel: \"Resolver\",\n    resourceName: resolverName,\n    localNamespaces: application.resolverServices.map((service) => service.namespace),\n    findLocalNamespace: () => findResolverNamespace(application, resolverName),\n    sameRunNamespaces,\n  });\n}\n\n/**\n * Collect IdP names declared by the application, including external IdP\n * subgraphs.\n * @param application - Loaded application\n * @returns IdP names visible from the application config\n */\nexport function collectApplicationIdpNames(\n  application: Readonly<Application>,\n): ReadonlySet<string> {\n  const names = new Set(application.idpServices.map((idp) => idp.name));\n  for (const subgraph of application.subgraphs) {\n    if (subgraph.Type === \"idp\") {\n      names.add(subgraph.Name);\n    }\n  }\n  return names;\n}\n\nfunction resolveIdpNamespace(\n  application: Readonly<Application>,\n  executorName: string,\n  idpName: string | undefined,\n  sameRunIdpNames?: ReadonlySet<string>,\n): string {\n  const localIdpNames = collectApplicationIdpNames(application);\n  if (idpName !== undefined) {\n    const candidateNames = sameRunIdpNames ?? localIdpNames;\n    if (!candidateNames.has(idpName)) {\n      const available = [...candidateNames].join(\", \");\n      throw CLIError({\n        code: \"EXECUTOR_IDP_NOT_FOUND\",\n        message:\n          `Executor \"${executorName}\" specifies IdP \"${idpName}\" in its idpUser trigger, ` +\n          `but no IdP with that name is configured. Available IdPs: ${available}`,\n      });\n    }\n    return idpName;\n  }\n  if (localIdpNames.size === 0) {\n    throw CLIError({\n      code: \"EXECUTOR_IDP_REQUIRED\",\n      message: `Executor \"${executorName}\" uses an idpUser trigger but no IdP is configured.`,\n    });\n  }\n  if (localIdpNames.size > 1) {\n    const available = [...localIdpNames].join(\", \");\n    throw CLIError({\n      code: \"EXECUTOR_IDP_AMBIGUOUS\",\n      message:\n        `Executor \"${executorName}\" uses an idpUser trigger but the project defines multiple IdPs ` +\n        `(${available}). Specify which IdP to subscribe to via the trigger's \"idp\" option.`,\n    });\n  }\n  return assertDefined([...localIdpNames][0], \"idp service missing\");\n}\n\nfunction protoExecutor(\n  context: PlanContext,\n  executor: Executor,\n): MessageInitShape<typeof ExecutorExecutorSchema> {\n  const { application } = context;\n  const appName = application.name;\n  const env = application.env;\n  const trigger = executor.trigger;\n  let triggerType: ExecutorTriggerType;\n  let triggerConfig: MessageInitShape<typeof ExecutorTriggerConfigSchema>;\n\n  const argsExpr = buildExecutorArgsExpr(trigger.kind, env);\n\n  function typedEventTrigger(\n    typedConfig: MessageInitShape<typeof ExecutorTriggerEventConfigSchema>[\"typedConfig\"],\n  ): MessageInitShape<typeof ExecutorTriggerConfigSchema> {\n    return { config: { case: \"event\", value: { typedConfig } } };\n  }\n\n  switch (trigger.kind) {\n    case \"schedule\":\n      triggerType = ExecutorTriggerType.SCHEDULE;\n      triggerConfig = {\n        config: {\n          case: \"schedule\",\n          value: {\n            timezone: trigger.timezone,\n            frequency: trigger.cron,\n          },\n        },\n      };\n      break;\n    case \"tailordb\":\n      triggerType = ExecutorTriggerType.EVENT;\n      triggerConfig = typedEventTrigger({\n        case: \"tailordb\",\n        value: {\n          eventTypes: trigger.events,\n          namespaceName: resolveTailorDBNamespace(\n            application,\n            trigger.tableName,\n            context.tailorDBTypeNamespaces,\n          ),\n          typeName: trigger.tableName,\n          ...(trigger.condition\n            ? { condition: { expr: `(${stringifyFunction(trigger.condition)})(${argsExpr})` } }\n            : {}),\n        },\n      });\n      break;\n    case \"resolverExecuted\":\n      triggerType = ExecutorTriggerType.EVENT;\n      triggerConfig = typedEventTrigger({\n        case: \"pipeline\",\n        value: {\n          eventTypes: [\"pipeline.resolver.executed\"],\n          namespaceName: resolveResolverNamespace(\n            application,\n            trigger.resolverName,\n            context.resolverNamespaces,\n          ),\n          resolverName: trigger.resolverName,\n          ...(trigger.condition\n            ? { condition: { expr: `(${stringifyFunction(trigger.condition)})(${argsExpr})` } }\n            : {}),\n        },\n      });\n      break;\n    case \"incomingWebhook\":\n      triggerType = ExecutorTriggerType.INCOMING_WEBHOOK;\n      triggerConfig = {\n        config: {\n          case: \"incomingWebhook\",\n          value: trigger.response\n            ? {\n                response: {\n                  ...(trigger.response.body\n                    ? {\n                        body: {\n                          expr: `(${stringifyFunction(trigger.response.body)})(${argsExpr})`,\n                        },\n                      }\n                    : {}),\n                  ...(trigger.response.statusCode != null\n                    ? { statusCode: trigger.response.statusCode }\n                    : {}),\n                },\n              }\n            : {},\n        },\n      };\n      break;\n    case \"idpUser\":\n      triggerType = ExecutorTriggerType.EVENT;\n      triggerConfig = typedEventTrigger({\n        case: \"idp\",\n        value: {\n          eventTypes: trigger.events,\n          namespaceName: resolveIdpNamespace(\n            application,\n            executor.name,\n            trigger.idp,\n            context.idpNames,\n          ),\n        },\n      });\n      break;\n    case \"authAccessToken\":\n      triggerType = ExecutorTriggerType.EVENT;\n      triggerConfig = typedEventTrigger({\n        case: \"auth\",\n        value: {\n          eventTypes: trigger.events,\n          namespaceName: requireApplicationAuthNamespace(application),\n        },\n      });\n      break;\n    case \"workflowExecution\":\n    case \"workflowJobExecution\":\n      triggerType = ExecutorTriggerType.EVENT;\n      triggerConfig = typedEventTrigger({\n        case: \"workflow\",\n        value: {\n          eventTypes: trigger.events,\n          workflowName: trigger.workflowName,\n          ...(trigger.condition\n            ? { condition: { expr: `(${stringifyFunction(trigger.condition)})(${argsExpr})` } }\n            : {}),\n        },\n      });\n      break;\n    default:\n      throw internalError(`Unknown trigger: ${trigger satisfies never}`);\n  }\n\n  const target = executor.operation;\n  let targetType: ExecutorTargetType;\n  let targetConfig: MessageInitShape<typeof ExecutorTargetConfigSchema>;\n\n  const authNamespace = getApplicationAuthNamespace(application);\n  const invokerContext = `Executor \"${executor.name}\"`;\n\n  switch (target.kind) {\n    case \"webhook\": {\n      targetType = ExecutorTargetType.WEBHOOK;\n      targetConfig = {\n        config: {\n          case: \"webhook\",\n          value: {\n            url: {\n              expr: `(${stringifyFunction(target.url)})(${argsExpr})`,\n            },\n            headers: target.headers\n              ? Object.entries(target.headers).map(([key, v]) => {\n                  let value: MessageInitShape<typeof ExecutorTargetWebhookHeaderSchema>[\"value\"];\n                  if (typeof v === \"string\") {\n                    value = {\n                      case: \"rawValue\",\n                      value: v,\n                    };\n                  } else {\n                    value = {\n                      case: \"secretValue\",\n                      value: {\n                        vaultName: v.vault,\n                        secretKey: v.key,\n                      },\n                    };\n                  }\n                  return { key, value };\n                })\n              : undefined,\n            body: target.requestBody\n              ? {\n                  expr: `(${stringifyFunction(target.requestBody)})(${argsExpr})`,\n                }\n              : undefined,\n          },\n        },\n      };\n      break;\n    }\n    case \"graphql\": {\n      targetType = ExecutorTargetType.TAILOR_GRAPHQL;\n      targetConfig = {\n        config: {\n          case: \"tailorGraphql\",\n          value: {\n            appName: target.appName ?? appName,\n            query: target.query,\n            variables: target.variables\n              ? {\n                  expr: `(${stringifyFunction(target.variables)})(${argsExpr})`,\n                }\n              : undefined,\n            invoker: normalizeInvoker(target.invoker, authNamespace, invokerContext),\n          },\n        },\n      };\n      break;\n    }\n    case \"function\":\n    case \"jobFunction\": {\n      if (target.kind === \"function\") {\n        targetType = ExecutorTargetType.FUNCTION;\n      } else {\n        targetType = ExecutorTargetType.JOB_FUNCTION;\n      }\n\n      targetConfig = {\n        config: {\n          case: \"function\",\n          value: {\n            name: \"operation\",\n            scriptRef: executorFunctionName(executor.name),\n            variables: {\n              expr: argsExpr,\n            },\n            invoker: normalizeInvoker(target.invoker, authNamespace, invokerContext),\n          },\n        },\n      };\n      break;\n    }\n    case \"workflow\": {\n      targetType = ExecutorTargetType.WORKFLOW;\n      targetConfig = {\n        config: {\n          case: \"workflow\",\n          value: {\n            workflowName: target.workflowName,\n            variables:\n              target.args !== undefined\n                ? typeof target.args === \"function\"\n                  ? { expr: `(${stringifyFunction(target.args)})(${argsExpr})` }\n                  : { expr: JSON.stringify(target.args) }\n                : undefined,\n            invoker: normalizeInvoker(target.invoker, authNamespace, invokerContext),\n          },\n        },\n      };\n      break;\n    }\n    default:\n      throw internalError(`Unknown target: ${target satisfies never}`);\n  }\n\n  return {\n    name: executor.name,\n    description: executor.description,\n    disabled: executor.disabled,\n    triggerType,\n    triggerConfig,\n    targetType,\n    targetConfig,\n  };\n}\n","import { type MessageInitShape } from \"@bufbuild/protobuf\";\nimport {\n  type CreatePipelineResolverRequestSchema,\n  type CreatePipelineServiceRequestSchema,\n  type DeletePipelineResolverRequestSchema,\n  type DeletePipelineServiceRequestSchema,\n  type UpdatePipelineResolverRequestSchema,\n  type UpdatePipelineServiceRequestSchema,\n} from \"@tailor-platform/tailor-proto/pipeline_pb\";\nimport {\n  type PipelineResolver_FieldSchema,\n  PipelineResolver_OperationType,\n  type PipelineResolver_PipelineSchema,\n  type PipelineResolver_TypeSchema,\n  PipelineResolverSchema,\n} from \"@tailor-platform/tailor-proto/pipeline_resource_pb\";\nimport * as inflection from \"inflection\";\nimport { type ResolverService } from \"#/cli/services/resolver/service\";\nimport { getApplicationAuthNamespace } from \"#/cli/shared/auth-namespace\";\nimport { fetchAllTolerant, type OperatorClient } from \"#/cli/shared/client\";\nimport {\n  assertNoPublishEventsConflict,\n  publishEventsConflict,\n  resolvePublishEvents,\n  subscribesToEvents,\n} from \"#/cli/shared/publish-events\";\nimport { buildResolverOperationHookExpr } from \"#/cli/shared/runtime-exprs\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { createChangeSet, type ChangeSet } from \"./change-set\";\nimport { areNormalizedEqual, toComparableProtoJson } from \"./compare\";\nimport { resolverFunctionName } from \"./function-registry\";\nimport {\n  formatChangeEntriesWithFunctionRegistry,\n  type GroupedDisplayEntry,\n  type RelatedFunctionRegistryChanges,\n} from \"./grouped-display\";\nimport { normalizeInvoker } from \"./invoker\";\nimport {\n  addDependencyRecords,\n  buildMetaRequest,\n  type DependentAppsByResource,\n  eventSourceKey,\n  hasMatchingSdkVersion,\n  type MetadataLabelWrite,\n  resolverTrn,\n  resourceTrn,\n  writeMetadataLabels,\n} from \"./label\";\nimport {\n  fetchExistingResourcesWithLabels,\n  trackDesiredResourceOwnership,\n  trackRemainingResourceOwner,\n} from \"./owned-resource\";\nimport type { ApplyPhase, PlanContext } from \"#/cli/commands/deploy/types\";\nimport type { Executor } from \"#/types/executor.generated\";\nimport type { TailorField } from \"#/types/field.generated\";\nimport type { Resolver } from \"#/types/resolver.generated\";\nimport type { OwnerConflict, UnmanagedResource } from \"./confirm\";\n\n// Scalar type mapping for field type conversion\nconst SCALAR_TYPE_MAP = {\n  uuid: { kind: \"ScalarType\", name: \"ID\" },\n  string: { kind: \"ScalarType\", name: \"String\" },\n  integer: { kind: \"ScalarType\", name: \"Int\" },\n  float: { kind: \"ScalarType\", name: \"Float\" },\n  decimal: { kind: \"CustomScalarType\", name: \"Decimal\" },\n  boolean: { kind: \"ScalarType\", name: \"Boolean\" },\n  date: { kind: \"CustomScalarType\", name: \"Date\" },\n  datetime: { kind: \"CustomScalarType\", name: \"DateTime\" },\n  time: { kind: \"CustomScalarType\", name: \"Time\" },\n} as const satisfies Record<\n  Exclude<TailorField[\"type\"], \"enum\" | \"nested\">,\n  { kind: \"ScalarType\" | \"CustomScalarType\"; name: string }\n>;\n\n/**\n * Apply resolver pipeline changes for the given phase.\n * @param client - Operator client instance\n * @param result - Planned pipeline changes\n * @param phase - Apply phase\n * @returns Promise that resolves when pipeline changes are applied\n */\nexport async function applyPipeline(\n  client: OperatorClient,\n  result: Awaited<ReturnType<typeof planPipeline>>,\n  phase: Exclude<ApplyPhase, \"delete\"> = \"create-update\",\n) {\n  const { changeSet } = result;\n  if (phase === \"create-update\") {\n    // Services\n    await Promise.all([\n      ...changeSet.service.creates.map(async (create) => {\n        await client.createPipelineService(create.request);\n        await writeMetadataLabels(client, create.metaRequest);\n      }),\n      ...changeSet.service.updates.map(async (update) => {\n        await client.updatePipelineService(update.request);\n        await writeMetadataLabels(client, update.metaRequest);\n      }),\n    ]);\n\n    // Resolvers. An unchanged resolver still gets its labels written, because its\n    // dependency records can change while its definition does not.\n    await Promise.all([\n      ...changeSet.resolver.creates.map(async (create) => {\n        await client.createPipelineResolver(create.request);\n        await writeMetadataLabels(client, create.metaRequest);\n      }),\n      ...changeSet.resolver.updates.map(async (update) => {\n        await client.updatePipelineResolver(update.request);\n        await writeMetadataLabels(client, update.metaRequest);\n      }),\n      ...changeSet.resolver.unchanged.flatMap((entry) =>\n        entry.metaRequest ? [writeMetadataLabels(client, entry.metaRequest)] : [],\n      ),\n    ]);\n  } else if (phase === \"delete-resources\") {\n    // Delete in reverse order of dependencies\n    // Resolvers\n    await Promise.all(\n      changeSet.resolver.deletes.map((del) => client.deletePipelineResolver(del.request)),\n    );\n  } else {\n    // Services only\n    await Promise.all(\n      changeSet.service.deletes.map((del) => client.deletePipelineService(del.request)),\n    );\n  }\n}\n\n/**\n * Plan resolver pipeline changes based on current and desired state.\n * @param context - Planning context\n * @returns Planned changes\n */\nexport async function planPipeline(context: PlanContext) {\n  const { client, workspaceId, application, forRemoval, forceApplyAll = false } = context;\n  const pipelines: Readonly<ResolverService>[] = [];\n  if (!forRemoval) {\n    for (const pipeline of application.resolverServices) {\n      await pipeline.loadResolvers();\n      pipelines.push(pipeline);\n    }\n  }\n  const executors = forRemoval\n    ? []\n    : Object.values((await application.executorService?.loadExecutors()) ?? {});\n\n  const {\n    changeSet: serviceChangeSet,\n    conflicts,\n    unmanaged,\n    resourceOwners,\n  } = await planServices(client, workspaceId, application.name, application.id, pipelines);\n  const deletedServices = serviceChangeSet.deletes.map((del) => del.name);\n  const { changeSet: resolverChangeSet } = await planResolvers(\n    client,\n    workspaceId,\n    pipelines,\n    executors,\n    context.executorUsedResolvers ?? new Set<string>(),\n    deletedServices,\n    application.env,\n    getApplicationAuthNamespace(application),\n    forceApplyAll,\n    {\n      appName: application.name,\n      appId: application.id,\n      dependentApps: context.dependentApps,\n      runAppIds: context.runAppIds,\n    },\n  );\n\n  return {\n    changeSet: {\n      service: serviceChangeSet,\n      resolver: resolverChangeSet,\n    },\n    conflicts,\n    unmanaged,\n    resourceOwners,\n  };\n}\n\ntype CreateService = {\n  name: string;\n  request: MessageInitShape<typeof CreatePipelineServiceRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype UpdateService = {\n  name: string;\n  request: MessageInitShape<typeof UpdatePipelineServiceRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype DeleteService = {\n  name: string;\n  request: MessageInitShape<typeof DeletePipelineServiceRequestSchema>;\n};\n\nasync function planServices(\n  client: OperatorClient,\n  workspaceId: string,\n  appName: string,\n  appId: string | undefined,\n  pipelines: ReadonlyArray<Readonly<ResolverService>>,\n) {\n  const changeSet = createChangeSet<CreateService, UpdateService, DeleteService>(\n    \"Pipeline services\",\n  );\n  const conflicts: OwnerConflict[] = [];\n  const unmanaged: UnmanagedResource[] = [];\n  const resourceOwners = new Set<string>();\n\n  const existingServices = await fetchExistingResourcesWithLabels({\n    client,\n    fetchPage: async (pageToken, maxPageSize) => {\n      const { pipelineServices, nextPageToken } = await client.listPipelineServices({\n        workspaceId,\n        pageToken,\n        pageSize: maxPageSize,\n      });\n      return [pipelineServices, nextPageToken];\n    },\n    getName: (resource) => resource.namespace?.name,\n    getTrn: (name) => resourceTrn(workspaceId, \"pipeline\", name),\n  });\n\n  for (const pipeline of pipelines) {\n    const existing = existingServices[pipeline.namespace];\n    const metaRequest = await buildMetaRequest({\n      trn: resourceTrn(workspaceId, \"pipeline\", pipeline.namespace),\n      appName,\n      appId,\n    });\n    if (existing) {\n      const owned = trackDesiredResourceOwnership({\n        labels: existing.allLabels,\n        ownerLabel: existing.label,\n        appName,\n        appId,\n        resourceType: \"Pipeline service\",\n        resourceName: pipeline.namespace,\n        conflicts,\n        unmanaged,\n      });\n\n      if (owned && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels)) {\n        changeSet.unchanged.push({ name: pipeline.namespace });\n      } else {\n        changeSet.updates.push({\n          name: pipeline.namespace,\n          request: {\n            workspaceId,\n            namespaceName: pipeline.namespace,\n          },\n          metaRequest,\n        });\n      }\n      delete existingServices[pipeline.namespace];\n    } else {\n      changeSet.creates.push({\n        name: pipeline.namespace,\n        request: {\n          workspaceId,\n          namespaceName: pipeline.namespace,\n        },\n        metaRequest,\n      });\n    }\n  }\n  Object.entries(existingServices).forEach(([namespaceName]) => {\n    const entry = existingServices[namespaceName];\n    const owned = trackRemainingResourceOwner({\n      labels: entry?.allLabels,\n      ownerLabel: entry?.label,\n      appName,\n      appId,\n      resourceOwners,\n    });\n    // Only delete services managed by this application (by name or stable id)\n    if (owned) {\n      changeSet.deletes.push({\n        name: namespaceName,\n        request: {\n          workspaceId,\n          namespaceName,\n        },\n      });\n    }\n  });\n\n  return { changeSet, conflicts, unmanaged, resourceOwners };\n}\n\ntype CreateResolver = {\n  name: string;\n  request: MessageInitShape<typeof CreatePipelineResolverRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype UpdateResolver = {\n  name: string;\n  request: MessageInitShape<typeof UpdatePipelineResolverRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\n/**\n * A resolver whose definition is unchanged but whose dependency records are not.\n * The plan shows it as unchanged; apply still writes its labels.\n */\ntype UnchangedResolver = {\n  name: string;\n  metaRequest?: MetadataLabelWrite;\n};\n\ntype DeleteResolver = {\n  name: string;\n  request: MessageInitShape<typeof DeletePipelineResolverRequestSchema>;\n};\n\n/** What planResolvers needs to record dependencies on each resolver. */\ntype ResolverRecordInputs = {\n  appName?: string;\n  appId?: string;\n  dependentApps?: DependentAppsByResource;\n  runAppIds?: ReadonlySet<string>;\n};\n\nasync function planResolvers(\n  client: OperatorClient,\n  workspaceId: string,\n  pipelines: ReadonlyArray<Readonly<ResolverService>>,\n  executors: ReadonlyArray<Executor>,\n  initialExecutorUsedResolvers: ReadonlySet<string>,\n  deletedServices: ReadonlyArray<string>,\n  env: Record<string, string | number | boolean>,\n  authNamespace: string | undefined,\n  forceApplyAll = false,\n  records: ResolverRecordInputs = {},\n) {\n  const changeSet = createChangeSet<\n    CreateResolver,\n    UpdateResolver,\n    DeleteResolver,\n    never,\n    UnchangedResolver\n  >(\"Pipeline resolvers\");\n  const { appName, appId, dependentApps, runAppIds } = records;\n\n  /**\n   * Build one resolver's metadata write, carrying the dependency records that\n   * belong to it. The resolver is what publishes, so the record lives there.\n   * @param namespace - Namespace holding the resolver\n   * @param resolver - Resolver being planned\n   * @returns The resolver's metadata write\n   */\n  const resolverMetaRequest = async (\n    namespace: string,\n    resolver: { name: string; publishEvents?: boolean },\n  ) => {\n    const trn = resolverTrn(workspaceId, namespace, resolver.name);\n    return addDependencyRecords(await buildMetaRequest({ trn, appName: appName ?? \"\", appId }), {\n      key: eventSourceKey.resolver(namespace, resolver.name),\n      dependentApps,\n      runAppIds,\n      pinned: resolver.publishEvents !== undefined,\n    });\n  };\n\n  const fetchResolvers = (namespaceName: string) => {\n    return fetchAllTolerant(async (pageToken, maxPageSize) => {\n      const { pipelineResolvers, nextPageToken } = await client.listPipelineResolvers({\n        workspaceId,\n        namespaceName,\n        pageToken,\n        pageSize: maxPageSize,\n      });\n      return [pipelineResolvers, nextPageToken];\n    });\n  };\n\n  const executorUsedResolvers = new Set(initialExecutorUsedResolvers);\n  for (const executor of executors) {\n    if (!subscribesToEvents(executor)) continue;\n    if (executor.trigger.kind === \"resolverExecuted\") {\n      executorUsedResolvers.add(executor.trigger.resolverName);\n    }\n  }\n\n  // Reject a conflicting opt-out before any request, not partway through.\n  for (const pipeline of pipelines) {\n    for (const resolver of Object.values(pipeline.resolvers)) {\n      assertNoPublishEventsConflict({\n        explicit: resolver.publishEvents,\n        subscribed: executorUsedResolvers.has(resolver.name),\n        conflict: publishEventsConflict.resolver(resolver.name),\n      });\n    }\n  }\n\n  for (const pipeline of pipelines) {\n    const existingResolvers = await fetchResolvers(pipeline.namespace);\n    const existingResolversMap = new Map(\n      existingResolvers.map((resolver) => [resolver.name, resolver]),\n    );\n    for (const resolver of Object.values(pipeline.resolvers)) {\n      const desiredResolver = processResolver(\n        pipeline.namespace,\n        resolver,\n        executorUsedResolvers,\n        env,\n        authNamespace,\n      );\n      const existingResolver = existingResolversMap.get(resolver.name);\n      const metaRequest = await resolverMetaRequest(pipeline.namespace, resolver);\n      if (existingResolver) {\n        const { pipelineResolver: existingResolverDetail } = await client.getPipelineResolver({\n          workspaceId,\n          namespaceName: pipeline.namespace,\n          resolverName: resolver.name,\n        });\n        if (\n          !forceApplyAll &&\n          existingResolverDetail &&\n          areResolversEqual(existingResolverDetail, desiredResolver)\n        ) {\n          // The definition matches, but the records may not, so the labels still go.\n          changeSet.unchanged.push({ name: resolver.name, metaRequest });\n        } else {\n          changeSet.updates.push({\n            name: resolver.name,\n            request: {\n              workspaceId,\n              namespaceName: pipeline.namespace,\n              pipelineResolver: desiredResolver,\n            },\n            metaRequest,\n          });\n        }\n        existingResolversMap.delete(resolver.name);\n      } else {\n        changeSet.creates.push({\n          name: resolver.name,\n          request: {\n            workspaceId,\n            namespaceName: pipeline.namespace,\n            pipelineResolver: desiredResolver,\n          },\n          metaRequest,\n        });\n      }\n    }\n    existingResolversMap.forEach((_resolver, name) => {\n      changeSet.deletes.push({\n        name,\n        request: {\n          workspaceId,\n          namespaceName: pipeline.namespace,\n          resolverName: name,\n        },\n      });\n    });\n  }\n\n  for (const namespaceName of deletedServices) {\n    const existingResolvers = await fetchResolvers(namespaceName);\n    existingResolvers.forEach((resolver) => {\n      changeSet.deletes.push({\n        name: resolver.name,\n        request: {\n          workspaceId,\n          namespaceName,\n          resolverName: resolver.name,\n        },\n      });\n    });\n  }\n  return { changeSet };\n}\n\ntype ResolverDisplayEntry = GroupedDisplayEntry;\n\n/**\n * Format resolver changes for grouped dry-run display.\n * @param changeSet - Resolver changes\n * @param resolverFunctionChanges - Related function registry changes for resolvers\n * @returns Display entries for resolver output\n */\nexport function formatResolverChangeEntries(\n  changeSet: Pick<\n    ChangeSet<CreateResolver, UpdateResolver, DeleteResolver>,\n    \"creates\" | \"updates\" | \"deletes\" | \"replaces\"\n  >,\n  resolverFunctionChanges?: RelatedFunctionRegistryChanges,\n): ResolverDisplayEntry[] {\n  return formatChangeEntriesWithFunctionRegistry(\n    \"resolver\",\n    changeSet,\n    resolverFunctionChanges,\n    (item) => {\n      const namespace = item.request.namespaceName;\n      return namespace ? [resolverFunctionName(namespace, item.name)] : [];\n    },\n    {\n      getNamespace: (item) => item.request.namespaceName,\n    },\n  );\n}\n\nfunction normalizeComparableResolver(resolver: MessageInitShape<typeof PipelineResolverSchema>) {\n  return toComparableProtoJson(PipelineResolverSchema, resolver);\n}\n\nfunction areResolversEqual(\n  existing: MessageInitShape<typeof PipelineResolverSchema>,\n  desired: MessageInitShape<typeof PipelineResolverSchema>,\n): boolean {\n  return areNormalizedEqual(\n    normalizeComparableResolver(existing),\n    normalizeComparableResolver(desired),\n  );\n}\n\nfunction processResolver(\n  namespace: string,\n  resolver: Resolver,\n  executorUsedResolvers: ReadonlySet<string>,\n  env: Record<string, string | number | boolean>,\n  authNamespace: string | undefined,\n): MessageInitShape<typeof PipelineResolverSchema> {\n  const pipelines: MessageInitShape<typeof PipelineResolver_PipelineSchema>[] = [\n    {\n      name: \"body\",\n      operationName: \"body\",\n      description: `${resolver.name} function body`,\n      operationType: PipelineResolver_OperationType.FUNCTION,\n      operationSourceRef: resolverFunctionName(namespace, resolver.name),\n      operationHook: {\n        expr: buildResolverOperationHookExpr(env),\n      },\n      postScript: `args.body`,\n      invoker: normalizeInvoker(resolver.invoker, authNamespace, `Resolver \"${resolver.name}\"`),\n    },\n  ];\n\n  const typeBaseName = inflection.camelize(resolver.name);\n\n  // Build inputs\n  const inputs: MessageInitShape<typeof PipelineResolver_FieldSchema>[] = resolver.input\n    ? protoFields(resolver.input, `${typeBaseName}Input`, true)\n    : [];\n\n  // Build response\n  const response: MessageInitShape<typeof PipelineResolver_FieldSchema> = assertDefined(\n    protoFields({ \"\": resolver.output }, `${typeBaseName}Output`, false)[0],\n    \"resolver output field missing\",\n  );\n\n  // Build description (combine resolver description and output description)\n  const resolverDescription = resolver.description || `${resolver.name} resolver`;\n  const outputDescription = resolver.output.metadata.description;\n  const combinedDescription = outputDescription\n    ? `${resolverDescription}\\n\\nReturns:\\n${outputDescription}`\n    : resolverDescription;\n\n  const publishExecutionEvents = resolvePublishEvents({\n    explicit: resolver.publishEvents,\n    subscribed: executorUsedResolvers.has(resolver.name),\n    conflict: publishEventsConflict.resolver(resolver.name),\n  });\n\n  return {\n    authorization: \"true==true\",\n    description: combinedDescription,\n    inputs,\n    name: resolver.name,\n    operationType: resolver.operation,\n    response,\n    pipelines,\n    publishExecutionEvents,\n  };\n}\n\nfunction protoFields(\n  fields: Record<string, TailorField>,\n  baseName: string,\n  isInput: boolean,\n): MessageInitShape<typeof PipelineResolver_FieldSchema>[] {\n  return Object.entries(fields).map(([fieldName, field]) => {\n    let type: MessageInitShape<typeof PipelineResolver_TypeSchema>;\n    const hasCreateHook = isInput && field.metadata.hooks?.create !== undefined;\n    const required = hasCreateHook ? false : (field.metadata.required ?? true);\n\n    if (field.type === \"nested\") {\n      const typeName = field.metadata.typeName ?? `${baseName}${inflection.camelize(fieldName)}`;\n      type = {\n        kind: \"UserDefined\",\n        name: typeName,\n        description: field.metadata.description ?? \"\",\n        required,\n        fields: protoFields(field.fields, typeName, isInput),\n      };\n    } else if (field.type === \"enum\") {\n      const typeName = field.metadata.typeName ?? `${baseName}${inflection.camelize(fieldName)}`;\n      type = {\n        kind: \"EnumType\",\n        name: typeName,\n        required,\n        allowedValues: field.metadata.allowedValues,\n      };\n    } else {\n      type = { ...SCALAR_TYPE_MAP[field.type], required };\n    }\n\n    return {\n      name: fieldName,\n      description: field.metadata.description,\n      array: field.metadata.array ?? false,\n      required,\n      type,\n    };\n  });\n}\n","import { fetchAllTolerant, type OperatorClient } from \"#/cli/shared/client\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { createChangeSet } from \"./change-set\";\nimport { buildMetaRequest, hasMatchingSdkVersion, resourceTrn, writeMetadataLabels } from \"./label\";\nimport {\n  fetchExistingResourcesWithLabels,\n  trackDesiredResourceOwnership,\n  trackRemainingResourceOwner,\n} from \"./owned-resource\";\nimport {\n  hashValue,\n  loadSecretsState,\n  saveSecretsState,\n  serializeUpdateTime,\n  withSecretsStateLock,\n} from \"./secrets-state\";\nimport type { ApplyPhase, PlanContext } from \"#/cli/commands/deploy/types\";\nimport type { Application } from \"#/cli/services/application\";\nimport type { OwnerConflict, UnmanagedResource } from \"./confirm\";\nimport type { MessageInitShape } from \"@bufbuild/protobuf\";\nimport type {\n  CreateSecretManagerSecretRequestSchema,\n  CreateSecretManagerVaultRequestSchema,\n  UpdateSecretManagerSecretRequestSchema,\n} from \"@tailor-platform/tailor-proto/secret_manager_pb\";\n\ntype CreateVault = {\n  name: string;\n  workspaceId: string;\n};\n\ntype ExistingVault = {\n  name: string;\n  workspaceId: string;\n};\n\ntype DeleteVault = {\n  name: string;\n  workspaceId: string;\n};\n\ntype CreateSecret = {\n  name: string;\n  secretName: string;\n  workspaceId: string;\n  vaultName: string;\n  value: string;\n};\n\ntype UpdateSecret = {\n  name: string;\n  secretName: string;\n  workspaceId: string;\n  vaultName: string;\n  value: string;\n};\n\ntype DeleteSecret = {\n  name: string;\n  secretName: string;\n  workspaceId: string;\n  vaultName: string;\n};\n\n/**\n * Build the CreateSecretManagerVault request for a planned vault create.\n * @param create - Planned vault create\n * @returns Request init shape\n */\nexport function vaultCreateRequest(\n  create: CreateVault,\n): MessageInitShape<typeof CreateSecretManagerVaultRequestSchema> {\n  return {\n    workspaceId: create.workspaceId,\n    secretmanagerVaultName: create.name,\n  };\n}\n\n/**\n * Build the CreateSecretManagerSecret request for a planned secret create.\n * @param create - Planned secret create\n * @returns Request init shape\n */\nexport function secretCreateRequest(\n  create: CreateSecret,\n): MessageInitShape<typeof CreateSecretManagerSecretRequestSchema> {\n  return {\n    workspaceId: create.workspaceId,\n    secretmanagerVaultName: create.vaultName,\n    secretmanagerSecretName: create.secretName,\n    secretmanagerSecretValue: create.value,\n  };\n}\n\n/**\n * Build the UpdateSecretManagerSecret request for a planned secret update.\n * @param update - Planned secret update\n * @returns Request init shape\n */\nexport function secretUpdateRequest(\n  update: UpdateSecret,\n): MessageInitShape<typeof UpdateSecretManagerSecretRequestSchema> {\n  return {\n    workspaceId: update.workspaceId,\n    secretmanagerVaultName: update.vaultName,\n    secretmanagerSecretName: update.secretName,\n    secretmanagerSecretValue: update.value,\n  };\n}\n\n/**\n * Plan secret manager changes based on current and desired state.\n * @param context - Planning context\n * @returns Planned changes for vaults and secrets\n */\nexport async function planSecretManager(context: PlanContext) {\n  const { client, workspaceId, application, forRemoval, forceApplyAll = false } = context;\n  const secretVaults = forRemoval ? [] : application.secrets;\n\n  const vaultChangeSet = createChangeSet<CreateVault, ExistingVault, DeleteVault>(\n    \"Secret Manager vaults\",\n  );\n  const secretChangeSet = createChangeSet<CreateSecret, UpdateSecret, DeleteSecret>(\n    \"Secret Manager secrets\",\n  );\n  const conflicts: OwnerConflict[] = [];\n  const unmanaged: UnmanagedResource[] = [];\n  const resourceOwners = new Set<string>();\n\n  // Fetch all existing vaults with metadata to track managed resources\n  const existingVaults = await fetchExistingResourcesWithLabels({\n    client,\n    fetchPage: async (pageToken, maxPageSize) => {\n      const { vaults, nextPageToken } = await client.listSecretManagerVaults({\n        workspaceId,\n        pageToken,\n        pageSize: maxPageSize,\n      });\n      return [vaults, nextPageToken];\n    },\n    getName: (resource) => resource.name,\n    getTrn: (name) => resourceTrn(workspaceId, \"vault\", name),\n  });\n\n  const stateScope = {\n    workspaceId,\n    applicationId: application.id,\n    applicationName: application.name,\n  };\n  const state = loadSecretsState(stateScope);\n  const skippedSecrets: string[] = [];\n\n  await Promise.all(\n    secretVaults.map(async (vault) => {\n      const vaultName = vault.vaultName;\n      const existing = existingVaults[vaultName];\n\n      if (existing) {\n        const metaRequest = await buildMetaRequest({\n          trn: resourceTrn(workspaceId, \"vault\", vaultName),\n          appName: application.name,\n          appId: application.id,\n        });\n        const owned = trackDesiredResourceOwnership({\n          labels: existing.allLabels,\n          ownerLabel: existing.label,\n          appName: application.name,\n          appId: application.id,\n          resourceType: \"Secret Manager vault\",\n          resourceName: vaultName,\n          conflicts,\n          unmanaged,\n        });\n        if (owned && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels)) {\n          vaultChangeSet.unchanged.push({ name: vaultName });\n        } else {\n          vaultChangeSet.updates.push({\n            name: vaultName,\n            workspaceId,\n          });\n        }\n        delete existingVaults[vaultName];\n      } else {\n        vaultChangeSet.creates.push({\n          name: vaultName,\n          workspaceId,\n        });\n      }\n\n      // Fetch existing secrets in this vault\n      const existingSecretTimes = new Map<string, string | undefined>();\n      if (existing) {\n        const secrets = await fetchAllTolerant(async (pageToken, maxPageSize) => {\n          const { secrets, nextPageToken } = await client.listSecretManagerSecrets({\n            workspaceId,\n            secretmanagerVaultName: vaultName,\n            pageToken,\n            pageSize: maxPageSize,\n          });\n          return [secrets, nextPageToken];\n        });\n        for (const secret of secrets) {\n          existingSecretTimes.set(secret.name, serializeUpdateTime(secret.updateTime));\n        }\n      }\n\n      const existingSet = new Set(existingSecretTimes.keys());\n\n      // Diff secrets\n      for (const secret of vault.secrets) {\n        if (secret.value == null) {\n          // Nullish value: skip create/update/delete for this secret\n          existingSet.delete(secret.name);\n          skippedSecrets.push(`${vaultName}/${secret.name}`);\n          continue;\n        }\n        logger.registerSecret(secret.value);\n\n        if (existingSet.has(secret.name)) {\n          const stored = state.vaults[vaultName]?.[secret.name];\n          const remoteUpdateTime = existingSecretTimes.get(secret.name);\n          // Skip only when the stored hash matches and the remote updateTime\n          // proves no other writer changed the secret since that hash was saved.\n          const unchanged =\n            stored !== undefined &&\n            stored.hash === hashValue(secret.value) &&\n            stored.updateTime !== undefined &&\n            stored.updateTime === remoteUpdateTime;\n          if (forceApplyAll || !unchanged) {\n            secretChangeSet.updates.push({\n              name: `${vaultName}/${secret.name}`,\n              secretName: secret.name,\n              workspaceId,\n              vaultName,\n              value: secret.value,\n            });\n          }\n          existingSet.delete(secret.name);\n        } else {\n          secretChangeSet.creates.push({\n            name: `${vaultName}/${secret.name}`,\n            secretName: secret.name,\n            workspaceId,\n            vaultName,\n            value: secret.value,\n          });\n        }\n      }\n\n      // Remaining in existingSet are orphans - mark for deletion\n      for (const orphanName of existingSet) {\n        secretChangeSet.deletes.push({\n          name: `${vaultName}/${orphanName}`,\n          secretName: orphanName,\n          workspaceId,\n          vaultName,\n        });\n      }\n    }),\n  );\n\n  // Remaining existing vaults not in config - mark managed ones for deletion\n  for (const [name, entry] of Object.entries(existingVaults)) {\n    if (!entry) continue;\n    const owned = trackRemainingResourceOwner({\n      labels: entry.allLabels,\n      ownerLabel: entry.label,\n      appName: application.name,\n      appId: application.id,\n      resourceOwners,\n    });\n    if (owned) {\n      // Delete secrets inside the vault before deleting the vault itself\n      const secrets = await fetchAllTolerant(async (pageToken, maxPageSize) => {\n        const { secrets, nextPageToken } = await client.listSecretManagerSecrets({\n          workspaceId,\n          secretmanagerVaultName: name,\n          pageToken,\n          pageSize: maxPageSize,\n        });\n        return [secrets, nextPageToken];\n      });\n      for (const secret of secrets) {\n        secretChangeSet.deletes.push({\n          name: `${name}/${secret.name}`,\n          secretName: secret.name,\n          workspaceId,\n          vaultName: name,\n        });\n      }\n\n      vaultChangeSet.deletes.push({\n        name,\n        workspaceId,\n      });\n    }\n  }\n\n  return {\n    vaultChangeSet,\n    secretChangeSet,\n    skippedSecrets,\n    conflicts,\n    unmanaged,\n    resourceOwners,\n    stateScope,\n  };\n}\n\n/**\n * Apply secret manager changes for the given phase.\n * @param client - Operator client instance\n * @param result - Planned secret changes\n * @param phase - Apply phase\n * @param application - Application used for ownership metadata and hash state persistence\n * @returns Promise that resolves when secret changes are applied\n */\nexport async function applySecretManager(\n  client: OperatorClient,\n  result: Awaited<ReturnType<typeof planSecretManager>>,\n  phase: Extract<ApplyPhase, \"create-update\" | \"delete\"> = \"create-update\",\n  application?: Readonly<Application>,\n) {\n  const { vaultChangeSet, secretChangeSet, stateScope } = result;\n\n  if (phase === \"create-update\") {\n    // Create vaults first and set metadata\n    await Promise.all(\n      vaultChangeSet.creates.map(async (create) => {\n        await client.createSecretManagerVault(vaultCreateRequest(create));\n        if (application) {\n          const metaRequest = await buildMetaRequest({\n            trn: resourceTrn(create.workspaceId, \"vault\", create.name),\n            appName: application.name,\n            appId: application.id,\n          });\n          await writeMetadataLabels(client, metaRequest);\n        }\n      }),\n    );\n\n    // Update metadata for existing vaults\n    if (application) {\n      await Promise.all(\n        vaultChangeSet.updates.map(async (update) => {\n          const metaRequest = await buildMetaRequest({\n            trn: resourceTrn(update.workspaceId, \"vault\", update.name),\n            appName: application.name,\n            appId: application.id,\n          });\n          await writeMetadataLabels(client, metaRequest);\n        }),\n      );\n    }\n\n    const secretHashUpdates = [...secretChangeSet.creates, ...secretChangeSet.updates];\n    if (secretHashUpdates.length > 0) {\n      await withSecretsStateLock(stateScope, async () => {\n        // Evidence must come from this deploy's own mutation responses; pairing\n        // the hash with a re-listed timestamp could adopt another writer's.\n        const appliedUpdateTimes = new Map<string, string | undefined>();\n\n        // Create new secrets\n        await Promise.all(\n          secretChangeSet.creates.map(async (create) => {\n            const response = await client.createSecretManagerSecret(secretCreateRequest(create));\n            appliedUpdateTimes.set(create.name, serializeUpdateTime(response.secret?.updateTime));\n          }),\n        );\n\n        // Update existing secrets\n        await Promise.all(\n          secretChangeSet.updates.map(async (update) => {\n            const response = await client.updateSecretManagerSecret(secretUpdateRequest(update));\n            appliedUpdateTimes.set(update.name, serializeUpdateTime(response.secret?.updateTime));\n          }),\n        );\n\n        if (application) {\n          const state = loadSecretsState(stateScope);\n          for (const secret of secretHashUpdates) {\n            if (!Object.hasOwn(state.vaults, secret.vaultName)) {\n              state.vaults[secret.vaultName] = {};\n            }\n            const updateTime = appliedUpdateTimes.get(secret.name);\n            assertDefined(state.vaults[secret.vaultName], \"vault state entry missing\")[\n              secret.secretName\n            ] = {\n              hash: hashValue(secret.value),\n              ...(updateTime === undefined ? {} : { updateTime }),\n            };\n          }\n          saveSecretsState(stateScope, state);\n        }\n      });\n    }\n  } else if (secretChangeSet.deletes.length > 0 || vaultChangeSet.deletes.length > 0) {\n    await withSecretsStateLock(stateScope, async () => {\n      // Delete orphan secrets\n      await Promise.all(\n        secretChangeSet.deletes.map((del) =>\n          client.deleteSecretManagerSecret({\n            workspaceId: del.workspaceId,\n            secretmanagerVaultName: del.vaultName,\n            secretmanagerSecretName: del.secretName,\n          }),\n        ),\n      );\n\n      // Delete orphan vaults\n      await Promise.all(\n        vaultChangeSet.deletes.map((del) =>\n          client.deleteSecretManagerVault({\n            workspaceId: del.workspaceId,\n            secretmanagerVaultName: del.name,\n          }),\n        ),\n      );\n\n      // Remove deleted secrets and vaults from hash state\n      const state = loadSecretsState(stateScope);\n      for (const del of secretChangeSet.deletes) {\n        if (Object.hasOwn(state.vaults, del.vaultName)) {\n          delete assertDefined(state.vaults[del.vaultName], \"vault state entry missing\")[\n            del.secretName\n          ];\n          if (\n            Object.keys(assertDefined(state.vaults[del.vaultName], \"vault state entry missing\"))\n              .length === 0\n          ) {\n            delete state.vaults[del.vaultName];\n          }\n        }\n      }\n      for (const del of vaultChangeSet.deletes) {\n        delete state.vaults[del.name];\n      }\n      saveSecretsState(stateScope, state);\n    });\n  }\n}\n","/**\n * Schema snapshot data model for TailorDB migrations.\n *\n * Leaf module: these types describe the persisted snapshot format\n * (XXXX/schema.json) and are shared by snapshot.ts (snapshot management)\n * and diff-calculator.ts (diff types and formatting) without creating\n * import cycles between them.\n */\n\n// ============================================================================\n// Snapshot Types\n// ============================================================================\n\n/**\n * Hook configuration in schema snapshot\n */\nexport interface SnapshotHook {\n  expr: string;\n}\n\n/**\n * Validation configuration in schema snapshot\n */\nexport interface SnapshotValidation {\n  script?: { expr: string };\n  errorMessage: string;\n}\n\n/**\n * Serial configuration in schema snapshot\n */\nexport interface SnapshotSerial {\n  start: number;\n  maxValue?: number;\n  format?: string;\n}\n\n/**\n * Enum value with optional description in schema snapshot\n */\nexport interface SnapshotEnumValue {\n  value: string;\n  description?: string;\n}\n\n/**\n * Optional boolean properties of {@link SnapshotFieldConfig}, absent meaning\n * `false`. Every comparator over snapshot fields iterates this single list so\n * a newly added property cannot be silently skipped by one of them; a\n * comparator that ignores some of these must declare its exclusions\n * explicitly.\n */\nexport const SNAPSHOT_FIELD_BOOLEAN_PROPS = [\n  \"array\",\n  \"index\",\n  \"unique\",\n  \"foreignKey\",\n  \"vector\",\n  \"optionalOnCreate\",\n] as const;\n\n/**\n * One of the {@link SNAPSHOT_FIELD_BOOLEAN_PROPS} property names.\n */\nexport type SnapshotFieldBooleanProp = (typeof SNAPSHOT_FIELD_BOOLEAN_PROPS)[number];\n\n/**\n * Field configuration in schema snapshot\n */\nexport interface SnapshotFieldConfig {\n  type: string;\n  required: boolean;\n  array?: boolean;\n  index?: boolean;\n  unique?: boolean;\n  allowedValues?: SnapshotEnumValue[];\n  foreignKey?: boolean;\n  foreignKeyType?: string;\n  foreignKeyField?: string;\n  description?: string;\n  vector?: boolean;\n  hooks?: {\n    create?: SnapshotHook;\n    update?: SnapshotHook;\n  };\n  validate?: SnapshotValidation[];\n  serial?: SnapshotSerial;\n  scale?: number;\n  default?: unknown;\n  /** Recorded on remote-derived snapshots when the platform fills the value on create. */\n  optionalOnCreate?: boolean;\n  /** Nested fields (recursive) */\n  fields?: Record<string, SnapshotFieldConfig>;\n}\n\n/**\n * Index configuration in schema snapshot\n */\nexport interface SnapshotIndexConfig {\n  fields: string[];\n  unique?: boolean;\n}\n\n/**\n * Relationship configuration in schema snapshot\n */\nexport interface SnapshotRelationship {\n  targetType: string;\n  targetField: string;\n  sourceField: string;\n  isArray: boolean;\n  description: string;\n}\n\n// ============================================================================\n// Permission Types\n// ============================================================================\n\n/**\n * Field-reference operand in a permission condition. Always an object with\n * exactly one of `user` / `record` / `newRecord` / `oldRecord` keys.\n */\nexport type SnapshotFieldRefOperand =\n  | { user: string }\n  | { record: string }\n  | { newRecord: string }\n  | { oldRecord: string };\n\n/**\n * Literal value operand (right-hand side of a permission condition). Matches\n * the SDK-level value operand surface — primitives and their arrays — as\n * defined in the Zod parser schema (RecordPermissionOperandSchema /\n * GqlPermissionOperandSchema in parser/service/tailordb/schema.ts).\n */\ntype SnapshotValueOperand = string | boolean | string[] | boolean[];\n\n/**\n * Permission operand union. Either a field-ref object or a literal value.\n */\nexport type SnapshotPermissionOperand = SnapshotFieldRefOperand | SnapshotValueOperand;\n\n/**\n * Permission operators\n */\nexport type SnapshotPermissionOperator = \"eq\" | \"ne\" | \"in\" | \"nin\" | \"hasAny\" | \"nhasAny\";\n\n/**\n * Permission condition tuple\n */\nexport type SnapshotPermissionCondition = readonly [\n  SnapshotPermissionOperand,\n  SnapshotPermissionOperator,\n  SnapshotPermissionOperand,\n];\n\n/**\n * Type guard: is the operand a field-reference (object) operand?\n * @param {SnapshotPermissionOperand} operand - Operand to test\n * @returns {boolean} True if operand is a field-ref (not a value operand)\n */\nexport function isSnapshotFieldRefOperand(\n  operand: SnapshotPermissionOperand,\n): operand is SnapshotFieldRefOperand {\n  // snapshot JSON may contain null; z.unknown() does not reject it\n  // oxlint-disable-next-line typescript/no-unnecessary-condition\n  return typeof operand === \"object\" && operand !== null && !Array.isArray(operand);\n}\n\n/**\n * Action permission policy\n */\nexport interface SnapshotActionPermission {\n  conditions: readonly SnapshotPermissionCondition[];\n  description?: string;\n  permit: \"allow\" | \"deny\";\n}\n\n/**\n * Record-level permission configuration\n */\nexport interface SnapshotRecordPermission {\n  create: readonly SnapshotActionPermission[];\n  read: readonly SnapshotActionPermission[];\n  update: readonly SnapshotActionPermission[];\n  delete: readonly SnapshotActionPermission[];\n}\n\n/**\n * GQL permission actions\n */\nexport type SnapshotGqlAction =\n  | \"read\"\n  | \"create\"\n  | \"update\"\n  | \"delete\"\n  | \"aggregate\"\n  | \"bulkUpsert\"\n  | \"all\";\n\n/**\n * GQL permission policy\n */\nexport interface SnapshotGqlPermissionPolicy {\n  conditions: readonly SnapshotPermissionCondition[];\n  actions: readonly SnapshotGqlAction[];\n  permit: \"allow\" | \"deny\";\n  description?: string;\n}\n\n/**\n * GQL permission configuration\n */\nexport type SnapshotGqlPermission = readonly SnapshotGqlPermissionPolicy[];\n\n/**\n * Type definition in schema snapshot.\n * `pluralForm` is always materialized — either set by the SDK user, derived\n * via inflection at snapshot construction, or backfilled when loading legacy\n * snapshots in `loadSnapshot`.\n */\nexport interface TailorDBSnapshotType {\n  name: string;\n  pluralForm: string;\n  description?: string;\n  fields: Record<string, SnapshotFieldConfig>;\n  settings?: {\n    aggregation?: boolean;\n    bulkUpsert?: boolean;\n    gqlOperations?: {\n      create?: boolean;\n      update?: boolean;\n      delete?: boolean;\n      read?: boolean;\n    };\n    publishEvents?: boolean;\n  };\n  indexes?: Record<string, SnapshotIndexConfig>;\n  files?: Record<string, string>;\n  forwardRelationships?: Record<string, SnapshotRelationship>;\n  backwardRelationships?: Record<string, SnapshotRelationship>;\n  permissions?: {\n    record?: SnapshotRecordPermission;\n    gql?: SnapshotGqlPermission;\n  };\n  typeHookExpr?: { create?: string; update?: string };\n  typeValidateExpr?: string;\n}\n\nexport type SnapshotSettings = NonNullable<TailorDBSnapshotType[\"settings\"]>;\nexport type SnapshotGqlOperations = NonNullable<SnapshotSettings[\"gqlOperations\"]>;\n\n/** Identifies the history transition created by a full rebaseline. */\nexport interface RebaselineMarker {\n  historyId: string;\n  replacedHistoryId: string | null;\n  replacedLatestMigration: number;\n}\n\n/**\n * Schema snapshot - full schema state at a point in time.\n * Stored as XXXX/schema.json. Defined here (leaf module) so that\n * snapshot-schema.ts can reference it without importing snapshot.ts.\n */\nexport interface SchemaSnapshot {\n  /** Format version for future compatibility */\n  version: number;\n  namespace: string;\n  createdAt: string;\n  tables: Record<string, TailorDBSnapshotType>;\n  rebaseline?: RebaselineMarker;\n}\n\ndeclare const normalizedSchemaSnapshotBrand: unique symbol;\n\n/**\n * Schema snapshot normalized to a canonical form for consistent comparison.\n *\n * Returned by snapshot creation and loading functions so drift detection stays\n * stable when local definitions omit defaults that the platform materializes.\n */\nexport type NormalizedSchemaSnapshot = SchemaSnapshot & {\n  readonly [normalizedSchemaSnapshotBrand]: true;\n};\n","/**\n * Member-level diff of a nested field\n *\n * The diff engine compares nested fields wholesale: any member change surfaces\n * as one `field_modified` on the top-level field. This module walks the member\n * structures so the diff display can name the changed members and removed\n * members can be surfaced as data-loss warnings. It also owns the field\n * configuration comparison that the diff engine and the member walk share.\n */\n\nimport { assertDefined } from \"#/utils/assert\";\nimport { SNAPSHOT_FIELD_BOOLEAN_PROPS, type SnapshotFieldConfig } from \"./snapshot-types\";\n\n/**\n * Look up a member inside a nested field by its path relative to the field.\n * @param {SnapshotFieldConfig | undefined} field - Top-level field configuration\n * @param {readonly string[]} path - Member path, e.g. `[\"geo\", \"lat\"]`\n * @returns {SnapshotFieldConfig | undefined} The member, or undefined when any segment is missing\n */\nexport function getNestedMember(\n  field: SnapshotFieldConfig | undefined,\n  path: readonly string[],\n): SnapshotFieldConfig | undefined {\n  return path.reduce<SnapshotFieldConfig | undefined>(\n    (current, segment) =>\n      current?.fields && Object.hasOwn(current.fields, segment)\n        ? current.fields[segment]\n        : undefined,\n    field,\n  );\n}\n\n/** A change to one member inside a nested field. */\nexport type NestedMemberChange =\n  | { kind: \"removed\"; path: string[]; before: SnapshotFieldConfig }\n  | { kind: \"added\"; path: string[]; after: SnapshotFieldConfig }\n  | { kind: \"modified\"; path: string[]; before: SnapshotFieldConfig; after: SnapshotFieldConfig };\n\n/**\n * Collect the member changes between two versions of a nested field.\n *\n * A member present on both sides is recursed into; it is reported as\n * `modified` only when its own configuration (everything except its members)\n * differs. A member present on one side only, or a field or member whose type\n * changed, is treated as a whole without descending into its members. Removed\n * members come first, then added, then the rest in `before` order.\n * @param {SnapshotFieldConfig} before - Field configuration before the change\n * @param {SnapshotFieldConfig} after - Field configuration after the change\n * @returns {NestedMemberChange[]} Member changes with paths relative to the field (may be empty)\n */\nexport function collectNestedMemberChanges(\n  before: SnapshotFieldConfig,\n  after: SnapshotFieldConfig,\n): NestedMemberChange[] {\n  if (before.type !== after.type) return [];\n  return collectMemberChanges(before.fields ?? {}, after.fields ?? {}, []);\n}\n\nfunction collectMemberChanges(\n  beforeMembers: Record<string, SnapshotFieldConfig>,\n  afterMembers: Record<string, SnapshotFieldConfig>,\n  parentPath: string[],\n): NestedMemberChange[] {\n  const removed: NestedMemberChange[] = [];\n  const added: NestedMemberChange[] = [];\n  const rest: NestedMemberChange[] = [];\n\n  for (const [name, beforeMember] of Object.entries(beforeMembers)) {\n    const path = [...parentPath, name];\n    const afterMember = Object.hasOwn(afterMembers, name) ? afterMembers[name] : undefined;\n    if (!afterMember) {\n      removed.push({ kind: \"removed\", path, before: beforeMember });\n      continue;\n    }\n    if (beforeMember.type === afterMember.type) {\n      rest.push(...collectMemberChanges(beforeMember.fields ?? {}, afterMember.fields ?? {}, path));\n    }\n    if (areOwnFieldConfigsDifferent(beforeMember, afterMember)) {\n      rest.push({ kind: \"modified\", path, before: beforeMember, after: afterMember });\n    }\n  }\n\n  for (const [name, afterMember] of Object.entries(afterMembers)) {\n    if (!Object.hasOwn(beforeMembers, name)) {\n      added.push({ kind: \"added\", path: [...parentPath, name], after: afterMember });\n    }\n  }\n\n  return [...removed, ...added, ...rest];\n}\n\n/**\n * Whether two field configurations differ in anything but their nested\n * members. Optional booleans default to `false`, enum values are compared as a\n * set, and hooks and validations by their expressions.\n * @param {SnapshotFieldConfig} oldField - Old field configuration\n * @param {SnapshotFieldConfig} newField - New field configuration\n * @returns {boolean} True if the configurations differ\n */\nexport function areOwnFieldConfigsDifferent(\n  oldField: SnapshotFieldConfig,\n  newField: SnapshotFieldConfig,\n): boolean {\n  if (oldField.type !== newField.type) return true;\n  if (oldField.required !== newField.required) return true;\n\n  for (const prop of SNAPSHOT_FIELD_BOOLEAN_PROPS) {\n    if ((oldField[prop] ?? false) !== (newField[prop] ?? false)) return true;\n  }\n\n  if (oldField.foreignKeyType !== newField.foreignKeyType) return true;\n  if (oldField.foreignKeyField !== newField.foreignKeyField) return true;\n\n  if ((oldField.description ?? \"\") !== (newField.description ?? \"\")) return true;\n\n  const oldAllowed = oldField.allowedValues ?? [];\n  const newAllowed = newField.allowedValues ?? [];\n  if (oldAllowed.length !== newAllowed.length) return true;\n  const newAllowedMap = new Map(newAllowed.map((v) => [v.value, v.description]));\n  for (const v of oldAllowed) {\n    if (!newAllowedMap.has(v.value)) return true;\n    if ((v.description ?? \"\") !== (newAllowedMap.get(v.value) ?? \"\")) return true;\n  }\n\n  const oldHooks = oldField.hooks;\n  const newHooks = newField.hooks;\n  if (Boolean(oldHooks) !== Boolean(newHooks)) return true;\n  if (oldHooks && newHooks) {\n    if ((oldHooks.create?.expr ?? \"\") !== (newHooks.create?.expr ?? \"\")) return true;\n    if ((oldHooks.update?.expr ?? \"\") !== (newHooks.update?.expr ?? \"\")) return true;\n  }\n\n  const oldValidate = oldField.validate ?? [];\n  const newValidate = newField.validate ?? [];\n  if (oldValidate.length !== newValidate.length) return true;\n  for (let i = 0; i < oldValidate.length; i++) {\n    const oldV = assertDefined(oldValidate[i], `oldValidate missing index ${i}`);\n    const newV = assertDefined(newValidate[i], `newValidate missing index ${i}`);\n    if ((oldV.script?.expr ?? \"\") !== (newV.script?.expr ?? \"\")) return true;\n    if (oldV.errorMessage !== newV.errorMessage) return true;\n  }\n\n  const oldSerial = oldField.serial;\n  const newSerial = newField.serial;\n  if (Boolean(oldSerial) !== Boolean(newSerial)) return true;\n  if (oldSerial && newSerial) {\n    if (oldSerial.start !== newSerial.start) return true;\n    if (oldSerial.maxValue !== newSerial.maxValue) return true;\n    if ((oldSerial.format ?? \"\") !== (newSerial.format ?? \"\")) return true;\n  }\n\n  if (oldField.scale !== newField.scale) return true;\n\n  if (oldField.default !== newField.default) {\n    if (typeof oldField.default !== typeof newField.default) return true;\n    if (JSON.stringify(oldField.default) !== JSON.stringify(newField.default)) return true;\n  }\n\n  return false;\n}\n","/**\n * Diff calculator and formatter for TailorDB schema migrations\n *\n * This module provides utilities for formatting and displaying migration diffs.\n * The actual diff calculation is performed by snapshot.ts.\n */\n\nimport { collectNestedMemberChanges, type NestedMemberChange } from \"./nested-members\";\nimport type {\n  SnapshotFieldConfig,\n  SnapshotGqlPermission,\n  SnapshotIndexConfig,\n  SnapshotRecordPermission,\n  SnapshotRelationship,\n  TailorDBSnapshotType,\n} from \"./snapshot-types\";\n\n// ============================================================================\n// Diff Types\n// ============================================================================\n\n/**\n * Current schema snapshot format version\n */\nexport const SCHEMA_SNAPSHOT_VERSION = 6 as const;\n\n/** Oldest migration file format this SDK can replay. */\nexport const MIN_SUPPORTED_MIGRATION_FILE_VERSION = 1 as const;\n\n/**\n * Change kind in migration diff\n */\nexport type DiffChangeKind = DiffChange[\"kind\"];\n\n/**\n * Properties shared by all diff change variants\n */\ninterface DiffChangeBase {\n  tableName: string;\n  reason?: string;\n}\n\n/**\n * Table-level settings patch carried by legacy `type_modified` changes.\n * Current SDK versions no longer produce this kind, but persisted\n * diff.json files written by older versions may still contain it.\n */\nexport interface TypeSettingsPatch {\n  indexes?: Record<string, SnapshotIndexConfig>;\n  files?: Record<string, string>;\n}\n\n/** Table-level settings and metadata state used by current diffs. */\nexport interface SnapshotTypeSettingsState {\n  description?: string;\n  pluralForm: string;\n  settings?: TailorDBSnapshotType[\"settings\"];\n}\n\n/**\n * Permission state carried by `permission_modified` changes.\n */\nexport interface SnapshotPermissionState {\n  recordPermission?: SnapshotRecordPermission;\n  gqlPermission?: SnapshotGqlPermission;\n}\n\n/** A new table was added to the schema. */\nexport interface TableAddedChange extends DiffChangeBase {\n  kind: \"table_added\";\n  after: TailorDBSnapshotType;\n}\n\n/** An existing table was removed from the schema. */\nexport interface TableRemovedChange extends DiffChangeBase {\n  kind: \"table_removed\";\n  before: TailorDBSnapshotType;\n}\n\n/**\n * A table was renamed. Recorded when the user confirms that a removed + added\n * table pair is a rename (interactively or via `--rename`).\n * `tableName` is the new name; `previousTableName` is the old name.\n */\nexport interface TableRenamedChange extends DiffChangeBase {\n  kind: \"table_renamed\";\n  previousTableName: string;\n  before: TailorDBSnapshotType;\n  after: TailorDBSnapshotType;\n}\n\n/**\n * Legacy table-level settings change. Kept for backward compatibility with\n * diff.json files written by older SDK versions; `before`/`after` may be\n * absent in those files, hence optional.\n */\nexport interface TableModifiedChange extends DiffChangeBase {\n  kind: \"table_modified\";\n  before?: TypeSettingsPatch;\n  after?: TypeSettingsPatch;\n}\n\n/** Table-level settings or metadata changed. */\nexport interface TableSettingsModifiedChange extends DiffChangeBase {\n  kind: \"table_settings_modified\";\n  before: SnapshotTypeSettingsState;\n  after: SnapshotTypeSettingsState;\n}\n\n/** A field was added to a table. */\nexport interface FieldAddedChange extends DiffChangeBase {\n  kind: \"field_added\";\n  fieldName: string;\n  after: SnapshotFieldConfig;\n}\n\n/** A field was removed from a table. */\nexport interface FieldRemovedChange extends DiffChangeBase {\n  kind: \"field_removed\";\n  fieldName: string;\n  before: SnapshotFieldConfig;\n}\n\n/**\n * A member inside a nested field was renamed. `previousPath` and `path` are\n * relative to the top-level field and share the same parent.\n */\nexport interface NestedMemberRename {\n  previousPath: string[];\n  path: string[];\n}\n\n/**\n * A field configuration was modified. `memberRenames` records members inside a\n * nested field that the user confirmed as renames (interactively or via\n * `--rename Table.field.old:new`); their values must be copied by the\n * migration script.\n */\nexport interface FieldModifiedChange extends DiffChangeBase {\n  kind: \"field_modified\";\n  fieldName: string;\n  before: SnapshotFieldConfig;\n  after: SnapshotFieldConfig;\n  memberRenames?: NestedMemberRename[];\n}\n\n/**\n * A field was renamed within a table. Recorded when the user confirms that a\n * removed + added field pair is a rename (interactively or via `--rename`).\n * `fieldName` is the new name; `previousFieldName` is the old name.\n */\nexport interface FieldRenamedChange extends DiffChangeBase {\n  kind: \"field_renamed\";\n  fieldName: string;\n  previousFieldName: string;\n  before: SnapshotFieldConfig;\n  after: SnapshotFieldConfig;\n}\n\n/** A field type changed and must remain on the previous type until Post-phase. */\nexport interface FieldTypeModifiedChange extends DiffChangeBase {\n  kind: \"field_type_modified\";\n  fieldName: string;\n  before: SnapshotFieldConfig;\n  after: SnapshotFieldConfig;\n}\n\n/** An index was added to a table. */\nexport interface IndexAddedChange extends DiffChangeBase {\n  kind: \"index_added\";\n  indexName: string;\n  after: SnapshotIndexConfig;\n}\n\n/** An index was removed from a table. */\nexport interface IndexRemovedChange extends DiffChangeBase {\n  kind: \"index_removed\";\n  indexName: string;\n  before: SnapshotIndexConfig;\n}\n\n/** An index configuration was modified. */\nexport interface IndexModifiedChange extends DiffChangeBase {\n  kind: \"index_modified\";\n  indexName: string;\n  before: SnapshotIndexConfig;\n  after: SnapshotIndexConfig;\n}\n\n/** A file field was added to a table. `before`/`after` hold the description. */\nexport interface FileAddedChange extends DiffChangeBase {\n  kind: \"file_added\";\n  fieldName: string;\n  after: string;\n}\n\n/** A file field was removed from a table. */\nexport interface FileRemovedChange extends DiffChangeBase {\n  kind: \"file_removed\";\n  fieldName: string;\n  before: string;\n}\n\n/** A file field description was modified. */\nexport interface FileModifiedChange extends DiffChangeBase {\n  kind: \"file_modified\";\n  fieldName: string;\n  before: string;\n  after: string;\n}\n\n/**\n * A relationship was added to a table. `relationshipType` is optional for\n * backward compatibility: diff.json files written by older SDK versions\n * predate the field.\n */\nexport interface RelationshipAddedChange extends DiffChangeBase {\n  kind: \"relationship_added\";\n  relationshipName: string;\n  relationshipType?: \"forward\" | \"backward\";\n  after: SnapshotRelationship;\n}\n\n/** A relationship was removed from a table. */\nexport interface RelationshipRemovedChange extends DiffChangeBase {\n  kind: \"relationship_removed\";\n  relationshipName: string;\n  relationshipType?: \"forward\" | \"backward\";\n  before: SnapshotRelationship;\n}\n\n/** A relationship configuration was modified. */\nexport interface RelationshipModifiedChange extends DiffChangeBase {\n  kind: \"relationship_modified\";\n  relationshipName: string;\n  relationshipType?: \"forward\" | \"backward\";\n  before: SnapshotRelationship;\n  after: SnapshotRelationship;\n}\n\n/**\n * Table-level permissions were modified. `before`/`after` are optional for\n * robustness against hand-edited or legacy diff.json files; consumers guard\n * on their presence.\n */\nexport interface PermissionModifiedChange extends DiffChangeBase {\n  kind: \"permission_modified\";\n  before?: SnapshotPermissionState;\n  after?: SnapshotPermissionState;\n}\n\n/** Table-level hook/validate script state for diff tracking. */\nexport interface TypeScriptsState {\n  typeHookExpr?: { create?: string; update?: string };\n  typeValidateExpr?: string;\n}\n\n/** Table-level hook/validate scripts changed. */\nexport interface TableScriptsModifiedChange extends DiffChangeBase {\n  kind: \"table_scripts_modified\";\n  before: TypeScriptsState;\n  after: TypeScriptsState;\n}\n\n/**\n * Single change in migration diff, discriminated by `kind` so that\n * `before`/`after` are typed per change kind.\n */\nexport type DiffChange =\n  | TableAddedChange\n  | TableRemovedChange\n  | TableRenamedChange\n  | TableModifiedChange\n  | TableSettingsModifiedChange\n  | FieldAddedChange\n  | FieldRemovedChange\n  | FieldModifiedChange\n  | FieldRenamedChange\n  | FieldTypeModifiedChange\n  | IndexAddedChange\n  | IndexRemovedChange\n  | IndexModifiedChange\n  | FileAddedChange\n  | FileRemovedChange\n  | FileModifiedChange\n  | RelationshipAddedChange\n  | RelationshipRemovedChange\n  | RelationshipModifiedChange\n  | PermissionModifiedChange\n  | TableScriptsModifiedChange;\n\n/**\n * Field-level diff change (added / removed / modified / renamed).\n */\nexport type FieldDiffChange =\n  | FieldAddedChange\n  | FieldRemovedChange\n  | FieldModifiedChange\n  | FieldRenamedChange\n  | FieldTypeModifiedChange;\n\n/**\n * Index-level diff change (added / removed / modified).\n */\nexport type IndexDiffChange = IndexAddedChange | IndexRemovedChange | IndexModifiedChange;\n\n/**\n * Migration diff - changes between two schema versions\n * Stored as XXXX/diff.json (e.g., 0001/diff.json)\n */\nexport interface MigrationDiff {\n  /** Format version for future compatibility */\n  version: number;\n  namespace: string;\n  createdAt: string;\n  description?: string;\n  changes: DiffChange[];\n  /** Whether there are breaking changes (data loss or constraint violations possible) */\n  hasBreakingChanges: boolean;\n  /** List of breaking changes */\n  breakingChanges: BreakingChangeInfo[];\n  /** Whether there are non-breaking changes that may cause data loss (e.g. field/table removal) */\n  hasWarnings: boolean;\n  /** List of non-breaking warnings */\n  warnings: WarningChangeInfo[];\n  /** Whether a migration script is required to handle data migration */\n  requiresMigrationScript: boolean;\n  /** Explicit acknowledgment that this migration needs no script despite breaking changes or data-loss warnings */\n  scriptSkipped?: ScriptSkippedInfo;\n}\n\n/**\n * Acknowledgment that a migration requiring or recommending a script intentionally has none.\n * Recorded by `tailordb migration script <n> --no-script --reason \"...\"`.\n */\nexport interface ScriptSkippedInfo {\n  reason: string;\n  acknowledgedAt: string;\n}\n\n/**\n * Breaking change information in migration diff\n */\nexport interface BreakingChangeInfo {\n  tableName: string;\n  fieldName?: string;\n  reason: string;\n  /** If true, this change is not supported and migration generation will fail */\n  unsupported?: boolean;\n  /** If true, show 3-step migration instructions for this unsupported change */\n  showThreeStepHint?: boolean;\n}\n\n/**\n * Warning change information in migration diff.\n *\n * Warnings are non-breaking changes that may still cause data loss\n * (e.g. removing a field or table). Unlike breaking changes, a migration\n * script is not required, but writing one is recommended if you need to\n * preserve or transform data before the change applies.\n */\nexport interface WarningChangeInfo {\n  tableName: string;\n  /** Field name, or the dotted path of a member inside a nested field (e.g. `address.zip`). */\n  fieldName?: string;\n  reason: string;\n}\n\n/**\n * Check if a migration diff has any changes\n * @param {MigrationDiff} diff - Migration diff to check\n * @returns {boolean} True if diff has changes\n */\nexport function hasChanges(diff: MigrationDiff): boolean {\n  return diff.changes.length > 0;\n}\n\n/**\n * Format a migration diff for display\n * @param {MigrationDiff} diff - Migration diff to format\n * @returns {string} Formatted diff string\n */\nexport function formatMigrationDiff(diff: MigrationDiff): string {\n  if (diff.changes.length === 0) {\n    return \"No schema differences detected.\";\n  }\n\n  const lines: string[] = [];\n\n  // Group changes by table name\n  const changesByType = new Map<string, DiffChange[]>();\n  for (const change of diff.changes) {\n    const existing = changesByType.get(change.tableName) ?? [];\n    existing.push(change);\n    changesByType.set(change.tableName, existing);\n  }\n\n  for (const [tableName, changes] of changesByType) {\n    lines.push(`${diff.namespace}.${tableName}:`);\n\n    for (const change of changes) {\n      lines.push(formatDiffChange(change));\n    }\n  }\n\n  return lines.join(\"\\n\");\n}\n\n/**\n * Format a single diff change for display\n * @param {DiffChange} change - Diff change to format\n * @returns {string} Formatted change string\n */\nfunction formatDiffChange(change: DiffChange): string {\n  switch (change.kind) {\n    case \"table_added\":\n      return `  + [Table] ${change.tableName} (new table)`;\n    case \"table_removed\":\n      return `  - [Table] ${change.tableName} (removed)`;\n    case \"table_renamed\":\n      return `  ~ [Table] ${change.previousTableName} → ${change.tableName} (renamed)`;\n    case \"table_modified\":\n      return `  ~ [Table] ${change.tableName}: ${change.reason}`;\n    case \"table_settings_modified\":\n      return `  ~ [Table Settings] ${change.tableName}: ${change.reason ?? \"settings changed\"}`;\n    case \"field_added\": {\n      const typeStr = formatFieldType(change.after);\n      return `  + ${change.fieldName}: ${typeStr}`;\n    }\n    case \"field_removed\":\n      return `  - ${change.fieldName}: ${change.before.type}`;\n    case \"field_modified\":\n      return `  ~ ${change.fieldName}: ${formatFieldModification(change.before, change.after, change.memberRenames)}`;\n    case \"field_type_modified\":\n      return `  ~ ${change.fieldName}: ${formatFieldModification(change.before, change.after)}`;\n    case \"field_renamed\":\n      return `  ~ ${change.previousFieldName} → ${change.fieldName}: ${formatFieldType(change.after)} (renamed)`;\n    case \"index_added\":\n      return `  + [Index] ${change.indexName}`;\n    case \"index_removed\":\n      return `  - [Index] ${change.indexName}`;\n    case \"index_modified\":\n      return `  ~ [Index] ${change.indexName}: ${change.reason ?? \"modified\"}`;\n    case \"file_added\":\n      return `  + [File] ${change.fieldName}`;\n    case \"file_removed\":\n      return `  - [File] ${change.fieldName}`;\n    case \"file_modified\":\n      return `  ~ [File] ${change.fieldName}: ${change.reason ?? \"modified\"}`;\n    case \"relationship_added\":\n      return `  + [Relationship${change.relationshipType ? ` (${change.relationshipType})` : \"\"}] ${change.relationshipName}`;\n    case \"relationship_removed\":\n      return `  - [Relationship${change.relationshipType ? ` (${change.relationshipType})` : \"\"}] ${change.relationshipName}`;\n    case \"relationship_modified\":\n      return `  ~ [Relationship${change.relationshipType ? ` (${change.relationshipType})` : \"\"}] ${change.relationshipName}: ${change.reason ?? \"modified\"}`;\n    case \"permission_modified\":\n      return `  ~ [Permission] ${change.reason ?? \"modified\"}`;\n    case \"table_scripts_modified\":\n      return `  ~ [Table Scripts] ${change.tableName}: ${change.reason ?? \"table-level hooks/validate changed\"}`;\n    default: {\n      // Runtime fallback: diff.json is parsed without validation, so\n      // hand-edited or future-version files may carry unknown kinds.\n      const unknown = change as { tableName: string; fieldName?: string };\n      return `  ? ${unknown.tableName}.${unknown.fieldName ?? \"\"}`;\n    }\n  }\n}\n\n/**\n * Format field type with attributes\n * @param {SnapshotFieldConfig} field - Field configuration\n * @returns {string} Formatted field type string\n */\nfunction formatFieldType(field: SnapshotFieldConfig): string {\n  let type = field.type;\n  if (field.array) type += \"[]\";\n  if (field.required) type += \" (required)\";\n  else type += \" (optional)\";\n  return type;\n}\n\n/**\n * Format field modification details\n * @param {SnapshotFieldConfig} before - Before field configuration\n * @param {SnapshotFieldConfig} after - After field configuration\n * @param {readonly NestedMemberRename[]} [memberRenames] - Confirmed renames of members inside the nested field\n * @returns {string} Formatted modification details\n */\nfunction formatFieldModification(\n  before: SnapshotFieldConfig,\n  after: SnapshotFieldConfig,\n  memberRenames: readonly NestedMemberRename[] = [],\n): string {\n  const changes: string[] = [];\n\n  if (before.type !== after.type) {\n    changes.push(`type: ${before.type} → ${after.type}`);\n  }\n  if (before.required !== after.required) {\n    changes.push(`required: ${before.required} → ${after.required}`);\n  }\n  if (Boolean(before.array) !== Boolean(after.array)) {\n    changes.push(`array: ${before.array ?? false} → ${after.array ?? false}`);\n  }\n  if (Boolean(before.index) !== Boolean(after.index)) {\n    changes.push(`index: ${before.index ?? false} → ${after.index ?? false}`);\n  }\n  if (Boolean(before.unique) !== Boolean(after.unique)) {\n    changes.push(`unique: ${before.unique ?? false} → ${after.unique ?? false}`);\n  }\n  if (Boolean(before.vector) !== Boolean(after.vector)) {\n    changes.push(`vector: ${before.vector ?? false} → ${after.vector ?? false}`);\n  }\n\n  const beforeAllowed = before.allowedValues ?? [];\n  const afterAllowed = after.allowedValues ?? [];\n  const afterSet = new Set(afterAllowed.map((v) => v.value));\n  const hasAllowedValuesChange =\n    beforeAllowed.length !== afterAllowed.length ||\n    beforeAllowed.some((v) => !afterSet.has(v.value));\n  if (hasAllowedValuesChange) {\n    const beforeValues = beforeAllowed.map((v) => v.value).join(\", \");\n    const afterValues = afterAllowed.map((v) => v.value).join(\", \");\n    changes.push(`allowedValues: [${beforeValues}] → [${afterValues}]`);\n  }\n\n  const beforeHooks = before.hooks;\n  const afterHooks = after.hooks;\n  if (\n    (beforeHooks?.create?.expr ?? \"\") !== (afterHooks?.create?.expr ?? \"\") ||\n    (beforeHooks?.update?.expr ?? \"\") !== (afterHooks?.update?.expr ?? \"\")\n  ) {\n    changes.push(\"hooks modified\");\n  }\n\n  const beforeValidate = before.validate ?? [];\n  const afterValidate = after.validate ?? [];\n  if (beforeValidate.length !== afterValidate.length) {\n    changes.push(`validations: ${beforeValidate.length} → ${afterValidate.length}`);\n  }\n\n  if (Boolean(before.serial) !== Boolean(after.serial)) {\n    changes.push(\n      `serial: ${before.serial ? \"enabled\" : \"disabled\"} → ${after.serial ? \"enabled\" : \"disabled\"}`,\n    );\n  }\n\n  const renamedPaths = new Set(\n    memberRenames.flatMap((rename) => [rename.previousPath.join(\".\"), rename.path.join(\".\")]),\n  );\n  const members = collectNestedMemberChanges(before, after)\n    .filter((m) => !renamedPaths.has(m.path.join(\".\")))\n    .map((m) => `${NESTED_MEMBER_CHANGE_MARKERS[m.kind]}${m.path.join(\".\")}`);\n  members.push(\n    ...memberRenames.map(\n      (rename) => `${rename.previousPath.join(\".\")} → ${rename.path.join(\".\")} (renamed)`,\n    ),\n  );\n  if (members.length > 0) {\n    changes.push(`members: ${members.join(\", \")}`);\n  }\n\n  return changes.length > 0 ? changes.join(\", \") : \"configuration changed\";\n}\n\nconst NESTED_MEMBER_CHANGE_MARKERS: Record<NestedMemberChange[\"kind\"], string> = {\n  removed: \"-\",\n  added: \"+\",\n  modified: \"~\",\n};\n\n/**\n * Format breaking changes for display\n * @param {BreakingChangeInfo[]} breakingChanges - Breaking changes to format\n * @returns {string} Formatted breaking changes string\n */\nexport function formatBreakingChanges(breakingChanges: BreakingChangeInfo[]): string {\n  if (breakingChanges.length === 0) {\n    return \"\";\n  }\n\n  const lines: string[] = [\"Breaking changes detected:\", \"\"];\n\n  for (const bc of breakingChanges) {\n    const location = bc.fieldName ? `${bc.tableName}.${bc.fieldName}` : bc.tableName;\n    lines.push(`  - ${location}: ${bc.reason}`);\n  }\n\n  return lines.join(\"\\n\");\n}\n\n/**\n * Format warning changes for display\n * @param {WarningChangeInfo[]} warnings - Warning changes to format\n * @returns {string} Formatted warning changes string\n */\nexport function formatWarnings(warnings: WarningChangeInfo[]): string {\n  if (warnings.length === 0) {\n    return \"\";\n  }\n\n  const lines: string[] = [\"Warning: data loss possible:\", \"\"];\n\n  for (const w of warnings) {\n    const location = w.fieldName ? `${w.tableName}.${w.fieldName}` : w.tableName;\n    lines.push(`  - ${location}: ${w.reason}`);\n  }\n\n  return lines.join(\"\\n\");\n}\n\nconst DIFF_CHANGE_LABELS: Record<DiffChangeKind, string> = {\n  table_added: \"table(s) added\",\n  table_removed: \"table(s) removed\",\n  table_renamed: \"table(s) renamed\",\n  table_modified: \"table(s) modified\",\n  table_settings_modified: \"table setting(s) modified\",\n  field_added: \"field(s) added\",\n  field_removed: \"field(s) removed\",\n  field_modified: \"field(s) modified\",\n  field_renamed: \"field(s) renamed\",\n  field_type_modified: \"field type(s) modified\",\n  index_added: \"index(es) added\",\n  index_removed: \"index(es) removed\",\n  index_modified: \"index(es) modified\",\n  file_added: \"file field(s) added\",\n  file_removed: \"file field(s) removed\",\n  file_modified: \"file field(s) modified\",\n  relationship_added: \"relationship(s) added\",\n  relationship_removed: \"relationship(s) removed\",\n  relationship_modified: \"relationship(s) modified\",\n  permission_modified: \"permission(s) modified\",\n  table_scripts_modified: \"table script(s) modified\",\n};\n\n/**\n * Format a summary of the migration diff\n * @param {MigrationDiff} diff - Migration diff to summarize\n * @returns {string} Formatted summary string\n */\nexport function formatDiffSummary(diff: MigrationDiff): string {\n  const stats: Partial<Record<DiffChangeKind, number>> = {};\n  for (const change of diff.changes) {\n    stats[change.kind] = (stats[change.kind] ?? 0) + 1;\n  }\n\n  const parts = Object.keys(stats).map(\n    (kind) => `${stats[kind as DiffChangeKind]} ${DIFF_CHANGE_LABELS[kind as DiffChangeKind]}`,\n  );\n\n  return parts.length > 0 ? parts.join(\", \") : \"No changes\";\n}\n","import { CLIError } from \"#/cli/shared/errors\";\n\n/**\n * Format migration number as 4-digit string.\n * @param num - Migration number\n * @returns 4-digit padded string\n */\nexport function formatMigrationNumber(num: number): string {\n  return num.toString().padStart(4, \"0\");\n}\n\n/**\n * Parse a migration number CLI argument.\n *\n * Accepts the canonical 4-digit form (\"0001\") or a bare integer without\n * leading zeros (\"0\"–\"9999\"). Commands that disallow the baseline reject\n * 0 themselves with a context-specific message.\n * @param numberStr - Raw CLI argument\n * @returns Parsed migration number\n */\nexport function parseMigrationNumberArg(numberStr: string): number {\n  if (/^\\d{4}$/.test(numberStr)) {\n    return parseInt(numberStr, 10);\n  }\n  if (/^(0|[1-9]\\d*)$/.test(numberStr)) {\n    const parsed = parseInt(numberStr, 10);\n    if (parsed > 9999) {\n      throw CLIError({\n        code: \"MIGRATION_NUMBER_INVALID\",\n        message: `Migration number ${numberStr} is out of range. Expected 0-9999.`,\n      });\n    }\n    return parsed;\n  }\n  throw CLIError({\n    code: \"MIGRATION_NUMBER_INVALID\",\n    message: `Invalid migration number format: ${numberStr}. Expected 4-digit format (e.g., 0001) or integer 0-9999 (e.g., 1).`,\n  });\n}\n","import * as inflection from \"inflection\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport {\n  type DiffChangeKind,\n  MIN_SUPPORTED_MIGRATION_FILE_VERSION,\n  SCHEMA_SNAPSHOT_VERSION,\n} from \"./diff-calculator\";\nimport {\n  type NormalizedSchemaSnapshot,\n  type SchemaSnapshot,\n  type SnapshotFieldConfig,\n  type TailorDBSnapshotType,\n} from \"./snapshot-types\";\n\n/**\n * Platform default scale for decimal fields when scale is not explicitly specified.\n * Must stay in sync with the platform's default decimal scale.\n */\nexport const DEFAULT_DECIMAL_SCALE = 6;\n\nexport const MIGRATION_FILE_VERSION_UNSUPPORTED = \"MIGRATION_FILE_VERSION_UNSUPPORTED\";\n\nexport function assertSupportedMigrationFileVersion(filePath: string, raw: unknown): void {\n  if (typeof raw !== \"object\" || raw === null || !(\"version\" in raw)) return;\n  const version = raw.version;\n  if (typeof version !== \"number\") return;\n  if (\n    Number.isInteger(version) &&\n    version >= MIN_SUPPORTED_MIGRATION_FILE_VERSION &&\n    version <= SCHEMA_SNAPSHOT_VERSION\n  ) {\n    return;\n  }\n\n  const supportedRange = `${MIN_SUPPORTED_MIGRATION_FILE_VERSION}-${SCHEMA_SNAPSHOT_VERSION}`;\n  let guidance: string;\n  if (version > SCHEMA_SNAPSHOT_VERSION) {\n    guidance = `Upgrade to an SDK that supports migration file format version ${version}.`;\n  } else if (version < MIN_SUPPORTED_MIGRATION_FILE_VERSION) {\n    guidance =\n      \"Re-baseline with an SDK that still supports this migration history, then upgrade the SDK.\";\n  } else {\n    guidance = \"Restore the migration file from version control or regenerate it.\";\n  }\n  throw CLIError({\n    code: MIGRATION_FILE_VERSION_UNSUPPORTED,\n    message: `Unsupported migration file format version ${version} at ${filePath}.`,\n    details: `This SDK supports migration file format versions ${supportedRange}.`,\n    suggestion: guidance,\n  });\n}\n\n/**\n * Diff change kinds renamed when TailorDB table terminology replaced \"type\".\n * Migration histories written before the rename persist the old names, so\n * diff.json files keep being read through this mapping.\n */\nconst LEGACY_CHANGE_KINDS = new Map<string, DiffChangeKind>([\n  [\"type_added\", \"table_added\"],\n  [\"type_removed\", \"table_removed\"],\n  [\"type_renamed\", \"table_renamed\"],\n  [\"type_modified\", \"table_modified\"],\n  [\"type_settings_modified\", \"table_settings_modified\"],\n  [\"type_scripts_modified\", \"table_scripts_modified\"],\n]);\n\n/**\n * Rewrite pre-rename `type_*` change kinds to their current `table_*` names\n * so that the diff schema, which only knows the current names, accepts them.\n * @param {unknown} raw - Parsed diff.json contents\n * @returns {unknown} Diff contents with legacy change kinds rewritten\n */\nexport function normalizeLegacyChangeKinds(raw: unknown): unknown {\n  if (typeof raw !== \"object\" || raw === null || !(\"changes\" in raw)) return raw;\n  const changes = raw.changes;\n  if (!Array.isArray(changes)) return raw;\n\n  const normalized = changes.map((change) => {\n    if (typeof change !== \"object\" || change === null || !(\"kind\" in change)) return change;\n    const kind = (change as { kind: unknown }).kind;\n    if (typeof kind !== \"string\") return change;\n    const currentKind = LEGACY_CHANGE_KINDS.get(kind);\n    return currentKind === undefined ? change : { ...change, kind: currentKind };\n  });\n\n  return { ...raw, changes: normalized };\n}\n\n/**\n * Persisted field names renamed when TailorDB table terminology replaced\n * \"type\". Applied to every entry that carries a table name, so diff.json files\n * written before the rename keep validating against the current schema.\n */\nconst LEGACY_ENTRY_FIELDS = new Map<string, string>([\n  [\"typeName\", \"tableName\"],\n  [\"previousTypeName\", \"previousTableName\"],\n]);\n\nfunction renameLegacyEntryFields(entry: unknown): unknown {\n  if (typeof entry !== \"object\" || entry === null || Array.isArray(entry)) return entry;\n  const source = entry as Record<string, unknown>;\n  const renamed: Record<string, unknown> = {};\n  let changed = false;\n  for (const [key, value] of Object.entries(source)) {\n    const currentKey = LEGACY_ENTRY_FIELDS.get(key);\n    if (currentKey !== undefined && !(currentKey in source)) {\n      renamed[currentKey] = value;\n      changed = true;\n    } else {\n      renamed[key] = value;\n    }\n  }\n  return changed ? renamed : entry;\n}\n\n/** Persisted arrays whose entries carry a table name. */\nconst LEGACY_FIELD_CARRIERS = [\"changes\", \"breakingChanges\", \"warnings\"] as const;\n\n/**\n * Move a pre-rename `types` record to `tables` so schema.json files written\n * before the rename keep validating against the current schema.\n * @param {unknown} raw - Parsed schema.json contents\n * @returns {unknown} Snapshot contents with the legacy key moved\n */\nexport function normalizeLegacyTablesKey(raw: unknown): unknown {\n  if (typeof raw !== \"object\" || raw === null) return raw;\n  const source = raw as Record<string, unknown>;\n  if (!(\"types\" in source) || \"tables\" in source) return raw;\n  const { types, ...rest } = source;\n  return { ...rest, tables: types };\n}\n\n/**\n * Rewrite the pre-rename `typeName` / `previousTypeName` keys to their current\n * names across every persisted position that carries a table name.\n * @param {unknown} raw - Parsed diff.json contents\n * @returns {unknown} Diff contents with legacy field names rewritten\n */\nexport function normalizeLegacyFieldNames(raw: unknown): unknown {\n  if (typeof raw !== \"object\" || raw === null) return raw;\n  const source = raw as Record<string, unknown>;\n  const normalized: Record<string, unknown> = { ...source };\n  for (const key of LEGACY_FIELD_CARRIERS) {\n    const entries = source[key];\n    if (!Array.isArray(entries)) continue;\n    normalized[key] = entries.map(renameLegacyEntryFields);\n  }\n  return normalized;\n}\n\nexport function createSnapshotRecord<T>(): Record<string, T> {\n  return Object.create(null) as Record<string, T>;\n}\n\nexport function copySnapshotRecord<T>(record: Record<string, T> | undefined): Record<string, T> {\n  const copy = createSnapshotRecord<T>();\n  for (const [key, value] of Object.entries(record ?? {})) {\n    copy[key] = value;\n  }\n  return copy;\n}\n\n/**\n * Normalize a snapshot field into the canonical form for comparison, returning\n * a new object rather than mutating the input. Currently fills in the platform\n * default decimal scale when omitted, which avoids false drift between local\n * schemas (where scale may be omitted) and the platform (which always\n * materializes a scale).\n * @param {SnapshotFieldConfig} field - Field configuration to normalize\n * @returns {SnapshotFieldConfig} A new, normalized field object\n */\nexport function normalizeSnapshotField(field: SnapshotFieldConfig): SnapshotFieldConfig {\n  const fields = field.fields\n    ? Object.fromEntries(\n        Object.entries(field.fields).map(([name, nested]) => [\n          name,\n          normalizeSnapshotField(nested),\n        ]),\n      )\n    : undefined;\n\n  return {\n    ...field,\n    ...(field.type === \"decimal\" && field.scale === undefined && { scale: DEFAULT_DECIMAL_SCALE }),\n    ...(fields && { fields }),\n  };\n}\n\n/**\n * Normalize a snapshot table into the canonical comparison shape, returning a\n * new object rather than mutating the input. Currently fills:\n *   - `pluralForm` via inflection when missing (legacy snapshots written\n *     before `pluralForm` became required may omit it)\n *   - per-field `scale` defaults via {@link normalizeSnapshotField}\n *\n * Idempotent — safe to call multiple times on the same input.\n * @param {TailorDBSnapshotType} type - Snapshot table to normalize\n * @returns {TailorDBSnapshotType} A new, normalized snapshot table object\n */\nexport function normalizeSnapshotType(type: TailorDBSnapshotType): TailorDBSnapshotType {\n  // `pluralForm` is typed as required by TailorDBSnapshotType, but JSON.parse'd legacy\n  // snapshots may have it undefined at runtime — backfill from inflection.\n  const pluralForm =\n    (type as { pluralForm?: string }).pluralForm || inflection.pluralize(type.name);\n  const fields = createSnapshotRecord<SnapshotFieldConfig>();\n  for (const [fieldName, field] of Object.entries(type.fields)) {\n    fields[fieldName] = normalizeSnapshotField(field);\n  }\n  return { ...type, pluralForm, fields };\n}\n\n/**\n * Normalize a schema snapshot into the canonical comparison shape, returning a\n * new object rather than mutating the input.\n * @param {SchemaSnapshot} snapshot - Schema snapshot to normalize\n * @returns {NormalizedSchemaSnapshot} A new schema snapshot object branded as normalized\n */\nexport function normalizeSchemaSnapshot(snapshot: SchemaSnapshot): NormalizedSchemaSnapshot {\n  const tables = createSnapshotRecord<TailorDBSnapshotType>();\n  for (const [tableName, type] of Object.entries(snapshot.tables)) {\n    tables[tableName] = normalizeSnapshotType(type);\n  }\n  return { ...snapshot, tables } as NormalizedSchemaSnapshot;\n}\n\n// Re-export SCHEMA_SNAPSHOT_VERSION for convenience\n","import { DEFAULT_DECIMAL_SCALE } from \"./snapshot-normalization\";\nimport type { SnapshotFieldConfig } from \"./snapshot-types\";\n\n/**\n * Scalar type changes whose complete source domain is accepted by the target\n * representation without relying on per-row index recreation.\n *\n * The whole source domain has to cast, not just the values present when the\n * script runs: the field keeps its previous type until the post-migration\n * phase, so an application can still write any value the source type allows\n * after the script has passed over the table. A pair that needs the script to\n * rewrite values first — `string` to `integer`, say, where `\"abc\"` never\n * casts — would fail that late write at the post-migration phase.\n *\n * Values must also read back with their meaning intact. Date, datetime, and\n * time values are not stored in the textual form they were written in, so\n * converting them to or from another type reads back as a different instant;\n * those pairs stay off this list even though the platform accepts the schema\n * change.\n *\n * Keep this list deliberately narrow. Pair-specific platform experiments can\n * extend it once both indexed and unindexed read paths have been verified.\n */\nexport const IN_PLACE_TYPE_CHANGES: ReadonlySet<string> = new Set([\n  \"boolean:string\",\n  \"decimal:float\",\n  \"decimal:string\",\n  \"enum:string\",\n  \"float:decimal\",\n  \"float:string\",\n  \"integer:decimal\",\n  \"integer:float\",\n  \"integer:string\",\n  \"uuid:string\",\n]);\n\n/**\n * Determine whether a field type change can use a single phased migration.\n * @param before - Previous field configuration\n * @param after - Target field configuration\n * @returns Whether the migration can normalize data before applying the type\n */\nexport function supportsInPlaceFieldTypeChange(\n  before: SnapshotFieldConfig,\n  after: SnapshotFieldConfig,\n): boolean {\n  if (before.type === after.type) return false;\n  if (before.array || after.array) return false;\n  if (before.type === \"nested\" || after.type === \"nested\") return false;\n  if (before.serial || after.serial) return false;\n  if (before.vector || after.vector) return false;\n  if (before.foreignKey || after.foreignKey) return false;\n\n  if (!IN_PLACE_TYPE_CHANGES.has(`${before.type}:${after.type}`)) return false;\n\n  // Rounding a float to the target scale can merge two distinct values. A field\n  // that is already unique gets no generated dedupe script, so the collision\n  // would fail the constraint after the migration instead of surfacing while it\n  // can still be resolved.\n  return !(before.unique ?? false) || after.type !== \"decimal\" || before.type !== \"float\";\n}\n\n/**\n * Field type with its array marker, as a user would write it.\n * @param field - Field configuration\n * @returns The type name, suffixed with `[]` for an array field\n */\nexport function formatFieldShape(field: SnapshotFieldConfig): string {\n  return field.array ? `${field.type}[]` : field.type;\n}\n\n/**\n * Whether a field change alters the shape its values must take.\n * @param before - Previous field configuration\n * @param after - Target field configuration\n * @returns Whether the type or the array-ness differs\n */\nexport function hasFieldShapeChange(\n  before: SnapshotFieldConfig,\n  after: SnapshotFieldConfig,\n): boolean {\n  return before.type !== after.type || (before.array ?? false) !== (after.array ?? false);\n}\n\n/**\n * Whether a change turns a single value into an array whose elements accept\n * every stored value, which the generated conversion completes on its own by\n * wrapping each value. Narrowing enum values or decimal scale still needs the\n * stored value converted before it is wrapped.\n * @param before - Previous field configuration\n * @param after - Target field configuration\n * @returns Whether the element domain is unchanged and only the array-ness differs\n */\nexport function isSingleValueToArrayChange(\n  before: SnapshotFieldConfig,\n  after: SnapshotFieldConfig,\n): boolean {\n  if (before.type !== after.type || before.array || !after.array) return false;\n  if (\n    before.type === \"decimal\" &&\n    (after.scale ?? DEFAULT_DECIMAL_SCALE) < (before.scale ?? DEFAULT_DECIMAL_SCALE)\n  ) {\n    return false;\n  }\n  const afterValues = new Set((after.allowedValues ?? []).map((v) => v.value));\n  return (before.allowedValues ?? []).every((v) => afterValues.has(v.value));\n}\n\n/** Result of checking whether a field type change can use expand-contract. */\nexport type ExpandContractFieldChangeEligibility =\n  | { eligible: true }\n  | { eligible: false; reason: string };\n\n/**\n * Explain whether a field type change can be carried by a pair of migrations\n * that move values through a temporary field.\n *\n * The copy is a whole-value overwrite, so it can only carry a field whose value\n * stands on its own: a serial number belongs to a sequence the copy cannot\n * reproduce, a foreign key would dangle while both fields exist, a vector\n * belongs to an index built from it, and a nested value would need its members\n * converted individually. A field that is already an array is excluded because\n * collapsing it into a single value has no answer the generated script could\n * choose, while a single value becomes a one-element array. Unique fields are\n * excluded because the duplicate-resolution scaffold the rename half would emit\n * only produces string values.\n * @param before - Previous field configuration\n * @param after - Target field configuration\n * @returns Eligibility and, when ineligible, the reason\n */\nexport function getExpandContractFieldChangeEligibility(\n  before: SnapshotFieldConfig,\n  after: SnapshotFieldConfig,\n): ExpandContractFieldChangeEligibility {\n  if (!hasFieldShapeChange(before, after))\n    return { eligible: false, reason: \"the field type did not change\" };\n  if (supportsInPlaceFieldTypeChange(before, after)) {\n    return {\n      eligible: false,\n      reason: `the ${before.type} to ${after.type} change is already supported in place`,\n    };\n  }\n  if (before.unique || after.unique) return { eligible: false, reason: \"the field is unique\" };\n  if (before.array) return { eligible: false, reason: \"the field is an array\" };\n  if (before.type === \"nested\" || after.type === \"nested\") {\n    return { eligible: false, reason: \"the field is nested\" };\n  }\n  if (before.serial || after.serial) {\n    return { eligible: false, reason: \"the field uses a serial sequence\" };\n  }\n  if (before.vector || after.vector) return { eligible: false, reason: \"the field is a vector\" };\n  if (before.foreignKey || after.foreignKey) {\n    return { eligible: false, reason: \"the field is a foreign key\" };\n  }\n\n  return { eligible: true };\n}\n","/**\n * Field and table rename detection for TailorDB migrations\n *\n * A rename has no dedicated platform API, so the diff decomposes it into\n * `field_removed` + `field_added` (`table_removed` + `table_added` for tables).\n * This module detects removed/added pairs that are compatible enough to be a\n * rename so that `migration generate` can ask the user (or accept\n * `--rename Table.oldField:newField` / `--rename OldTable:NewTable`) and record a single\n * `field_renamed` / `table_renamed` change instead.\n */\n\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { collectNestedMemberChanges, getNestedMember } from \"./nested-members\";\nimport {\n  SNAPSHOT_FIELD_BOOLEAN_PROPS,\n  type NormalizedSchemaSnapshot,\n  type SchemaSnapshot,\n  type SnapshotFieldBooleanProp,\n  type SnapshotFieldConfig,\n  type TailorDBSnapshotType,\n} from \"./snapshot-types\";\nimport type {\n  FieldAddedChange,\n  FieldRemovedChange,\n  MigrationDiff,\n  TableAddedChange,\n  TableRemovedChange,\n} from \"./diff-calculator\";\n\n/**\n * A confirmed field rename to record in the migration diff.\n */\nexport interface FieldRenameSpec {\n  tableName: string;\n  /** Field name before the rename. */\n  previousFieldName: string;\n  /** Field name after the rename. */\n  fieldName: string;\n}\n\n/**\n * A removed field together with the added fields it could have been renamed to.\n */\nexport interface FieldRenameCandidate {\n  tableName: string;\n  removed: FieldRemovedChange;\n  /** Compatible added fields in the same table, in diff order. */\n  added: FieldAddedChange[];\n}\n\n/** Modifiers a rename may change, since the Pre-phase relaxes them. */\nconst RENAME_TOLERATED_BOOLEAN_PROPS = new Set<SnapshotFieldBooleanProp>([\n  \"index\",\n  \"unique\",\n  \"vector\",\n]);\n\n/**\n * Whether copying values from `before` into `after` preserves their meaning,\n * i.e. the removed + added pair can be treated as a rename.\n *\n * Serial fields are excluded because their values are platform-generated and\n * cannot be written by a migration script.\n * @param {SnapshotFieldConfig} before - Removed field's configuration\n * @param {SnapshotFieldConfig} after - Added field's configuration\n * @returns {boolean} True if the pair is rename-compatible\n */\nexport function isRenameCompatible(\n  before: SnapshotFieldConfig,\n  after: SnapshotFieldConfig,\n): boolean {\n  if (before.type !== after.type) return false;\n  for (const prop of SNAPSHOT_FIELD_BOOLEAN_PROPS) {\n    if (RENAME_TOLERATED_BOOLEAN_PROPS.has(prop)) continue;\n    if ((before[prop] ?? false) !== (after[prop] ?? false)) return false;\n  }\n  if ((before.foreignKeyType ?? \"\") !== (after.foreignKeyType ?? \"\")) return false;\n  if ((before.foreignKeyField ?? \"\") !== (after.foreignKeyField ?? \"\")) return false;\n  if (before.serial || after.serial) return false;\n  if (before.type === \"enum\") {\n    const afterValues = new Set((after.allowedValues ?? []).map((v) => v.value));\n    if ((before.allowedValues ?? []).some((v) => !afterValues.has(v.value))) return false;\n  }\n  // Top-level `required` may differ: the Pre-phase relaxes it and the\n  // scaffolded copy script carries a TODO to resolve nulls before the\n  // Post-phase enforces it. Nested member constraints are never relaxed, so\n  // the wholesale-copied nested structures must match exactly: same member\n  // names, same requiredness, recursively compatible members.\n  const beforeNested = before.fields ?? {};\n  const afterNested = after.fields ?? {};\n  const beforeNames = Object.keys(beforeNested);\n  const afterNames = Object.keys(afterNested);\n  if (beforeNames.length !== afterNames.length) return false;\n  for (const name of beforeNames) {\n    const beforeMember = beforeNested[name];\n    const afterMember = afterNested[name];\n    if (!beforeMember || !afterMember) return false;\n    if (beforeMember.required !== afterMember.required) return false;\n    if (!isRenameCompatible(beforeMember, afterMember)) return false;\n  }\n  return true;\n}\n\n/**\n * Find removed + added field pairs in a diff that could be renames.\n * @param {MigrationDiff} diff - Migration diff to scan\n * @returns {FieldRenameCandidate[]} Candidates in diff order (may be empty)\n */\nexport function findRenameCandidates(diff: MigrationDiff): FieldRenameCandidate[] {\n  const removedByType = new Map<string, FieldRemovedChange[]>();\n  const addedByType = new Map<string, FieldAddedChange[]>();\n  for (const change of diff.changes) {\n    if (change.kind === \"field_removed\") {\n      const list = removedByType.get(change.tableName) ?? [];\n      list.push(change);\n      removedByType.set(change.tableName, list);\n    } else if (change.kind === \"field_added\") {\n      const list = addedByType.get(change.tableName) ?? [];\n      list.push(change);\n      addedByType.set(change.tableName, list);\n    }\n  }\n\n  const candidates: FieldRenameCandidate[] = [];\n  for (const [tableName, removedChanges] of removedByType) {\n    const addedChanges = addedByType.get(tableName);\n    if (!addedChanges) continue;\n    for (const removed of removedChanges) {\n      const added = addedChanges.filter((a) => isRenameCompatible(removed.before, a.after));\n      if (added.length > 0) {\n        candidates.push({ tableName, removed, added });\n      }\n    }\n  }\n  return candidates;\n}\n\n/**\n * Whether a rename spec matches a removed + added field pair between two\n * snapshots: the old field existed before and is gone now, and the new field\n * exists now but did not before. Field compatibility is checked separately\n * when the diff is recomputed with the spec.\n * @param {FieldRenameSpec} spec - Rename spec to test\n * @param {SchemaSnapshot} previousSnapshot - Previous schema snapshot\n * @param {SchemaSnapshot} currentSnapshot - Current schema snapshot\n * @returns {boolean} True if the spec matches a removed + added pair\n */\nexport function renameSpecApplies(\n  spec: FieldRenameSpec,\n  previousSnapshot: SchemaSnapshot,\n  currentSnapshot: SchemaSnapshot,\n): boolean {\n  const prevFields = previousSnapshot.tables[spec.tableName]?.fields;\n  const currFields = currentSnapshot.tables[spec.tableName]?.fields;\n  return Boolean(\n    prevFields?.[spec.previousFieldName] &&\n    !currFields?.[spec.previousFieldName] &&\n    currFields?.[spec.fieldName] &&\n    !prevFields[spec.fieldName],\n  );\n}\n\n/**\n * Assert that every rename spec matches a compatible removed + added field\n * pair between the two normalized snapshots.\n * @param {NormalizedSchemaSnapshot} previous - Previous normalized snapshot\n * @param {NormalizedSchemaSnapshot} current - Current normalized snapshot\n * @param {readonly FieldRenameSpec[]} fieldRenames - Rename specs to validate\n */\nexport function assertValidFieldRenames(\n  previous: NormalizedSchemaSnapshot,\n  current: NormalizedSchemaSnapshot,\n  fieldRenames: readonly FieldRenameSpec[],\n): void {\n  const seen = new Set<string>();\n  for (const rename of fieldRenames) {\n    const { tableName, previousFieldName, fieldName } = rename;\n    const label = `${tableName}.${previousFieldName}:${fieldName}`;\n    for (const key of [`${tableName}.${previousFieldName}`, `${tableName}.${fieldName}`]) {\n      if (seen.has(key)) {\n        throw CLIError({\n          code: \"MIGRATION_RENAME_INVALID\",\n          message: `Field \"${key}\" appears in more than one rename.`,\n        });\n      }\n      seen.add(key);\n    }\n\n    const prevType = previous.tables[tableName];\n    const currType = current.tables[tableName];\n    if (!prevType || !currType) {\n      throw CLIError({\n        code: \"MIGRATION_RENAME_INVALID\",\n        message: `Cannot rename ${label}: table \"${tableName}\" must exist in both the previous and the current schema.`,\n      });\n    }\n    const prevField = prevType.fields[previousFieldName];\n    if (!prevField) {\n      throw CLIError({\n        code: \"MIGRATION_RENAME_INVALID\",\n        message: `Cannot rename ${label}: field \"${previousFieldName}\" does not exist in the previous schema.`,\n      });\n    }\n    if (currType.fields[previousFieldName]) {\n      throw CLIError({\n        code: \"MIGRATION_RENAME_INVALID\",\n        message: `Cannot rename ${label}: field \"${previousFieldName}\" still exists in the current schema.`,\n      });\n    }\n    const currField = currType.fields[fieldName];\n    if (!currField) {\n      throw CLIError({\n        code: \"MIGRATION_RENAME_INVALID\",\n        message: `Cannot rename ${label}: field \"${fieldName}\" does not exist in the current schema.`,\n      });\n    }\n    if (prevType.fields[fieldName]) {\n      throw CLIError({\n        code: \"MIGRATION_RENAME_INVALID\",\n        message: `Cannot rename ${label}: field \"${fieldName}\" already exists in the previous schema.`,\n      });\n    }\n    if (!isRenameCompatible(prevField, currField)) {\n      throw CLIError({\n        code: \"MIGRATION_RENAME_INVALID\",\n        message:\n          `Cannot rename ${label}: the fields are not rename-compatible ` +\n          `(the field type, array-ness, and foreign key target must match, ` +\n          `enum values must not be removed, nested member names, requiredness, and types must ` +\n          `match recursively, and serial fields cannot be renamed).`,\n      });\n    }\n  }\n}\n\nconst RENAME_OPTION_PATTERN = /^([^.:\\s]+)\\.([^.:\\s]+):([^.:\\s]+)$/;\n\n/**\n * Parse a `--rename` option value of the form `Table.oldField:newField`.\n * @param {string} value - Raw option value\n * @returns {FieldRenameSpec} Parsed rename spec\n */\nexport function parseRenameOption(value: string): FieldRenameSpec {\n  const match = value.match(RENAME_OPTION_PATTERN);\n  const [, tableName, previousFieldName, fieldName] = match ?? [];\n  if (!tableName || !previousFieldName || !fieldName) {\n    throw CLIError({\n      code: \"MIGRATION_RENAME_FLAG_INVALID\",\n      message: `Invalid --rename value \"${value}\". Expected format: \"Table.oldField:newField\".`,\n      command: \"tailordb migration generate\",\n    });\n  }\n  if (previousFieldName === fieldName) {\n    throw CLIError({\n      code: \"MIGRATION_RENAME_FLAG_INVALID\",\n      message: `Invalid --rename value \"${value}\": old and new field names are identical.`,\n      command: \"tailordb migration generate\",\n    });\n  }\n  return { tableName, previousFieldName, fieldName };\n}\n\n/**\n * A field removal confirmed as intentional (`--drop Table.field`), so its\n * rename candidates need no interactive confirmation.\n */\nexport interface FieldDropSpec {\n  tableName: string;\n  fieldName: string;\n}\n\nconst DROP_OPTION_PATTERN = /^([^.:\\s]+)\\.([^.:\\s]+)$/;\n\n/**\n * Parse a `--drop` option value of the form `Table.field`.\n * @param {string} value - Raw option value\n * @returns {FieldDropSpec} Parsed drop spec\n */\nexport function parseDropOption(value: string): FieldDropSpec {\n  const match = value.match(DROP_OPTION_PATTERN);\n  const [, tableName, fieldName] = match ?? [];\n  if (!tableName || !fieldName) {\n    throw CLIError({\n      code: \"MIGRATION_DROP_FLAG_INVALID\",\n      message: `Invalid --drop value \"${value}\". Expected format: \"Table.field\".`,\n      command: \"tailordb migration generate\",\n    });\n  }\n  return { tableName, fieldName };\n}\n\n/**\n * Whether a drop spec matches a field that was removed between two snapshots:\n * the field existed before and is gone now.\n * @param {FieldDropSpec} spec - Drop spec to test\n * @param {SchemaSnapshot} previousSnapshot - Previous schema snapshot\n * @param {SchemaSnapshot} currentSnapshot - Current schema snapshot\n * @returns {boolean} True if the spec matches a removed field\n */\nexport function dropSpecApplies(\n  spec: FieldDropSpec,\n  previousSnapshot: SchemaSnapshot,\n  currentSnapshot: SchemaSnapshot,\n): boolean {\n  const prevFields = previousSnapshot.tables[spec.tableName]?.fields;\n  const currFields = currentSnapshot.tables[spec.tableName]?.fields;\n  return Boolean(prevFields?.[spec.fieldName] && !currFields?.[spec.fieldName]);\n}\n\n/** A field the user approved for conversion through a temporary field. */\nexport interface FieldExpandContractSpec {\n  tableName: string;\n  fieldName: string;\n}\n\n/**\n * Parse an `--expand-contract` option value of the form `Table.field`.\n * @param {string} value - Raw option value\n * @returns {FieldExpandContractSpec} Parsed spec\n */\nexport function parseExpandContractOption(value: string): FieldExpandContractSpec {\n  const match = value.match(DROP_OPTION_PATTERN);\n  const [, tableName, fieldName] = match ?? [];\n  if (!tableName || !fieldName) {\n    throw CLIError({\n      code: \"MIGRATION_EXPAND_CONTRACT_FLAG_INVALID\",\n      message: `Invalid --expand-contract value \"${value}\". Expected format: \"Table.field\".`,\n      command: \"tailordb migration generate\",\n    });\n  }\n  return { tableName, fieldName };\n}\n\n// ============================================================================\n// Nested Member Renames\n// ============================================================================\n\n/**\n * A confirmed rename of a member inside a nested field. Paths are relative to\n * the top-level field and share the same parent.\n */\nexport interface NestedMemberRenameSpec {\n  tableName: string;\n  /** Top-level nested field containing the member. */\n  fieldName: string;\n  /** Member path before the rename. */\n  previousPath: string[];\n  /** Member path after the rename. */\n  path: string[];\n}\n\n/**\n * A removed nested member together with the added siblings it could have been\n * renamed to.\n */\nexport interface NestedMemberRenameCandidate {\n  tableName: string;\n  fieldName: string;\n  previousPath: string[];\n  removed: SnapshotFieldConfig;\n  /** Compatible added sibling names, in diff order. */\n  added: string[];\n}\n\n/**\n * Whether copying values from `before` into `after` preserves their meaning\n * for members inside a nested field. The Pre-phase relaxes nothing but the\n * new member's requiredness, so unlike a top-level rename the requiredness,\n * foreign key target, scale, hooks, and validations must match as well as the\n * type and array-ness. Index, unique, and vector may differ as for top-level\n * renames. Enum values may be added but not removed, serial members cannot be\n * renamed, and nested members must match recursively. Description and\n * default values may differ.\n * @param {SnapshotFieldConfig} before - Removed member's configuration\n * @param {SnapshotFieldConfig} after - Added member's configuration\n * @returns {boolean} True if the pair is rename-compatible\n */\nexport function isNestedMemberRenameCompatible(\n  before: SnapshotFieldConfig,\n  after: SnapshotFieldConfig,\n): boolean {\n  if (before.type !== after.type) return false;\n  if (before.required !== after.required) return false;\n  for (const prop of SNAPSHOT_FIELD_BOOLEAN_PROPS) {\n    if (RENAME_TOLERATED_BOOLEAN_PROPS.has(prop)) continue;\n    if ((before[prop] ?? false) !== (after[prop] ?? false)) return false;\n  }\n  if ((before.foreignKeyType ?? \"\") !== (after.foreignKeyType ?? \"\")) return false;\n  if ((before.foreignKeyField ?? \"\") !== (after.foreignKeyField ?? \"\")) return false;\n  if (before.serial || after.serial) return false;\n  if ((before.scale ?? null) !== (after.scale ?? null)) return false;\n  if ((before.hooks?.create?.expr ?? \"\") !== (after.hooks?.create?.expr ?? \"\")) return false;\n  if ((before.hooks?.update?.expr ?? \"\") !== (after.hooks?.update?.expr ?? \"\")) return false;\n  const beforeValidate = before.validate ?? [];\n  const afterValidate = after.validate ?? [];\n  if (beforeValidate.length !== afterValidate.length) return false;\n  for (const [index, beforeRule] of beforeValidate.entries()) {\n    const afterRule = afterValidate[index];\n    if ((beforeRule.script?.expr ?? \"\") !== (afterRule?.script?.expr ?? \"\")) return false;\n    if (beforeRule.errorMessage !== afterRule?.errorMessage) return false;\n  }\n  if (before.type === \"enum\") {\n    const afterValues = new Set((after.allowedValues ?? []).map((v) => v.value));\n    if ((before.allowedValues ?? []).some((v) => !afterValues.has(v.value))) return false;\n  }\n  const beforeMembers = before.fields ?? {};\n  const afterMembers = after.fields ?? {};\n  const beforeNames = Object.keys(beforeMembers);\n  if (beforeNames.length !== Object.keys(afterMembers).length) return false;\n  for (const name of beforeNames) {\n    const beforeMember = beforeMembers[name];\n    const afterMember = Object.hasOwn(afterMembers, name) ? afterMembers[name] : undefined;\n    if (!beforeMember || !afterMember) return false;\n    if (!isNestedMemberRenameCompatible(beforeMember, afterMember)) return false;\n  }\n  return true;\n}\n\n/**\n * Whether two member paths have the same length and the same parent path.\n * @param {readonly string[]} a - First member path\n * @param {readonly string[]} b - Second member path\n * @returns {boolean} True if the paths name siblings\n */\nexport function haveSameParent(a: readonly string[], b: readonly string[]): boolean {\n  return a.length === b.length && a.slice(0, -1).every((segment, index) => segment === b[index]);\n}\n\n/**\n * Find removed members inside nested fields that a compatible added sibling\n * could be the renamed form of.\n * @param {MigrationDiff} diff - Migration diff to scan\n * @returns {NestedMemberRenameCandidate[]} Candidates in diff order (may be empty)\n */\nexport function findNestedMemberRenameCandidates(\n  diff: MigrationDiff,\n): NestedMemberRenameCandidate[] {\n  const candidates: NestedMemberRenameCandidate[] = [];\n  for (const change of diff.changes) {\n    if (change.kind !== \"field_modified\") continue;\n    const memberChanges = collectNestedMemberChanges(change.before, change.after);\n    for (const removed of memberChanges) {\n      if (removed.kind !== \"removed\") continue;\n      const added = memberChanges\n        .filter(\n          (candidate) =>\n            candidate.kind === \"added\" &&\n            haveSameParent(candidate.path, removed.path) &&\n            isNestedMemberRenameCompatible(removed.before, candidate.after),\n        )\n        .map((candidate) => candidate.path[candidate.path.length - 1])\n        .filter((name): name is string => name !== undefined);\n      if (added.length > 0) {\n        candidates.push({\n          tableName: change.tableName,\n          fieldName: change.fieldName,\n          previousPath: removed.path,\n          removed: removed.before,\n          added,\n        });\n      }\n    }\n  }\n  return candidates;\n}\n\n/**\n * Whether a nested member rename spec matches a removed + added member pair\n * between two snapshots. Compatibility is checked separately when the diff is\n * recomputed with the spec.\n * @param {NestedMemberRenameSpec} spec - Rename spec to test\n * @param {SchemaSnapshot} previousSnapshot - Previous schema snapshot\n * @param {SchemaSnapshot} currentSnapshot - Current schema snapshot\n * @returns {boolean} True if the spec matches a removed + added pair\n */\nexport function nestedMemberRenameSpecApplies(\n  spec: NestedMemberRenameSpec,\n  previousSnapshot: SchemaSnapshot,\n  currentSnapshot: SchemaSnapshot,\n): boolean {\n  const prevField = previousSnapshot.tables[spec.tableName]?.fields[spec.fieldName];\n  const currField = currentSnapshot.tables[spec.tableName]?.fields[spec.fieldName];\n  return Boolean(\n    getNestedMember(prevField, spec.previousPath) &&\n    !getNestedMember(currField, spec.previousPath) &&\n    getNestedMember(currField, spec.path) &&\n    !getNestedMember(prevField, spec.path),\n  );\n}\n\n/**\n * Assert that every nested member rename spec matches a compatible removed +\n * added member pair between the two normalized snapshots.\n * @param {NormalizedSchemaSnapshot} previous - Previous normalized snapshot\n * @param {NormalizedSchemaSnapshot} current - Current normalized snapshot\n * @param {readonly NestedMemberRenameSpec[]} renames - Rename specs to validate\n */\nexport function assertValidNestedMemberRenames(\n  previous: NormalizedSchemaSnapshot,\n  current: NormalizedSchemaSnapshot,\n  renames: readonly NestedMemberRenameSpec[],\n): void {\n  const seen = new Set<string>();\n  for (const rename of renames) {\n    const { tableName, fieldName, previousPath, path } = rename;\n    const previousLabel = `${tableName}.${fieldName}.${previousPath.join(\".\")}`;\n    const label = `${previousLabel}:${path[path.length - 1] ?? \"\"}`;\n    for (const key of [previousLabel, `${tableName}.${fieldName}.${path.join(\".\")}`]) {\n      if (seen.has(key)) {\n        throw CLIError({\n          code: \"MIGRATION_RENAME_INVALID\",\n          message: `Member \"${key}\" appears in more than one rename.`,\n        });\n      }\n      seen.add(key);\n    }\n    if (previousPath.length === 0 || !haveSameParent(previousPath, path)) {\n      throw CLIError({\n        code: \"MIGRATION_RENAME_INVALID\",\n        message: `Cannot rename ${label}: the old and new member must share the same parent inside \"${fieldName}\".`,\n      });\n    }\n    const prevField = previous.tables[tableName]?.fields[fieldName];\n    const currField = current.tables[tableName]?.fields[fieldName];\n    if (prevField?.type !== \"nested\" || currField?.type !== \"nested\") {\n      throw CLIError({\n        code: \"MIGRATION_RENAME_INVALID\",\n        message: `Cannot rename ${label}: \"${tableName}.${fieldName}\" must be a nested field in both the previous and the current schema.`,\n      });\n    }\n    const prevMember = getNestedMember(prevField, previousPath);\n    if (!prevMember) {\n      throw CLIError({\n        code: \"MIGRATION_RENAME_INVALID\",\n        message: `Cannot rename ${label}: member \"${previousPath.join(\".\")}\" does not exist in the previous schema.`,\n      });\n    }\n    if (getNestedMember(currField, previousPath)) {\n      throw CLIError({\n        code: \"MIGRATION_RENAME_INVALID\",\n        message: `Cannot rename ${label}: member \"${previousPath.join(\".\")}\" still exists in the current schema.`,\n      });\n    }\n    const currMember = getNestedMember(currField, path);\n    if (!currMember) {\n      throw CLIError({\n        code: \"MIGRATION_RENAME_INVALID\",\n        message: `Cannot rename ${label}: member \"${path.join(\".\")}\" does not exist in the current schema.`,\n      });\n    }\n    if (getNestedMember(prevField, path)) {\n      throw CLIError({\n        code: \"MIGRATION_RENAME_INVALID\",\n        message: `Cannot rename ${label}: member \"${path.join(\".\")}\" already exists in the previous schema.`,\n      });\n    }\n    if (!isNestedMemberRenameCompatible(prevMember, currMember)) {\n      throw CLIError({\n        code: \"MIGRATION_RENAME_INVALID\",\n        message:\n          `Cannot rename ${label}: the members are not rename-compatible ` +\n          `(the member type, array-ness, requiredness, foreign key target, scale, ` +\n          `hooks, and validations must match, enum values must not be removed, nested members ` +\n          `must match recursively, and serial members cannot be renamed).`,\n      });\n    }\n  }\n}\n\nconst NESTED_MEMBER_RENAME_OPTION_PATTERN = /^([^.:\\s]+)\\.([^.:\\s]+)((?:\\.[^.:\\s]+)+):([^.:\\s]+)$/;\n\n/**\n * Parse a `--rename` option value of the form `Table.field.member:newName`,\n * where `member` may be a deeper dotted path inside the nested field.\n * @param {string} value - Raw option value\n * @returns {NestedMemberRenameSpec} Parsed rename spec\n */\nexport function parseNestedMemberRenameOption(value: string): NestedMemberRenameSpec {\n  const match = value.match(NESTED_MEMBER_RENAME_OPTION_PATTERN);\n  const [, tableName, fieldName, memberPath, newName] = match ?? [];\n  if (!tableName || !fieldName || !memberPath || !newName) {\n    throw CLIError({\n      code: \"MIGRATION_RENAME_FLAG_INVALID\",\n      message: `Invalid --rename value \"${value}\". Expected format: \"Table.field.member:newName\".`,\n      command: \"tailordb migration generate\",\n    });\n  }\n  const previousPath = memberPath.slice(1).split(\".\");\n  if (previousPath[previousPath.length - 1] === newName) {\n    throw CLIError({\n      code: \"MIGRATION_RENAME_FLAG_INVALID\",\n      message: `Invalid --rename value \"${value}\": old and new member names are identical.`,\n      command: \"tailordb migration generate\",\n    });\n  }\n  return { tableName, fieldName, previousPath, path: [...previousPath.slice(0, -1), newName] };\n}\n\n/**\n * A nested member removal confirmed as intentional (`--drop Table.field.member`),\n * so its rename candidates need no interactive confirmation.\n */\nexport interface NestedMemberDropSpec {\n  tableName: string;\n  fieldName: string;\n  path: string[];\n}\n\nconst NESTED_MEMBER_DROP_OPTION_PATTERN = /^([^.:\\s]+)\\.([^.:\\s]+)((?:\\.[^.:\\s]+)+)$/;\n\n/**\n * Parse a `--drop` option value of the form `Table.field.member`.\n * @param {string} value - Raw option value\n * @returns {NestedMemberDropSpec} Parsed drop spec\n */\nexport function parseNestedMemberDropOption(value: string): NestedMemberDropSpec {\n  const match = value.match(NESTED_MEMBER_DROP_OPTION_PATTERN);\n  const [, tableName, fieldName, memberPath] = match ?? [];\n  if (!tableName || !fieldName || !memberPath) {\n    throw CLIError({\n      code: \"MIGRATION_DROP_FLAG_INVALID\",\n      message: `Invalid --drop value \"${value}\". Expected format: \"Table.field.member\".`,\n      command: \"tailordb migration generate\",\n    });\n  }\n  return { tableName, fieldName, path: memberPath.slice(1).split(\".\") };\n}\n\n/**\n * Whether a nested member drop spec matches a member that was removed between\n * two snapshots: the member existed before and is gone now while its parent\n * still exists, so the spec names the removal itself rather than a descendant\n * of a removed parent.\n * @param {NestedMemberDropSpec} spec - Drop spec to test\n * @param {SchemaSnapshot} previousSnapshot - Previous schema snapshot\n * @param {SchemaSnapshot} currentSnapshot - Current schema snapshot\n * @returns {boolean} True if the spec matches a removed member\n */\nexport function nestedMemberDropSpecApplies(\n  spec: NestedMemberDropSpec,\n  previousSnapshot: SchemaSnapshot,\n  currentSnapshot: SchemaSnapshot,\n): boolean {\n  const prevField = previousSnapshot.tables[spec.tableName]?.fields[spec.fieldName];\n  const currField = currentSnapshot.tables[spec.tableName]?.fields[spec.fieldName];\n  return Boolean(\n    getNestedMember(prevField, spec.path) &&\n    !getNestedMember(currField, spec.path) &&\n    getNestedMember(currField, spec.path.slice(0, -1)),\n  );\n}\n\n// ============================================================================\n// Table Renames\n// ============================================================================\n\n/**\n * A confirmed table rename to record in the migration diff.\n */\nexport interface TypeRenameSpec {\n  /** Type name before the rename. */\n  previousTableName: string;\n  /** Type name after the rename. */\n  tableName: string;\n}\n\n/**\n * A removed table together with the added tables it could have been renamed to.\n */\nexport interface TypeRenameCandidate {\n  removed: TableRemovedChange;\n  /** Compatible added tables, in diff order. */\n  added: TableAddedChange[];\n}\n\n/**\n * Return a copy of a field config with foreign key references to the old table\n * name retargeted at the new name, so a self-referential table compares equal\n * to its renamed shape.\n * @param {SnapshotFieldConfig} field - Field configuration to retarget\n * @param {string} previousTableName - Type name before the rename\n * @param {string} tableName - Type name after the rename\n * @returns {SnapshotFieldConfig} Retargeted copy of the field\n */\nfunction retargetSelfReferences(\n  field: SnapshotFieldConfig,\n  previousTableName: string,\n  tableName: string,\n): SnapshotFieldConfig {\n  const nested = field.fields\n    ? Object.fromEntries(\n        Object.entries(field.fields).map(([name, member]) => [\n          name,\n          retargetSelfReferences(member, previousTableName, tableName),\n        ]),\n      )\n    : undefined;\n  return {\n    ...field,\n    ...(field.foreignKeyType === previousTableName && { foreignKeyType: tableName }),\n    ...(nested && { fields: nested }),\n  };\n}\n\n/**\n * JSON serialization with recursively sorted object keys, for deep equality.\n * @param {unknown} value - Value to serialize\n * @returns {string} Canonical JSON representation\n */\nfunction stableStringify(value: unknown): string {\n  if (Array.isArray(value)) {\n    return `[${value.map(stableStringify).join(\",\")}]`;\n  }\n  if (typeof value === \"object\" && value !== null) {\n    const entries = Object.entries(value as Record<string, unknown>)\n      .filter(([, v]) => v !== undefined)\n      .toSorted(([a], [b]) => a.localeCompare(b))\n      .map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`);\n    return `{${entries.join(\",\")}}`;\n  }\n  return JSON.stringify(value);\n}\n\nfunction isTypeRenameFieldCompatible(\n  before: SnapshotFieldConfig,\n  after: SnapshotFieldConfig,\n): boolean {\n  if (!isRenameCompatible(before, after)) return false;\n  if (before.required !== after.required) return false;\n  if ((before.unique ?? false) !== (after.unique ?? false)) return false;\n  if ((before.scale ?? null) !== (after.scale ?? null)) return false;\n\n  for (const [name, beforeMember] of Object.entries(before.fields ?? {})) {\n    const afterMember = after.fields?.[name];\n    if (!afterMember || !isTypeRenameFieldCompatible(beforeMember, afterMember)) return false;\n  }\n  return true;\n}\n\n/**\n * Whether copying every row of `before` into `after` preserves the data, i.e.\n * the removed + added table pair can be treated as a rename.\n *\n * A renamed table is created with its full constraints in the Pre-phase (there\n * is no relaxation machinery for a fresh table), so the shape must match\n * strictly: same field names with the same type, array-ness, required/unique\n * constraints, foreign key target (self references compare against the new\n * name), and scale; enum values must not be removed; indexes must match.\n * Serial values cannot be written by a script and file contents are not\n * copied by SQL, so tables with serial or file fields are never candidates.\n * Name-derived and data-independent surfaces (pluralForm, description,\n * settings, permissions, hooks, validations, relationships) may differ.\n * @param {TailorDBSnapshotType} before - Removed table's snapshot\n * @param {TailorDBSnapshotType} after - Added table's snapshot\n * @returns {boolean} True if the pair is rename-compatible\n */\nexport function isTypeRenameCompatible(\n  before: TailorDBSnapshotType,\n  after: TailorDBSnapshotType,\n): boolean {\n  if (Object.keys(before.files ?? {}).length > 0 || Object.keys(after.files ?? {}).length > 0) {\n    return false;\n  }\n\n  const beforeFieldNames = Object.keys(before.fields);\n  const afterFieldNames = Object.keys(after.fields);\n  if (beforeFieldNames.length !== afterFieldNames.length) return false;\n  for (const fieldName of beforeFieldNames) {\n    const beforeField = before.fields[fieldName];\n    const afterField = after.fields[fieldName];\n    if (!beforeField || !afterField) return false;\n    // A required self-referential foreign key cannot survive the copy: the\n    // batched insert cannot order rows parent-first and the two-phase\n    // backfill needs the column to accept null first.\n    if (beforeField.foreignKeyType === before.name && beforeField.required) return false;\n    const retargeted = retargetSelfReferences(beforeField, before.name, after.name);\n    if (!isTypeRenameFieldCompatible(retargeted, afterField)) return false;\n  }\n\n  return stableStringify(before.indexes ?? {}) === stableStringify(after.indexes ?? {});\n}\n\n/**\n * Find removed + added table pairs in a diff that could be renames.\n * @param {MigrationDiff} diff - Migration diff to scan\n * @returns {TypeRenameCandidate[]} Candidates in diff order (may be empty)\n */\nexport function findTypeRenameCandidates(diff: MigrationDiff): TypeRenameCandidate[] {\n  const removedChanges = diff.changes.filter(\n    (change): change is TableRemovedChange => change.kind === \"table_removed\",\n  );\n  const addedChanges = diff.changes.filter(\n    (change): change is TableAddedChange => change.kind === \"table_added\",\n  );\n\n  const candidates: TypeRenameCandidate[] = [];\n  for (const removed of removedChanges) {\n    const added = addedChanges.filter((a) => isTypeRenameCompatible(removed.before, a.after));\n    if (added.length > 0) {\n      candidates.push({ removed, added });\n    }\n  }\n  return candidates;\n}\n\n/**\n * Whether a table rename spec matches a removed + added table pair between two\n * snapshots: the old table existed before and is gone now, and the new table\n * exists now but did not before. Type compatibility is checked separately\n * when the diff is recomputed with the spec.\n * @param {TypeRenameSpec} spec - Rename spec to test\n * @param {SchemaSnapshot} previousSnapshot - Previous schema snapshot\n * @param {SchemaSnapshot} currentSnapshot - Current schema snapshot\n * @returns {boolean} True if the spec matches a removed + added pair\n */\nexport function typeRenameSpecApplies(\n  spec: TypeRenameSpec,\n  previousSnapshot: SchemaSnapshot,\n  currentSnapshot: SchemaSnapshot,\n): boolean {\n  return Boolean(\n    previousSnapshot.tables[spec.previousTableName] &&\n    !currentSnapshot.tables[spec.previousTableName] &&\n    currentSnapshot.tables[spec.tableName] &&\n    !previousSnapshot.tables[spec.tableName],\n  );\n}\n\n/**\n * Assert that every table rename spec matches a compatible removed + added\n * table pair between the two normalized snapshots.\n * @param {NormalizedSchemaSnapshot} previous - Previous normalized snapshot\n * @param {NormalizedSchemaSnapshot} current - Current normalized snapshot\n * @param {readonly TypeRenameSpec[]} typeRenames - Rename specs to validate\n */\nexport function assertValidTypeRenames(\n  previous: NormalizedSchemaSnapshot,\n  current: NormalizedSchemaSnapshot,\n  typeRenames: readonly TypeRenameSpec[],\n): void {\n  const seen = new Set<string>();\n  for (const rename of typeRenames) {\n    const { previousTableName, tableName } = rename;\n    const label = `${previousTableName}:${tableName}`;\n    for (const key of [previousTableName, tableName]) {\n      if (seen.has(key)) {\n        throw CLIError({\n          code: \"MIGRATION_RENAME_INVALID\",\n          message: `Table \"${key}\" appears in more than one rename.`,\n        });\n      }\n      seen.add(key);\n    }\n\n    const prevType = previous.tables[previousTableName];\n    if (!prevType) {\n      throw CLIError({\n        code: \"MIGRATION_RENAME_INVALID\",\n        message: `Cannot rename ${label}: table \"${previousTableName}\" does not exist in the previous schema.`,\n      });\n    }\n    if (current.tables[previousTableName]) {\n      throw CLIError({\n        code: \"MIGRATION_RENAME_INVALID\",\n        message: `Cannot rename ${label}: table \"${previousTableName}\" still exists in the current schema.`,\n      });\n    }\n    const currType = current.tables[tableName];\n    if (!currType) {\n      throw CLIError({\n        code: \"MIGRATION_RENAME_INVALID\",\n        message: `Cannot rename ${label}: table \"${tableName}\" does not exist in the current schema.`,\n      });\n    }\n    if (previous.tables[tableName]) {\n      throw CLIError({\n        code: \"MIGRATION_RENAME_INVALID\",\n        message: `Cannot rename ${label}: table \"${tableName}\" already exists in the previous schema.`,\n      });\n    }\n    if (!isTypeRenameCompatible(prevType, currType)) {\n      throw CLIError({\n        code: \"MIGRATION_RENAME_INVALID\",\n        message:\n          `Cannot rename ${label}: the tables are not rename-compatible ` +\n          `(every field must keep its name, type, array-ness, required/unique constraints, ` +\n          `foreign key target, and scale, enum values must not be removed, indexes must match, ` +\n          `self-referential foreign keys must be optional, ` +\n          `and tables with serial or file fields cannot be renamed).`,\n      });\n    }\n  }\n}\n\n/**\n * Whether a field's foreign key target changed in a way that is not explained\n * by a confirmed table rename. Such a retarget is breaking (stored references\n * may become invalid) and needs a reference fixup script; a retarget that\n * follows a rename does not, because record ids are preserved by the copy —\n * provided the referenced field is unchanged, since the copy only guarantees\n * that the same ids exist under the new table name.\n * @param {SnapshotFieldConfig} before - Field configuration before the change\n * @param {SnapshotFieldConfig} after - Field configuration after the change\n * @param {ReadonlyMap<string, string>} [typeRenameTargets] - Confirmed table renames (old name → new name)\n * @returns {boolean} True if the retarget is breaking\n */\nexport function isBreakingForeignKeyRetarget(\n  before: SnapshotFieldConfig,\n  after: SnapshotFieldConfig,\n  typeRenameTargets?: ReadonlyMap<string, string>,\n): boolean {\n  return Boolean(\n    before.foreignKeyType &&\n    after.foreignKeyType &&\n    before.foreignKeyType !== after.foreignKeyType &&\n    (typeRenameTargets?.get(before.foreignKeyType) !== after.foreignKeyType ||\n      (before.foreignKeyField ?? \"\") !== (after.foreignKeyField ?? \"\")),\n  );\n}\n\nconst TYPE_RENAME_OPTION_PATTERN = /^([^.:\\s]+):([^.:\\s]+)$/;\n\n/**\n * Parse a `--rename` option value of the form `OldTable:NewTable`.\n * @param {string} value - Raw option value\n * @returns {TypeRenameSpec} Parsed rename spec\n */\nexport function parseTypeRenameOption(value: string): TypeRenameSpec {\n  const match = value.match(TYPE_RENAME_OPTION_PATTERN);\n  const [, previousTableName, tableName] = match ?? [];\n  if (!previousTableName || !tableName) {\n    throw CLIError({\n      code: \"MIGRATION_RENAME_FLAG_INVALID\",\n      message: `Invalid --rename value \"${value}\". Expected format: \"Table.oldField:newField\" or \"OldTable:NewTable\".`,\n      command: \"tailordb migration generate\",\n    });\n  }\n  if (previousTableName === tableName) {\n    throw CLIError({\n      code: \"MIGRATION_RENAME_FLAG_INVALID\",\n      message: `Invalid --rename value \"${value}\": old and new table names are identical.`,\n      command: \"tailordb migration generate\",\n    });\n  }\n  return { previousTableName, tableName };\n}\n\n/**\n * A table removal confirmed as intentional (`--drop Table`), so its rename\n * candidates need no interactive confirmation.\n */\nexport interface TypeDropSpec {\n  tableName: string;\n}\n\nconst TYPE_DROP_OPTION_PATTERN = /^([^.:\\s]+)$/;\n\n/**\n * Parse a `--drop` option value of the form `Table`.\n * @param {string} value - Raw option value\n * @returns {TypeDropSpec} Parsed drop spec\n */\nexport function parseTypeDropOption(value: string): TypeDropSpec {\n  const match = value.match(TYPE_DROP_OPTION_PATTERN);\n  const [, tableName] = match ?? [];\n  if (!tableName) {\n    throw CLIError({\n      code: \"MIGRATION_DROP_FLAG_INVALID\",\n      message: `Invalid --drop value \"${value}\". Expected format: \"Table.field\" or \"Table\".`,\n      command: \"tailordb migration generate\",\n    });\n  }\n  return { tableName };\n}\n\n/**\n * Whether a table drop spec matches a table that was removed between two\n * snapshots: the table existed before and is gone now.\n * @param {TypeDropSpec} spec - Drop spec to test\n * @param {SchemaSnapshot} previousSnapshot - Previous schema snapshot\n * @param {SchemaSnapshot} currentSnapshot - Current schema snapshot\n * @returns {boolean} True if the spec matches a removed table\n */\nexport function typeDropSpecApplies(\n  spec: TypeDropSpec,\n  previousSnapshot: SchemaSnapshot,\n  currentSnapshot: SchemaSnapshot,\n): boolean {\n  return Boolean(\n    previousSnapshot.tables[spec.tableName] && !currentSnapshot.tables[spec.tableName],\n  );\n}\n","import { collectNestedMemberChanges } from \"./nested-members\";\nimport { haveSameParent, isNestedMemberRenameCompatible } from \"./rename-detection\";\nimport type { FieldModifiedChange, MigrationDiff, WarningChangeInfo } from \"./diff-calculator\";\n\nexport const FIELD_REMOVED_WARNING_REASON =\n  \"Field removed (existing data will no longer be accessible through the schema)\";\nexport const TABLE_REMOVED_WARNING_REASON =\n  \"Table removed (all records in this table will be deleted during post-migration cleanup)\";\nconst NESTED_MEMBER_REMOVED_WARNING_REASON =\n  \"Nested member removed (existing values will no longer be accessible through the schema)\";\n\n/**\n * Data-loss warnings for members removed inside a nested field.\n *\n * Members confirmed as renamed (`change.memberRenames`) are not data loss and\n * are skipped, and their new names are not offered as rename hints. The\n * Pre-phase keeps every removed member readable, and a compatible member added\n * at the same level is named in the warning as a hint.\n * @param {FieldModifiedChange} change - Modification of the top-level nested field\n * @returns {WarningChangeInfo[]} One warning per removed member, keyed by dotted member path\n */\nexport function collectNestedMemberRemovalWarnings(\n  change: FieldModifiedChange,\n): WarningChangeInfo[] {\n  const changes = collectNestedMemberChanges(change.before, change.after);\n  const renamedPaths = new Set(\n    (change.memberRenames ?? []).flatMap((rename) => [\n      rename.previousPath.join(\".\"),\n      rename.path.join(\".\"),\n    ]),\n  );\n  const warnings: WarningChangeInfo[] = [];\n  for (const removed of changes) {\n    if (removed.kind !== \"removed\" || renamedPaths.has(removed.path.join(\".\"))) continue;\n    const renameTargets = changes\n      .filter(\n        (added) =>\n          added.kind === \"added\" &&\n          !renamedPaths.has(added.path.join(\".\")) &&\n          haveSameParent(added.path, removed.path) &&\n          isNestedMemberRenameCompatible(removed.before, added.after),\n      )\n      .map((added) => added.path.at(-1));\n    const hint =\n      renameTargets.length > 0\n        ? `. Possibly renamed to ${renameTargets.join(\", \")}: confirm it with ` +\n          `--rename \"${change.tableName}.${change.fieldName}.${removed.path.join(\".\")}:<newName>\" ` +\n          \"to scaffold a copy script, or keep the removal and copy the values yourself\"\n        : \"\";\n    warnings.push({\n      tableName: change.tableName,\n      fieldName: [change.fieldName, ...removed.path].join(\".\"),\n      reason: `${NESTED_MEMBER_REMOVED_WARNING_REASON}${hint}`,\n    });\n  }\n  return warnings;\n}\n\n/**\n * Reconstruct data-loss warnings from removal changes for diff.json files\n * written before the warning tier existed\n * @param {MigrationDiff} diff - Parsed legacy migration diff\n * @returns {WarningChangeInfo[]} Warnings equivalent to what diff generation would have recorded\n */\nexport function deriveWarningsFromChanges(diff: MigrationDiff): WarningChangeInfo[] {\n  const warnings: WarningChangeInfo[] = [];\n  for (const change of diff.changes) {\n    if (change.kind === \"field_removed\") {\n      warnings.push({\n        tableName: change.tableName,\n        fieldName: change.fieldName,\n        reason: FIELD_REMOVED_WARNING_REASON,\n      });\n    } else if (change.kind === \"table_removed\") {\n      warnings.push({ tableName: change.tableName, reason: TABLE_REMOVED_WARNING_REASON });\n    } else if (change.kind === \"field_modified\") {\n      warnings.push(...collectNestedMemberRemovalWarnings(change));\n    }\n  }\n  return warnings;\n}\n","import * as inflection from \"inflection\";\nimport { assertDefined } from \"#/utils/assert\";\nimport {\n  type MigrationDiff,\n  type DiffChange,\n  type FieldDiffChange,\n  type BreakingChangeInfo,\n  type SnapshotTypeSettingsState,\n  type TypeScriptsState,\n  type WarningChangeInfo,\n  SCHEMA_SNAPSHOT_VERSION,\n} from \"./diff-calculator\";\nimport { supportsInPlaceFieldTypeChange } from \"./field-type-change\";\nimport { areOwnFieldConfigsDifferent, collectNestedMemberChanges } from \"./nested-members\";\nimport {\n  assertValidFieldRenames,\n  assertValidNestedMemberRenames,\n  assertValidTypeRenames,\n  isBreakingForeignKeyRetarget,\n  type FieldRenameSpec,\n  type NestedMemberRenameSpec,\n  type TypeRenameSpec,\n} from \"./rename-detection\";\nimport { copySnapshotRecord, normalizeSchemaSnapshot } from \"./snapshot-normalization\";\nimport {\n  type NormalizedSchemaSnapshot,\n  type SchemaSnapshot,\n  type SnapshotActionPermission,\n  type SnapshotFieldConfig,\n  type SnapshotGqlAction,\n  type SnapshotGqlPermission,\n  type SnapshotGqlOperations,\n  type SnapshotIndexConfig,\n  type SnapshotRecordPermission,\n  type SnapshotRelationship,\n  type SnapshotSettings,\n  type TailorDBSnapshotType,\n} from \"./snapshot-types\";\nimport {\n  collectNestedMemberRemovalWarnings,\n  FIELD_REMOVED_WARNING_REASON,\n  TABLE_REMOVED_WARNING_REASON,\n} from \"./snapshot-warnings\";\nimport type { ExpandContractPlan } from \"./expand-contract\";\n\n// ============================================================================\n// Snapshot Comparison\n// ============================================================================\n\n/**\n * Compare two field configs and determine if they are different\n * @param {SnapshotFieldConfig} oldField - Old field configuration\n * @param {SnapshotFieldConfig} newField - New field configuration\n * @returns {boolean} True if fields are different\n */\nfunction areFieldsDifferent(oldField: SnapshotFieldConfig, newField: SnapshotFieldConfig): boolean {\n  return (\n    areOwnFieldConfigsDifferent(oldField, newField) ||\n    collectNestedMemberChanges(oldField, newField).length > 0\n  );\n}\n\n/**\n * Collect breaking changes for a field change\n * @param {string} tableName - Name of the table containing the field\n * @param {string} fieldName - Name of the field being changed\n * @param {SnapshotFieldConfig | undefined} oldField - Old field configuration\n * @param {SnapshotFieldConfig | undefined} newField - New field configuration\n * @param {ReadonlyMap<string, string>} [typeRenameTargets] - Confirmed table renames (old name → new name)\n * @returns {BreakingChangeInfo[]} Breaking change information\n */\nfunction getBreakingFieldChanges(\n  tableName: string,\n  fieldName: string,\n  oldField: SnapshotFieldConfig | undefined,\n  newField: SnapshotFieldConfig | undefined,\n  typeRenameTargets?: ReadonlyMap<string, string>,\n): BreakingChangeInfo[] {\n  const breakingChanges: BreakingChangeInfo[] = [];\n\n  // Field added as required - breaking (existing records don't have this value)\n  if (!oldField && newField && newField.required) {\n    breakingChanges.push({\n      tableName,\n      fieldName,\n      reason: \"Required field added\",\n    });\n  }\n\n  // Compatible scalar type changes use a phased in-place migration. Other\n  // pairs still require expand-contract migration support.\n  if (oldField && newField && oldField.type !== newField.type) {\n    const supported = supportsInPlaceFieldTypeChange(oldField, newField);\n    breakingChanges.push({\n      tableName,\n      fieldName,\n      reason: `Field type changed from ${oldField.type} to ${newField.type}`,\n      ...(!supported && { unsupported: true, showThreeStepHint: true }),\n    });\n  }\n\n  // Optional to required - breaking\n  if (oldField && newField && !oldField.required && newField.required) {\n    breakingChanges.push({\n      tableName,\n      fieldName,\n      reason: \"Field changed from optional to required\",\n    });\n  }\n\n  // Array property changed - never applied in place; a single value becoming\n  // an array can go through expand-contract, the reverse needs the 3-step migration\n  if (oldField && newField && (oldField.array ?? false) !== (newField.array ?? false)) {\n    const [fromType, toType] = oldField.array\n      ? [\"array\", \"single value\"]\n      : [\"single value\", \"array\"];\n    breakingChanges.push({\n      tableName,\n      fieldName,\n      reason: `Field changed from ${fromType} to ${toType}`,\n      unsupported: true,\n      showThreeStepHint: true,\n    });\n  }\n\n  // Foreign key relationship changed - breaking (existing references may become\n  // invalid), unless it retargets a confirmed table rename: record ids are\n  // preserved by the rename copy, so the stored references stay valid.\n  if (oldField && newField && isBreakingForeignKeyRetarget(oldField, newField, typeRenameTargets)) {\n    breakingChanges.push({\n      tableName,\n      fieldName,\n      reason: `Foreign key target type changed from ${oldField.foreignKeyType} to ${newField.foreignKeyType}`,\n    });\n  }\n\n  // Unique constraint added - breaking (existing duplicate values would violate constraint)\n  if (oldField && newField && !(oldField.unique ?? false) && (newField.unique ?? false)) {\n    breakingChanges.push({\n      tableName,\n      fieldName,\n      reason: \"Unique constraint added to field\",\n    });\n  }\n\n  // Decimal scale changed - breaking (rows stored under the old scale must be\n  // re-saved so their stored precision matches the new schema)\n  if (\n    oldField?.type === \"decimal\" &&\n    newField?.type === \"decimal\" &&\n    oldField.scale !== newField.scale\n  ) {\n    breakingChanges.push({\n      tableName,\n      fieldName,\n      reason: `Decimal scale changed from ${oldField.scale} to ${newField.scale}`,\n    });\n  }\n\n  // Enum values removed - breaking (existing records may have removed values)\n  if (oldField && newField && oldField.type === \"enum\" && newField.type === \"enum\") {\n    const oldAllowed = oldField.allowedValues ?? [];\n    const newAllowed = newField.allowedValues ?? [];\n    const oldValues = oldAllowed.map((v) => v.value);\n    const newValuesSet = new Set(newAllowed.map((v) => v.value));\n    const removedValues = oldValues.filter((v) => !newValuesSet.has(v));\n    if (removedValues.length > 0) {\n      breakingChanges.push({\n        tableName,\n        fieldName,\n        reason: `Enum values removed: ${removedValues.join(\", \")}`,\n      });\n    }\n  }\n\n  return breakingChanges;\n}\n\n/**\n * Context for collecting diff changes, breaking changes, and warnings\n */\ninterface DiffContext {\n  changes: DiffChange[];\n  breakingChanges: BreakingChangeInfo[];\n  warnings: WarningChangeInfo[];\n  /** Confirmed table renames (old name → new name), for reference retargets. */\n  typeRenameTargets?: ReadonlyMap<string, string>;\n}\n\nfunction addChange(\n  ctx: DiffContext,\n  change: FieldDiffChange,\n  oldField: SnapshotFieldConfig | undefined,\n  newField: SnapshotFieldConfig | undefined,\n): void {\n  ctx.changes.push(change);\n\n  if (!change.fieldName) return;\n\n  // A removed nested member is data loss regardless of any breaking change on the field.\n  if (change.kind === \"field_modified\") {\n    ctx.warnings.push(...collectNestedMemberRemovalWarnings(change));\n  }\n\n  const breakingChanges = getBreakingFieldChanges(\n    change.tableName,\n    change.fieldName,\n    oldField,\n    newField,\n    ctx.typeRenameTargets,\n  );\n  if (breakingChanges.length > 0) {\n    ctx.breakingChanges.push(...breakingChanges);\n    return;\n  }\n\n  // Non-breaking removal still risks losing schema access: surface a warning so users\n  // can decide whether to add a migration script (e.g. JOIN through a\n  // soon-to-be-dropped foreign key before it disappears).\n  if (change.kind === \"field_removed\") {\n    ctx.warnings.push({\n      tableName: change.tableName,\n      fieldName: change.fieldName,\n      reason: FIELD_REMOVED_WARNING_REASON,\n    });\n  }\n}\n\nfunction compareTypeFields(\n  ctx: DiffContext,\n  tableName: string,\n  prevType: TailorDBSnapshotType,\n  currType: TailorDBSnapshotType,\n  fieldRenames: readonly FieldRenameSpec[] = [],\n  nestedMemberRenames: readonly NestedMemberRenameSpec[] = [],\n): void {\n  const prevFieldNames = new Set(Object.keys(prevType.fields));\n  const currFieldNames = new Set(Object.keys(currType.fields));\n  const renamedFromNames = new Set(fieldRenames.map((r) => r.previousFieldName));\n  const renamedToNames = new Set(fieldRenames.map((r) => r.fieldName));\n\n  for (const rename of fieldRenames) {\n    const prevField = assertDefined(\n      prevType.fields[rename.previousFieldName],\n      `renamed field \"${rename.previousFieldName}\" missing from prevType`,\n    );\n    const currField = assertDefined(\n      currType.fields[rename.fieldName],\n      `renamed field \"${rename.fieldName}\" missing from currType`,\n    );\n    ctx.changes.push({\n      kind: \"field_renamed\",\n      tableName,\n      fieldName: rename.fieldName,\n      previousFieldName: rename.previousFieldName,\n      before: prevField,\n      after: currField,\n    });\n    ctx.breakingChanges.push({\n      tableName,\n      fieldName: rename.fieldName,\n      reason: `Field renamed from ${rename.previousFieldName} to ${rename.fieldName} (existing values must be copied by the migration script)`,\n    });\n  }\n\n  // Check for added fields\n  for (const fieldName of currFieldNames) {\n    if (renamedToNames.has(fieldName)) continue;\n    if (!prevFieldNames.has(fieldName)) {\n      const currField = assertDefined(\n        currType.fields[fieldName],\n        `field \"${fieldName}\" missing from currType`,\n      );\n      addChange(\n        ctx,\n        {\n          kind: \"field_added\",\n          tableName,\n          fieldName,\n          after: currField,\n        },\n        undefined,\n        currField,\n      );\n    }\n  }\n\n  // Check for removed fields\n  for (const fieldName of prevFieldNames) {\n    if (renamedFromNames.has(fieldName)) continue;\n    if (!currFieldNames.has(fieldName)) {\n      const prevField = assertDefined(\n        prevType.fields[fieldName],\n        `field \"${fieldName}\" missing from prevType`,\n      );\n      addChange(\n        ctx,\n        {\n          kind: \"field_removed\",\n          tableName,\n          fieldName,\n          before: prevField,\n        },\n        prevField,\n        undefined,\n      );\n    }\n  }\n\n  // Check for modified fields\n  for (const fieldName of currFieldNames) {\n    if (!prevFieldNames.has(fieldName)) continue;\n\n    const prevField = assertDefined(\n      prevType.fields[fieldName],\n      `field \"${fieldName}\" missing from prevType`,\n    );\n    const currField = assertDefined(\n      currType.fields[fieldName],\n      `field \"${fieldName}\" missing from currType`,\n    );\n\n    if (!areFieldsDifferent(prevField, currField)) continue;\n\n    if (prevField.type !== currField.type) {\n      addChange(\n        ctx,\n        { kind: \"field_type_modified\", tableName, fieldName, before: prevField, after: currField },\n        prevField,\n        currField,\n      );\n      continue;\n    }\n\n    const memberRenames = nestedMemberRenames\n      .filter((rename) => rename.fieldName === fieldName)\n      .map(({ previousPath, path }) => ({ previousPath, path }));\n    addChange(\n      ctx,\n      {\n        kind: \"field_modified\",\n        tableName,\n        fieldName,\n        before: prevField,\n        after: currField,\n        ...(memberRenames.length > 0 && { memberRenames }),\n      },\n      prevField,\n      currField,\n    );\n    for (const rename of memberRenames) {\n      ctx.breakingChanges.push({\n        tableName,\n        fieldName: [fieldName, ...rename.path].join(\".\"),\n        reason:\n          `Nested member renamed from ${rename.previousPath.join(\".\")} to ${rename.path.join(\".\")} ` +\n          \"(existing values must be copied by the migration script)\",\n      });\n    }\n  }\n}\n\n/**\n * Determine if a table-level index change is breaking. Mirrors the field-level\n * unique reasoning: enforcing a unique constraint over existing rows can fail\n * on duplicates, so both adding a unique index and re-pointing an existing\n * unique index at a different field set require a data migration.\n * @param {string} tableName - Name of the table containing the index\n * @param {string} indexName - Name of the index being changed\n * @param {SnapshotIndexConfig | undefined} oldIndex - Old index configuration\n * @param {SnapshotIndexConfig | undefined} newIndex - New index configuration\n * @returns {BreakingChangeInfo | null} Breaking change info or null if not breaking\n */\nexport function isBreakingIndexChange(\n  tableName: string,\n  indexName: string,\n  oldIndex: SnapshotIndexConfig | undefined,\n  newIndex: SnapshotIndexConfig | undefined,\n): BreakingChangeInfo | null {\n  if (!newIndex || !(newIndex.unique ?? false)) return null;\n\n  // Unique index added, or unique constraint added to an existing index\n  if (!oldIndex || !(oldIndex.unique ?? false)) {\n    return {\n      tableName,\n      reason: `Unique constraint added to index \"${indexName}\"`,\n    };\n  }\n\n  // Unique index re-pointed at a different field set: the old constraint is\n  // dropped and a new one enforced, so duplicates are just as possible.\n  if (JSON.stringify(oldIndex.fields.toSorted()) !== JSON.stringify(newIndex.fields.toSorted())) {\n    return {\n      tableName,\n      reason: `Unique index fields changed on index \"${indexName}\"`,\n    };\n  }\n\n  return null;\n}\n\n/**\n * Compare table-level indexes\n * @param {DiffContext} ctx - Diff context\n * @param {string} tableName - Table name\n * @param {Record<string, SnapshotIndexConfig> | undefined} oldIndexes - Previous indexes\n * @param {Record<string, SnapshotIndexConfig> | undefined} newIndexes - Current indexes\n * @returns {void}\n */\nfunction compareIndexes(\n  ctx: DiffContext,\n  tableName: string,\n  oldIndexes: Record<string, SnapshotIndexConfig> | undefined,\n  newIndexes: Record<string, SnapshotIndexConfig> | undefined,\n): void {\n  const oldKeys = new Set(Object.keys(oldIndexes || {}));\n  const newKeys = new Set(Object.keys(newIndexes || {}));\n\n  // Index added\n  for (const [indexName, indexConfig] of Object.entries(newIndexes ?? {})) {\n    if (!oldKeys.has(indexName)) {\n      ctx.changes.push({\n        kind: \"index_added\",\n        tableName,\n        indexName,\n        after: indexConfig,\n      });\n      const breaking = isBreakingIndexChange(tableName, indexName, undefined, indexConfig);\n      if (breaking) {\n        ctx.breakingChanges.push(breaking);\n      }\n    }\n  }\n\n  // Index removed\n  for (const [indexName, indexConfig] of Object.entries(oldIndexes ?? {})) {\n    if (!newKeys.has(indexName)) {\n      ctx.changes.push({\n        kind: \"index_removed\",\n        tableName,\n        indexName,\n        before: indexConfig,\n      });\n    }\n  }\n\n  // Index modified\n  for (const [indexName, newIndex] of Object.entries(newIndexes ?? {})) {\n    if (oldKeys.has(indexName)) {\n      const oldIndex = assertDefined(\n        assertDefined(oldIndexes, \"oldIndexes is undefined when oldKeys has entry\")[indexName],\n        `index \"${indexName}\" missing from oldIndexes`,\n      );\n\n      const oldFieldsStr = JSON.stringify(oldIndex.fields.toSorted());\n      const newFieldsStr = JSON.stringify(newIndex.fields.toSorted());\n\n      if (\n        oldFieldsStr !== newFieldsStr ||\n        (oldIndex.unique ?? false) !== (newIndex.unique ?? false)\n      ) {\n        const reasons: string[] = [];\n        if (oldFieldsStr !== newFieldsStr) reasons.push(\"fields changed\");\n        if ((oldIndex.unique ?? false) !== (newIndex.unique ?? false))\n          reasons.push(\"unique constraint changed\");\n        ctx.changes.push({\n          kind: \"index_modified\",\n          tableName,\n          indexName,\n          reason: reasons.join(\", \"),\n          before: oldIndex,\n          after: newIndex,\n        });\n        const breaking = isBreakingIndexChange(tableName, indexName, oldIndex, newIndex);\n        if (breaking) {\n          ctx.breakingChanges.push(breaking);\n        }\n      }\n    }\n  }\n}\n\n/**\n * Compare table-level file fields\n * @param {DiffContext} ctx - Diff context\n * @param {string} tableName - Table name\n * @param {Record<string, string> | undefined} oldFiles - Previous file fields\n * @param {Record<string, string> | undefined} newFiles - Current file fields\n * @returns {void}\n */\nfunction compareFiles(\n  ctx: DiffContext,\n  tableName: string,\n  oldFiles: Record<string, string> | undefined,\n  newFiles: Record<string, string> | undefined,\n): void {\n  const oldKeys = new Set(Object.keys(oldFiles || {}));\n  const newKeys = new Set(Object.keys(newFiles || {}));\n\n  // File field added\n  for (const [fileName, fileDesc] of Object.entries(newFiles ?? {})) {\n    if (!oldKeys.has(fileName)) {\n      ctx.changes.push({\n        kind: \"file_added\",\n        tableName,\n        fieldName: fileName,\n        after: fileDesc,\n      });\n    }\n  }\n\n  // File field removed\n  for (const [fileName, fileDesc] of Object.entries(oldFiles ?? {})) {\n    if (!newKeys.has(fileName)) {\n      ctx.changes.push({\n        kind: \"file_removed\",\n        tableName,\n        fieldName: fileName,\n        before: fileDesc,\n      });\n    }\n  }\n\n  // File field modified (description changed)\n  for (const [fileName, newDesc] of Object.entries(newFiles ?? {})) {\n    if (oldKeys.has(fileName)) {\n      const oldDesc = assertDefined(\n        assertDefined(oldFiles, \"oldFiles is undefined when oldKeys has entry\")[fileName],\n        `file \"${fileName}\" missing from oldFiles`,\n      );\n      if (oldDesc !== newDesc) {\n        ctx.changes.push({\n          kind: \"file_modified\",\n          tableName,\n          fieldName: fileName,\n          reason: \"description changed\",\n          before: oldDesc,\n          after: newDesc,\n        });\n      }\n    }\n  }\n}\n\n/**\n * Compare table-level relationships\n * @param {DiffContext} ctx - Diff context\n * @param {string} tableName - Table name\n * @param {\"forward\" | \"backward\"} relationshipType - Relationship direction to compare\n * @param {Record<string, SnapshotRelationship> | undefined} oldRelationships - Previous relationships\n * @param {Record<string, SnapshotRelationship> | undefined} newRelationships - Current relationships\n * @returns {void}\n */\nfunction compareRelationships(\n  ctx: DiffContext,\n  tableName: string,\n  relationshipType: \"forward\" | \"backward\",\n  oldRelationships: Record<string, SnapshotRelationship> | undefined,\n  newRelationships: Record<string, SnapshotRelationship> | undefined,\n): void {\n  const oldKeys = new Set(Object.keys(oldRelationships || {}));\n  const newKeys = new Set(Object.keys(newRelationships || {}));\n\n  // Relationship added\n  for (const [relName, rel] of Object.entries(newRelationships ?? {})) {\n    if (!oldKeys.has(relName)) {\n      ctx.changes.push({\n        kind: \"relationship_added\",\n        tableName,\n        relationshipName: relName,\n        relationshipType,\n        after: rel,\n      });\n    }\n  }\n\n  // Relationship removed\n  for (const [relName, rel] of Object.entries(oldRelationships ?? {})) {\n    if (!newKeys.has(relName)) {\n      ctx.changes.push({\n        kind: \"relationship_removed\",\n        tableName,\n        relationshipName: relName,\n        relationshipType,\n        before: rel,\n      });\n    }\n  }\n\n  // Relationship modified\n  for (const [relName, newRel] of Object.entries(newRelationships ?? {})) {\n    if (oldKeys.has(relName)) {\n      const oldRel = assertDefined(\n        assertDefined(oldRelationships, \"oldRelationships is undefined when oldKeys has entry\")[\n          relName\n        ],\n        `relationship \"${relName}\" missing from oldRelationships`,\n      );\n\n      const reasons: string[] = [];\n      if (oldRel.targetType !== newRel.targetType) reasons.push(\"targetType changed\");\n      if (oldRel.targetField !== newRel.targetField) reasons.push(\"targetField changed\");\n      if (oldRel.sourceField !== newRel.sourceField) reasons.push(\"sourceField changed\");\n      if (oldRel.isArray !== newRel.isArray) reasons.push(\"isArray changed\");\n      if (oldRel.description !== newRel.description) {\n        reasons.push(\"description changed\");\n      }\n\n      if (reasons.length > 0) {\n        ctx.changes.push({\n          kind: \"relationship_modified\",\n          tableName,\n          relationshipName: relName,\n          relationshipType,\n          reason: reasons.join(\", \"),\n          before: oldRel,\n          after: newRel,\n        });\n      }\n    }\n  }\n}\n\n/**\n * Compare table-level permissions\n * @param {DiffContext} ctx - Diff context\n * @param {string} tableName - Table name\n * @param {SnapshotRecordPermission | undefined} oldRecordPerm - Previous record permission\n * @param {SnapshotRecordPermission | undefined} newRecordPerm - Current record permission\n * @param {SnapshotGqlPermission | undefined} oldGqlPerm - Previous GQL permission\n * @param {SnapshotGqlPermission | undefined} newGqlPerm - Current GQL permission\n * @returns {void}\n */\nfunction comparePermissions(\n  ctx: DiffContext,\n  tableName: string,\n  oldRecordPerm: SnapshotRecordPermission | undefined,\n  newRecordPerm: SnapshotRecordPermission | undefined,\n  oldGqlPerm: SnapshotGqlPermission | undefined,\n  newGqlPerm: SnapshotGqlPermission | undefined,\n): void {\n  // Compare record permissions\n  const oldComparableRecordPerm = comparableRecordPermission(oldRecordPerm);\n  const newComparableRecordPerm = comparableRecordPermission(newRecordPerm);\n  const oldRecordStr = JSON.stringify(oldComparableRecordPerm ?? null);\n  const newRecordStr = JSON.stringify(newComparableRecordPerm ?? null);\n  const recordPermChanged = oldRecordStr !== newRecordStr;\n\n  // Compare GQL permissions\n  const oldComparableGqlPerm = comparableGqlPermission(oldGqlPerm);\n  const newComparableGqlPerm = comparableGqlPermission(newGqlPerm);\n  const oldGqlStr = JSON.stringify(oldComparableGqlPerm ?? null);\n  const newGqlStr = JSON.stringify(newComparableGqlPerm ?? null);\n  const gqlPermChanged = oldGqlStr !== newGqlStr;\n\n  if (recordPermChanged || gqlPermChanged) {\n    const reasons: string[] = [];\n    if (recordPermChanged) reasons.push(\"record permission\");\n    if (gqlPermChanged) reasons.push(\"GQL permission\");\n\n    ctx.changes.push({\n      kind: \"permission_modified\",\n      tableName,\n      reason: `${reasons.join(\" and \")} changed`,\n      before: { recordPermission: oldComparableRecordPerm, gqlPermission: oldComparableGqlPerm },\n      after: { recordPermission: newComparableRecordPerm, gqlPermission: newComparableGqlPerm },\n    });\n  }\n}\n\nconst GQL_ACTION_ORDER: Record<SnapshotGqlAction, number> = {\n  all: 0,\n  create: 1,\n  read: 2,\n  update: 3,\n  delete: 4,\n  aggregate: 5,\n  bulkUpsert: 6,\n};\n\n// Policies and conditions combine as an order-independent set on the platform,\n// so canonicalize their order before comparison to avoid false drift when the\n// remote returns them in a different order than the local snapshot declares.\nfunction sortByJson<T>(items: readonly T[]): T[] {\n  return items\n    .map((item) => [JSON.stringify(item), item] as const)\n    .toSorted(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))\n    .map(([, item]) => item);\n}\n\nfunction comparableGqlPermission(\n  permission: SnapshotGqlPermission | undefined,\n): SnapshotGqlPermission | undefined {\n  const policies = permission?.map((policy) => ({\n    ...policy,\n    conditions: sortByJson(policy.conditions),\n    actions: policy.actions.toSorted(\n      (left, right) => GQL_ACTION_ORDER[left] - GQL_ACTION_ORDER[right],\n    ),\n  }));\n  return policies && policies.length > 0 ? sortByJson(policies) : undefined;\n}\n\nfunction comparableRecordPermission(\n  permission: SnapshotRecordPermission | undefined,\n): SnapshotRecordPermission | undefined {\n  if (!permission) return undefined;\n  if (!Object.values(permission).some((policies) => policies.length > 0)) return undefined;\n\n  const canonical: SnapshotRecordPermission = {\n    create: sortByJson(permission.create.map(canonicalActionPermission)),\n    read: sortByJson(permission.read.map(canonicalActionPermission)),\n    update: sortByJson(permission.update.map(canonicalActionPermission)),\n    delete: sortByJson(permission.delete.map(canonicalActionPermission)),\n  };\n  return canonical;\n}\n\nfunction canonicalActionPermission(policy: SnapshotActionPermission): SnapshotActionPermission {\n  return { ...policy, conditions: sortByJson(policy.conditions) };\n}\n\nfunction normalizeComparableGqlOperations(\n  operations: SnapshotGqlOperations | undefined,\n): SnapshotGqlOperations | undefined {\n  if (!operations) return undefined;\n\n  return {\n    create: operations.create ?? true,\n    update: operations.update ?? true,\n    delete: operations.delete ?? true,\n    read: operations.read ?? true,\n  };\n}\n\nfunction normalizeComparableSettings(\n  settings: TailorDBSnapshotType[\"settings\"],\n): TailorDBSnapshotType[\"settings\"] | undefined {\n  const normalized: SnapshotSettings = {};\n\n  if (settings?.aggregation === true) normalized.aggregation = true;\n  if (settings?.bulkUpsert === true) normalized.bulkUpsert = true;\n  if (settings?.publishEvents === true) normalized.publishEvents = true;\n\n  const gqlOperations = normalizeComparableGqlOperations(settings?.gqlOperations);\n  if (gqlOperations) normalized.gqlOperations = gqlOperations;\n\n  return Object.keys(normalized).length > 0 ? normalized : undefined;\n}\n\nfunction typeSettingsState(\n  description: string | undefined,\n  pluralForm: string,\n  settings: TailorDBSnapshotType[\"settings\"],\n): SnapshotTypeSettingsState {\n  return {\n    ...(description ? { description } : {}),\n    pluralForm,\n    ...(settings && { settings }),\n  };\n}\n\nfunction comparableTypeSettings(type: TailorDBSnapshotType): SnapshotTypeSettingsState {\n  return typeSettingsState(\n    type.description,\n    inflection.camelize(type.pluralForm, true),\n    normalizeComparableSettings(type.settings),\n  );\n}\n\nfunction snapshotTypeSettingsState(type: TailorDBSnapshotType): SnapshotTypeSettingsState {\n  return typeSettingsState(type.description, type.pluralForm, type.settings ?? {});\n}\n\nfunction compareTypeSettings(\n  ctx: DiffContext,\n  tableName: string,\n  previous: TailorDBSnapshotType,\n  current: TailorDBSnapshotType,\n): void {\n  const previousComparable = comparableTypeSettings(previous);\n  const currentComparable = comparableTypeSettings(current);\n\n  if (JSON.stringify(previousComparable) === JSON.stringify(currentComparable)) return;\n\n  ctx.changes.push({\n    kind: \"table_settings_modified\",\n    tableName,\n    reason: \"settings changed\",\n    before: snapshotTypeSettingsState(previous),\n    after: snapshotTypeSettingsState(current),\n  });\n}\n\nfunction typeScriptsState(type: TailorDBSnapshotType): TypeScriptsState {\n  return {\n    ...(type.typeHookExpr && { typeHookExpr: type.typeHookExpr }),\n    ...(type.typeValidateExpr !== undefined && { typeValidateExpr: type.typeValidateExpr }),\n  };\n}\n\nfunction compareTypeScripts(\n  ctx: DiffContext,\n  tableName: string,\n  previous: TailorDBSnapshotType,\n  current: TailorDBSnapshotType,\n): void {\n  const prevState = typeScriptsState(previous);\n  const currState = typeScriptsState(current);\n\n  if (JSON.stringify(prevState) === JSON.stringify(currState)) return;\n\n  ctx.changes.push({\n    kind: \"table_scripts_modified\",\n    tableName,\n    reason: \"table-level scripts changed\",\n    before: prevState,\n    after: currState,\n  });\n}\n\n/**\n * Restate the schema an expand migration starts from, with each converted field\n * relaxed to optional.\n *\n * The expand script clears the original field once it has carried the value\n * across. That write reaches the field under the contract recorded on the\n * removal, which the deploy restores for the duration of the migration, so a\n * field left required would reject it.\n * @param previous - Snapshot the expand migration starts from\n * @param plans - Field changes carried through temporary fields\n * @returns Snapshot to compare the expand migration against\n */\nfunction buildExpandBaseSnapshot(\n  previous: NormalizedSchemaSnapshot,\n  plans: readonly ExpandContractPlan[],\n): NormalizedSchemaSnapshot {\n  const tables = copySnapshotRecord(previous.tables);\n  for (const plan of plans) {\n    const type = tables[plan.tableName];\n    const original = type?.fields[plan.fieldName];\n    if (!type || !original) continue;\n    const fields = copySnapshotRecord(type.fields);\n    fields[plan.fieldName] = { ...original, required: false };\n    tables[plan.tableName] = { ...type, fields };\n  }\n  return normalizeSchemaSnapshot({ ...previous, tables });\n}\n\n/**\n * Build the diff for the migration that converts values into temporary fields.\n *\n * Adding an optional field and removing one are both non-breaking, so nothing\n * in the comparison marks the script as required — yet it is the only thing\n * carrying the values across before the original field is dropped.\n * @param previous - Snapshot the expand migration starts from\n * @param intermediate - Snapshot the expand migration produces\n * @param plans - Field changes carried through temporary fields\n * @returns Diff to write for the expand migration\n */\nexport function buildExpandDiff(\n  previous: NormalizedSchemaSnapshot,\n  intermediate: NormalizedSchemaSnapshot,\n  plans: readonly ExpandContractPlan[],\n): MigrationDiff {\n  const diff = compareSnapshots(buildExpandBaseSnapshot(previous, plans), intermediate);\n  return { ...diff, requiresMigrationScript: true };\n}\n\n/**\n * Build the schema state that sits between an expand and a contract migration:\n * each converted field is replaced by its temporary counterpart.\n *\n * The original field is dropped here rather than in the contract migration so\n * the contract can reuse its name. It stays readable while the expand script\n * runs, because a field removed by a migration is retained until that same\n * migration's post phase.\n *\n * The temporary field is optional and non-unique regardless of its final\n * contract, since the expand script fills it in batches.\n * @param previous - Snapshot the expand migration starts from\n * @param plans - Field changes carried through temporary fields\n * @returns Snapshot the contract migration compares against\n */\nexport function buildIntermediateSnapshot(\n  previous: NormalizedSchemaSnapshot,\n  plans: readonly ExpandContractPlan[],\n): NormalizedSchemaSnapshot {\n  const tables = copySnapshotRecord(previous.tables);\n  for (const plan of plans) {\n    const type = tables[plan.tableName];\n    if (!type) continue;\n    const fields = copySnapshotRecord(type.fields);\n    // Hooks and validation stay off the temporary field: the rename re-applies\n    // the real contract, and a non-idempotent update hook would otherwise run\n    // once on the conversion and again on the copy.\n    const { hooks: _hooks, validate: _validate, ...carried } = plan.after;\n    fields[plan.tempFieldName] = { ...carried, required: false, unique: false };\n    delete fields[plan.fieldName];\n    tables[plan.tableName] = { ...type, fields };\n  }\n  return normalizeSchemaSnapshot({ ...previous, tables });\n}\n\n/**\n * Options for {@link compareSnapshots}.\n */\nexport interface CompareSnapshotsOptions {\n  /**\n   * Confirmed field renames. Each spec replaces the corresponding\n   * `field_removed` + `field_added` pair with a single breaking\n   * `field_renamed` change. Specs are validated against both snapshots.\n   */\n  fieldRenames?: readonly FieldRenameSpec[];\n  /**\n   * Confirmed table renames. Each spec replaces the corresponding\n   * `table_removed` + `table_added` pair with a single breaking\n   * `table_renamed` change. Specs are validated against both snapshots.\n   */\n  typeRenames?: readonly TypeRenameSpec[];\n  /**\n   * Confirmed renames of members inside nested fields. Each spec is recorded on\n   * the field's `field_modified` change as a breaking `memberRenames` entry\n   * instead of a removal warning. Specs are validated against both snapshots.\n   */\n  nestedMemberRenames?: readonly NestedMemberRenameSpec[];\n}\n\n/**\n * Compare two normalized snapshots and generate a diff\n * @param {NormalizedSchemaSnapshot} previous - Previous normalized snapshot\n * @param {NormalizedSchemaSnapshot} current - Current normalized snapshot\n * @param {CompareSnapshotsOptions} [options] - Comparison options\n * @returns {MigrationDiff} Migration diff between snapshots\n */\nexport function compareSnapshots(\n  previous: NormalizedSchemaSnapshot,\n  current: NormalizedSchemaSnapshot,\n  options?: CompareSnapshotsOptions,\n): MigrationDiff {\n  const fieldRenames = options?.fieldRenames ?? [];\n  assertValidFieldRenames(previous, current, fieldRenames);\n  const renamesByType = new Map<string, FieldRenameSpec[]>();\n  for (const rename of fieldRenames) {\n    const list = renamesByType.get(rename.tableName) ?? [];\n    list.push(rename);\n    renamesByType.set(rename.tableName, list);\n  }\n  const nestedMemberRenames = options?.nestedMemberRenames ?? [];\n  assertValidNestedMemberRenames(previous, current, nestedMemberRenames);\n  const nestedRenamesByType = new Map<string, NestedMemberRenameSpec[]>();\n  for (const rename of nestedMemberRenames) {\n    const list = nestedRenamesByType.get(rename.tableName) ?? [];\n    list.push(rename);\n    nestedRenamesByType.set(rename.tableName, list);\n  }\n  const typeRenames = options?.typeRenames ?? [];\n  assertValidTypeRenames(previous, current, typeRenames);\n  const typeRenameTargets = new Map(typeRenames.map((r) => [r.previousTableName, r.tableName]));\n  const renamedToTypeNames = new Set(typeRenames.map((r) => r.tableName));\n\n  const ctx: DiffContext = {\n    changes: [],\n    breakingChanges: [],\n    warnings: [],\n    typeRenameTargets,\n  };\n\n  const previousTypeNames = new Set(Object.keys(previous.tables));\n  const currentTypeNames = new Set(Object.keys(current.tables));\n\n  // Record confirmed table renames\n  for (const rename of typeRenames) {\n    const prevType = assertDefined(\n      previous.tables[rename.previousTableName],\n      `renamed table \"${rename.previousTableName}\" missing from previous snapshot`,\n    );\n    const currType = assertDefined(\n      current.tables[rename.tableName],\n      `renamed table \"${rename.tableName}\" missing from current snapshot`,\n    );\n    ctx.changes.push({\n      kind: \"table_renamed\",\n      tableName: rename.tableName,\n      previousTableName: rename.previousTableName,\n      before: prevType,\n      after: currType,\n    });\n    ctx.breakingChanges.push({\n      tableName: rename.tableName,\n      reason: `Table renamed from ${rename.previousTableName} to ${rename.tableName} (existing records must be copied by the migration script)`,\n    });\n    ctx.breakingChanges.push({\n      tableName: rename.tableName,\n      reason:\n        `GraphQL API names derived from ${rename.previousTableName}/${prevType.pluralForm} change to ` +\n        `${rename.tableName}/${currType.pluralForm} — breaking for API clients`,\n    });\n  }\n\n  // Check for added tables\n  for (const [tableName, type] of Object.entries(current.tables)) {\n    if (renamedToTypeNames.has(tableName)) continue;\n    if (!previousTypeNames.has(tableName)) {\n      ctx.changes.push({\n        kind: \"table_added\",\n        tableName,\n        after: type,\n      });\n    }\n  }\n\n  // Check for removed tables\n  for (const [tableName, type] of Object.entries(previous.tables)) {\n    if (typeRenameTargets.has(tableName)) continue;\n    if (!currentTypeNames.has(tableName)) {\n      ctx.changes.push({\n        kind: \"table_removed\",\n        tableName,\n        before: type,\n      });\n      ctx.warnings.push({\n        tableName,\n        reason: TABLE_REMOVED_WARNING_REASON,\n      });\n    }\n  }\n\n  // Check for modified tables\n  for (const tableName of currentTypeNames) {\n    if (!previousTypeNames.has(tableName)) continue;\n\n    const prevType = assertDefined(\n      previous.tables[tableName],\n      `table \"${tableName}\" missing from previous snapshot`,\n    );\n    const currType = assertDefined(\n      current.tables[tableName],\n      `table \"${tableName}\" missing from current snapshot`,\n    );\n\n    // Compare table-level settings and metadata\n    compareTypeSettings(ctx, tableName, prevType, currType);\n\n    // Compare table-level hook/validate scripts\n    compareTypeScripts(ctx, tableName, prevType, currType);\n\n    // Compare fields\n    compareTypeFields(\n      ctx,\n      tableName,\n      prevType,\n      currType,\n      renamesByType.get(tableName),\n      nestedRenamesByType.get(tableName),\n    );\n\n    // Compare indexes\n    compareIndexes(ctx, tableName, prevType.indexes, currType.indexes);\n\n    // Compare file fields\n    compareFiles(ctx, tableName, prevType.files, currType.files);\n\n    // Compare relationships\n    compareRelationships(\n      ctx,\n      tableName,\n      \"forward\",\n      prevType.forwardRelationships,\n      currType.forwardRelationships,\n    );\n    compareRelationships(\n      ctx,\n      tableName,\n      \"backward\",\n      prevType.backwardRelationships,\n      currType.backwardRelationships,\n    );\n\n    // Compare permissions\n    comparePermissions(\n      ctx,\n      tableName,\n      prevType.permissions?.record,\n      currType.permissions?.record,\n      prevType.permissions?.gql,\n      currType.permissions?.gql,\n    );\n  }\n\n  return {\n    version: SCHEMA_SNAPSHOT_VERSION,\n    namespace: current.namespace,\n    createdAt: new Date().toISOString(),\n    changes: ctx.changes,\n    hasBreakingChanges: ctx.breakingChanges.length > 0,\n    breakingChanges: ctx.breakingChanges,\n    hasWarnings: ctx.warnings.length > 0,\n    warnings: ctx.warnings,\n    requiresMigrationScript: ctx.breakingChanges.length > 0,\n  };\n}\n\n/**\n * Compare a snapshot against canonical TailorDBSnapshotType-shaped local tables.\n * Callers are expected to pre-convert TailorDBService.types to TailorDBSnapshotType via\n * `createSnapshotType`. As a safety net, both sides are re-run through idempotent\n * normalization here, so a caller that forgets will still get correct\n * comparisons (no silent false drift).\n * @param {SchemaSnapshot} snapshot - Schema snapshot to compare against\n * @param {Record<string, TailorDBSnapshotType>} localTypes - Local snapshot-shaped tables\n * @param {string} namespace - Namespace for comparison\n * @returns {MigrationDiff} Migration diff\n */\nexport function compareLocalTypesWithSnapshot(\n  snapshot: SchemaSnapshot,\n  localTypes: Record<string, TailorDBSnapshotType>,\n  namespace: string,\n): MigrationDiff {\n  const currentSnapshot: SchemaSnapshot = {\n    version: SCHEMA_SNAPSHOT_VERSION,\n    namespace,\n    createdAt: new Date().toISOString(),\n    tables: localTypes,\n  };\n  return compareSnapshots(\n    normalizeSchemaSnapshot(snapshot),\n    normalizeSchemaSnapshot(currentSnapshot),\n  );\n}\n","/**\n * Types for TailorDB migration execution\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { Code, ConnectError } from \"@connectrpc/connect\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { formatMigrationNumber } from \"./migration-number\";\nimport type { MigrationDiff } from \"./diff-calculator\";\n\n// ============================================================================\n// Label Constants\n// ============================================================================\n\n/**\n * Maximum length for Kubernetes label values\n * Labels must match pattern: ^[a-z][a-z0-9_-]{0,62}\n */\nexport const MAX_LABEL_LENGTH = 63;\n\n/**\n * Prefix added to migration numbers in labels (required because migration names start with numbers)\n */\nconst MIGRATION_LABEL_PREFIX = \"m\";\n\n/**\n * Label key for storing migration state in TailorDB Service metadata\n */\nexport const MIGRATION_LABEL_KEY = \"sdk-migration\";\n\n/** Label key identifying which migration history ID is deployed. */\nexport const MIGRATION_HISTORY_LABEL_KEY = \"sdk-migration-history\";\n\n/** Valid migration history ID syntax for metadata label values. */\nexport const MIGRATION_HISTORY_ID_PATTERN = /^[a-z][a-z0-9_-]{0,62}$/;\n\n// ============================================================================\n// Error Constants\n// ============================================================================\n\n/**\n * Error patterns that indicate schema corruption\n */\nexport const SCHEMA_ERROR_PATTERNS = [\n  \"failed to fetch schema\",\n  \"sqlaccess error\",\n  \"schema not found\",\n  \"invalid schema\",\n] as const;\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Pending migration to be executed\n */\nexport interface PendingMigration {\n  /** Migration number */\n  number: number;\n  /** Path to migration script file (may not exist on disk) */\n  scriptPath: string;\n  /** Whether a migration script file exists on disk for this migration */\n  hasScript: boolean;\n  /** Path to diff file */\n  diffPath: string;\n  /** Namespace this migration belongs to */\n  namespace: string;\n  /** Migrations directory path */\n  migrationsDir: string;\n  /** Migration diff content */\n  diff: MigrationDiff;\n}\n\n// ============================================================================\n// Label Helper Functions\n// ============================================================================\n\n/**\n * Sanitize migration number for use as label value\n * Label pattern: ^[a-z][a-z0-9_-]{0,62}\n * - Must start with lowercase letter (add prefix since migration numbers start with digits)\n * - Max 63 characters\n * @param {number} migrationNumber - Migration number to sanitize\n * @returns {string} Sanitized label value\n */\nexport function sanitizeMigrationLabel(migrationNumber: number): string {\n  const sanitized = MIGRATION_LABEL_PREFIX + formatMigrationNumber(migrationNumber);\n  return sanitized.slice(0, MAX_LABEL_LENGTH);\n}\n\n/**\n * Parse migration number from label value\n * @param {string} label - Label value (e.g., \"m0001\")\n * @returns {number | null} Parsed number or null if invalid\n */\nexport function parseMigrationLabelNumber(label: string): number | null {\n  if (!label.startsWith(MIGRATION_LABEL_PREFIX)) return null;\n  const numStr = label.slice(MIGRATION_LABEL_PREFIX.length);\n  // Strict digits-only match: a malformed label (e.g. \"m0001-extra\") must\n  // read as unset, not as migration 1. Same for numbers outside the\n  // 0000-9999 directory range the migrations system supports.\n  if (!/^\\d+$/.test(numStr)) return null;\n  const num = parseInt(numStr, 10);\n  return num > 9999 ? null : num;\n}\n\n/**\n * Parse and validate a migration history ID stored in metadata.\n * @param label - Metadata label value\n * @returns Valid history ID, or null for malformed input\n */\nexport function parseMigrationHistoryId(label: string): string | null {\n  return MIGRATION_HISTORY_ID_PATTERN.test(label) ? label : null;\n}\n\n/**\n * Create a migration history ID that is valid as a metadata label value.\n * @returns New migration history ID\n */\nexport function createMigrationHistoryId(): string {\n  return `h${randomUUID().replaceAll(\"-\", \"\")}`;\n}\n\n// ============================================================================\n// Error Helper Functions\n// ============================================================================\n\n/**\n * Check if an error message indicates schema corruption\n * @param {string} errorMessage - Error message to check\n * @returns {boolean} True if error indicates schema corruption\n */\nexport function isSchemaError(errorMessage: string): boolean {\n  const lowerMessage = errorMessage.toLowerCase();\n  return SCHEMA_ERROR_PATTERNS.some((pattern) => lowerMessage.includes(pattern));\n}\n\n/**\n * Handle optional-to-required field change error with helpful message\n * @param {unknown} error - Error to handle\n * @param {string[]} messages - Additional messages to display\n */\nexport function handleOptionalToRequiredError(error: unknown, messages: string[]): never {\n  if (\n    error instanceof ConnectError &&\n    error.code === Code.FailedPrecondition &&\n    error.message.includes(\"cannot be updated from non-required to required when records exist\")\n  ) {\n    logger.error(\n      \"Schema change failed: Cannot change field from optional to required when records exist.\",\n    );\n    logger.newline();\n    for (const message of messages) {\n      logger.info(message);\n    }\n  }\n  throw error;\n}\n\n// ============================================================================\n// Remote Schema Verification Types\n// ============================================================================\n\n/**\n * Type of schema drift detected between remote and local snapshot\n */\ntype SchemaDriftKind =\n  | \"type_missing_remote\"\n  | \"type_missing_local\"\n  | \"type_settings_mismatch\"\n  | \"field_missing_remote\"\n  | \"field_missing_local\"\n  | \"field_mismatch\"\n  | \"index_missing_remote\"\n  | \"index_missing_local\"\n  | \"index_mismatch\"\n  | \"file_missing_remote\"\n  | \"file_missing_local\"\n  | \"file_mismatch\"\n  | \"relationship_missing_remote\"\n  | \"relationship_missing_local\"\n  | \"relationship_mismatch\"\n  | \"permission_mismatch\"\n  | \"script_mismatch\";\n\n/**\n * Single schema drift item\n */\nexport interface SchemaDrift {\n  tableName: string;\n  kind: SchemaDriftKind;\n  fieldName?: string;\n  indexName?: string;\n  fileName?: string;\n  relationshipName?: string;\n  relationshipType?: \"forward\" | \"backward\";\n  details: string;\n}\n\n/**\n * Reason why remote schema verification was skipped for a namespace\n */\nexport type RemoteSchemaVerificationSkipReason =\n  | \"not_deployed\"\n  | \"no_migration_label\"\n  | \"no_snapshot\";\n\nexport interface MigrationCheckpointRepair {\n  namespace: string;\n  from: number;\n  to: 0;\n  fromHistoryId: string | null;\n  toHistoryId: string;\n}\n\n/**\n * Diagnostic detail for {@link RemoteSchemaVerificationResult.checkpointMissingLocal} when the\n * cause is specifically an environment that fell behind before `migration rebaseline` ran: its\n * remote history still matches the pre-rebaseline history, but at a migration number other than\n * the one every environment was required to reach first.\n */\nexport interface RebaselinePendingInfo {\n  replacedLatestMigration: number;\n}\n\n/**\n * Result of remote schema verification for a single namespace\n */\nexport interface RemoteSchemaVerificationResult {\n  namespace: string;\n  remoteMigrationNumber: number;\n  drifts: SchemaDrift[];\n  hasDrift: boolean;\n  /** Set when the remote migration checkpoint does not exist in the local migration history */\n  checkpointMissingLocal?: boolean;\n  /**\n   * Set alongside `checkpointMissingLocal` when the cause is an environment that fell behind\n   * before `migration rebaseline` ran, rather than a generic history mismatch.\n   */\n  rebaselinePending?: RebaselinePendingInfo;\n  /** Safe checkpoint reset offered after the remote schema matched the local baseline */\n  checkpointRepair?: Omit<MigrationCheckpointRepair, \"namespace\">;\n  /** Set when verification could not run (no remote migration label, or no snapshot at the remote migration number) */\n  skipped?: RemoteSchemaVerificationSkipReason;\n}\n","/**\n * Zod schemas for TailorDB migration snapshot and diff files.\n *\n * Each schema mirrors the corresponding hand-written interface from\n * snapshot-types.ts / diff-calculator.ts. Schemas are cast to\n * `z.ZodType<T>` to keep them aligned with the interfaces at compile time.\n *\n * All object schemas use `z.looseObject` so that unknown keys written\n * by newer CLI versions survive a load → save round-trip.\n */\n\nimport { z } from \"zod\";\nimport { MIGRATION_HISTORY_ID_PATTERN } from \"./types\";\nimport type {\n  TypeSettingsPatch,\n  SnapshotPermissionState,\n  TableAddedChange,\n  TableRemovedChange,\n  TableRenamedChange,\n  TableModifiedChange,\n  TableSettingsModifiedChange,\n  SnapshotTypeSettingsState,\n  FieldAddedChange,\n  FieldRemovedChange,\n  FieldModifiedChange,\n  FieldRenamedChange,\n  FieldTypeModifiedChange,\n  IndexAddedChange,\n  IndexRemovedChange,\n  IndexModifiedChange,\n  FileAddedChange,\n  FileRemovedChange,\n  FileModifiedChange,\n  RelationshipAddedChange,\n  RelationshipRemovedChange,\n  RelationshipModifiedChange,\n  PermissionModifiedChange,\n  TableScriptsModifiedChange,\n  TypeScriptsState,\n  DiffChange,\n  BreakingChangeInfo,\n  WarningChangeInfo,\n  MigrationDiff,\n  ScriptSkippedInfo,\n} from \"./diff-calculator\";\nimport type {\n  SnapshotHook,\n  SnapshotValidation,\n  SnapshotSerial,\n  SnapshotEnumValue,\n  SnapshotFieldConfig,\n  SnapshotIndexConfig,\n  SnapshotRelationship,\n  SnapshotActionPermission,\n  SnapshotRecordPermission,\n  SnapshotGqlPermissionPolicy,\n  SnapshotGqlPermission,\n  TailorDBSnapshotType,\n  SchemaSnapshot,\n  RebaselineMarker,\n  SnapshotPermissionOperand,\n  SnapshotPermissionCondition,\n} from \"./snapshot-types\";\n\nfunction snapshotRecordSchema<T>(valueSchema: z.ZodType<T>): z.ZodType<Record<string, T>> {\n  return z\n    .custom<Record<string, unknown>>(\n      (value) => typeof value === \"object\" && value !== null && !Array.isArray(value),\n      { message: \"Expected record\" },\n    )\n    .transform((value, ctx) => {\n      const record = Object.create(null) as Record<string, T>;\n      for (const key of Object.keys(value)) {\n        const result = valueSchema.safeParse(value[key]);\n        if (!result.success) {\n          for (const issue of result.error.issues) {\n            ctx.addIssue({ ...issue, path: [key, ...issue.path] });\n          }\n          continue;\n        }\n        record[key] = result.data;\n      }\n      return record;\n    });\n}\n\n// ============================================================================\n// Snapshot Leaf Types\n// ============================================================================\n\nconst snapshotHookSchema: z.ZodType<SnapshotHook> = z.looseObject({\n  expr: z.string(),\n});\n\nconst snapshotValidationSchema: z.ZodType<SnapshotValidation> = z.looseObject({\n  script: z.looseObject({ expr: z.string() }).optional() as z.ZodType<{ expr: string }>,\n  errorMessage: z.string(),\n});\n\nconst snapshotSerialSchema: z.ZodType<SnapshotSerial> = z.looseObject({\n  start: z.number(),\n  maxValue: z.number().optional(),\n  format: z.string().optional(),\n});\n\nconst snapshotEnumValueSchema: z.ZodType<SnapshotEnumValue> = z.looseObject({\n  value: z.string(),\n  description: z.string().optional(),\n});\n\n// SnapshotFieldConfig is self-referential (fields?: Record<string, SnapshotFieldConfig>)\n// z.lazy handles the recursion; the outer cast closes the type cycle.\nconst snapshotFieldConfigSchema: z.ZodType<SnapshotFieldConfig> = z.looseObject({\n  type: z.string(),\n  // `required` defaults to true to match the pre-validation `?? true` behaviour.\n  required: z.boolean().default(true),\n  array: z.boolean().optional(),\n  index: z.boolean().optional(),\n  unique: z.boolean().optional(),\n  allowedValues: z.array(snapshotEnumValueSchema).optional(),\n  foreignKey: z.boolean().optional(),\n  foreignKeyType: z.string().optional(),\n  foreignKeyField: z.string().optional(),\n  description: z.string().optional(),\n  vector: z.boolean().optional(),\n  hooks: z\n    .looseObject({\n      create: snapshotHookSchema.optional(),\n      update: snapshotHookSchema.optional(),\n    })\n    .optional(),\n  validate: z.array(snapshotValidationSchema).optional(),\n  serial: snapshotSerialSchema.optional(),\n  scale: z.number().optional(),\n  default: z.unknown().optional(),\n  fields: z.lazy(() => snapshotRecordSchema(snapshotFieldConfigSchema)).optional(),\n});\n\nconst snapshotIndexConfigSchema: z.ZodType<SnapshotIndexConfig> = z.looseObject({\n  fields: z.array(z.string()),\n  unique: z.boolean().optional(),\n});\n\nconst snapshotRelationshipSchema: z.ZodType<SnapshotRelationship> = z.looseObject({\n  targetType: z.string(),\n  targetField: z.string(),\n  sourceField: z.string(),\n  isArray: z.boolean(),\n  description: z.string(),\n});\n\n// ============================================================================\n// Permission Types\n// ============================================================================\n\n// Structure validated; vocabulary kept open for platform evolution\nconst FIELD_REF_KEYS = [\"user\", \"record\", \"newRecord\", \"oldRecord\"] as const;\n\n// Record-level operand: reject a plain object that contains two or more known\n// ref keys — such an object is ambiguous and signals a malformed condition.\nconst snapshotPermissionOperandSchema = z.unknown().refine((v) => {\n  if (typeof v !== \"object\" || v === null || Array.isArray(v)) return true;\n  const keys = Object.keys(v);\n  const refKeyCount = FIELD_REF_KEYS.filter((k) => keys.includes(k)).length;\n  return refKeyCount < 2;\n}, \"Ambiguous field-ref operand: contains more than one of user/record/newRecord/oldRecord\") as unknown as z.ZodType<SnapshotPermissionOperand>;\n\n// GQL operand: same ambiguity check, plus reject record/newRecord/oldRecord refs.\nconst snapshotGqlPermissionOperandSchema = z\n  .unknown()\n  .refine((v) => {\n    if (typeof v !== \"object\" || v === null || Array.isArray(v)) return true;\n    const keys = Object.keys(v);\n    const refKeyCount = FIELD_REF_KEYS.filter((k) => keys.includes(k)).length;\n    return refKeyCount < 2;\n  }, \"Ambiguous field-ref operand: contains more than one of user/record/newRecord/oldRecord\")\n  .refine((v) => {\n    if (typeof v !== \"object\" || v === null || Array.isArray(v)) return true;\n    const keys = Object.keys(v);\n    return ![\"record\", \"newRecord\", \"oldRecord\"].some((k) => keys.includes(k));\n  }, \"GQL permissions only support { user } field references\") as unknown as z.ZodType<SnapshotPermissionOperand>;\n\n// Structure validated; vocabulary kept open for platform evolution\nconst snapshotPermissionOperatorSchema = z.string();\n\n// SnapshotPermissionCondition is a readonly 3-tuple; extra trailing elements tolerated.\nconst snapshotPermissionConditionSchema = z\n  .tuple([\n    snapshotPermissionOperandSchema,\n    snapshotPermissionOperatorSchema,\n    snapshotPermissionOperandSchema,\n  ])\n  .rest(z.unknown()) as unknown as z.ZodType<SnapshotPermissionCondition>;\n\nconst snapshotGqlPermissionConditionSchema = z\n  .tuple([\n    snapshotGqlPermissionOperandSchema,\n    snapshotPermissionOperatorSchema,\n    snapshotGqlPermissionOperandSchema,\n  ])\n  .rest(z.unknown()) as unknown as z.ZodType<SnapshotPermissionCondition>;\n\nconst snapshotActionPermissionSchema: z.ZodType<SnapshotActionPermission> = z.looseObject({\n  conditions: z.array(snapshotPermissionConditionSchema),\n  description: z.string().optional(),\n  permit: z.enum([\"allow\", \"deny\"]),\n});\n\nconst snapshotRecordPermissionSchema: z.ZodType<SnapshotRecordPermission> = z.looseObject({\n  create: z.array(snapshotActionPermissionSchema).default([]),\n  read: z.array(snapshotActionPermissionSchema).default([]),\n  update: z.array(snapshotActionPermissionSchema).default([]),\n  delete: z.array(snapshotActionPermissionSchema).default([]),\n});\n\n// Structure validated; vocabulary kept open for platform evolution\nconst snapshotGqlActionSchema = z.string();\n\nconst snapshotGqlPermissionPolicySchema: z.ZodType<SnapshotGqlPermissionPolicy> = z.looseObject({\n  conditions: z.array(snapshotGqlPermissionConditionSchema),\n  actions: z.array(snapshotGqlActionSchema),\n  permit: z.enum([\"allow\", \"deny\"]),\n  description: z.string().optional(),\n}) as unknown as z.ZodType<SnapshotGqlPermissionPolicy>;\n\n// SnapshotGqlPermission = readonly SnapshotGqlPermissionPolicy[]\nconst snapshotGqlPermissionSchema: z.ZodType<SnapshotGqlPermission> = z.array(\n  snapshotGqlPermissionPolicySchema,\n);\n\n// ============================================================================\n// TailorDBSnapshotType\n// ============================================================================\n\nconst tailorDBSnapshotTypeSchema: z.ZodType<TailorDBSnapshotType> = z.looseObject({\n  name: z.string(),\n  // `pluralForm` is typed as required but legacy snapshots may omit it;\n  // loadSnapshot backfills it via inflection so we accept undefined here.\n  pluralForm: z.string().optional() as z.ZodType<string>,\n  description: z.string().optional(),\n  fields: snapshotRecordSchema(snapshotFieldConfigSchema),\n  settings: z\n    .looseObject({\n      aggregation: z.boolean().optional(),\n      bulkUpsert: z.boolean().optional(),\n      gqlOperations: z\n        .looseObject({\n          create: z.boolean().optional(),\n          update: z.boolean().optional(),\n          delete: z.boolean().optional(),\n          read: z.boolean().optional(),\n        })\n        .optional(),\n      publishEvents: z.boolean().optional(),\n    })\n    .optional(),\n  indexes: snapshotRecordSchema(snapshotIndexConfigSchema).optional(),\n  files: snapshotRecordSchema(z.string()).optional(),\n  forwardRelationships: snapshotRecordSchema(snapshotRelationshipSchema).optional(),\n  backwardRelationships: snapshotRecordSchema(snapshotRelationshipSchema).optional(),\n  permissions: z\n    .looseObject({\n      record: snapshotRecordPermissionSchema.optional(),\n      gql: snapshotGqlPermissionSchema.optional(),\n    })\n    .optional(),\n});\n\n// ============================================================================\n// SchemaSnapshot\n// ============================================================================\n\nconst rebaselineMarkerSchema: z.ZodType<RebaselineMarker> = z.looseObject({\n  historyId: z.string().regex(MIGRATION_HISTORY_ID_PATTERN),\n  replacedHistoryId: z.string().regex(MIGRATION_HISTORY_ID_PATTERN).nullable(),\n  replacedLatestMigration: z.number().int().min(0).max(9999),\n});\n\nexport const schemaSnapshotSchema: z.ZodType<SchemaSnapshot> = z.looseObject({\n  version: z.number(),\n  namespace: z.string(),\n  createdAt: z.string(),\n  tables: snapshotRecordSchema(tailorDBSnapshotTypeSchema),\n  rebaseline: rebaselineMarkerSchema.optional(),\n});\n\n// ============================================================================\n// Diff Types\n// ============================================================================\n\nconst typeSettingsPatchSchema: z.ZodType<TypeSettingsPatch> = z.looseObject({\n  indexes: snapshotRecordSchema(snapshotIndexConfigSchema).optional(),\n  files: snapshotRecordSchema(z.string()).optional(),\n});\n\nconst snapshotTypeSettingsStateSchema: z.ZodType<SnapshotTypeSettingsState> = z.looseObject({\n  description: z.string().optional(),\n  pluralForm: z.string(),\n  settings: z\n    .looseObject({\n      aggregation: z.boolean().optional(),\n      bulkUpsert: z.boolean().optional(),\n      gqlOperations: z\n        .looseObject({\n          create: z.boolean().optional(),\n          update: z.boolean().optional(),\n          delete: z.boolean().optional(),\n          read: z.boolean().optional(),\n        })\n        .optional(),\n      publishEvents: z.boolean().optional(),\n    })\n    .optional(),\n});\n\nconst snapshotPermissionStateSchema: z.ZodType<SnapshotPermissionState> = z.looseObject({\n  recordPermission: snapshotRecordPermissionSchema.optional(),\n  gqlPermission: snapshotGqlPermissionSchema.optional(),\n});\n\n// Individual change schemas are typed as z.ZodType<T> after the looseObject\n// cast so that z.discriminatedUnion can accept them.\nconst typeAddedChangeSchema = z.looseObject({\n  kind: z.literal(\"table_added\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  after: tailorDBSnapshotTypeSchema,\n}) as unknown as z.ZodType<TableAddedChange>;\n\nconst typeRemovedChangeSchema = z.looseObject({\n  kind: z.literal(\"table_removed\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  before: tailorDBSnapshotTypeSchema,\n}) as unknown as z.ZodType<TableRemovedChange>;\n\nconst typeRenamedChangeSchema = z.looseObject({\n  kind: z.literal(\"table_renamed\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  previousTableName: z.string(),\n  before: tailorDBSnapshotTypeSchema,\n  after: tailorDBSnapshotTypeSchema,\n}) as unknown as z.ZodType<TableRenamedChange>;\n\nconst typeModifiedChangeSchema = z.looseObject({\n  kind: z.literal(\"table_modified\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  before: typeSettingsPatchSchema.optional(),\n  after: typeSettingsPatchSchema.optional(),\n}) as unknown as z.ZodType<TableModifiedChange>;\n\nconst typeSettingsModifiedChangeSchema = z.looseObject({\n  kind: z.literal(\"table_settings_modified\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  before: snapshotTypeSettingsStateSchema,\n  after: snapshotTypeSettingsStateSchema,\n}) as unknown as z.ZodType<TableSettingsModifiedChange>;\n\nconst fieldAddedChangeSchema = z.looseObject({\n  kind: z.literal(\"field_added\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  fieldName: z.string(),\n  after: snapshotFieldConfigSchema,\n}) as unknown as z.ZodType<FieldAddedChange>;\n\nconst fieldRemovedChangeSchema = z.looseObject({\n  kind: z.literal(\"field_removed\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  fieldName: z.string(),\n  before: snapshotFieldConfigSchema,\n}) as unknown as z.ZodType<FieldRemovedChange>;\n\nconst fieldModifiedChangeSchema = z.looseObject({\n  kind: z.literal(\"field_modified\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  fieldName: z.string(),\n  before: snapshotFieldConfigSchema,\n  after: snapshotFieldConfigSchema,\n  memberRenames: z\n    .array(\n      z\n        .looseObject({\n          previousPath: z.array(z.string()).min(1),\n          path: z.array(z.string()).min(1),\n        })\n        .refine(\n          ({ previousPath, path }) =>\n            previousPath.length === path.length &&\n            previousPath.slice(0, -1).every((segment, index) => segment === path[index]) &&\n            previousPath.at(-1) !== path.at(-1),\n          { message: \"memberRenames entries must rename a member within its parent\" },\n        ),\n    )\n    .optional(),\n}) as unknown as z.ZodType<FieldModifiedChange>;\n\nconst fieldRenamedChangeSchema = z.looseObject({\n  kind: z.literal(\"field_renamed\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  fieldName: z.string(),\n  previousFieldName: z.string(),\n  before: snapshotFieldConfigSchema,\n  after: snapshotFieldConfigSchema,\n}) as unknown as z.ZodType<FieldRenamedChange>;\n\nconst fieldTypeModifiedChangeSchema = z.looseObject({\n  kind: z.literal(\"field_type_modified\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  fieldName: z.string(),\n  before: snapshotFieldConfigSchema,\n  after: snapshotFieldConfigSchema,\n}) as unknown as z.ZodType<FieldTypeModifiedChange>;\n\nconst indexAddedChangeSchema = z.looseObject({\n  kind: z.literal(\"index_added\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  indexName: z.string(),\n  after: snapshotIndexConfigSchema,\n}) as unknown as z.ZodType<IndexAddedChange>;\n\nconst indexRemovedChangeSchema = z.looseObject({\n  kind: z.literal(\"index_removed\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  indexName: z.string(),\n  before: snapshotIndexConfigSchema,\n}) as unknown as z.ZodType<IndexRemovedChange>;\n\nconst indexModifiedChangeSchema = z.looseObject({\n  kind: z.literal(\"index_modified\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  indexName: z.string(),\n  before: snapshotIndexConfigSchema,\n  after: snapshotIndexConfigSchema,\n}) as unknown as z.ZodType<IndexModifiedChange>;\n\nconst fileAddedChangeSchema = z.looseObject({\n  kind: z.literal(\"file_added\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  fieldName: z.string(),\n  after: z.string(),\n}) as unknown as z.ZodType<FileAddedChange>;\n\nconst fileRemovedChangeSchema = z.looseObject({\n  kind: z.literal(\"file_removed\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  fieldName: z.string(),\n  before: z.string(),\n}) as unknown as z.ZodType<FileRemovedChange>;\n\nconst fileModifiedChangeSchema = z.looseObject({\n  kind: z.literal(\"file_modified\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  fieldName: z.string(),\n  before: z.string(),\n  after: z.string(),\n}) as unknown as z.ZodType<FileModifiedChange>;\n\nconst relationshipAddedChangeSchema = z.looseObject({\n  kind: z.literal(\"relationship_added\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  relationshipName: z.string(),\n  relationshipType: z.enum([\"forward\", \"backward\"]).optional(),\n  after: snapshotRelationshipSchema,\n}) as unknown as z.ZodType<RelationshipAddedChange>;\n\nconst relationshipRemovedChangeSchema = z.looseObject({\n  kind: z.literal(\"relationship_removed\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  relationshipName: z.string(),\n  relationshipType: z.enum([\"forward\", \"backward\"]).optional(),\n  before: snapshotRelationshipSchema,\n}) as unknown as z.ZodType<RelationshipRemovedChange>;\n\nconst relationshipModifiedChangeSchema = z.looseObject({\n  kind: z.literal(\"relationship_modified\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  relationshipName: z.string(),\n  relationshipType: z.enum([\"forward\", \"backward\"]).optional(),\n  before: snapshotRelationshipSchema,\n  after: snapshotRelationshipSchema,\n}) as unknown as z.ZodType<RelationshipModifiedChange>;\n\nconst permissionModifiedChangeSchema = z.looseObject({\n  kind: z.literal(\"permission_modified\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  before: snapshotPermissionStateSchema.optional(),\n  after: snapshotPermissionStateSchema.optional(),\n}) as unknown as z.ZodType<PermissionModifiedChange>;\n\nconst typeScriptsStateSchema: z.ZodType<TypeScriptsState> = z.looseObject({\n  typeHookExpr: z\n    .looseObject({\n      create: z.string().optional(),\n      update: z.string().optional(),\n    })\n    .optional(),\n  typeValidateExpr: z.string().optional(),\n});\n\nconst typeScriptsModifiedChangeSchema = z.looseObject({\n  kind: z.literal(\"table_scripts_modified\"),\n  tableName: z.string(),\n  reason: z.string().optional(),\n  before: typeScriptsStateSchema,\n  after: typeScriptsStateSchema,\n}) as unknown as z.ZodType<TableScriptsModifiedChange>;\n\ntype DiscriminableSchema = Parameters<typeof z.discriminatedUnion>[1][number];\n\nconst diffChangeSchema: z.ZodType<DiffChange> = z.discriminatedUnion(\"kind\", [\n  typeAddedChangeSchema as unknown as DiscriminableSchema,\n  typeRemovedChangeSchema as unknown as DiscriminableSchema,\n  typeRenamedChangeSchema as unknown as DiscriminableSchema,\n  typeModifiedChangeSchema as unknown as DiscriminableSchema,\n  typeSettingsModifiedChangeSchema as unknown as DiscriminableSchema,\n  fieldAddedChangeSchema as unknown as DiscriminableSchema,\n  fieldRemovedChangeSchema as unknown as DiscriminableSchema,\n  fieldModifiedChangeSchema as unknown as DiscriminableSchema,\n  fieldRenamedChangeSchema as unknown as DiscriminableSchema,\n  fieldTypeModifiedChangeSchema as unknown as DiscriminableSchema,\n  indexAddedChangeSchema as unknown as DiscriminableSchema,\n  indexRemovedChangeSchema as unknown as DiscriminableSchema,\n  indexModifiedChangeSchema as unknown as DiscriminableSchema,\n  fileAddedChangeSchema as unknown as DiscriminableSchema,\n  fileRemovedChangeSchema as unknown as DiscriminableSchema,\n  fileModifiedChangeSchema as unknown as DiscriminableSchema,\n  relationshipAddedChangeSchema as unknown as DiscriminableSchema,\n  relationshipRemovedChangeSchema as unknown as DiscriminableSchema,\n  relationshipModifiedChangeSchema as unknown as DiscriminableSchema,\n  permissionModifiedChangeSchema as unknown as DiscriminableSchema,\n  typeScriptsModifiedChangeSchema as unknown as DiscriminableSchema,\n]) as z.ZodType<DiffChange>;\n\nconst breakingChangeInfoSchema: z.ZodType<BreakingChangeInfo> = z.looseObject({\n  tableName: z.string(),\n  fieldName: z.string().optional(),\n  reason: z.string(),\n  unsupported: z.boolean().optional(),\n  showThreeStepHint: z.boolean().optional(),\n});\n\nconst warningChangeInfoSchema: z.ZodType<WarningChangeInfo> = z.looseObject({\n  tableName: z.string(),\n  fieldName: z.string().optional(),\n  reason: z.string(),\n});\n\nconst scriptSkippedInfoSchema: z.ZodType<ScriptSkippedInfo> = z.looseObject({\n  reason: z.string().trim().min(1),\n  acknowledgedAt: z.string(),\n});\n\n// MigrationDiff: `warnings` and `hasWarnings` are optional here so that\n// older diff.json files that predate these fields still validate cleanly.\n// loadDiff backfills both from the warnings array after validation.\nexport const migrationDiffSchema: z.ZodType<MigrationDiff> = z.looseObject({\n  version: z.number(),\n  namespace: z.string(),\n  createdAt: z.string(),\n  description: z.string().optional(),\n  changes: z.array(diffChangeSchema),\n  hasBreakingChanges: z.boolean(),\n  breakingChanges: z.array(breakingChangeInfoSchema),\n  // Optional for backward compat: loadDiff backfills these after validation.\n  hasWarnings: z.boolean().optional() as z.ZodType<boolean>,\n  warnings: z.array(warningChangeInfoSchema).optional() as z.ZodType<WarningChangeInfo[]>,\n  requiresMigrationScript: z.boolean(),\n  scriptSkipped: scriptSkippedInfoSchema.optional(),\n});\n","import * as fs from \"node:fs\";\nimport * as path from \"pathe\";\nimport { z } from \"zod\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { type MigrationDiff } from \"./diff-calculator\";\nimport { formatMigrationNumber } from \"./migration-number\";\nimport {\n  assertSupportedMigrationFileVersion,\n  normalizeLegacyChangeKinds,\n  normalizeLegacyFieldNames,\n  normalizeLegacyTablesKey,\n  normalizeSchemaSnapshot,\n} from \"./snapshot-normalization\";\nimport { schemaSnapshotSchema, migrationDiffSchema } from \"./snapshot-schema\";\nimport { type NormalizedSchemaSnapshot, type SchemaSnapshot } from \"./snapshot-types\";\nimport { deriveWarningsFromChanges } from \"./snapshot-warnings\";\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * Initial schema migration number (0000)\n */\nexport const INITIAL_SCHEMA_NUMBER = 0;\n\n/**\n * Migration file names (used within migration directories)\n */\nexport const SCHEMA_FILE_NAME = \"schema.json\";\n/** File name for migration diff metadata. */\nexport const DIFF_FILE_NAME = \"diff.json\";\n/** File name for migration script. */\nexport const MIGRATE_FILE_NAME = \"migrate.ts\";\n/** File name for migration script unit test. */\nexport const MIGRATE_TEST_FILE_NAME = \"migrate.test.ts\";\n/** File name for generated DB type definitions. */\nexport const DB_TYPES_FILE_NAME = \"db.ts\";\n/** File name for the generated PGlite schema script module. */\nexport const DB_PGLITE_SCHEMA_FILE_NAME = \"db.pglite.ts\";\n/** File name for the migration script PGlite test. */\nexport const MIGRATE_PGLITE_TEST_FILE_NAME = \"migrate.pglite.test.ts\";\n\n/**\n * Pattern for validating migration number format (4-digit sequential number)\n * Examples: 0001, 0002, 0003, ...\n */\nexport const MIGRATION_NUMBER_PATTERN = /^\\d{4}$/;\n\n/** Highest migration number the four-digit directory name can hold. */\nexport const MAX_MIGRATION_NUMBER = 9999;\n\n/**\n * Migration file type\n */\nexport type MigrationFileType =\n  | \"schema\"\n  | \"diff\"\n  | \"migrate\"\n  | \"test\"\n  | \"db\"\n  | \"pgliteSchema\"\n  | \"pgliteTest\";\n\n// ============================================================================\n// Migration Number Helpers\n// ============================================================================\n\n/**\n * Validate that a migration number follows the expected format (4-digit number)\n * @param {string} numberStr - Migration number string to validate\n * @returns {boolean} True if number matches expected format\n */\nexport function isValidMigrationNumber(numberStr: string): boolean {\n  return MIGRATION_NUMBER_PATTERN.test(numberStr);\n}\n\n// ============================================================================\n// Path Helpers\n// ============================================================================\n\n/**\n * Map of migration file types to their file names\n */\nexport const MIGRATION_FILE_NAMES: Record<MigrationFileType, string> = {\n  schema: SCHEMA_FILE_NAME,\n  diff: DIFF_FILE_NAME,\n  migrate: MIGRATE_FILE_NAME,\n  test: MIGRATE_TEST_FILE_NAME,\n  db: DB_TYPES_FILE_NAME,\n  pgliteSchema: DB_PGLITE_SCHEMA_FILE_NAME,\n  pgliteTest: MIGRATE_PGLITE_TEST_FILE_NAME,\n};\n\n/**\n * Get migration directory path for a given number\n * @param {string} migrationsDir - Base migrations directory path\n * @param {number} num - Migration number\n * @returns {string} Full directory path for the migration\n */\nexport function getMigrationDirPath(migrationsDir: string, num: number): string {\n  const numStr = formatMigrationNumber(num);\n  return path.join(migrationsDir, numStr);\n}\n\n/**\n * Get migration file path for a given number and type\n * @param {string} migrationsDir - Migrations directory path\n * @param {number} num - Migration number\n * @param {MigrationFileType} type - File type\n * @returns {string} Full file path\n */\nexport function getMigrationFilePath(\n  migrationsDir: string,\n  num: number,\n  type: MigrationFileType,\n): string {\n  const migrationDir = getMigrationDirPath(migrationsDir, num);\n  return path.join(migrationDir, MIGRATION_FILE_NAMES[type]);\n}\n\n// ============================================================================\n// Snapshot Loading\n// ============================================================================\n\n/**\n * Load a schema snapshot from a file\n * @param {string} filePath - Path to the snapshot file\n * @returns {NormalizedSchemaSnapshot} Loaded normalized schema snapshot\n */\nexport function loadSnapshot(filePath: string): NormalizedSchemaSnapshot {\n  const content = fs.readFileSync(filePath, \"utf-8\");\n  let raw: unknown;\n  try {\n    raw = JSON.parse(content);\n  } catch (error) {\n    throw CLIError({\n      code: \"MIGRATION_FILE_INVALID\",\n      message: `Invalid schema snapshot at ${filePath}: ${String(error)}`,\n      cause: error,\n    });\n  }\n  assertSupportedMigrationFileVersion(filePath, raw);\n  const result = schemaSnapshotSchema.safeParse(normalizeLegacyTablesKey(raw));\n  if (!result.success) {\n    throw CLIError({\n      code: \"MIGRATION_FILE_INVALID\",\n      message: `Invalid schema snapshot at ${filePath}: ${z.prettifyError(result.error)}`,\n      cause: result.error,\n    });\n  }\n  const snapshot = result.data;\n  return normalizeSchemaSnapshot(snapshot);\n}\n\n/**\n * Load a migration diff from a file\n * @param {string} filePath - Path to the diff file\n * @returns {MigrationDiff} Loaded migration diff\n */\nexport function loadDiff(filePath: string): MigrationDiff {\n  const content = fs.readFileSync(filePath, \"utf-8\");\n  let raw: unknown;\n  try {\n    raw = JSON.parse(content);\n  } catch (error) {\n    throw CLIError({\n      code: \"MIGRATION_FILE_INVALID\",\n      message: `Invalid migration diff at ${filePath}: ${String(error)}`,\n      cause: error,\n    });\n  }\n  assertSupportedMigrationFileVersion(filePath, raw);\n  const result = migrationDiffSchema.safeParse(\n    normalizeLegacyFieldNames(normalizeLegacyChangeKinds(raw)),\n  );\n  if (!result.success) {\n    throw CLIError({\n      code: \"MIGRATION_FILE_INVALID\",\n      message: `Invalid migration diff at ${filePath}: ${z.prettifyError(result.error)}`,\n      cause: result.error,\n    });\n  }\n  const parsed = result.data;\n  // Backfill fields introduced after the initial diff.json schema so that older\n  // migrations on disk remain readable without manual edits. A missing warnings\n  // field (pre-warning-tier diff.json) is reconstructed from the recorded\n  // removal changes so those migrations keep their data-loss classification.\n  // hasWarnings is derived from the warnings array to stay consistent even if\n  // a hand-edited diff.json sets one side without the other.\n  // `warnings` is optional in the schema (backcompat) but cast to required; guard for safety\n  // oxlint-disable-next-line typescript/no-unnecessary-condition\n  const warnings = parsed.warnings ?? deriveWarningsFromChanges(parsed);\n  return {\n    ...parsed,\n    warnings,\n    hasWarnings: warnings.length > 0,\n  };\n}\n\n/**\n * Get all migration directories and their files, sorted by number\n * @param {string} migrationsDir - Migrations directory path\n * @returns {Array<{number: number, type: \"schema\" | \"diff\", path: string}>} Migration files sorted by number\n */\nexport function getMigrationFiles(\n  migrationsDir: string,\n): { number: number; type: \"schema\" | \"diff\"; path: string }[] {\n  if (!fs.existsSync(migrationsDir)) {\n    return [];\n  }\n\n  const entries = fs.readdirSync(migrationsDir, { withFileTypes: true });\n  const migrations: {\n    number: number;\n    type: \"schema\" | \"diff\";\n    path: string;\n  }[] = [];\n\n  for (const entry of entries) {\n    // Only process directories with valid migration numbers (e.g., \"0000\", \"0001\")\n    if (!entry.isDirectory()) continue;\n    if (!isValidMigrationNumber(entry.name)) continue;\n\n    const num = parseInt(entry.name, 10);\n    const migrationDir = path.join(migrationsDir, entry.name);\n\n    // Check for schema.json\n    const schemaPath = path.join(migrationDir, SCHEMA_FILE_NAME);\n    if (fs.existsSync(schemaPath)) {\n      migrations.push({\n        number: num,\n        type: \"schema\",\n        path: schemaPath,\n      });\n    }\n\n    // Check for diff.json\n    const diffPath = path.join(migrationDir, DIFF_FILE_NAME);\n    if (fs.existsSync(diffPath)) {\n      migrations.push({\n        number: num,\n        type: \"diff\",\n        path: diffPath,\n      });\n    }\n  }\n\n  // Sort by number\n  return migrations.toSorted((a, b) => a.number - b.number);\n}\n\n/**\n * Get the next migration number for a directory\n * Returns INITIAL_SCHEMA_NUMBER (0) if no migrations exist\n * @param {string} migrationsDir - Migrations directory path\n * @returns {number} Next migration number\n */\nexport function getNextMigrationNumber(migrationsDir: string): number {\n  const files = getMigrationFiles(migrationsDir);\n  if (files.length === 0) return INITIAL_SCHEMA_NUMBER;\n  return Math.max(...files.map((f) => f.number)) + 1;\n}\n\n/**\n * Get the latest migration number from a directory\n * Returns 0 if no migrations exist\n * @param {string} migrationsDir - Migrations directory path\n * @returns {number} Latest migration number or 0 if no migrations exist\n */\nexport function getLatestMigrationNumber(migrationsDir: string): number {\n  return latestMigrationNumber(getMigrationFiles(migrationsDir));\n}\n\nfunction latestMigrationNumber(files: { number: number }[]): number {\n  if (files.length === 0) return 0;\n  return Math.max(...files.map((f) => f.number));\n}\n\n/**\n * Assert that a migration number exists in the local migration history.\n * 0 is always accepted as the baseline snapshot.\n *\n * Returns the latest migration number so callers that need it (e.g. sync's\n * post-sync hint) can reuse this function's directory scan instead of\n * scanning the migrations directory a second time.\n * @param {string} migrationsDir - Migrations directory path\n * @param {number} migrationNumber - Migration number to check\n * @returns {number} The latest migration number in the history\n */\nexport function assertMigrationNumberExists(\n  migrationsDir: string,\n  migrationNumber: number,\n): number {\n  const files = getMigrationFiles(migrationsDir);\n  if (migrationNumber !== 0 && !files.some((f) => f.number === migrationNumber)) {\n    throw CLIError({\n      code: \"MIGRATION_NOT_FOUND\",\n      message: `Migration ${formatMigrationNumber(migrationNumber)} does not exist in working tree (latest is ${formatMigrationNumber(latestMigrationNumber(files))}).`,\n    });\n  }\n  return latestMigrationNumber(files);\n}\n\n// ============================================================================\n// Snapshot Writing\n// ============================================================================\n\n/**\n * Write a schema snapshot to a file (creates directory structure)\n * @param {SchemaSnapshot} snapshot - Snapshot to write\n * @param {string} migrationsDir - Migrations directory path\n * @param {number} num - Migration number\n * @returns {string} Path to the written file\n */\nexport function writeSnapshot(\n  snapshot: SchemaSnapshot,\n  migrationsDir: string,\n  num: number,\n): string {\n  const migrationDir = getMigrationDirPath(migrationsDir, num);\n  fs.mkdirSync(migrationDir, { recursive: true });\n  const filePath = getMigrationFilePath(migrationsDir, num, \"schema\");\n  fs.writeFileSync(filePath, JSON.stringify(snapshot, null, 2));\n  return filePath;\n}\n\n/**\n * Write a migration diff to a file (creates directory structure)\n * @param {MigrationDiff} diff - Diff to write\n * @param {string} migrationsDir - Migrations directory path\n * @param {number} num - Migration number\n * @returns {string} Path to the written file\n */\nexport function writeDiff(diff: MigrationDiff, migrationsDir: string, num: number): string {\n  const migrationDir = getMigrationDirPath(migrationsDir, num);\n  fs.mkdirSync(migrationDir, { recursive: true });\n  const filePath = getMigrationFilePath(migrationsDir, num, \"diff\");\n  fs.writeFileSync(filePath, JSON.stringify(diff, null, 2));\n  return filePath;\n}\n","import * as fs from \"node:fs\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { type MigrationDiff } from \"./diff-calculator\";\nimport { formatMigrationNumber } from \"./migration-number\";\nimport { INITIAL_SCHEMA_NUMBER, getMigrationFiles, loadDiff, loadSnapshot } from \"./snapshot-files\";\nimport { copySnapshotRecord, normalizeSchemaSnapshot } from \"./snapshot-normalization\";\nimport { type NormalizedSchemaSnapshot, type SchemaSnapshot } from \"./snapshot-types\";\n\n/**\n * Apply a diff to a snapshot to get the resulting snapshot\n * @param {SchemaSnapshot} snapshot - Base snapshot to apply diff to\n * @param {MigrationDiff} diff - Diff to apply\n * @returns {NormalizedSchemaSnapshot} Normalized snapshot after applying diff\n */\nexport function applyDiffToSnapshot(\n  snapshot: SchemaSnapshot,\n  diff: MigrationDiff,\n): NormalizedSchemaSnapshot {\n  const tables = copySnapshotRecord(snapshot.tables);\n\n  for (const change of diff.changes) {\n    switch (change.kind) {\n      case \"table_added\":\n        tables[change.tableName] = change.after;\n        break;\n      case \"table_removed\":\n        delete tables[change.tableName];\n        break;\n      case \"table_modified\": {\n        const existing = tables[change.tableName];\n        if (existing && change.after) {\n          const after = change.after;\n          tables[change.tableName] = {\n            ...existing,\n            ...(after.indexes !== undefined && { indexes: after.indexes }),\n            ...(after.files !== undefined && { files: after.files }),\n          };\n        }\n        break;\n      }\n      case \"table_settings_modified\": {\n        const existing = tables[change.tableName];\n        if (existing) {\n          tables[change.tableName] = {\n            ...existing,\n            description: change.after.description,\n            pluralForm: change.after.pluralForm,\n            settings: change.after.settings ?? {},\n          };\n        }\n        break;\n      }\n      case \"table_scripts_modified\": {\n        const existing = tables[change.tableName];\n        if (existing) {\n          const { typeHookExpr: _, typeValidateExpr: __, ...rest } = existing;\n          tables[change.tableName] = {\n            ...rest,\n            ...(change.after.typeHookExpr && { typeHookExpr: change.after.typeHookExpr }),\n            ...(change.after.typeValidateExpr !== undefined && {\n              typeValidateExpr: change.after.typeValidateExpr,\n            }),\n          };\n        }\n        break;\n      }\n      case \"field_added\":\n      case \"field_modified\":\n      case \"field_type_modified\": {\n        const existing = tables[change.tableName];\n        if (existing) {\n          const fields = copySnapshotRecord(existing.fields);\n          fields[change.fieldName] = change.after;\n          tables[change.tableName] = {\n            ...existing,\n            fields,\n          };\n        }\n        break;\n      }\n      case \"field_removed\": {\n        const existing = tables[change.tableName];\n        if (existing) {\n          const remainingFields = copySnapshotRecord(existing.fields);\n          delete remainingFields[change.fieldName];\n          tables[change.tableName] = {\n            ...existing,\n            fields: remainingFields,\n          };\n        }\n        break;\n      }\n      case \"field_renamed\": {\n        const existing = tables[change.tableName];\n        if (existing) {\n          const fields = copySnapshotRecord(existing.fields);\n          delete fields[change.previousFieldName];\n          fields[change.fieldName] = change.after;\n          tables[change.tableName] = {\n            ...existing,\n            fields,\n          };\n        }\n        break;\n      }\n      case \"table_renamed\":\n        delete tables[change.previousTableName];\n        tables[change.tableName] = change.after;\n        break;\n      case \"index_added\":\n      case \"index_modified\": {\n        const existing = tables[change.tableName];\n        if (existing) {\n          const indexes = copySnapshotRecord(existing.indexes);\n          indexes[change.indexName] = change.after;\n          tables[change.tableName] = {\n            ...existing,\n            indexes,\n          };\n        }\n        break;\n      }\n      case \"index_removed\": {\n        const existing = tables[change.tableName];\n        if (existing && existing.indexes) {\n          const remainingIndexes = copySnapshotRecord(existing.indexes);\n          delete remainingIndexes[change.indexName];\n          tables[change.tableName] = {\n            ...existing,\n            indexes: Object.keys(remainingIndexes).length > 0 ? remainingIndexes : undefined,\n          };\n        }\n        break;\n      }\n      case \"file_added\":\n      case \"file_modified\": {\n        const existing = tables[change.tableName];\n        if (existing) {\n          const files = copySnapshotRecord(existing.files);\n          files[change.fieldName] = change.after;\n          tables[change.tableName] = {\n            ...existing,\n            files,\n          };\n        }\n        break;\n      }\n      case \"file_removed\": {\n        const existing = tables[change.tableName];\n        if (existing && existing.files) {\n          const remainingFiles = copySnapshotRecord(existing.files);\n          delete remainingFiles[change.fieldName];\n          tables[change.tableName] = {\n            ...existing,\n            files: Object.keys(remainingFiles).length > 0 ? remainingFiles : undefined,\n          };\n        }\n        break;\n      }\n      case \"relationship_added\":\n      case \"relationship_modified\": {\n        const existing = tables[change.tableName];\n        if (existing) {\n          const rel = change.after;\n          // Use relationshipType if specified, fallback to existing logic for backwards compatibility\n          const targetType =\n            change.relationshipType ??\n            (existing.forwardRelationships?.[change.relationshipName]\n              ? \"forward\"\n              : existing.backwardRelationships?.[change.relationshipName]\n                ? \"backward\"\n                : \"forward\");\n\n          if (targetType === \"forward\") {\n            const forwardRelationships = copySnapshotRecord(existing.forwardRelationships);\n            forwardRelationships[change.relationshipName] = rel;\n            tables[change.tableName] = {\n              ...existing,\n              forwardRelationships,\n            };\n          } else {\n            const backwardRelationships = copySnapshotRecord(existing.backwardRelationships);\n            backwardRelationships[change.relationshipName] = rel;\n            tables[change.tableName] = {\n              ...existing,\n              backwardRelationships,\n            };\n          }\n        }\n        break;\n      }\n      case \"relationship_removed\": {\n        const type = tables[change.tableName];\n        if (type) {\n          // Use relationshipType if specified\n          const targetType =\n            change.relationshipType ??\n            (type.forwardRelationships?.[change.relationshipName]\n              ? \"forward\"\n              : type.backwardRelationships?.[change.relationshipName]\n                ? \"backward\"\n                : null);\n\n          if (targetType === \"forward\" && type.forwardRelationships?.[change.relationshipName]) {\n            const remaining = copySnapshotRecord(type.forwardRelationships);\n            delete remaining[change.relationshipName];\n            tables[change.tableName] = {\n              ...type,\n              forwardRelationships: Object.keys(remaining).length > 0 ? remaining : undefined,\n            };\n          } else if (\n            targetType === \"backward\" &&\n            type.backwardRelationships?.[change.relationshipName]\n          ) {\n            const remaining = copySnapshotRecord(type.backwardRelationships);\n            delete remaining[change.relationshipName];\n            tables[change.tableName] = {\n              ...type,\n              backwardRelationships: Object.keys(remaining).length > 0 ? remaining : undefined,\n            };\n          }\n        }\n        break;\n      }\n      case \"permission_modified\": {\n        const existing = tables[change.tableName];\n        if (existing && change.after) {\n          const after = change.after;\n          tables[change.tableName] = {\n            ...existing,\n            permissions: {\n              record: after.recordPermission,\n              gql: after.gqlPermission,\n            },\n          };\n        }\n        break;\n      }\n    }\n  }\n\n  return normalizeSchemaSnapshot({\n    ...snapshot,\n    tables,\n    createdAt: diff.createdAt,\n  });\n}\n\n/**\n * Reconstruct the latest schema snapshot from all migration files\n * Returns null if no migrations exist\n * @param {string} migrationsDir - Migrations directory path\n * @param {number} [maxVersion] - Optional maximum migration version to apply\n * @returns {NormalizedSchemaSnapshot | null} Reconstructed normalized snapshot or null if no migrations exist\n */\nexport function reconstructSnapshotFromMigrations(\n  migrationsDir: string,\n  maxVersion?: number,\n): NormalizedSchemaSnapshot | null {\n  const files = getMigrationFiles(migrationsDir);\n  if (files.length === 0) return null;\n\n  // Find the initial schema file (should be 0000/schema.json)\n  const schemaFile = files.find((f) => f.type === \"schema\" && f.number === INITIAL_SCHEMA_NUMBER);\n  if (!schemaFile) {\n    throw CLIError({\n      code: \"MIGRATION_BASELINE_NOT_FOUND\",\n      message: `No initial schema file found in ${migrationsDir}. Expected ${formatMigrationNumber(\n        INITIAL_SCHEMA_NUMBER,\n      )}/schema.json`,\n    });\n  }\n\n  let snapshot = loadSnapshot(schemaFile.path);\n\n  // Apply subsequent diffs in order (up to maxVersion if specified)\n  for (const file of files) {\n    if (file.type === \"diff\" && file.number > schemaFile.number) {\n      // Skip diffs beyond maxVersion if specified\n      if (maxVersion !== undefined && file.number > maxVersion) {\n        continue;\n      }\n      const diff = loadDiff(file.path);\n      snapshot = applyDiffToSnapshot(snapshot, diff);\n    }\n  }\n\n  return snapshot;\n}\n\n// ============================================================================\n// Migration Validation\n// ============================================================================\n\n/**\n * Validation error for migration files\n */\nexport interface MigrationValidationError {\n  type: \"missing_schema\" | \"missing_diff\" | \"duplicate\" | \"gap\" | \"invalid_schema_number\";\n  message: string;\n  migrationNumber?: number;\n}\n\n/**\n * Validate migration files in a directory\n *\n * Checks:\n * - Schema file exists at 0000 (initial schema)\n * - No gaps in migration numbers\n * - No duplicate migration numbers (schema at 0000, diffs at 1+)\n * - Diff files exist for migrations 1+\n * @param {string} migrationsDir - Migrations directory path\n * @returns {MigrationValidationError[]} Array of validation errors (empty if valid)\n */\nexport function validateMigrationFiles(migrationsDir: string): MigrationValidationError[] {\n  const errors: MigrationValidationError[] = [];\n\n  if (!fs.existsSync(migrationsDir)) {\n    // No migrations directory - this is valid (no migrations yet)\n    return errors;\n  }\n\n  // Use getMigrationFiles to get directory-based migration files\n  const migrationFiles = getMigrationFiles(migrationsDir);\n  if (migrationFiles.length === 0) {\n    // No migration files at all - valid\n    return errors;\n  }\n\n  // Categorize files by type\n  const schemaFiles: number[] = [];\n  const diffFiles: number[] = [];\n\n  for (const file of migrationFiles) {\n    if (file.type === \"schema\") {\n      schemaFiles.push(file.number);\n    } else {\n      diffFiles.push(file.number);\n    }\n  }\n\n  // Check for schema file at INITIAL_SCHEMA_NUMBER (0000)\n  if (!schemaFiles.includes(INITIAL_SCHEMA_NUMBER)) {\n    errors.push({\n      type: \"missing_schema\",\n      message: `Initial schema snapshot (${formatMigrationNumber(\n        INITIAL_SCHEMA_NUMBER,\n      )}/schema.json) is missing`,\n      migrationNumber: INITIAL_SCHEMA_NUMBER,\n    });\n  }\n\n  // Check for schema files at wrong positions (only 0000 should have schema)\n  for (const num of schemaFiles) {\n    if (num !== INITIAL_SCHEMA_NUMBER) {\n      errors.push({\n        type: \"invalid_schema_number\",\n        message: `Schema file found at migration ${formatMigrationNumber(\n          num,\n        )}, but schema should only exist at ${formatMigrationNumber(INITIAL_SCHEMA_NUMBER)}`,\n        migrationNumber: num,\n      });\n    }\n  }\n\n  // Get all migration numbers\n  const allNumbers = [...new Set([...schemaFiles, ...diffFiles])].toSorted((a, b) => a - b);\n\n  if (allNumbers.length === 0) {\n    return errors;\n  }\n\n  // Check for duplicate files (same number with both schema and diff, except for INITIAL_SCHEMA_NUMBER)\n  for (const num of schemaFiles) {\n    if (num !== INITIAL_SCHEMA_NUMBER && diffFiles.includes(num)) {\n      errors.push({\n        type: \"duplicate\",\n        message: `Migration ${formatMigrationNumber(num)} has both schema and diff files`,\n        migrationNumber: num,\n      });\n    }\n  }\n\n  // Check for gaps in sequence (from INITIAL_SCHEMA_NUMBER to max)\n  const maxNum = Math.max(...allNumbers);\n  for (let i = INITIAL_SCHEMA_NUMBER; i <= maxNum; i++) {\n    if (!allNumbers.includes(i)) {\n      errors.push({\n        type: \"gap\",\n        message: `Migration ${formatMigrationNumber(i)} is missing (gap in sequence)`,\n        migrationNumber: i,\n      });\n    }\n  }\n\n  // Check that migrations > INITIAL_SCHEMA_NUMBER have diff files\n  for (const num of allNumbers) {\n    if (num > INITIAL_SCHEMA_NUMBER && !diffFiles.includes(num)) {\n      errors.push({\n        type: \"missing_diff\",\n        message: `Migration ${formatMigrationNumber(num)} is missing diff file`,\n        migrationNumber: num,\n      });\n    }\n  }\n\n  return errors;\n}\n\n/**\n * Validate migration files and throw if invalid\n * @param {string} migrationsDir - Migrations directory path\n * @param {string} namespace - Namespace for error messages\n * @throws {Error} If validation fails\n */\nexport function assertValidMigrationFiles(migrationsDir: string, namespace: string): void {\n  const errors = validateMigrationFiles(migrationsDir);\n  if (errors.length > 0) {\n    const errorMessages = errors.map((e) => `  - ${e.message}`).join(\"\\n\");\n    throw CLIError({\n      code: \"MIGRATION_FILES_INVALID\",\n      message: `Migration file validation failed for namespace \"${namespace}\":\\n${errorMessages}`,\n    });\n  }\n}\n","import * as inflection from \"inflection\";\nimport { SCHEMA_SNAPSHOT_VERSION } from \"./diff-calculator\";\nimport {\n  createSnapshotRecord,\n  normalizeSchemaSnapshot,\n  normalizeSnapshotField,\n  normalizeSnapshotType,\n} from \"./snapshot-normalization\";\nimport {\n  type NormalizedSchemaSnapshot,\n  type SnapshotActionPermission,\n  type SnapshotFieldConfig,\n  type SnapshotGqlAction,\n  type SnapshotIndexConfig,\n  type SnapshotPermissionCondition,\n  type SnapshotRelationship,\n  type TailorDBSnapshotType,\n} from \"./snapshot-types\";\nimport type {\n  TailorDBType,\n  OperatorFieldConfig,\n  StandardActionPermission,\n} from \"#/parser/service/tailordb/types\";\n\n// ============================================================================\n// Snapshot Creation\n// ============================================================================\n\n/**\n * Create a snapshot field config from an OperatorFieldConfig.\n * @param {import(\"#/parser/service/tailordb/types\").OperatorFieldConfig} fieldConfig - Field configuration\n * @returns {SnapshotFieldConfig} Snapshot field configuration\n */\nfunction createSnapshotFieldConfigFromOperatorConfig(\n  fieldConfig: OperatorFieldConfig,\n): SnapshotFieldConfig {\n  const config: SnapshotFieldConfig = {\n    type: fieldConfig.type,\n    required: fieldConfig.required !== false,\n  };\n\n  if (fieldConfig.array) config.array = true;\n  if (fieldConfig.index) config.index = true;\n  if (fieldConfig.unique) config.unique = true;\n\n  if (fieldConfig.allowedValues && fieldConfig.allowedValues.length > 0) {\n    config.allowedValues = fieldConfig.allowedValues.map((v) => ({\n      value: v.value,\n      ...(v.description && { description: v.description }),\n    }));\n  }\n\n  if (fieldConfig.foreignKey) {\n    config.foreignKey = true;\n    if (fieldConfig.foreignKeyType) config.foreignKeyType = fieldConfig.foreignKeyType;\n    if (fieldConfig.foreignKeyField) config.foreignKeyField = fieldConfig.foreignKeyField;\n  }\n\n  if (fieldConfig.description) config.description = fieldConfig.description;\n  if (fieldConfig.vector) config.vector = true;\n\n  if (fieldConfig.hooks) {\n    config.hooks = {};\n    if (fieldConfig.hooks.create) {\n      config.hooks.create = { expr: fieldConfig.hooks.create.expr };\n    }\n    if (fieldConfig.hooks.update) {\n      config.hooks.update = { expr: fieldConfig.hooks.update.expr };\n    }\n  }\n\n  if (fieldConfig.validate && fieldConfig.validate.length > 0) {\n    config.validate = fieldConfig.validate.map((v) => ({\n      script: { expr: v.script.expr },\n      errorMessage: v.errorMessage,\n    }));\n  }\n\n  if (fieldConfig.serial) {\n    config.serial = {\n      start: fieldConfig.serial.start,\n      ...(fieldConfig.serial.maxValue !== undefined && { maxValue: fieldConfig.serial.maxValue }),\n      ...(fieldConfig.serial.format && { format: fieldConfig.serial.format }),\n    };\n  }\n\n  if (fieldConfig.scale !== undefined) config.scale = fieldConfig.scale;\n  if (fieldConfig.default !== undefined) config.default = fieldConfig.default;\n\n  // Recursive for nested fields\n  if (fieldConfig.fields && Object.keys(fieldConfig.fields).length > 0) {\n    const fields = createSnapshotRecord<SnapshotFieldConfig>();\n    for (const [nestedName, nestedConfig] of Object.entries(fieldConfig.fields)) {\n      fields[nestedName] = createSnapshotFieldConfigFromOperatorConfig(nestedConfig);\n    }\n    config.fields = fields;\n  }\n\n  return normalizeSnapshotField(config);\n}\n\n/**\n * Create a snapshot table from a parsed table\n * @param {TailorDBType} type - Parsed TailorDB table definition\n * @returns {TailorDBSnapshotType} Snapshot table configuration\n */\nexport function createSnapshotType(type: TailorDBType): TailorDBSnapshotType {\n  const fields = createSnapshotRecord<SnapshotFieldConfig>();\n\n  for (const [fieldName, field] of Object.entries(type.fields)) {\n    fields[fieldName] = createSnapshotFieldConfigFromOperatorConfig(field.config);\n  }\n\n  const snapshotType: TailorDBSnapshotType = {\n    name: type.name,\n    pluralForm: type.pluralForm || inflection.pluralize(type.name),\n    fields,\n  };\n\n  if (type.description) snapshotType.description = type.description;\n  snapshotType.settings = {};\n  if (type.settings.aggregation !== undefined) {\n    snapshotType.settings.aggregation = type.settings.aggregation;\n  }\n  if (type.settings.bulkUpsert !== undefined) {\n    snapshotType.settings.bulkUpsert = type.settings.bulkUpsert;\n  }\n  if (type.settings.gqlOperations) {\n    // gqlOperations is already normalized by schema transform\n    const ops = type.settings.gqlOperations;\n    snapshotType.settings.gqlOperations = {\n      ...(ops.create !== undefined && {\n        create: ops.create,\n      }),\n      ...(ops.update !== undefined && {\n        update: ops.update,\n      }),\n      ...(ops.delete !== undefined && {\n        delete: ops.delete,\n      }),\n      ...(ops.read !== undefined && {\n        read: ops.read,\n      }),\n    };\n  }\n  if (type.settings.publishEvents !== undefined) {\n    snapshotType.settings.publishEvents = type.settings.publishEvents;\n  }\n\n  if (type.indexes && Object.keys(type.indexes).length > 0) {\n    const indexes = createSnapshotRecord<SnapshotIndexConfig>();\n    for (const [indexName, indexConfig] of Object.entries(type.indexes)) {\n      indexes[indexName] = {\n        fields: indexConfig.fields,\n        unique: indexConfig.unique,\n      };\n    }\n    snapshotType.indexes = indexes;\n  }\n\n  if (type.files && Object.keys(type.files).length > 0) {\n    snapshotType.files = { ...type.files };\n  }\n\n  if (type.typeHookExpr) {\n    snapshotType.typeHookExpr = type.typeHookExpr;\n  }\n\n  if (type.typeValidateExpr) {\n    snapshotType.typeValidateExpr = type.typeValidateExpr;\n  }\n\n  if (Object.keys(type.forwardRelationships).length > 0) {\n    const forwardRelationships = createSnapshotRecord<SnapshotRelationship>();\n    for (const [relName, rel] of Object.entries(type.forwardRelationships)) {\n      forwardRelationships[relName] = {\n        targetType: rel.targetType,\n        targetField: rel.targetField,\n        sourceField: rel.sourceField,\n        isArray: rel.isArray,\n        description: rel.description,\n      };\n    }\n    snapshotType.forwardRelationships = forwardRelationships;\n  }\n\n  if (Object.keys(type.backwardRelationships).length > 0) {\n    const backwardRelationships = createSnapshotRecord<SnapshotRelationship>();\n    for (const [relName, rel] of Object.entries(type.backwardRelationships)) {\n      backwardRelationships[relName] = {\n        targetType: rel.targetType,\n        targetField: rel.targetField,\n        sourceField: rel.sourceField,\n        isArray: rel.isArray,\n        description: rel.description,\n      };\n    }\n    snapshotType.backwardRelationships = backwardRelationships;\n  }\n\n  if (type.permissions.record || type.permissions.gql) {\n    snapshotType.permissions = {};\n\n    if (type.permissions.record) {\n      snapshotType.permissions.record = {\n        create: type.permissions.record.create.map(convertActionPermission),\n        read: type.permissions.record.read.map(convertActionPermission),\n        update: type.permissions.record.update.map(convertActionPermission),\n        delete: type.permissions.record.delete.map(convertActionPermission),\n      };\n    }\n\n    if (type.permissions.gql) {\n      snapshotType.permissions.gql = type.permissions.gql.map((policy) => ({\n        conditions: policy.conditions as SnapshotPermissionCondition[],\n        actions: policy.actions as SnapshotGqlAction[],\n        permit: policy.permit,\n        ...(policy.description && { description: policy.description }),\n      }));\n    }\n  }\n\n  return normalizeSnapshotType(snapshotType);\n}\n\n/**\n * Convert an action permission to snapshot format\n * @param {StandardActionPermission<\"record\">} permission - Action permission\n * @returns {SnapshotActionPermission} Snapshot action permission\n */\nfunction convertActionPermission(\n  permission: StandardActionPermission<\"record\">,\n): SnapshotActionPermission {\n  return {\n    conditions: permission.conditions,\n    permit: permission.permit,\n    ...(permission.description && { description: permission.description }),\n  };\n}\n\n/**\n * Create a schema snapshot from local table definitions\n * @param {Record<string, TailorDBType>} types - Local table definitions\n * @param {string} namespace - Namespace for the snapshot\n * @returns {NormalizedSchemaSnapshot} Normalized schema snapshot\n */\nexport function createSnapshotFromLocalTypes(\n  types: Record<string, TailorDBType>,\n  namespace: string,\n): NormalizedSchemaSnapshot {\n  const snapshotTypes = createSnapshotRecord<TailorDBSnapshotType>();\n\n  for (const [tableName, type] of Object.entries(types)) {\n    snapshotTypes[tableName] = createSnapshotType(type);\n  }\n\n  return normalizeSchemaSnapshot({\n    version: SCHEMA_SNAPSHOT_VERSION,\n    namespace,\n    createdAt: new Date().toISOString(),\n    tables: snapshotTypes,\n  });\n}\n","import { createHash } from \"node:crypto\";\nimport { tailorPrincipalMap } from \"./field\";\nimport { PRINCIPAL_VAR } from \"./hook-args-object\";\n\n// Platform-injected record map for table-level hook/validate scripts.\nconst INPUT = \"_input\";\nconst NEW_RECORD = \"_newRecord\";\nconst OLD_RECORD = \"_oldRecord\";\n// Shared operation timestamp bound once per script execution.\nconst NOW = \"_now\";\n\nconst SOURCE_HASH_PREFIX = \"// @sdk-source-hash:\";\n\nconst TIME_TYPES = new Set([\"datetime\", \"date\", \"time\"]);\n\ntype HookOperation = \"create\" | \"update\";\n\ninterface ScriptRef {\n  expr: string;\n}\n\n/**\n * Minimal structural shape shared by parser `OperatorFieldConfig` and migration\n * `SnapshotFieldConfig`. Only the parts needed to aggregate table-level scripts.\n */\nexport interface ScriptFieldConfig {\n  type: string;\n  array?: boolean;\n  hooks?: {\n    create?: ScriptRef;\n    update?: ScriptRef;\n  };\n  validate?: { script?: ScriptRef; errorMessage: string }[];\n  default?: unknown;\n  fields?: Record<string, ScriptFieldConfig>;\n}\n\nexport interface TypeScripts {\n  typeHook?: { create?: ScriptRef; update?: ScriptRef };\n  typeValidate?: { create?: ScriptRef; update?: ScriptRef };\n}\n\nconst key = (name: string) => JSON.stringify(name);\n\nfunction collectFieldScriptSources(fields: Record<string, ScriptFieldConfig>): [string, unknown][] {\n  const entries: [string, unknown][] = [];\n\n  for (const [name, config] of Object.entries(fields).toSorted(([a], [b]) => a.localeCompare(b))) {\n    const data: Record<string, unknown> = {};\n\n    if (config.hooks?.create?.expr) data.hc = config.hooks.create.expr;\n    if (config.hooks?.update?.expr) data.hu = config.hooks.update.expr;\n    if (config.validate?.some((v) => v.script?.expr)) {\n      data.v = config.validate\n        .filter((v) => v.script?.expr)\n        .map((v) => [v.script?.expr, v.errorMessage]);\n    }\n    if (config.default !== undefined) {\n      data.d = config.default instanceof Date ? config.default.toISOString() : config.default;\n      data.t = config.type;\n    }\n\n    if (config.fields) {\n      const nested = collectFieldScriptSources(config.fields);\n      if (nested.length > 0) {\n        data.f = nested;\n        data.a = !!config.array;\n      }\n    }\n\n    if (Object.keys(data).length > 0) {\n      entries.push([name, data]);\n    }\n  }\n\n  return entries;\n}\n\nexport function computeSourceScriptHash(\n  fields: Record<string, ScriptFieldConfig>,\n  options?: {\n    typeHookExpr?: { create?: string; update?: string };\n    typeValidateExpr?: string;\n  },\n): string | undefined {\n  const fieldSources = collectFieldScriptSources(fields);\n  const hasTypeScripts =\n    fieldSources.length > 0 ||\n    options?.typeHookExpr?.create ||\n    options?.typeHookExpr?.update ||\n    options?.typeValidateExpr;\n\n  if (!hasTypeScripts) return undefined;\n\n  const payload: unknown[] = [fieldSources];\n  if (options?.typeHookExpr?.create) payload.push([\"thc\", options.typeHookExpr.create]);\n  if (options?.typeHookExpr?.update) payload.push([\"thu\", options.typeHookExpr.update]);\n  if (options?.typeValidateExpr) payload.push([\"tve\", options.typeValidateExpr]);\n\n  return createHash(\"sha256\").update(JSON.stringify(payload)).digest(\"hex\").slice(0, 16);\n}\n\nexport function extractSourceScriptHash(expr: string): string | undefined {\n  const match = expr.match(/\\/\\/ @sdk-source-hash:([0-9a-f]+)\\s*$/);\n  return match?.[1];\n}\n\nconst isNestedType = (config: ScriptFieldConfig): boolean =>\n  config.type === \"nested\" && config.fields !== undefined;\n\nfunction serializeDefault(value: unknown, fieldType: string): string {\n  if (value === \"now\" && TIME_TYPES.has(fieldType)) return NOW;\n  if (value instanceof Date) return `new Date(${JSON.stringify(value.toISOString())})`;\n  return JSON.stringify(value);\n}\n\n/**\n * Build the object literal that reconstructs one record level with hook\n * overrides and defaults applied.  For create, defaults are appended as\n * `?? defaultValue` after the hook expression (field hook → default).\n * Returns null when no field under this level has a hook or default for\n * the operation.\n * @param {Record<string, ScriptFieldConfig>} fields - Field configurations\n * @param {string} accessExpr - JS expression to access the parent object\n * @param {string} oldAccessExpr - JS expression to access the old record parent\n * @param {HookOperation} operation - Hook operation type\n * @param {boolean} nested - Whether building inside a nested field (rejects defaults)\n * @param {string} recordAccessExpr - Parent record after applying input replacements\n * @returns {string | null} Object literal expression or null\n */\nfunction buildHookObject(\n  fields: Record<string, ScriptFieldConfig>,\n  accessExpr: string,\n  oldAccessExpr: string,\n  operation: HookOperation,\n  nested = false,\n  recordAccessExpr = accessExpr,\n): string | null {\n  const parts: string[] = [];\n\n  for (const [name, config] of Object.entries(fields)) {\n    const access = `${accessExpr}[${key(name)}]`;\n    const oldAccess = `${oldAccessExpr}?.[${key(name)}]`;\n    if (isNestedType(config) && config.fields) {\n      const recordAccess = `${recordAccessExpr}[${key(name)}]`;\n      if (config.array) {\n        const inner = buildHookObject(\n          config.fields,\n          operation === \"update\" ? \"(__arrInput === undefined ? {} : __el)\" : \"__el\",\n          operation === \"update\" ? \"(__arrInput === undefined ? __el : undefined)\" : \"undefined\",\n          operation,\n          true,\n          \"__el\",\n        );\n        if (inner !== null) {\n          const mapped = `${recordAccess}.map((__el) => Object.assign({}, __el, ${inner}))`;\n          // Replacement arrays have no element identity; only omitted arrays retain prior elements.\n          const result = operation === \"update\" ? `((__arrInput) => ${mapped})(${access})` : mapped;\n          parts.push(`${key(name)}: ${recordAccess} == null ? ${recordAccess} : ${result}`);\n        }\n      } else {\n        const inner = buildHookObject(\n          config.fields,\n          `(${access} || {})`,\n          oldAccess,\n          operation,\n          true,\n          `(${recordAccess} || {})`,\n        );\n        if (inner !== null) {\n          parts.push(\n            `${key(name)}: ${recordAccess} == null ? ${recordAccess} : Object.assign({}, ${recordAccess}, ${inner})`,\n          );\n        }\n      }\n      continue;\n    }\n\n    const hook = config.hooks?.[operation];\n    if (nested && config.default !== undefined) {\n      throw new Error(`.default() cannot be used on nested inner field \"${name}\"`);\n    }\n    const hasDefault = operation === \"create\" && config.default !== undefined;\n\n    if (hook && hasDefault) {\n      parts.push(\n        `${key(name)}: ((_value) => (${hook.expr}))(${access}) ?? ${serializeDefault(config.default, config.type)}`,\n      );\n    } else if (hook && operation === \"create\") {\n      parts.push(`${key(name)}: ((_value) => (${hook.expr}))(${access})`);\n    } else if (hook) {\n      parts.push(\n        `${key(name)}: ((_value, _oldValue) => (${hook.expr}))(${access}, ${oldAccess} ?? null)`,\n      );\n    } else if (hasDefault) {\n      parts.push(`${key(name)}: ${access} ?? ${serializeDefault(config.default, config.type)}`);\n    }\n  }\n\n  if (parts.length === 0) return null;\n  return `{ ${parts.join(\", \")} }`;\n}\n\n/**\n * Build validation statements for one record level.\n * Each leaf field with validators contributes a block that runs every\n * validator and records all failing messages keyed by dotted field path.\n * @param {Record<string, ScriptFieldConfig>} fields - Field configurations\n * @param {string} accessExpr - JS expression to access the parent object\n * @param {string} keyPrefix - JavaScript expression for the error-key prefix\n * @param {number} arrayDepth - Array nesting depth used to name index variables\n * @returns {string[]} Array of validation statement strings\n */\nfunction buildValidateStatements(\n  fields: Record<string, ScriptFieldConfig>,\n  accessExpr: string,\n  keyPrefix: string,\n  arrayDepth = 0,\n): string[] {\n  const statements: string[] = [];\n\n  for (const [name, config] of Object.entries(fields)) {\n    const access = `${accessExpr}[${key(name)}]`;\n    const fieldPath = keyPrefix ? `${keyPrefix} + ${key(`.${name}`)}` : key(name);\n\n    const validators = (config.validate ?? []).filter((v) => v.script?.expr);\n    if (validators.length > 0) {\n      const checks = validators\n        .map(\n          (v) =>\n            `{ const __r = (${v.script?.expr}); if (typeof __r === \"string\") { __errs[${fieldPath}] = __r; } }`,\n        )\n        .join(\"\\n\");\n      statements.push(`{ const _value = ${access};\\n${checks}\\n}`);\n    }\n\n    if (isNestedType(config) && config.fields) {\n      if (config.array) {\n        const indexVar = arrayDepth === 0 ? \"__idx\" : `__idx${arrayDepth}`;\n        const elementPath = `${fieldPath} + \"[\" + ${indexVar} + \"]\"`;\n        const innerParts = buildValidateStatements(\n          config.fields,\n          \"__el\",\n          elementPath,\n          arrayDepth + 1,\n        );\n        if (innerParts.length > 0) {\n          statements.push(\n            `(${access} || []).forEach((__el, ${indexVar}) => {\\n${innerParts.join(\"\\n\")}\\n});`,\n          );\n        }\n      } else {\n        const nested = buildValidateStatements(config.fields, access, fieldPath, arrayDepth);\n        if (nested.length > 0) {\n          statements.push(`if (${access} != null) {\\n${nested.join(\"\\n\")}\\n}`);\n        }\n      }\n    }\n  }\n\n  return statements;\n}\n\nfunction principalDeclIfReferenced(...exprs: (string | undefined)[]): string {\n  return exprs.some((expr) => expr?.includes(PRINCIPAL_VAR))\n    ? ` const ${PRINCIPAL_VAR} = (${tailorPrincipalMap});`\n    : \"\";\n}\n\nfunction wrapHook(objectExpr: string): string {\n  return `((_invoker) => { const ${NOW} = new Date();${principalDeclIfReferenced(objectExpr)} return ${objectExpr}; })(typeof _invoker !== \"undefined\" ? _invoker : undefined)`;\n}\n\nfunction wrapValidate(statements: string[], typeValidateExpr?: string): string {\n  const issuesFn = typeValidateExpr ? \" const __issues = (f, m) => { __errs[f] = m; };\" : \"\";\n  const principalDecl = principalDeclIfReferenced(typeValidateExpr, ...statements);\n  const typeValidateStmt = typeValidateExpr ? ` ${typeValidateExpr};` : \"\";\n  return `((_invoker) => { const __errs = {};${issuesFn}${principalDecl}\\n${statements.join(\"\\n\")}${typeValidateStmt}\\nreturn __errs; })(typeof _invoker !== \"undefined\" ? _invoker : undefined)`;\n}\n\ninterface BuildTypeScriptsOptions {\n  typeHookExpr?: { create?: string; update?: string };\n  typeValidateExpr?: string;\n  /** Original fields to hash when execution requires compatibility transformations. */\n  sourceFields?: Record<string, ScriptFieldConfig>;\n}\n\n/**\n * Aggregate every field's create/update hook, default, and validate into\n * table-level scripts.  Hooks compute a single shared timestamp (`now`) per\n * operation, so all fields touched in one create/update observe the same\n * instant.  Defaults are applied after hooks on create only.  Validators\n * run with the same rules on create and update.\n * @param fields - Per-field script configuration\n * @param options - Optional table-level hook/validate expressions\n * @returns Aggregated table-level scripts\n */\nexport function buildTypeScripts(\n  fields: Record<string, ScriptFieldConfig>,\n  options?: BuildTypeScriptsOptions,\n): TypeScripts {\n  const result: TypeScripts = {};\n  const typeHookExpr = options?.typeHookExpr;\n  const typeValidateExpr = options?.typeValidateExpr;\n\n  const hash = computeSourceScriptHash(options?.sourceFields ?? fields, options);\n  const hashSuffix = hash ? ` ${SOURCE_HASH_PREFIX}${hash}` : \"\";\n\n  const hook: { create?: ScriptRef; update?: ScriptRef } = {};\n  for (const operation of [\"create\", \"update\"] as const) {\n    const perFieldExpr = buildHookObject(\n      fields,\n      INPUT,\n      OLD_RECORD,\n      operation,\n      false,\n      operation === \"update\" ? `Object.assign({}, ${OLD_RECORD}, ${INPUT})` : INPUT,\n    );\n    const typeLevelExpr = typeHookExpr?.[operation];\n    let expr: string | undefined;\n    if (perFieldExpr !== null && typeLevelExpr) {\n      const principalDecl = principalDeclIfReferenced(perFieldExpr, typeLevelExpr);\n      expr = `((_invoker) => { const ${NOW} = new Date();${principalDecl} const __fl = ${perFieldExpr}; return Object.assign({}, __fl, ((${INPUT}) => ${typeLevelExpr})(Object.assign({}, ${INPUT}, __fl))); })(typeof _invoker !== \"undefined\" ? _invoker : undefined)`;\n    } else if (typeLevelExpr) {\n      expr = wrapHook(typeLevelExpr);\n    } else if (perFieldExpr !== null) {\n      expr = wrapHook(perFieldExpr);\n    }\n\n    if (expr) {\n      hook[operation] = { expr: expr + hashSuffix };\n    }\n  }\n  if (hook.create || hook.update) {\n    result.typeHook = hook;\n  }\n\n  const statements = buildValidateStatements(fields, NEW_RECORD, \"\");\n  if (statements.length > 0 || typeValidateExpr) {\n    const expr = wrapValidate(statements, typeValidateExpr) + hashSuffix;\n    result.typeValidate = { create: { expr }, update: { expr } };\n  }\n\n  return result;\n}\n","import { toJson } from \"@bufbuild/protobuf\";\nimport { ValueSchema } from \"@bufbuild/protobuf/wkt\";\nimport {\n  TailorDBGQLPermission_Action,\n  TailorDBType_PermitAction,\n  TailorDBType_Permission_Operator,\n  TailorDBType_Permission_Permit,\n  type TailorDBGQLPermission,\n  type TailorDBGQLPermission_Condition,\n  type TailorDBGQLPermission_Operand,\n  type TailorDBGQLPermission_Operator,\n  type TailorDBGQLPermission_Permit,\n  type TailorDBType as ProtoTailorDBType,\n  type TailorDBType_Permission,\n  type TailorDBType_Permission_Condition,\n  type TailorDBType_Permission_Operand,\n} from \"@tailor-platform/tailor-proto/tailordb_resource_pb\";\nimport * as inflection from \"inflection\";\nimport { internalError } from \"#/cli/shared/errors\";\nimport {\n  computeSourceScriptHash,\n  extractSourceScriptHash,\n} from \"#/parser/service/tailordb/type-script\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { type DiffChange, SCHEMA_SNAPSHOT_VERSION } from \"./diff-calculator\";\nimport { compareSnapshots } from \"./snapshot-comparison\";\nimport { createSnapshotRecord, normalizeSchemaSnapshot } from \"./snapshot-normalization\";\nimport {\n  SNAPSHOT_FIELD_BOOLEAN_PROPS,\n  type NormalizedSchemaSnapshot,\n  type SchemaSnapshot,\n  type SnapshotActionPermission,\n  type SnapshotFieldConfig,\n  type SnapshotGqlAction,\n  type SnapshotGqlPermission,\n  type SnapshotPermissionOperand,\n  type SnapshotPermissionOperator,\n  type SnapshotIndexConfig,\n  type SnapshotPermissionCondition,\n  type SnapshotRecordPermission,\n  type SnapshotRelationship,\n  type SnapshotSettings,\n  type TailorDBSnapshotType,\n} from \"./snapshot-types\";\nimport type { SchemaDrift } from \"./types\";\n\n// ============================================================================\n// Remote Schema Verification\n// ============================================================================\n\nexport interface RemoteGqlPermission {\n  typeName: string;\n  permission?: TailorDBGQLPermission;\n}\n\ntype RemoteFieldConfig = NonNullable<ProtoTailorDBType[\"schema\"]>[\"fields\"][string];\ntype RemoteRelationshipConfig = NonNullable<ProtoTailorDBType[\"schema\"]>[\"relationships\"][string];\n\nfunction convertRemoteFieldToSnapshot(remoteField: RemoteFieldConfig): SnapshotFieldConfig {\n  const config: SnapshotFieldConfig = {\n    type: remoteField.type,\n    required: remoteField.required,\n  };\n\n  if (remoteField.array) config.array = true;\n  if (remoteField.index) config.index = true;\n  if (remoteField.unique) config.unique = true;\n  if (remoteField.foreignKey) {\n    config.foreignKey = true;\n    if (remoteField.foreignKeyType) config.foreignKeyType = remoteField.foreignKeyType;\n    if (remoteField.foreignKeyField) config.foreignKeyField = remoteField.foreignKeyField;\n  }\n  const allowedValues = remoteField.allowedValues;\n  if (allowedValues.length > 0) {\n    config.allowedValues = allowedValues.map((v) => ({\n      value: v.value,\n      ...(v.description && { description: v.description }),\n    }));\n  }\n\n  if (remoteField.description) config.description = remoteField.description;\n  if (remoteField.vector) config.vector = true;\n\n  if (remoteField.hooks) {\n    config.hooks = {};\n    if (remoteField.hooks.create?.expr) {\n      config.hooks.create = { expr: remoteField.hooks.create.expr };\n    }\n    if (remoteField.hooks.update?.expr) {\n      config.hooks.update = { expr: remoteField.hooks.update.expr };\n    }\n  }\n\n  const validate = remoteField.validate;\n  if (validate.length > 0) {\n    config.validate = validate.map((v) => ({\n      script: { expr: convertRemoteValidateExpression(v.script?.expr ?? \"\", v.action) },\n      errorMessage: v.errorMessage ?? \"\",\n    }));\n  }\n\n  if (remoteField.serial) {\n    config.serial = {\n      start: Number(remoteField.serial.start),\n      ...(remoteField.serial.maxValue && { maxValue: Number(remoteField.serial.maxValue) }),\n      ...(remoteField.serial.format && { format: remoteField.serial.format }),\n    };\n  }\n\n  if (remoteField.scale !== undefined) config.scale = remoteField.scale;\n  // Remote schemas do not expose field defaults, so optionalOnCreate is the\n  // only signal when no field-level create hook carries the same contract.\n  if (remoteField.optionalOnCreate && !config.hooks?.create) {\n    config.optionalOnCreate = true;\n  }\n\n  const nestedFields = remoteField.fields;\n  if (Object.keys(nestedFields).length > 0) {\n    config.fields = createSnapshotRecord<SnapshotFieldConfig>();\n    for (const [fieldName, nestedField] of Object.entries(nestedFields)) {\n      config.fields[fieldName] = convertRemoteFieldToSnapshot(nestedField);\n    }\n  }\n\n  return config;\n}\n\n/**\n * Convert remote ParsedTailorDBType to SnapshotFieldConfig for comparison\n * @param {ProtoTailorDBType} remoteType - Remote TailorDB table from API\n * @returns {Record<string, SnapshotFieldConfig>} Converted field configs\n */\nfunction convertRemoteFieldsToSnapshot(\n  remoteType: ProtoTailorDBType,\n): Record<string, SnapshotFieldConfig> {\n  const fields = createSnapshotRecord<SnapshotFieldConfig>();\n  const remoteFields = remoteType.schema?.fields ?? {};\n\n  for (const [fieldName, remoteField] of Object.entries(remoteFields)) {\n    fields[fieldName] = convertRemoteFieldToSnapshot(remoteField);\n  }\n\n  return fields;\n}\n\nfunction convertRemoteValidateExpression(expr: string, action: TailorDBType_PermitAction): string {\n  return action === TailorDBType_PermitAction.DENY && expr.startsWith(\"!\") ? expr.slice(1) : expr;\n}\n\nfunction convertRemoteSettingsToSnapshot(\n  remoteSettings: NonNullable<ProtoTailorDBType[\"schema\"]>[\"settings\"] | undefined,\n  expectedSettings?: TailorDBSnapshotType[\"settings\"],\n): TailorDBSnapshotType[\"settings\"] | undefined {\n  const settings: SnapshotSettings = {};\n\n  if (remoteSettings?.aggregation) settings.aggregation = true;\n  if (remoteSettings?.bulkUpsert) settings.bulkUpsert = true;\n  if (remoteSettings?.publishRecordEvents) settings.publishEvents = true;\n\n  const disabled = remoteSettings?.disableGqlOperations;\n  if (disabled) {\n    const hasDisabledOperation =\n      disabled.create || disabled.update || disabled.delete || disabled.read;\n    if (expectedSettings?.gqlOperations !== undefined || hasDisabledOperation) {\n      settings.gqlOperations = {\n        create: !disabled.create,\n        update: !disabled.update,\n        delete: !disabled.delete,\n        read: !disabled.read,\n      };\n    }\n  }\n\n  return Object.keys(settings).length > 0 ? settings : undefined;\n}\n\nfunction convertRemoteIndexesToSnapshot(\n  remoteIndexes: NonNullable<ProtoTailorDBType[\"schema\"]>[\"indexes\"] | undefined,\n): Record<string, SnapshotIndexConfig> | undefined {\n  const indexes = createSnapshotRecord<SnapshotIndexConfig>();\n  for (const [indexName, indexConfig] of Object.entries(remoteIndexes ?? {})) {\n    indexes[indexName] = {\n      fields: indexConfig.fieldNames,\n      ...(indexConfig.unique && { unique: true }),\n    };\n  }\n  return Object.keys(indexes).length > 0 ? indexes : undefined;\n}\n\nfunction convertRemoteFilesToSnapshot(\n  remoteFiles: NonNullable<ProtoTailorDBType[\"schema\"]>[\"files\"] | undefined,\n): Record<string, string> | undefined {\n  const files = createSnapshotRecord<string>();\n  for (const [fileName, fileConfig] of Object.entries(remoteFiles ?? {})) {\n    files[fileName] = fileConfig.description || \"\";\n  }\n  return Object.keys(files).length > 0 ? files : undefined;\n}\n\nfunction convertRemoteRelationshipToSnapshot(\n  relationship: RemoteRelationshipConfig,\n  direction: \"forward\" | \"backward\",\n): SnapshotRelationship {\n  return direction === \"forward\"\n    ? {\n        targetType: relationship.refType,\n        targetField: relationship.srcField,\n        sourceField: relationship.refField,\n        isArray: relationship.array,\n        description: relationship.description || \"\",\n      }\n    : {\n        targetType: relationship.refType,\n        targetField: relationship.refField,\n        sourceField: relationship.srcField,\n        isArray: relationship.array,\n        description: relationship.description || \"\",\n      };\n}\n\nfunction remoteRelationshipMatchesExpectedDirection(\n  relationship: RemoteRelationshipConfig,\n  expected: SnapshotRelationship,\n  direction: \"forward\" | \"backward\",\n): boolean {\n  const converted = convertRemoteRelationshipToSnapshot(relationship, direction);\n  return (\n    converted.targetType === expected.targetType &&\n    converted.targetField === expected.targetField &&\n    converted.sourceField === expected.sourceField &&\n    converted.isArray === expected.isArray\n  );\n}\n\nfunction inferRemoteRelationshipDirection(\n  relationshipName: string,\n  relationship: RemoteRelationshipConfig,\n  expectedType: TailorDBSnapshotType | undefined,\n): \"forward\" | \"backward\" {\n  const expectedForward = expectedType?.forwardRelationships?.[relationshipName];\n  const expectedBackward = expectedType?.backwardRelationships?.[relationshipName];\n\n  if (expectedForward && !expectedBackward) return \"forward\";\n  if (expectedBackward && !expectedForward) return \"backward\";\n  if (\n    expectedForward &&\n    remoteRelationshipMatchesExpectedDirection(relationship, expectedForward, \"forward\")\n  ) {\n    return \"forward\";\n  }\n  if (\n    expectedBackward &&\n    remoteRelationshipMatchesExpectedDirection(relationship, expectedBackward, \"backward\")\n  ) {\n    return \"backward\";\n  }\n\n  return relationship.array ? \"backward\" : \"forward\";\n}\n\nfunction convertRemoteRelationshipsToSnapshot(\n  remoteRelationships: NonNullable<ProtoTailorDBType[\"schema\"]>[\"relationships\"] | undefined,\n  expectedType?: TailorDBSnapshotType,\n): Pick<TailorDBSnapshotType, \"forwardRelationships\" | \"backwardRelationships\"> {\n  const forwardRelationships = createSnapshotRecord<SnapshotRelationship>();\n  const backwardRelationships = createSnapshotRecord<SnapshotRelationship>();\n\n  for (const [relationshipName, relationship] of Object.entries(remoteRelationships ?? {})) {\n    const direction = inferRemoteRelationshipDirection(\n      relationshipName,\n      relationship,\n      expectedType,\n    );\n    if (direction === \"forward\") {\n      forwardRelationships[relationshipName] = convertRemoteRelationshipToSnapshot(\n        relationship,\n        direction,\n      );\n    } else {\n      backwardRelationships[relationshipName] = convertRemoteRelationshipToSnapshot(\n        relationship,\n        direction,\n      );\n    }\n  }\n\n  return {\n    ...(Object.keys(forwardRelationships).length > 0 && { forwardRelationships }),\n    ...(Object.keys(backwardRelationships).length > 0 && { backwardRelationships }),\n  };\n}\n\ntype RemoteRecordPolicy = NonNullable<TailorDBType_Permission>[\"create\"][number];\n\ntype RemotePermissionPermit = TailorDBType_Permission_Permit | TailorDBGQLPermission_Permit;\ntype RemotePermissionOperator = TailorDBType_Permission_Operator | TailorDBGQLPermission_Operator;\ntype PermissionSource = \"record\" | \"GQL\";\n\n// TailorDBType_Permission_Permit and TailorDBGQLPermission_Permit share identical numeric values.\nconst REMOTE_PERMISSION_PERMITS = new Map<number, \"allow\" | \"deny\">([\n  [TailorDBType_Permission_Permit.ALLOW, \"allow\"],\n  [TailorDBType_Permission_Permit.DENY, \"deny\"],\n]);\n\n// TailorDBType_Permission_Operator and TailorDBGQLPermission_Operator share identical numeric values.\nconst REMOTE_PERMISSION_OPERATORS = new Map<number, SnapshotPermissionOperator>([\n  [TailorDBType_Permission_Operator.EQ, \"eq\"],\n  [TailorDBType_Permission_Operator.NE, \"ne\"],\n  [TailorDBType_Permission_Operator.IN, \"in\"],\n  [TailorDBType_Permission_Operator.NIN, \"nin\"],\n  [TailorDBType_Permission_Operator.HAS_ANY, \"hasAny\"],\n  [TailorDBType_Permission_Operator.NHAS_ANY, \"nhasAny\"],\n]);\n\nfunction convertRemotePermit(\n  permit: RemotePermissionPermit,\n  source: PermissionSource,\n): \"allow\" | \"deny\" {\n  const converted = REMOTE_PERMISSION_PERMITS.get(permit);\n  if (converted) return converted;\n  throw internalError(`Unsupported ${source} permission permit: ${permit}`);\n}\n\nfunction convertRemoteOperator(\n  operator: RemotePermissionOperator,\n  source: PermissionSource,\n): SnapshotPermissionOperator {\n  const converted = REMOTE_PERMISSION_OPERATORS.get(operator);\n  if (converted) return converted;\n  throw internalError(`Unsupported ${source} permission operator: ${operator}`);\n}\n\nfunction convertRemoteValueOperand(\n  operand: TailorDBType_Permission_Operand | TailorDBGQLPermission_Operand | undefined,\n): SnapshotPermissionOperand {\n  switch (operand?.kind.case) {\n    case \"userField\":\n      return { user: operand.kind.value };\n    case \"recordField\":\n      return { record: operand.kind.value };\n    case \"oldRecordField\":\n      return { oldRecord: operand.kind.value };\n    case \"newRecordField\":\n      return { newRecord: operand.kind.value };\n    case \"value\":\n      return toJson(ValueSchema, operand.kind.value) as SnapshotPermissionOperand;\n    default:\n      throw internalError(\"Unsupported permission operand\");\n  }\n}\n\nfunction convertRemoteRecordCondition(\n  condition: TailorDBType_Permission_Condition,\n): SnapshotPermissionCondition {\n  return [\n    convertRemoteValueOperand(condition.left),\n    convertRemoteOperator(condition.operator, \"record\"),\n    convertRemoteValueOperand(condition.right),\n  ];\n}\n\nfunction convertRemoteGqlCondition(\n  condition: TailorDBGQLPermission_Condition,\n): SnapshotPermissionCondition {\n  return [\n    convertRemoteValueOperand(condition.left),\n    convertRemoteOperator(condition.operator, \"GQL\"),\n    convertRemoteValueOperand(condition.right),\n  ];\n}\n\nfunction convertRemoteRecordPolicy(policy: RemoteRecordPolicy): SnapshotActionPermission {\n  return {\n    conditions: policy.conditions.map(convertRemoteRecordCondition),\n    permit: convertRemotePermit(policy.permit, \"record\"),\n    ...(policy.description && { description: policy.description }),\n  };\n}\n\nfunction convertRemoteRecordPermissionToSnapshot(\n  permission: TailorDBType_Permission | undefined,\n): SnapshotRecordPermission | undefined {\n  const recordPermission: SnapshotRecordPermission = {\n    create: permission?.create.map(convertRemoteRecordPolicy) ?? [],\n    read: permission?.read.map(convertRemoteRecordPolicy) ?? [],\n    update: permission?.update.map(convertRemoteRecordPolicy) ?? [],\n    delete: permission?.delete.map(convertRemoteRecordPolicy) ?? [],\n  };\n\n  return Object.values(recordPermission).some((policies) => policies.length > 0)\n    ? recordPermission\n    : undefined;\n}\n\nfunction convertRemoteGqlAction(action: TailorDBGQLPermission_Action): SnapshotGqlAction {\n  switch (action) {\n    case TailorDBGQLPermission_Action.ALL:\n      return \"all\";\n    case TailorDBGQLPermission_Action.CREATE:\n      return \"create\";\n    case TailorDBGQLPermission_Action.READ:\n      return \"read\";\n    case TailorDBGQLPermission_Action.UPDATE:\n      return \"update\";\n    case TailorDBGQLPermission_Action.DELETE:\n      return \"delete\";\n    case TailorDBGQLPermission_Action.AGGREGATE:\n      return \"aggregate\";\n    case TailorDBGQLPermission_Action.BULK_UPSERT:\n      return \"bulkUpsert\";\n    default:\n      throw internalError(`Unsupported GQL permission action: ${action}`);\n  }\n}\n\nfunction convertRemoteGqlPermissionToSnapshot(\n  permission: TailorDBGQLPermission | undefined,\n): SnapshotGqlPermission | undefined {\n  const policies =\n    permission?.policies.map((policy) => ({\n      conditions: policy.conditions.map(convertRemoteGqlCondition),\n      actions: policy.actions.map(convertRemoteGqlAction),\n      permit: convertRemotePermit(policy.permit, \"GQL\"),\n      ...(policy.description && { description: policy.description }),\n    })) ?? [];\n\n  return policies.length > 0 ? policies : undefined;\n}\n\nfunction convertRemoteTypeToSnapshot(\n  remoteType: ProtoTailorDBType,\n  expectedType?: TailorDBSnapshotType,\n): TailorDBSnapshotType {\n  const settings = convertRemoteSettingsToSnapshot(\n    remoteType.schema?.settings,\n    expectedType?.settings,\n  );\n  const relationships = convertRemoteRelationshipsToSnapshot(\n    remoteType.schema?.relationships,\n    expectedType,\n  );\n  const recordPermission = convertRemoteRecordPermissionToSnapshot(remoteType.schema?.permission);\n  const snapshotType: TailorDBSnapshotType = {\n    name: remoteType.name,\n    pluralForm: remoteType.schema?.settings?.pluralForm || inflection.pluralize(remoteType.name),\n    fields: convertRemoteFieldsToSnapshot(remoteType),\n    ...(settings && { settings }),\n    ...relationships,\n  };\n\n  if (remoteType.schema?.description) {\n    snapshotType.description = remoteType.schema.description;\n  }\n  const indexes = convertRemoteIndexesToSnapshot(remoteType.schema?.indexes);\n  if (indexes) snapshotType.indexes = indexes;\n\n  const files = convertRemoteFilesToSnapshot(remoteType.schema?.files);\n  if (files) snapshotType.files = files;\n\n  if (recordPermission) {\n    snapshotType.permissions = { record: recordPermission };\n  }\n\n  return snapshotType;\n}\n\n/**\n * Convert remote TailorDB tables into the normalized snapshot shape used by drift checks.\n * @param {ProtoTailorDBType[]} remoteTypes - Remote TailorDB tables from the API\n * @param {string} namespace - Namespace for the reconstructed snapshot\n * @param {readonly RemoteGqlPermission[]} remoteGqlPermissions - Remote GQL permissions for the namespace\n * @param {SchemaSnapshot} expectedSnapshot - Optional snapshot used to disambiguate remote relationship direction\n * @returns {NormalizedSchemaSnapshot} Normalized snapshot-shaped remote state\n */\nexport function createSnapshotFromRemoteTypes(\n  remoteTypes: ProtoTailorDBType[],\n  namespace: string,\n  remoteGqlPermissions: readonly RemoteGqlPermission[] = [],\n  expectedSnapshot?: SchemaSnapshot,\n): NormalizedSchemaSnapshot {\n  const tables = createSnapshotRecord<TailorDBSnapshotType>();\n  for (const remoteType of remoteTypes) {\n    tables[remoteType.name] = convertRemoteTypeToSnapshot(\n      remoteType,\n      expectedSnapshot?.tables[remoteType.name],\n    );\n  }\n\n  for (const permission of remoteGqlPermissions) {\n    const { typeName: tableName } = permission;\n    const snapshotType = tables[tableName];\n    if (!snapshotType) continue;\n\n    const gqlPermission = convertRemoteGqlPermissionToSnapshot(permission.permission);\n    if (!gqlPermission) continue;\n\n    snapshotType.permissions = {\n      ...snapshotType.permissions,\n      gql: gqlPermission,\n    };\n  }\n\n  return normalizeSchemaSnapshot({\n    version: SCHEMA_SNAPSHOT_VERSION,\n    namespace,\n    createdAt: new Date().toISOString(),\n    tables,\n  });\n}\n\nfunction fieldDifferenceValue(value: unknown): string {\n  if (value === undefined || value === \"\") return \"none\";\n  return String(value);\n}\n\nfunction fieldDifferenceKey(prefix: string, key: string): string {\n  return prefix ? `${prefix}.${key}` : key;\n}\n\nfunction addFieldDifference(\n  differences: string[],\n  prefix: string,\n  key: string,\n  remoteValue: unknown,\n  snapshotValue: unknown,\n): void {\n  if (remoteValue === snapshotValue) return;\n  differences.push(\n    `${fieldDifferenceKey(prefix, key)}: remote=${fieldDifferenceValue(\n      remoteValue,\n    )}, expected=${fieldDifferenceValue(snapshotValue)}`,\n  );\n}\n\nfunction addBooleanFieldDifference(\n  differences: string[],\n  prefix: string,\n  key: keyof SnapshotFieldConfig,\n  remoteField: SnapshotFieldConfig,\n  snapshotField: SnapshotFieldConfig,\n): void {\n  addFieldDifference(\n    differences,\n    prefix,\n    key,\n    remoteField[key] ?? false,\n    snapshotField[key] ?? false,\n  );\n}\n\nfunction addAllowedValuesDifferences(\n  differences: string[],\n  prefix: string,\n  remoteField: SnapshotFieldConfig,\n  snapshotField: SnapshotFieldConfig,\n): void {\n  const remoteAllowed = remoteField.allowedValues ?? [];\n  const snapshotAllowed = snapshotField.allowedValues ?? [];\n  if (remoteAllowed.length !== snapshotAllowed.length) {\n    differences.push(\n      `${fieldDifferenceKey(prefix, \"allowedValues\")} count: remote=${remoteAllowed.length}, expected=${snapshotAllowed.length}`,\n    );\n    return;\n  }\n\n  const snapshotAllowedValues = new Map(snapshotAllowed.map((v) => [v.value, v.description]));\n  for (const value of remoteAllowed) {\n    if (!snapshotAllowedValues.has(value.value)) {\n      differences.push(\n        `${fieldDifferenceKey(prefix, \"allowedValues\")}: remote has '${value.value}' not in snapshot`,\n      );\n      return;\n    }\n    const snapshotDescription = snapshotAllowedValues.get(value.value);\n    if ((value.description ?? \"\") !== (snapshotDescription ?? \"\")) {\n      addFieldDifference(\n        differences,\n        prefix,\n        `allowedValues.${value.value}.description`,\n        value.description ?? \"\",\n        snapshotDescription ?? \"\",\n      );\n      return;\n    }\n  }\n\n  const remoteAllowedValues = new Set(remoteAllowed.map((v) => v.value));\n  for (const value of snapshotAllowed) {\n    if (!remoteAllowedValues.has(value.value)) {\n      differences.push(\n        `${fieldDifferenceKey(prefix, \"allowedValues\")}: snapshot has '${value.value}' not in remote`,\n      );\n      return;\n    }\n  }\n}\n\nfunction addHooksDifferences(\n  differences: string[],\n  prefix: string,\n  remoteField: SnapshotFieldConfig,\n  snapshotField: SnapshotFieldConfig,\n): void {\n  addFieldDifference(\n    differences,\n    prefix,\n    \"hooks.create\",\n    remoteField.hooks?.create?.expr ?? \"\",\n    snapshotField.hooks?.create?.expr ?? \"\",\n  );\n  addFieldDifference(\n    differences,\n    prefix,\n    \"hooks.update\",\n    remoteField.hooks?.update?.expr ?? \"\",\n    snapshotField.hooks?.update?.expr ?? \"\",\n  );\n}\n\nfunction addValidationDifferences(\n  differences: string[],\n  prefix: string,\n  remoteField: SnapshotFieldConfig,\n  snapshotField: SnapshotFieldConfig,\n): void {\n  const remoteValidate = remoteField.validate ?? [];\n  const snapshotValidate = snapshotField.validate ?? [];\n  if (remoteValidate.length !== snapshotValidate.length) {\n    differences.push(\n      `${fieldDifferenceKey(prefix, \"validate\")} count: remote=${remoteValidate.length}, expected=${snapshotValidate.length}`,\n    );\n  }\n\n  const commonLength = Math.min(remoteValidate.length, snapshotValidate.length);\n  for (let index = 0; index < commonLength; index++) {\n    const remoteValidation = assertDefined(\n      remoteValidate[index],\n      `remoteValidate missing index ${index}`,\n    );\n    const snapshotValidation = assertDefined(\n      snapshotValidate[index],\n      `snapshotValidate missing index ${index}`,\n    );\n    addFieldDifference(\n      differences,\n      prefix,\n      `validate[${index}].script`,\n      remoteValidation.script?.expr ?? \"\",\n      snapshotValidation.script?.expr ?? \"\",\n    );\n    addFieldDifference(\n      differences,\n      prefix,\n      `validate[${index}].errorMessage`,\n      remoteValidation.errorMessage,\n      snapshotValidation.errorMessage,\n    );\n  }\n}\n\nfunction addSerialDifferences(\n  differences: string[],\n  prefix: string,\n  remoteField: SnapshotFieldConfig,\n  snapshotField: SnapshotFieldConfig,\n): void {\n  addFieldDifference(\n    differences,\n    prefix,\n    \"serial.start\",\n    remoteField.serial?.start,\n    snapshotField.serial?.start,\n  );\n  addFieldDifference(\n    differences,\n    prefix,\n    \"serial.maxValue\",\n    remoteField.serial?.maxValue,\n    snapshotField.serial?.maxValue,\n  );\n  addFieldDifference(\n    differences,\n    prefix,\n    \"serial.format\",\n    remoteField.serial?.format ?? \"\",\n    snapshotField.serial?.format ?? \"\",\n  );\n}\n\nfunction addNestedFieldDifferences(\n  differences: string[],\n  prefix: string,\n  remoteField: SnapshotFieldConfig,\n  snapshotField: SnapshotFieldConfig,\n): void {\n  const remoteFields = remoteField.fields ?? {};\n  const snapshotFields = snapshotField.fields ?? {};\n  const remoteFieldNames = Object.keys(remoteFields);\n  const snapshotFieldNames = Object.keys(snapshotFields);\n\n  if (remoteFieldNames.length !== snapshotFieldNames.length) {\n    differences.push(\n      `${fieldDifferenceKey(prefix, \"fields\")} count: remote=${remoteFieldNames.length}, expected=${snapshotFieldNames.length}`,\n    );\n  }\n\n  for (const fieldName of remoteFieldNames) {\n    const remoteNestedField = remoteFields[fieldName];\n    const snapshotNestedField = snapshotFields[fieldName];\n    const nestedPrefix = fieldDifferenceKey(prefix, `fields.${fieldName}`);\n    if (!snapshotNestedField) {\n      differences.push(`${nestedPrefix}: exists in remote but not snapshot`);\n      continue;\n    }\n    addFieldDifferences(\n      differences,\n      nestedPrefix,\n      assertDefined(remoteNestedField, `remote field \"${fieldName}\" missing`),\n      snapshotNestedField,\n    );\n  }\n\n  for (const fieldName of snapshotFieldNames) {\n    if (remoteFields[fieldName]) continue;\n    differences.push(\n      `${fieldDifferenceKey(prefix, `fields.${fieldName}`)}: exists in snapshot but not remote`,\n    );\n  }\n}\n\nfunction addFieldDifferences(\n  differences: string[],\n  prefix: string,\n  remoteField: SnapshotFieldConfig,\n  snapshotField: SnapshotFieldConfig,\n): void {\n  addFieldDifference(differences, prefix, \"type\", remoteField.type, snapshotField.type);\n  addFieldDifference(differences, prefix, \"required\", remoteField.required, snapshotField.required);\n\n  for (const key of SNAPSHOT_FIELD_BOOLEAN_PROPS) {\n    addBooleanFieldDifference(differences, prefix, key, remoteField, snapshotField);\n  }\n\n  addFieldDifference(\n    differences,\n    prefix,\n    \"foreignKeyType\",\n    remoteField.foreignKeyType,\n    snapshotField.foreignKeyType,\n  );\n  addFieldDifference(\n    differences,\n    prefix,\n    \"foreignKeyField\",\n    remoteField.foreignKeyField,\n    snapshotField.foreignKeyField,\n  );\n  addFieldDifference(\n    differences,\n    prefix,\n    \"description\",\n    remoteField.description ?? \"\",\n    snapshotField.description ?? \"\",\n  );\n  addAllowedValuesDifferences(differences, prefix, remoteField, snapshotField);\n  addHooksDifferences(differences, prefix, remoteField, snapshotField);\n  addValidationDifferences(differences, prefix, remoteField, snapshotField);\n  addSerialDifferences(differences, prefix, remoteField, snapshotField);\n  addFieldDifference(differences, prefix, \"scale\", remoteField.scale, snapshotField.scale);\n  addNestedFieldDifferences(differences, prefix, remoteField, snapshotField);\n}\n\n/**\n * Compare a single field between remote and snapshot\n * @param {string} tableName - Name of the table\n * @param {string} fieldName - Name of the field\n * @param {SnapshotFieldConfig} remoteField - Remote field config\n * @param {SnapshotFieldConfig} snapshotField - Snapshot field config\n * @returns {SchemaDrift | null} Drift info or null if fields match\n */\nfunction compareFields(\n  tableName: string,\n  fieldName: string,\n  remoteField: SnapshotFieldConfig,\n  snapshotField: SnapshotFieldConfig,\n): SchemaDrift | null {\n  const differences: string[] = [];\n  addFieldDifferences(differences, \"\", remoteField, snapshotField);\n\n  if (differences.length > 0) {\n    return {\n      tableName,\n      kind: \"field_mismatch\",\n      fieldName,\n      details: differences.join(\"; \"),\n    };\n  }\n\n  return null;\n}\n\n/**\n * System fields that are auto-generated and should be excluded from comparison\n */\nconst SYSTEM_FIELDS = new Set([\"id\"]);\n\n/**\n * Compare remote TailorDB tables with a local snapshot\n * @param {ProtoTailorDBType[]} remoteTypes - Remote tables from listParsedTailorDBTypes API\n * @param {SchemaSnapshot} snapshot - Local schema snapshot\n * @param {readonly RemoteGqlPermission[]} remoteGqlPermissions - Remote GQL permissions for the namespace\n * @returns {SchemaDrift[]} List of drifts detected\n */\nexport function compareRemoteWithSnapshot(\n  remoteTypes: ProtoTailorDBType[],\n  snapshot: SchemaSnapshot,\n  remoteGqlPermissions: readonly RemoteGqlPermission[] = [],\n): SchemaDrift[] {\n  const structuralDrifts = compareNormalizedRemoteWithSnapshot(\n    createRemoteComparableSnapshot(\n      createSnapshotFromRemoteTypes(\n        remoteTypes,\n        snapshot.namespace,\n        remoteGqlPermissions,\n        snapshot,\n      ),\n    ),\n    createRemoteComparableSnapshot(snapshot),\n  );\n\n  const scriptDrifts = compareScriptHashes(remoteTypes, snapshot);\n\n  return [...structuralDrifts, ...scriptDrifts];\n}\n\n/**\n * Result of scanning a remote type's script expressions for an embedded\n * source hash: a single agreed-upon hash, no hash found at all (the pattern\n * left by a pre-v2 CLI deploy), or disagreeing hashes across expressions\n * (a distinct anomaly, not the pre-v2 pattern).\n */\ntype RemoteScriptHashState =\n  | { kind: \"hash\"; hash: string }\n  | { kind: \"absent\" }\n  | { kind: \"conflicting\" };\n\nfunction extractRemoteScriptHashState(remoteType: ProtoTailorDBType): RemoteScriptHashState {\n  const exprs = [\n    remoteType.schema?.typeHook?.create?.expr,\n    remoteType.schema?.typeHook?.update?.expr,\n    remoteType.schema?.typeValidate?.create?.expr,\n    remoteType.schema?.typeValidate?.update?.expr,\n  ];\n  let found: string | undefined;\n  for (const expr of exprs) {\n    if (!expr) continue;\n    const hash = extractSourceScriptHash(expr);\n    if (!hash) continue;\n    if (found && found !== hash) return { kind: \"conflicting\" };\n    found = hash;\n  }\n  return found ? { kind: \"hash\", hash: found } : { kind: \"absent\" };\n}\n\nfunction remoteHasScripts(remoteType: ProtoTailorDBType): boolean {\n  return !!(\n    remoteType.schema?.typeHook?.create?.expr ||\n    remoteType.schema?.typeHook?.update?.expr ||\n    remoteType.schema?.typeValidate?.create?.expr ||\n    remoteType.schema?.typeValidate?.update?.expr\n  );\n}\n\n/**\n * Detail suffix used when a script-carrying table has no script hash on the\n * remote at all — the pattern left by an environment whose last deploy used\n * the pre-v2 CLI, which never wrote script hashes.\n */\nexport const MISSING_REMOTE_SCRIPT_HASH_SUFFIX = \"has no script hash on remote\";\n\nfunction compareScriptHashes(\n  remoteTypes: ProtoTailorDBType[],\n  snapshot: SchemaSnapshot,\n): SchemaDrift[] {\n  const drifts: SchemaDrift[] = [];\n  const remoteByName = new Map(remoteTypes.map((t) => [t.name, t]));\n\n  for (const [tableName, snapshotType] of Object.entries(snapshot.tables)) {\n    const localHash = computeSourceScriptHash(snapshotType.fields, {\n      typeHookExpr: snapshotType.typeHookExpr,\n      typeValidateExpr: snapshotType.typeValidateExpr,\n    });\n\n    const remoteType = remoteByName.get(tableName);\n    if (!remoteType) continue;\n\n    if (localHash) {\n      const remoteState = extractRemoteScriptHashState(remoteType);\n      const remoteHash = remoteState.kind === \"hash\" ? remoteState.hash : undefined;\n      if (localHash !== remoteHash) {\n        const details =\n          remoteState.kind === \"hash\"\n            ? `Table '${tableName}' scripts differ between remote and snapshot`\n            : remoteState.kind === \"conflicting\"\n              ? `Table '${tableName}' has conflicting script hashes on remote`\n              : remoteHasScripts(remoteType)\n                ? `Table '${tableName}' ${MISSING_REMOTE_SCRIPT_HASH_SUFFIX}`\n                : `Table '${tableName}' has scripts in snapshot but not on remote`;\n        drifts.push({ tableName, kind: \"script_mismatch\", details });\n      }\n    } else if (remoteHasScripts(remoteType)) {\n      drifts.push({\n        tableName,\n        kind: \"script_mismatch\",\n        details: `Table '${tableName}' has scripts on remote but not in snapshot`,\n      });\n    }\n  }\n\n  return drifts;\n}\n\nfunction stripFieldScriptProps(field: SnapshotFieldConfig): SnapshotFieldConfig {\n  const {\n    hooks: _hooks,\n    validate: _validate,\n    default: _default,\n    optionalOnCreate: _optionalOnCreate,\n    ...rest\n  } = field;\n  if (rest.fields) {\n    const nested = createSnapshotRecord<SnapshotFieldConfig>();\n    for (const [name, f] of Object.entries(rest.fields)) {\n      nested[name] = stripFieldScriptProps(f);\n    }\n    return { ...rest, fields: nested };\n  }\n  return rest;\n}\n\n/**\n * Project a snapshot onto the shape comparable with remote-derived state:\n * system fields, script-bearing props (hooks, validate, default), and\n * type-level script expressions are stripped, since the platform stores them\n * in a transformed or unrepresented form.\n * @param {SchemaSnapshot} snapshot - Snapshot to project\n * @returns {NormalizedSchemaSnapshot} Normalized snapshot without script-bearing props\n */\nexport function createRemoteComparableSnapshot(snapshot: SchemaSnapshot): NormalizedSchemaSnapshot {\n  const tables = createSnapshotRecord<TailorDBSnapshotType>();\n\n  for (const [tableName, type] of Object.entries(snapshot.tables)) {\n    const fields = createSnapshotRecord<SnapshotFieldConfig>();\n    for (const [fieldName, field] of Object.entries(type.fields)) {\n      if (SYSTEM_FIELDS.has(fieldName)) continue;\n      fields[fieldName] = stripFieldScriptProps(field);\n    }\n    const { typeHookExpr: _, typeValidateExpr: __, ...typeRest } = type;\n    tables[tableName] = { ...typeRest, fields };\n  }\n\n  return normalizeSchemaSnapshot({\n    ...snapshot,\n    tables,\n  });\n}\n\nfunction fieldDriftFromChange(\n  change: Extract<DiffChange, { kind: \"field_modified\" | \"field_type_modified\" }>,\n): SchemaDrift {\n  return (\n    compareFields(change.tableName, change.fieldName, change.before, change.after) ?? {\n      tableName: change.tableName,\n      kind: \"field_mismatch\",\n      fieldName: change.fieldName,\n      details: `Field '${change.fieldName}' differs between remote and snapshot`,\n    }\n  );\n}\n\nfunction schemaDriftFromDiffChange(change: DiffChange): SchemaDrift {\n  switch (change.kind) {\n    case \"table_added\":\n      return {\n        tableName: change.tableName,\n        kind: \"type_missing_remote\",\n        details: `Table '${change.tableName}' exists in snapshot but not in remote`,\n      };\n    case \"table_removed\":\n      return {\n        tableName: change.tableName,\n        kind: \"type_missing_local\",\n        details: `Table '${change.tableName}' exists in remote but not in snapshot`,\n      };\n    // Drift comparison never confirms renames, so this kind cannot occur here;\n    // report it as a plain type mismatch if it ever does.\n    case \"table_renamed\":\n      return {\n        tableName: change.tableName,\n        kind: \"type_settings_mismatch\",\n        details: `Table '${change.previousTableName}' was renamed to '${change.tableName}'`,\n      };\n    case \"table_settings_modified\":\n    case \"table_modified\":\n      return {\n        tableName: change.tableName,\n        kind: \"type_settings_mismatch\",\n        details: change.reason ?? \"Table settings differ between remote and snapshot\",\n      };\n    case \"field_added\":\n      return {\n        tableName: change.tableName,\n        kind: \"field_missing_remote\",\n        fieldName: change.fieldName,\n        details: `Field '${change.fieldName}' exists in snapshot but not in remote`,\n      };\n    case \"field_removed\":\n      return {\n        tableName: change.tableName,\n        kind: \"field_missing_local\",\n        fieldName: change.fieldName,\n        details: `Field '${change.fieldName}' exists in remote but not in snapshot`,\n      };\n    case \"field_modified\":\n    case \"field_type_modified\":\n      return fieldDriftFromChange(change);\n    // Drift comparison never confirms renames, so this kind cannot occur here;\n    // report it as a plain field mismatch if it ever does.\n    case \"field_renamed\":\n      return {\n        tableName: change.tableName,\n        kind: \"field_mismatch\",\n        fieldName: change.fieldName,\n        details: `Field '${change.previousFieldName}' was renamed to '${change.fieldName}'`,\n      };\n    case \"index_added\":\n      return {\n        tableName: change.tableName,\n        kind: \"index_missing_remote\",\n        indexName: change.indexName,\n        details: `Index '${change.indexName}' exists in snapshot but not in remote`,\n      };\n    case \"index_removed\":\n      return {\n        tableName: change.tableName,\n        kind: \"index_missing_local\",\n        indexName: change.indexName,\n        details: `Index '${change.indexName}' exists in remote but not in snapshot`,\n      };\n    case \"index_modified\":\n      return {\n        tableName: change.tableName,\n        kind: \"index_mismatch\",\n        indexName: change.indexName,\n        details: change.reason ?? `Index '${change.indexName}' differs between remote and snapshot`,\n      };\n    case \"file_added\":\n      return {\n        tableName: change.tableName,\n        kind: \"file_missing_remote\",\n        fileName: change.fieldName,\n        details: `File '${change.fieldName}' exists in snapshot but not in remote`,\n      };\n    case \"file_removed\":\n      return {\n        tableName: change.tableName,\n        kind: \"file_missing_local\",\n        fileName: change.fieldName,\n        details: `File '${change.fieldName}' exists in remote but not in snapshot`,\n      };\n    case \"file_modified\":\n      return {\n        tableName: change.tableName,\n        kind: \"file_mismatch\",\n        fileName: change.fieldName,\n        details: change.reason ?? `File '${change.fieldName}' differs between remote and snapshot`,\n      };\n    case \"relationship_added\":\n      return {\n        tableName: change.tableName,\n        kind: \"relationship_missing_remote\",\n        relationshipName: change.relationshipName,\n        relationshipType: change.relationshipType,\n        details: `Relationship '${change.relationshipName}' exists in snapshot but not in remote`,\n      };\n    case \"relationship_removed\":\n      return {\n        tableName: change.tableName,\n        kind: \"relationship_missing_local\",\n        relationshipName: change.relationshipName,\n        relationshipType: change.relationshipType,\n        details: `Relationship '${change.relationshipName}' exists in remote but not in snapshot`,\n      };\n    case \"relationship_modified\":\n      return {\n        tableName: change.tableName,\n        kind: \"relationship_mismatch\",\n        relationshipName: change.relationshipName,\n        relationshipType: change.relationshipType,\n        details:\n          change.reason ??\n          `Relationship '${change.relationshipName}' differs between remote and snapshot`,\n      };\n    case \"permission_modified\":\n      return {\n        tableName: change.tableName,\n        kind: \"permission_mismatch\",\n        details: change.reason ?? \"Permissions differ between remote and snapshot\",\n      };\n    case \"table_scripts_modified\":\n      return {\n        tableName: change.tableName,\n        kind: \"script_mismatch\",\n        details: change.reason ?? \"Table-level scripts differ between remote and snapshot\",\n      };\n    default: {\n      change satisfies never;\n      throw internalError(\"Unsupported diff change\");\n    }\n  }\n}\n\nfunction compareNormalizedRemoteWithSnapshot(\n  remoteSnapshot: NormalizedSchemaSnapshot,\n  snapshot: NormalizedSchemaSnapshot,\n): SchemaDrift[] {\n  return compareSnapshots(remoteSnapshot, snapshot).changes.map(schemaDriftFromDiffChange);\n}\n\n/**\n * Format schema drifts for display\n * @param {SchemaDrift[]} drifts - List of drifts to format\n * @returns {string} Formatted drift report\n */\nexport function formatSchemaDrifts(drifts: SchemaDrift[]): string {\n  if (drifts.length === 0) {\n    return \"No schema drifts detected.\";\n  }\n\n  const lines: string[] = [];\n\n  // Group drifts by table\n  const driftsByType = new Map<string, SchemaDrift[]>();\n  for (const drift of drifts) {\n    const existing = driftsByType.get(drift.tableName) ?? [];\n    existing.push(drift);\n    driftsByType.set(drift.tableName, existing);\n  }\n\n  for (const [tableName, typeDrifts] of driftsByType) {\n    lines.push(`  Table '${tableName}':`);\n    for (const drift of typeDrifts) {\n      if (drift.fieldName) {\n        lines.push(`    - Field '${drift.fieldName}': ${drift.details}`);\n      } else if (drift.indexName) {\n        lines.push(`    - Index '${drift.indexName}': ${drift.details}`);\n      } else if (drift.fileName) {\n        lines.push(`    - File '${drift.fileName}': ${drift.details}`);\n      } else if (drift.relationshipName) {\n        const relationshipType = drift.relationshipType ? ` (${drift.relationshipType})` : \"\";\n        lines.push(\n          `    - Relationship${relationshipType} '${drift.relationshipName}': ${drift.details}`,\n        );\n      } else {\n        lines.push(`    - ${drift.details}`);\n      }\n    }\n  }\n\n  return lines.join(\"\\n\");\n}\n","import { createHash, type Hash } from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as path from \"pathe\";\nimport {\n  formatMigrationNumber,\n  getMigrationFilePath,\n  MIGRATION_FILE_NAMES,\n  MIGRATION_NUMBER_PATTERN,\n  type MigrationFileType,\n} from \"./snapshot\";\nimport type { NamespaceWithMigrations } from \"./config\";\n\nconst MIGRATION_FILE_KINDS = Object.keys(MIGRATION_FILE_NAMES) as MigrationFileType[];\n\nfunction getMigrationArtifactNumbers(migrationsDir: string): number[] {\n  if (!fs.existsSync(migrationsDir)) return [];\n\n  return fs\n    .readdirSync(migrationsDir, { withFileTypes: true })\n    .filter((entry) => entry.isDirectory() && MIGRATION_NUMBER_PATTERN.test(entry.name))\n    .map((entry) => Number.parseInt(entry.name, 10))\n    .filter((migrationNumber) =>\n      MIGRATION_FILE_KINDS.some((kind) =>\n        fs.existsSync(getMigrationFilePath(migrationsDir, migrationNumber, kind)),\n      ),\n    )\n    .toSorted((a, b) => a - b);\n}\n\nfunction updateHashWithDirectory(\n  hash: Hash,\n  directoryPath: string,\n  prefix = \"\",\n  activeDirectories = new Set<string>(),\n): void {\n  const realDirectoryPath = fs.realpathSync(directoryPath);\n  if (activeDirectories.has(realDirectoryPath)) {\n    hash.update(`directory-cycle\\0${prefix}\\0${realDirectoryPath}\\0`);\n    return;\n  }\n  activeDirectories.add(realDirectoryPath);\n  const entries = fs\n    .readdirSync(directoryPath, { withFileTypes: true })\n    .toSorted((a, b) => a.name.localeCompare(b.name));\n\n  try {\n    for (const entry of entries) {\n      const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;\n      const entryPath = path.join(directoryPath, entry.name);\n      if (entry.isDirectory()) {\n        hash.update(`directory\\0${relativePath}\\0`);\n        updateHashWithDirectory(hash, entryPath, relativePath, activeDirectories);\n      } else if (entry.isFile()) {\n        hash.update(`file\\0${relativePath}\\0`);\n        hash.update(fs.readFileSync(entryPath));\n        hash.update(\"\\0\");\n      } else if (entry.isSymbolicLink()) {\n        hash.update(`symlink\\0${relativePath}\\0${fs.readlinkSync(entryPath)}\\0`);\n        try {\n          const target = fs.statSync(entryPath);\n          if (target.isDirectory()) {\n            hash.update(\"target-directory\\0\");\n            updateHashWithDirectory(hash, entryPath, `${relativePath}@target`, activeDirectories);\n          } else if (target.isFile()) {\n            hash.update(\"target-file\\0\");\n            hash.update(fs.readFileSync(entryPath));\n            hash.update(\"\\0\");\n          } else {\n            hash.update(\"target-other\\0\");\n          }\n        } catch (error) {\n          if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n          hash.update(\"target-missing\\0\");\n        }\n      } else {\n        hash.update(`other\\0${relativePath}\\0`);\n      }\n    }\n  } finally {\n    activeDirectories.delete(realDirectoryPath);\n  }\n}\n\n/**\n * Capture an exact set of input files.\n * @param filePaths - Files whose names and contents affect an operation\n * @returns SHA-256 digest of the sorted file set\n */\nexport function captureFileState(filePaths: ReadonlyArray<string>): string {\n  const hash = createHash(\"sha256\");\n  for (const filePath of [...new Set(filePaths)].toSorted()) {\n    hash.update(filePath);\n    hash.update(\"\\0\");\n    if (fs.existsSync(filePath)) {\n      hash.update(fs.readFileSync(filePath));\n    } else {\n      hash.update(\"<missing>\");\n    }\n    hash.update(\"\\0\");\n  }\n  return hash.digest(\"hex\");\n}\n\n/**\n * Capture the migration files that an operation depends on.\n * @param namespacesWithMigrations - Configured migration directories by namespace\n * @returns SHA-256 digest by namespace\n */\nexport function captureMigrationFileState(\n  namespacesWithMigrations: ReadonlyArray<NamespaceWithMigrations>,\n): Record<string, string> {\n  const state = Object.create(null) as Record<string, string>;\n  for (const { namespace, migrationsDir } of namespacesWithMigrations.toSorted((a, b) =>\n    a.namespace.localeCompare(b.namespace),\n  )) {\n    const hash = createHash(\"sha256\");\n    const migrationNumbers = getMigrationArtifactNumbers(migrationsDir);\n    for (const migrationNumber of migrationNumbers) {\n      const migrationDirectoryName = formatMigrationNumber(migrationNumber);\n      hash.update(`migration\\0${migrationDirectoryName}\\0`);\n      updateHashWithDirectory(hash, path.join(migrationsDir, migrationDirectoryName));\n    }\n    state[namespace] = hash.digest(\"hex\");\n  }\n  return state;\n}\n","/**\n * Migration configuration utilities\n */\n\nimport * as path from \"pathe\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { assertDefined } from \"#/utils/assert\";\nimport type { AppConfig } from \"#/configure/config/types\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Namespace with migrations configuration\n */\nexport interface NamespaceWithMigrations {\n  namespace: string;\n  migrationsDir: string;\n}\n\n// ============================================================================\n// Config Helpers\n// ============================================================================\n\nfunction hasMigrationConfig(dbConfig: unknown): dbConfig is { migration: { directory: string } } {\n  if (typeof dbConfig !== \"object\" || dbConfig === null) return false;\n  if (!(\"migration\" in dbConfig)) return false;\n\n  const migration = dbConfig.migration;\n  if (typeof migration !== \"object\" || migration === null) return false;\n  if (!(\"directory\" in migration)) return false;\n\n  return typeof migration.directory === \"string\";\n}\n\n/**\n * Get namespaces that have migrations configured\n * @param {AppConfig} config - Application configuration\n * @param {string} configDir - Configuration directory path\n * @returns {NamespaceWithMigrations[]} Array of namespaces with migrations configured\n */\nexport function getNamespacesWithMigrations(\n  config: AppConfig,\n  configDir: string,\n): NamespaceWithMigrations[] {\n  const result: NamespaceWithMigrations[] = [];\n\n  for (const namespace of Object.keys(config.db ?? {})) {\n    const dbConfig = config.db?.[namespace];\n    if (!hasMigrationConfig(dbConfig)) continue;\n\n    const migrationsDir = path.resolve(configDir, dbConfig.migration.directory);\n    result.push({ namespace, migrationsDir });\n  }\n\n  return result;\n}\n\n/**\n * Select the single target namespace for a migration command\n * @param {NamespaceWithMigrations[]} namespacesWithMigrations - Namespaces with migrations configured\n * @param {string | undefined} requested - Namespace requested via --namespace, if any\n * @returns {NamespaceWithMigrations} The selected namespace\n */\nexport function selectTargetNamespace(\n  namespacesWithMigrations: NamespaceWithMigrations[],\n  requested: string | undefined,\n): NamespaceWithMigrations {\n  if (namespacesWithMigrations.length === 0) {\n    throw migrationConfigNotFoundError();\n  }\n  if (requested) {\n    const found = namespacesWithMigrations.find((ns) => ns.namespace === requested);\n    if (!found) {\n      throw CLIError({\n        code: \"TAILORDB_NAMESPACE_NOT_FOUND\",\n        message: `Namespace \"${requested}\" not found or does not have migrations configured`,\n      });\n    }\n    return found;\n  }\n  if (namespacesWithMigrations.length > 1) {\n    throw CLIError({\n      code: \"MIGRATION_NAMESPACE_REQUIRED\",\n      message: `Multiple TailorDB services found. Please specify namespace with --namespace flag: ${namespacesWithMigrations\n        .map((ns) => ns.namespace)\n        .join(\", \")}`,\n    });\n  }\n  return assertDefined(namespacesWithMigrations[0], \"namespace with migrations missing\");\n}\n\n/**\n * Build the failure for a config without any TailorDB migration settings.\n * @returns CLIError pointing at the migration configuration\n */\nexport function migrationConfigNotFoundError(): CLIError {\n  return CLIError({\n    code: \"MIGRATION_CONFIG_NOT_FOUND\",\n    message: \"No TailorDB services with migrations configuration found\",\n    suggestion: \"Configure `migration` on the TailorDB service in tailor.config.ts.\",\n  });\n}\n","import { getOrNull, type OperatorClient } from \"#/cli/shared/client\";\nimport {\n  MIGRATION_HISTORY_LABEL_KEY,\n  MIGRATION_LABEL_KEY,\n  parseMigrationHistoryId,\n  parseMigrationLabelNumber,\n} from \"./types\";\n\nexport interface RemoteMigrationState {\n  metadataExists: boolean;\n  number: number | null;\n  historyId: string | null;\n  historyIdInvalid: boolean;\n}\n\n/**\n * Fetch the namespace's migration checkpoint and history ID.\n * @param client - Operator client\n * @param trn - Namespace TRN\n * @returns Parsed migration state with invalid history labels kept distinct from missing labels\n */\nexport async function fetchRemoteMigrationState(\n  client: OperatorClient,\n  trn: string,\n): Promise<RemoteMigrationState> {\n  const metadata = await getOrNull(async () => {\n    const { metadata } = await client.getMetadata({ trn });\n    return metadata;\n  });\n  if (!metadata) {\n    return {\n      metadataExists: false,\n      number: null,\n      historyId: null,\n      historyIdInvalid: false,\n    };\n  }\n\n  const migrationLabel = metadata.labels[MIGRATION_LABEL_KEY];\n  const historyLabel = metadata.labels[MIGRATION_HISTORY_LABEL_KEY];\n  const historyId = historyLabel ? parseMigrationHistoryId(historyLabel) : null;\n  return {\n    metadataExists: true,\n    number: migrationLabel ? parseMigrationLabelNumber(migrationLabel) : null,\n    historyId,\n    historyIdInvalid: historyLabel !== undefined && historyId === null,\n  };\n}\n\n/**\n * Fetch the namespace's current migration number from its metadata labels.\n *\n * Only a namespace that has not been deployed yet reads as \"no current\n * migration\". Every other lookup failure must propagate: treating it as\n * unset would misreport a transient error as \"no checkpoint\", showing\n * every migration as pending to callers.\n * @param client - Operator client\n * @param trn - Namespace TRN\n * @returns Parsed current migration number, or null when unset or unparseable\n */\nexport async function fetchRemoteMigrationNumber(\n  client: OperatorClient,\n  trn: string,\n): Promise<number | null> {\n  return (await fetchRemoteMigrationState(client, trn)).number;\n}\n","import { findUndefinedReferences } from \"#/cli/shared/free-variables\";\nimport { assertParsableExpression } from \"#/utils/script-expr\";\nimport type {\n  SnapshotFieldConfig,\n  SnapshotValidation,\n  TailorDBSnapshotType,\n} from \"./snapshot-types\";\n\nfunction usesLegacyData(expr: string): boolean {\n  return (\n    expr.includes(\"_data\") &&\n    findUndefinedReferences(`(${expr}\\n);`, { includeGuardedReferences: true }).has(\"_data\")\n  );\n}\n\nfunction normalizeValidations(\n  validations: SnapshotValidation[],\n  dataAccess: string,\n): SnapshotValidation[] {\n  const normalized: SnapshotValidation[] = [];\n  let firstLegacy: SnapshotValidation | undefined;\n  let checks: string[] = [];\n\n  function flushLegacy(): void {\n    if (!firstLegacy?.script) return;\n    normalized.push({\n      ...firstLegacy,\n      script: {\n        ...firstLegacy.script,\n        expr: assertParsableExpression(\n          `((_data) => { ${checks.join(\"\\n\")} })(${dataAccess})`,\n          \"legacy migration validator\",\n        ),\n      },\n    });\n    firstLegacy = undefined;\n    checks = [];\n  }\n\n  // Keep each legacy chain together to preserve short-circuiting on its first falsy result.\n  for (const validation of validations) {\n    if (validation.script && usesLegacyData(validation.script.expr)) {\n      firstLegacy ??= validation;\n      checks.push(\n        `if (!(${validation.script.expr}\\n)) return ${JSON.stringify(validation.errorMessage)};`,\n      );\n    } else {\n      flushLegacy();\n      normalized.push(validation);\n    }\n  }\n  flushLegacy();\n  return normalized;\n}\n\nfunction normalizeField(\n  field: SnapshotFieldConfig,\n  inputAccess: string,\n  updateAccess: string,\n  validateAccess: string,\n  fieldName: string,\n): SnapshotFieldConfig {\n  const normalized = { ...field };\n  if (field.fields) {\n    // The script compiler binds __el while evaluating hooks and validators in array elements.\n    const nestedInput = field.array ? \"__el\" : `${inputAccess}?.[${JSON.stringify(fieldName)}]`;\n    const nestedUpdate = field.array ? \"__el\" : `${updateAccess}?.[${JSON.stringify(fieldName)}]`;\n    const nestedValidate = field.array\n      ? \"__el\"\n      : `${validateAccess}?.[${JSON.stringify(fieldName)}]`;\n    normalized.fields = Object.fromEntries(\n      Object.entries(field.fields).map(([name, nested]) => [\n        name,\n        normalizeField(nested, nestedInput, nestedUpdate, nestedValidate, name),\n      ]),\n    );\n  }\n  if (field.hooks) {\n    normalized.hooks = { ...field.hooks };\n    for (const operation of [\"create\", \"update\"] as const) {\n      const hook = field.hooks[operation];\n      if (hook && usesLegacyData(hook.expr)) {\n        const dataExpr = operation === \"update\" ? updateAccess : inputAccess;\n        normalized.hooks[operation] = {\n          ...hook,\n          expr: assertParsableExpression(\n            `((_data) => (${hook.expr}\\n))(${dataExpr})`,\n            \"legacy migration hook\",\n          ),\n        };\n      }\n    }\n  }\n  if (field.validate) {\n    normalized.validate = normalizeValidations(field.validate, validateAccess);\n  }\n  return normalized;\n}\n\n/**\n * Adapt historical scripts for execution while leaving persisted metadata unchanged.\n * @param table - Table whose field scripts will be compiled\n * @returns Table with legacy field scripts adapted in memory\n */\nexport function normalizeTableScriptCompatibility(\n  table: TailorDBSnapshotType,\n): TailorDBSnapshotType {\n  return {\n    ...table,\n    fields: Object.fromEntries(\n      Object.entries(table.fields).map(([name, field]) => [\n        name,\n        normalizeField(\n          field,\n          \"_input\",\n          \"Object.assign({}, _oldRecord, _input)\",\n          \"_newRecord\",\n          name,\n        ),\n      ]),\n    ),\n  };\n}\n","/**\n * Snapshot-based Proto manifest generation for TailorDB migrations\n *\n * This module provides utilities for generating TailorDB proto manifests\n * directly from schema snapshots, enabling migration-based deployments\n * without relying on local TypeScript definitions.\n */\n\nimport { fromJson, type MessageInitShape } from \"@bufbuild/protobuf\";\nimport { ValueSchema } from \"@bufbuild/protobuf/wkt\";\nimport {\n  TailorDBGQLPermission_Action,\n  TailorDBGQLPermission_Operator,\n  TailorDBGQLPermission_Permit,\n  type TailorDBGQLPermission_ConditionSchema,\n  type TailorDBGQLPermission_OperandSchema,\n  type TailorDBGQLPermission_PolicySchema,\n  type TailorDBGQLPermissionSchema,\n  TailorDBType_Permission_Operator,\n  TailorDBType_Permission_Permit,\n  type TailorDBType_FieldConfigSchema,\n  type TailorDBType_FileConfigSchema,\n  type TailorDBType_IndexSchema,\n  type TailorDBType_Permission_ConditionSchema,\n  type TailorDBType_Permission_OperandSchema,\n  type TailorDBType_Permission_PolicySchema,\n  type TailorDBType_PermissionSchema,\n  type TailorDBType_RelationshipConfigSchema,\n  type TailorDBTypeSchema,\n} from \"@tailor-platform/tailor-proto/tailordb_resource_pb\";\nimport * as inflection from \"inflection\";\nimport { CLIError, internalError } from \"#/cli/shared/errors\";\nimport { publishEventsConflict, resolvePublishEvents } from \"#/cli/shared/publish-events\";\nimport { buildTypeScripts } from \"#/parser/service/tailordb/type-script\";\nimport { isSnapshotFieldRefOperand } from \"./snapshot\";\nimport { normalizeTableScriptCompatibility } from \"./snapshot-script-compatibility\";\nimport type {\n  SchemaSnapshot,\n  SnapshotEnumValue,\n  SnapshotFieldConfig,\n  TailorDBSnapshotType,\n  SnapshotRelationship,\n  SnapshotRecordPermission,\n  SnapshotActionPermission,\n  SnapshotGqlPermission,\n  SnapshotGqlPermissionPolicy,\n  SnapshotPermissionCondition,\n  SnapshotPermissionOperand,\n  SnapshotIndexConfig,\n} from \"./snapshot\";\n\n/**\n * Options for generating TailorDB table manifest from snapshot\n */\nexport interface GenerateManifestOptions {\n  /** Whether an executor taking part in the same run subscribes to its record events */\n  subscribed?: boolean;\n  /**\n   * Force record event publishing off, overriding a declared `publishEvents`.\n   *\n   * A table that declares `publishEvents: true` publishes no matter who\n   * subscribes, so `subscribed` alone cannot silence it while migrations run.\n   */\n  suppressRecordEvents?: boolean;\n  /** Force every GraphQL operation, including bulk upsert, off. */\n  suppressGqlOperations?: boolean;\n  /** Default gqlOperations for the namespace */\n  namespaceGqlOperations?: {\n    create?: boolean;\n    update?: boolean;\n    delete?: boolean;\n    read?: boolean;\n  };\n}\n\n/**\n * Whether a table's manifest enables record event publishing.\n *\n * The one place the rule lives: a declared `publishEvents` wins, and an unset\n * value follows whether an executor in the run subscribes.\n * @param snapshotType - Table to resolve the flag for\n * @param subscribed - Whether an executor taking part in the run subscribes\n * @returns Whether the table publishes record events\n */\nfunction publishesRecordEvents(snapshotType: TailorDBSnapshotType, subscribed: boolean): boolean {\n  return resolvePublishEvents({\n    explicit: snapshotType.settings?.publishEvents,\n    subscribed,\n    conflict: publishEventsConflict.tailorDBType(snapshotType.name),\n  });\n}\n\n/**\n * Generate a TailorDB table manifest from a snapshot table\n * @param {TailorDBSnapshotType} snapshotType - Snapshot table to generate manifest from\n * @param {GenerateManifestOptions} options - Generation options\n * @returns {MessageInitShape<typeof TailorDBTypeSchema>} Table manifest\n */\nexport function generateTailorDBTypeManifestFromSnapshot(\n  snapshotType: TailorDBSnapshotType,\n  options: GenerateManifestOptions = {},\n): MessageInitShape<typeof TailorDBTypeSchema> {\n  const pluralForm = inflection.camelize(snapshotType.pluralForm, true);\n\n  // Build settings\n  const defaultSettings: {\n    aggregation: boolean;\n    bulkUpsert: boolean;\n    draft: boolean;\n    defaultQueryLimitSize: bigint;\n    maxBulkUpsertSize: bigint;\n    pluralForm: string;\n    publishRecordEvents: boolean;\n    disableGqlOperations?: {\n      create: boolean;\n      update: boolean;\n      delete: boolean;\n      read: boolean;\n    };\n  } = {\n    aggregation: snapshotType.settings?.aggregation ?? false,\n    bulkUpsert:\n      options.suppressGqlOperations === true ? false : (snapshotType.settings?.bulkUpsert ?? false),\n    draft: false,\n    defaultQueryLimitSize: 100n,\n    maxBulkUpsertSize: 1000n,\n    pluralForm,\n    publishRecordEvents:\n      options.suppressRecordEvents === true\n        ? false\n        : publishesRecordEvents(snapshotType, options.subscribed ?? false),\n  };\n\n  // Apply gqlOperations from snapshot settings or namespace default\n  const ops = snapshotType.settings?.gqlOperations ?? options.namespaceGqlOperations;\n  if (ops || options.suppressGqlOperations === true) {\n    defaultSettings.disableGqlOperations = {\n      create: options.suppressGqlOperations === true || ops?.create === false,\n      update: options.suppressGqlOperations === true || ops?.update === false,\n      delete: options.suppressGqlOperations === true || ops?.delete === false,\n      read: options.suppressGqlOperations === true || ops?.read === false,\n    };\n  }\n\n  // Build fields\n  const fields: Record<\n    string,\n    MessageInitShape<typeof TailorDBType_FieldConfigSchema>\n  > = Object.fromEntries(\n    Object.entries(snapshotType.fields)\n      .filter(([fieldName]) => fieldName !== \"id\")\n      .map(([fieldName, fieldConfig]) => [fieldName, convertFieldConfigToProto(fieldConfig)]),\n  );\n\n  // Build relationships\n  const relationships = new Map<\n    string,\n    MessageInitShape<typeof TailorDBType_RelationshipConfigSchema>\n  >();\n\n  if (snapshotType.forwardRelationships) {\n    for (const [relationName, rel] of Object.entries(snapshotType.forwardRelationships)) {\n      relationships.set(relationName, convertRelationshipToProto(rel, \"forward\"));\n    }\n  }\n\n  if (snapshotType.backwardRelationships) {\n    for (const [relationName, rel] of Object.entries(snapshotType.backwardRelationships)) {\n      relationships.set(relationName, convertRelationshipToProto(rel, \"backward\"));\n    }\n  }\n\n  // Build indexes\n  const indexes = new Map<string, MessageInitShape<typeof TailorDBType_IndexSchema>>();\n  if (snapshotType.indexes) {\n    for (const [indexName, indexConfig] of Object.entries(snapshotType.indexes)) {\n      indexes.set(indexName, convertIndexToProto(indexConfig));\n    }\n  }\n\n  // Build files\n  const files = new Map<string, MessageInitShape<typeof TailorDBType_FileConfigSchema>>();\n  if (snapshotType.files) {\n    for (const [fileName, description] of Object.entries(snapshotType.files)) {\n      files.set(fileName, { description: description || \"\" });\n    }\n  }\n\n  // Build permission\n  const defaultPermission: MessageInitShape<typeof TailorDBType_PermissionSchema> = {\n    create: [],\n    read: [],\n    update: [],\n    delete: [],\n  };\n  const permission = snapshotType.permissions?.record\n    ? convertRecordPermissionToProto(snapshotType.permissions.record)\n    : defaultPermission;\n\n  // Field hooks/validators are aggregated into table-level scripts so that a\n  // single shared timestamp is observed across every field in one operation.\n  const scriptTable = normalizeTableScriptCompatibility(snapshotType);\n  const { typeHook, typeValidate } = buildTypeScripts(scriptTable.fields, {\n    sourceFields: snapshotType.fields,\n    typeHookExpr: snapshotType.typeHookExpr,\n    typeValidateExpr: snapshotType.typeValidateExpr,\n  });\n\n  return {\n    name: snapshotType.name,\n    schema: {\n      description: snapshotType.description || \"\",\n      fields,\n      relationships: Object.fromEntries(relationships),\n      settings: defaultSettings,\n      extends: false,\n      directives: [],\n      indexes: Object.fromEntries(indexes),\n      files: Object.fromEntries(files),\n      permission,\n      ...(typeHook && { typeHook }),\n      ...(typeValidate && { typeValidate }),\n    },\n  };\n}\n\nfunction optionalOnCreate(\n  config: Pick<SnapshotFieldConfig, \"hooks\" | \"default\">,\n): Pick<MessageInitShape<typeof TailorDBType_FieldConfigSchema>, \"optionalOnCreate\"> {\n  return config.hooks?.create || config.default !== undefined ? { optionalOnCreate: true } : {};\n}\n\n/**\n * Convert a snapshot field config to proto format\n * @param {SnapshotFieldConfig} config - Snapshot field config\n * @returns {MessageInitShape<typeof TailorDBType_FieldConfigSchema>} Proto field config\n */\nexport function convertFieldConfigToProto(\n  config: SnapshotFieldConfig,\n): MessageInitShape<typeof TailorDBType_FieldConfigSchema> {\n  const fieldEntry: MessageInitShape<typeof TailorDBType_FieldConfigSchema> = {\n    type: config.type,\n    allowedValues:\n      config.type === \"enum\"\n        ? (config.allowedValues?.map((v: SnapshotEnumValue) => ({ ...v })) ?? [])\n        : [],\n    description: config.description || \"\",\n    array: config.array ?? false,\n    index: config.index ?? false,\n    unique: config.unique ?? false,\n    foreignKey: config.foreignKey ?? false,\n    foreignKeyType: config.foreignKeyType,\n    foreignKeyField: config.foreignKeyField,\n    required: config.required,\n    vector: config.vector ?? false,\n    ...optionalOnCreate(config),\n    ...(config.serial && {\n      serial: {\n        start: BigInt(config.serial.start),\n        ...(config.serial.maxValue !== undefined && {\n          maxValue: BigInt(config.serial.maxValue),\n        }),\n        ...(config.serial.format && {\n          format: config.serial.format,\n        }),\n      },\n    }),\n    ...(config.scale !== undefined && { scale: config.scale }),\n  };\n\n  // Handle nested fields\n  if (config.type === \"nested\" && config.fields) {\n    fieldEntry.fields = processNestedFieldsFromSnapshot(config.fields);\n  }\n\n  return fieldEntry;\n}\n\n/**\n * Process nested fields from snapshot format to proto format\n * @param {Record<string, SnapshotFieldConfig>} fields - Nested fields\n * @returns {Record<string, MessageInitShape<typeof TailorDBType_FieldConfigSchema>>} Proto nested fields\n */\nexport function processNestedFieldsFromSnapshot(\n  fields: Record<string, SnapshotFieldConfig>,\n): Record<string, MessageInitShape<typeof TailorDBType_FieldConfigSchema>> {\n  const nestedFields = new Map<string, MessageInitShape<typeof TailorDBType_FieldConfigSchema>>();\n\n  for (const [fieldName, fieldConfig] of Object.entries(fields)) {\n    if (fieldConfig.type === \"nested\" && fieldConfig.fields) {\n      const deepNestedFields = processNestedFieldsFromSnapshot(fieldConfig.fields);\n      nestedFields.set(fieldName, {\n        type: \"nested\",\n        allowedValues: fieldConfig.allowedValues?.map((v: SnapshotEnumValue) => ({ ...v })) ?? [],\n        description: fieldConfig.description || \"\",\n        required: fieldConfig.required,\n        array: fieldConfig.array ?? false,\n        index: false,\n        unique: false,\n        foreignKey: false,\n        vector: false,\n        fields: deepNestedFields,\n        ...(fieldConfig.scale !== undefined && { scale: fieldConfig.scale }),\n      });\n    } else {\n      nestedFields.set(fieldName, {\n        type: fieldConfig.type,\n        allowedValues:\n          fieldConfig.type === \"enum\"\n            ? (fieldConfig.allowedValues?.map((v: SnapshotEnumValue) => ({ ...v })) ?? [])\n            : [],\n        description: fieldConfig.description || \"\",\n        required: fieldConfig.required,\n        array: fieldConfig.array ?? false,\n        index: false,\n        unique: false,\n        foreignKey: false,\n        vector: false,\n        ...optionalOnCreate(fieldConfig),\n        ...(fieldConfig.serial && {\n          serial: {\n            start: BigInt(fieldConfig.serial.start),\n            ...(fieldConfig.serial.maxValue !== undefined && {\n              maxValue: BigInt(fieldConfig.serial.maxValue),\n            }),\n            ...(fieldConfig.serial.format && {\n              format: fieldConfig.serial.format,\n            }),\n          },\n        }),\n        ...(fieldConfig.scale !== undefined && { scale: fieldConfig.scale }),\n      });\n    }\n  }\n\n  return Object.fromEntries(nestedFields);\n}\n\n/**\n * Convert a snapshot relationship to proto format\n * @param {SnapshotRelationship} rel - Snapshot relationship\n * @param {\"forward\" | \"backward\"} direction - Relationship direction\n * @returns {MessageInitShape<typeof TailorDBType_RelationshipConfigSchema>} Proto relationship config\n */\nfunction convertRelationshipToProto(\n  rel: SnapshotRelationship,\n  direction: \"forward\" | \"backward\",\n): MessageInitShape<typeof TailorDBType_RelationshipConfigSchema> {\n  if (direction === \"forward\") {\n    return {\n      refType: rel.targetType,\n      refField: rel.sourceField,\n      srcField: rel.targetField,\n      array: rel.isArray,\n      description: rel.description,\n    };\n  }\n  // backward\n  return {\n    refType: rel.targetType,\n    refField: rel.targetField,\n    srcField: rel.sourceField,\n    array: rel.isArray,\n    description: rel.description,\n  };\n}\n\n/**\n * Convert a snapshot index config to proto format\n * @param {SnapshotIndexConfig} indexConfig - Snapshot index config\n * @returns {MessageInitShape<typeof TailorDBType_IndexSchema>} Proto index config\n */\nexport function convertIndexToProto(\n  indexConfig: SnapshotIndexConfig,\n): MessageInitShape<typeof TailorDBType_IndexSchema> {\n  return {\n    fieldNames: indexConfig.fields,\n    unique: indexConfig.unique ?? false,\n  };\n}\n\n/**\n * Convert a snapshot record permission to proto format\n * @param {SnapshotRecordPermission} permission - Snapshot record permission\n * @returns {MessageInitShape<typeof TailorDBType_PermissionSchema>} Proto permission\n */\nfunction convertRecordPermissionToProto(\n  permission: SnapshotRecordPermission,\n): MessageInitShape<typeof TailorDBType_PermissionSchema> {\n  return {\n    create: permission.create.map(convertActionPermissionToProto),\n    read: permission.read.map(convertActionPermissionToProto),\n    update: permission.update.map(convertActionPermissionToProto),\n    delete: permission.delete.map(convertActionPermissionToProto),\n  };\n}\n\n/**\n * Convert a snapshot action permission to proto format\n * @param {SnapshotActionPermission} policy - Snapshot action permission\n * @returns {MessageInitShape<typeof TailorDBType_Permission_PolicySchema>} Proto policy\n */\nfunction convertActionPermissionToProto(\n  policy: SnapshotActionPermission,\n): MessageInitShape<typeof TailorDBType_Permission_PolicySchema> {\n  let permit: TailorDBType_Permission_Permit;\n  switch (policy.permit) {\n    case \"allow\":\n      permit = TailorDBType_Permission_Permit.ALLOW;\n      break;\n    case \"deny\":\n      permit = TailorDBType_Permission_Permit.DENY;\n      break;\n    default:\n      throw internalError(`Unknown permission: ${policy.permit satisfies never}`);\n  }\n\n  return {\n    conditions: policy.conditions.map(convertConditionToProto),\n    permit,\n    description: policy.description,\n  };\n}\n\n/**\n * Convert a snapshot permission condition to proto format\n * @param {SnapshotPermissionCondition} condition - Snapshot permission condition\n * @returns {MessageInitShape<typeof TailorDBType_Permission_ConditionSchema>} Proto condition\n */\nfunction convertConditionToProto(\n  condition: SnapshotPermissionCondition,\n): MessageInitShape<typeof TailorDBType_Permission_ConditionSchema> {\n  const [left, operator, right] = condition;\n\n  const l = convertOperandToProto(left);\n  const r = convertOperandToProto(right);\n\n  let op: TailorDBType_Permission_Operator;\n  switch (operator) {\n    case \"eq\":\n      op = TailorDBType_Permission_Operator.EQ;\n      break;\n    case \"ne\":\n      op = TailorDBType_Permission_Operator.NE;\n      break;\n    case \"in\":\n      op = TailorDBType_Permission_Operator.IN;\n      break;\n    case \"nin\":\n      op = TailorDBType_Permission_Operator.NIN;\n      break;\n    case \"hasAny\":\n      op = TailorDBType_Permission_Operator.HAS_ANY;\n      break;\n    case \"nhasAny\":\n      op = TailorDBType_Permission_Operator.NHAS_ANY;\n      break;\n    default:\n      throw internalError(`Unknown operator: ${operator satisfies never}`);\n  }\n\n  return {\n    left: l,\n    operator: op,\n    right: r,\n  };\n}\n\n/**\n * Convert a snapshot permission operand to proto format\n * @param {SnapshotPermissionOperand} operand - Snapshot permission operand\n * @returns {MessageInitShape<typeof TailorDBType_Permission_OperandSchema>} Proto operand\n */\nfunction convertOperandToProto(\n  operand: SnapshotPermissionOperand,\n): MessageInitShape<typeof TailorDBType_Permission_OperandSchema> {\n  if (isSnapshotFieldRefOperand(operand)) {\n    if (\"user\" in operand) {\n      return { kind: { case: \"userField\", value: operand.user } };\n    }\n    if (\"record\" in operand) {\n      return { kind: { case: \"recordField\", value: operand.record } };\n    }\n    if (\"newRecord\" in operand) {\n      return { kind: { case: \"newRecordField\", value: operand.newRecord } };\n    }\n    if (\"oldRecord\" in operand) {\n      return { kind: { case: \"oldRecordField\", value: operand.oldRecord } };\n    }\n    operand satisfies never;\n    throw internalError(`Unknown field-ref operand shape: ${JSON.stringify(operand)}`);\n  }\n\n  return {\n    kind: { case: \"value\", value: fromJson(ValueSchema, operand) },\n  };\n}\n\n/**\n * Options for generating all table manifests from a snapshot\n */\nexport interface GenerateAllManifestsOptions extends GenerateManifestOptions {\n  /** Set of table names that should have publishRecordEvents enabled */\n  executorUsedTables?: ReadonlySet<string>;\n}\n\n/**\n * Generate all TailorDB table manifests from a schema snapshot\n * @param {SchemaSnapshot} snapshot - Schema snapshot\n * @param {GenerateAllManifestsOptions} options - Generation options\n * @returns {Map<string, MessageInitShape<typeof TailorDBTypeSchema>>} Map of table name to manifest\n */\nexport function generateAllTypeManifestsFromSnapshot(\n  snapshot: SchemaSnapshot,\n  options: GenerateAllManifestsOptions = {},\n): Map<string, MessageInitShape<typeof TailorDBTypeSchema>> {\n  const manifests = new Map<string, MessageInitShape<typeof TailorDBTypeSchema>>();\n  const { executorUsedTables, ...baseOptions } = options;\n\n  for (const [tableName, snapshotType] of Object.entries(snapshot.tables)) {\n    const typeOptions: GenerateManifestOptions = {\n      ...baseOptions,\n      subscribed: executorUsedTables?.has(tableName) ?? false,\n    };\n    manifests.set(tableName, generateTailorDBTypeManifestFromSnapshot(snapshotType, typeOptions));\n  }\n\n  return manifests;\n}\n\n/**\n * Result of comparing snapshot tables with existing remote tables\n */\nexport interface SnapshotTypeComparison {\n  /** Tables to create (exist in snapshot but not in remote) */\n  creates: string[];\n  /** Tables to update (exist in both) */\n  updates: string[];\n  /** Tables to delete (exist in remote but not in snapshot) */\n  deletes: string[];\n}\n\n/**\n * Compare snapshot tables with existing remote table names\n * @param {SchemaSnapshot} snapshot - Schema snapshot\n * @param {ReadonlySet<string>} existingTableNames - Set of existing table names in remote\n * @returns {SnapshotTypeComparison} Comparison result\n */\nexport function compareSnapshotWithRemote(\n  snapshot: SchemaSnapshot,\n  existingTableNames: ReadonlySet<string>,\n): SnapshotTypeComparison {\n  const snapshotTableNames = new Set(Object.keys(snapshot.tables));\n\n  const creates: string[] = [];\n  const updates: string[] = [];\n  const deletes: string[] = [];\n\n  // Tables in snapshot\n  for (const tableName of snapshotTableNames) {\n    if (existingTableNames.has(tableName)) {\n      updates.push(tableName);\n    } else {\n      creates.push(tableName);\n    }\n  }\n\n  // Tables only in remote (to be deleted)\n  for (const tableName of existingTableNames) {\n    if (!snapshotTableNames.has(tableName)) {\n      deletes.push(tableName);\n    }\n  }\n\n  return { creates, updates, deletes };\n}\n\n/**\n * Convert snapshot GQL permission policies to the proto request shape.\n * @param permission - Snapshot GQL permission policies\n * @returns Proto GQL permission\n */\nexport function protoGqlPermission(\n  permission: SnapshotGqlPermission,\n): MessageInitShape<typeof TailorDBGQLPermissionSchema> {\n  return {\n    policies: permission.map((policy) => protoGqlPolicy(policy)),\n  };\n}\n\nfunction protoGqlPolicy(\n  policy: SnapshotGqlPermissionPolicy,\n): MessageInitShape<typeof TailorDBGQLPermission_PolicySchema> {\n  const actions: TailorDBGQLPermission_Action[] = [];\n  for (const action of policy.actions) {\n    switch (action) {\n      case \"all\":\n        actions.push(TailorDBGQLPermission_Action.ALL);\n        break;\n      case \"create\":\n        actions.push(TailorDBGQLPermission_Action.CREATE);\n        break;\n      case \"read\":\n        actions.push(TailorDBGQLPermission_Action.READ);\n        break;\n      case \"update\":\n        actions.push(TailorDBGQLPermission_Action.UPDATE);\n        break;\n      case \"delete\":\n        actions.push(TailorDBGQLPermission_Action.DELETE);\n        break;\n      case \"aggregate\":\n        actions.push(TailorDBGQLPermission_Action.AGGREGATE);\n        break;\n      case \"bulkUpsert\":\n        actions.push(TailorDBGQLPermission_Action.BULK_UPSERT);\n        break;\n      default:\n        throw internalError(`Unknown action: ${action satisfies never}`);\n    }\n  }\n  let permit: TailorDBGQLPermission_Permit;\n  switch (policy.permit) {\n    case \"allow\":\n      permit = TailorDBGQLPermission_Permit.ALLOW;\n      break;\n    case \"deny\":\n      permit = TailorDBGQLPermission_Permit.DENY;\n      break;\n    default:\n      throw internalError(`Unknown permission: ${policy.permit satisfies never}`);\n  }\n  return {\n    conditions: policy.conditions.map((cond) => protoGqlCondition(cond)),\n    actions,\n    permit,\n    description: policy.description,\n  };\n}\n\nfunction protoGqlCondition(\n  condition: SnapshotPermissionCondition,\n): MessageInitShape<typeof TailorDBGQLPermission_ConditionSchema> {\n  const [left, operator, right] = condition;\n\n  const l = protoGqlOperand(left);\n  const r = protoGqlOperand(right);\n  let op: TailorDBGQLPermission_Operator;\n  switch (operator) {\n    case \"eq\":\n      op = TailorDBGQLPermission_Operator.EQ;\n      break;\n    case \"ne\":\n      op = TailorDBGQLPermission_Operator.NE;\n      break;\n    case \"in\":\n      op = TailorDBGQLPermission_Operator.IN;\n      break;\n    case \"nin\":\n      op = TailorDBGQLPermission_Operator.NIN;\n      break;\n    case \"hasAny\":\n      op = TailorDBGQLPermission_Operator.HAS_ANY;\n      break;\n    case \"nhasAny\":\n      op = TailorDBGQLPermission_Operator.NHAS_ANY;\n      break;\n    default:\n      throw internalError(`Unknown operator: ${operator satisfies never}`);\n  }\n  return {\n    left: l,\n    operator: op,\n    right: r,\n  };\n}\n\nfunction protoGqlOperand(\n  operand: SnapshotPermissionOperand,\n): MessageInitShape<typeof TailorDBGQLPermission_OperandSchema> {\n  if (isSnapshotFieldRefOperand(operand)) {\n    if (\"user\" in operand) {\n      return { kind: { case: \"userField\", value: operand.user } };\n    }\n    throw CLIError({\n      code: \"TAILORDB_PERMISSION_OPERAND_UNSUPPORTED\",\n      message: `Unsupported field-ref operand in GQL permission: ${JSON.stringify(operand)}.`,\n      suggestion: \"GQL permissions only support { user } field references.\",\n    });\n  }\n\n  return {\n    kind: { case: \"value\", value: fromJson(ValueSchema, operand) },\n  };\n}\n","/**\n * Migration script bundler for TailorDB migrations\n *\n * Bundles migration scripts for server-side execution\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"pathe\";\nimport * as rolldown from \"rolldown\";\nimport { createBundleLog } from \"#/cli/shared/bundle-log\";\nimport { getDistDir } from \"#/cli/shared/dist-dir\";\nimport { platformBundleDefinePlugin } from \"#/cli/shared/platform-bundle-plugin\";\nimport { resolveTSConfigWithFallback } from \"#/cli/shared/resolve-tsconfig\";\nimport { createTsconfigPathsPlugin } from \"#/cli/shared/tsconfig-paths-plugin\";\nimport { createGeneratedEntryResolverPlugin } from \"#/cli/shared/virtual-entry\";\nimport ml from \"#/utils/multiline\";\n\nexport interface MigrationBundleResult {\n  namespace: string;\n  migrationNumber: number;\n  bundledCode: string;\n}\n\n/**\n * Bundle a single migration script\n *\n * Creates an entry that:\n * 1. Imports the migration script's main function\n * 2. Defines getDB() function inline\n * 3. Wraps migration in a transaction using getDB()\n * 4. Exports as main() for server-side execution\n * @param {string} sourceFile - Path to the migration script file\n * @param {string} namespace - TailorDB namespace\n * @param {number} migrationNumber - Migration number\n * @param {Record<string, string | number | boolean>} env - Environment variables to inject into the migration context\n * @param {string} [baseDir] - Directory to resolve the bundler's tsconfig against; defaults to the migration script's directory\n * @returns {Promise<MigrationBundleResult>} Bundled migration result\n */\nexport async function bundleMigrationScript(\n  sourceFile: string,\n  namespace: string,\n  migrationNumber: number,\n  env: Record<string, string | number | boolean> = {},\n  baseDir?: string,\n): Promise<MigrationBundleResult> {\n  // Output directory in .tailor (relative to project root)\n  const outputDir = path.resolve(getDistDir(), \"migrations\");\n  fs.mkdirSync(outputDir, { recursive: true });\n\n  // Entry file in output directory (consistent with resolver/executor bundlers)\n  const entryPath = path.join(outputDir, `migration_${namespace}_${migrationNumber}.entry.js`);\n\n  const absoluteSourcePath = path.resolve(sourceFile).replace(/\\\\/g, \"/\");\n\n  // Create entry file that wraps migration in a transaction\n  // getDB function is defined inline to avoid dependency on generated types\n  const entryContent = ml /* js */ `\n    import { main as _migrationMain } from \"${absoluteSourcePath}\";\n    import { Kysely, TailordbDialect } from \"@tailor-platform/sdk/kysely\";\n\n    function getDB(namespace) {\n      const client = new tailordb.Client({ namespace });\n      return new Kysely({\n        dialect: new TailordbDialect(client),\n      });\n    }\n\n    export async function main(input) {\n      const env = ${JSON.stringify(env)};\n      const db = getDB(\"${namespace}\");\n      await db.transaction().execute(async (trx) => {\n        await _migrationMain(trx, { env });\n      });\n      return { success: true };\n    }\n  `;\n  fs.writeFileSync(entryPath, entryContent);\n\n  const projectDir = baseDir ?? path.dirname(absoluteSourcePath);\n  const tsconfig = await resolveTSConfigWithFallback(projectDir);\n\n  // Bundle with tree-shaking (write: false to avoid unnecessary disk I/O)\n  const bundleLog = createBundleLog({ tsconfig });\n  const result = await rolldown.build({\n    plugins: [\n      createGeneratedEntryResolverPlugin(entryPath, projectDir),\n      createTsconfigPathsPlugin(),\n      platformBundleDefinePlugin,\n    ],\n    input: entryPath,\n    write: false,\n    output: {\n      format: \"esm\",\n      sourcemap: false,\n      minify: false,\n      codeSplitting: false,\n      globals: {\n        tailordb: \"tailordb\",\n      },\n    },\n    external: [\"tailordb\"],\n    resolve: {\n      conditionNames: [\"node\", \"import\"],\n    },\n    tsconfig,\n    treeshake: {\n      moduleSideEffects: false,\n      annotations: true,\n      unknownGlobalSideEffects: false,\n    },\n    ...bundleLog.options,\n  } as rolldown.BuildOptions);\n  bundleLog.assertAllResolved();\n\n  const bundledCode = result.output[0].code;\n\n  // Entry file remains in output directory (consistent with resolver/executor bundlers)\n\n  return {\n    namespace,\n    migrationNumber,\n    bundledCode,\n  };\n}\n","/**\n * Copyable command hints for migration remediation\n */\n\nimport { formatConfigArg } from \"#/cli/shared/args\";\nimport { formatCopyableCommand } from \"#/cli/shared/errors\";\nimport { formatMigrationNumber } from \"./migration-number\";\n\nexport interface MigrationScriptCommandOptions {\n  migrationNumber: number;\n  namespace: string;\n  /** Config path the current run used; omitted from the command when it resolves to the default */\n  configPath?: string;\n  /** Append `--no-script --reason` with a placeholder reason */\n  noScript?: boolean;\n}\n\n/**\n * Build the copyable `tailor tailordb migration script` command for\n * remediation hints, reproducing the current run's invocation context.\n * @param {MigrationScriptCommandOptions} options - Target migration and invocation context\n * @returns {string} Command line quoted for the current platform's shell\n */\nexport function formatMigrationScriptCommand(options: MigrationScriptCommandOptions): string {\n  const { migrationNumber, namespace, configPath, noScript } = options;\n  const argv = [\n    \"tailor\",\n    \"tailordb\",\n    \"migration\",\n    \"script\",\n    formatMigrationNumber(migrationNumber),\n    \"--namespace\",\n    namespace,\n  ];\n  const configArg = formatConfigArg(configPath);\n  if (configArg !== undefined) {\n    argv.push(configArg);\n  }\n  if (noScript) {\n    argv.push(\"--no-script\", \"--reason\", \"<reason>\");\n  }\n  return formatCopyableCommand(argv);\n}\n","import { renderFor } from \"@tailor-platform/shared/color\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { styles, symbols } from \"./logger\";\n\nconst FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\nconst FRAME_INTERVAL_MS = 80;\n\nconst CURSOR_HIDE = \"\\x1B[?25l\";\nconst CURSOR_SHOW = \"\\x1B[?25h\";\nconst CLEAR_LINE = \"\\x1B[2K\";\nconst CURSOR_TO_START = \"\\r\";\nconst CURSOR_UP = \"\\x1B[1A\";\n// DEC mode 2026: synchronized output. Brackets a frame redraw so supporting\n// terminals render the clear+rewrite atomically and avoid flicker on slow links.\nconst SYNC_BEGIN = \"\\x1B[?2026h\";\nconst SYNC_END = \"\\x1B[?2026l\";\n\n// eslint-disable-next-line no-control-regex -- ANSI escapes include ESC (U+001B) by definition\nconst ANSI_RE = /\\u001B\\[[0-9;]*[a-zA-Z]/g;\n\nfunction visibleLength(s: string): number {\n  return s.replace(ANSI_RE, \"\").length;\n}\n\nexport type SpinnerOptions = {\n  indent?: number;\n  stream?: NodeJS.WriteStream;\n};\n\nconst activeSpinners = new Set<Spinner>();\nlet exitHookInstalled = false;\nlet signalHookInstalled = false;\n\nfunction installExitHook(): void {\n  if (exitHookInstalled) return;\n  exitHookInstalled = true;\n  // Restore the terminal cursor when the process exits even if a spinner is still active\n  // (e.g. on Ctrl+C the SIGINT handler typically calls process.exit which fires this).\n  process.on(\"exit\", () => {\n    for (const s of activeSpinners) {\n      s.cleanupOnExit();\n    }\n  });\n}\n\nfunction installSignalHook(): void {\n  if (signalHookInstalled) return;\n  signalHookInstalled = true;\n  // Clear the spinner's drawn line on Ctrl+C so any subsequent stderr output\n  // (e.g. politty's \"✖ Process interrupted\") starts at column 0 on its own\n  // line instead of being appended after the spinner frame and the\n  // TTY-echoed \"^C\".\n  //\n  // We use prependListener so our handler runs before any pre-existing one.\n  // In particular, politty registers an async SIGINT handler whose body runs\n  // synchronously up to its first `await`, and that prefix calls\n  // `logger.error(\"Process interrupted\")`. If our handler were appended, the\n  // error message would already have been written to stderr — appended after\n  // the spinner frame on the same line — by the time we got control. Running\n  // first lets us tear down the spinner line cleanly first.\n  const handler = (): void => {\n    for (const s of activeSpinners) s.stop();\n  };\n  process.prependListener(\"SIGINT\", handler);\n  process.prependListener(\"SIGTERM\", handler);\n}\n\nexport class Spinner {\n  text: string;\n  readonly #indent: number;\n  readonly #stream: NodeJS.WriteStream;\n  readonly #isEnabled: boolean;\n  #frame = 0;\n  #timer?: NodeJS.Timeout;\n  #linesDrawn = 0;\n  #started = false;\n\n  constructor(options: SpinnerOptions = {}) {\n    this.text = \"\";\n    this.#indent = options.indent ?? 0;\n    this.#stream = options.stream ?? process.stderr;\n    this.#isEnabled = Boolean(this.#stream.isTTY);\n  }\n\n  start(text?: string): this {\n    if (text !== undefined) this.text = text;\n\n    if (!this.#isEnabled) {\n      this.#writeLine(`- ${this.text}`);\n      return this;\n    }\n\n    if (this.#started) {\n      // Already running; just update text. The next render frame will pick it up.\n      return this;\n    }\n\n    installExitHook();\n    installSignalHook();\n    activeSpinners.add(this);\n    this.#started = true;\n    this.#stream.write(CURSOR_HIDE);\n    this.#renderFrame();\n    this.#timer = setInterval(() => this.#renderFrame(), FRAME_INTERVAL_MS);\n    if (typeof this.#timer.unref === \"function\") this.#timer.unref();\n    return this;\n  }\n\n  stop(): this {\n    if (!this.#started) return this;\n    this.#started = false;\n    if (this.#timer) {\n      clearInterval(this.#timer);\n      this.#timer = undefined;\n    }\n    if (this.#isEnabled) {\n      this.#clearDrawn();\n      this.#stream.write(CURSOR_SHOW);\n    }\n    activeSpinners.delete(this);\n    return this;\n  }\n\n  succeed(text?: string): this {\n    return this.#stopAndPersist(symbols.success, text);\n  }\n\n  fail(text?: string): this {\n    return this.#stopAndPersist(symbols.error, text);\n  }\n\n  warn(text?: string): this {\n    return this.#stopAndPersist(symbols.warning, text);\n  }\n\n  /**\n   * Called by the global exit hook to restore the cursor.\n   * @internal\n   */\n  cleanupOnExit(): void {\n    if (this.#timer) {\n      clearInterval(this.#timer);\n      this.#timer = undefined;\n    }\n    if (this.#isEnabled) {\n      this.#stream.write(CURSOR_SHOW);\n    }\n  }\n\n  #stopAndPersist(symbol: string, text?: string): this {\n    if (text !== undefined) this.text = text;\n    if (this.#started) {\n      this.#started = false;\n      if (this.#timer) {\n        clearInterval(this.#timer);\n        this.#timer = undefined;\n      }\n      if (this.#isEnabled) {\n        this.#clearDrawn();\n        this.#stream.write(CURSOR_SHOW);\n      }\n      activeSpinners.delete(this);\n    }\n    this.#writeLine(`${symbol} ${this.text}`);\n    return this;\n  }\n\n  #renderFrame(): void {\n    this.#stream.write(SYNC_BEGIN);\n    this.#clearDrawn();\n    const frame = styles.info(\n      FRAMES[this.#frame] ?? assertDefined(FRAMES[0], \"spinner frames empty\"),\n    );\n    this.#frame = (this.#frame + 1) % FRAMES.length;\n    const indent = \" \".repeat(this.#indent);\n    const line = `${indent}${frame} ${this.text}`;\n    this.#stream.write(renderFor(this.#stream, line));\n    this.#stream.write(SYNC_END);\n    const cols = this.#stream.columns || 80;\n    this.#linesDrawn = Math.max(1, Math.ceil(visibleLength(line) / cols));\n  }\n\n  #clearDrawn(): void {\n    if (this.#linesDrawn === 0) return;\n    this.#stream.write(CURSOR_TO_START);\n    this.#stream.write(CLEAR_LINE);\n    for (let i = 1; i < this.#linesDrawn; i++) {\n      this.#stream.write(CURSOR_UP);\n      this.#stream.write(CLEAR_LINE);\n    }\n    this.#linesDrawn = 0;\n  }\n\n  #writeLine(content: string): void {\n    const indent = \" \".repeat(this.#indent);\n    this.#stream.write(renderFor(this.#stream, `${indent}${content}\\n`));\n  }\n}\n\n/**\n * Create a terminal spinner. Falls back to a single line write in non-TTY\n * environments so output stays useful in CI logs.\n * @param options - Spinner options\n * @returns A Spinner instance\n */\nexport function spinner(options?: SpinnerOptions): Spinner {\n  return new Spinner(options);\n}\n","/**\n * Migration execution via a temporary workflow\n *\n * Synchronous script execution is bound by the platform's 60s function\n * deadline. A migration is instead registered as a temporary workflow and\n * started asynchronously, so only the polling loop spans the migration's real\n * duration.\n *\n * The temporary function, job function, and workflow are removed once the\n * execution reaches a terminal state. Every resource is labeled with the app's\n * ownership immediately, so a run interrupted before teardown stays\n * attributable, and the next run of the same migration reclaims the leftovers\n * before recreating them.\n */\n\nimport * as crypto from \"node:crypto\";\nimport { WorkflowExecution_Status } from \"@tailor-platform/tailor-proto/workflow_resource_pb\";\nimport { formatMigrationNumber } from \"#/cli/commands/tailordb/migrate/snapshot\";\nimport { isNotFoundError } from \"#/cli/shared/client\";\nimport { CLIError, internalError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { buildMetaRequest, resourceTrn, writeMetadataLabelsDirect } from \"../label\";\nimport type { OperatorClient } from \"#/cli/shared/client\";\nimport type { MessageInitShape } from \"@bufbuild/protobuf\";\nimport type { AuthInvoker } from \"@tailor-platform/tailor-proto/auth_resource_pb\";\nimport type { CreateFunctionRegistryRequestSchema } from \"@tailor-platform/tailor-proto/function_registry_pb\";\nimport type { WorkflowExecution } from \"@tailor-platform/tailor-proto/workflow_resource_pb\";\n\nconst CHUNK_SIZE = 64 * 1024;\n\n/** Poll interval while waiting for the migration workflow to finish. */\nconst POLL_INTERVAL_MS = 3000;\n\nexport interface LongRunningMigrationOptions {\n  client: OperatorClient;\n  workspaceId: string;\n  /** Bundled migration script exporting `main`. */\n  code: string;\n  namespace: string;\n  migrationNumber: number;\n  invoker: AuthInvoker;\n  appName: string;\n  appId: string | undefined;\n  pollIntervalMs?: number;\n}\n\nexport interface LongRunningMigrationResult {\n  success: boolean;\n  logs: string;\n  error?: string;\n}\n\n/**\n * Build the shared resource name for a migration's temporary workflow resources.\n * The name is stable per migration so a retry reclaims an interrupted run's\n * leftovers rather than duplicating them.\n * @param namespace - TailorDB namespace\n * @param migrationNumber - Migration number\n * @returns Resource name\n */\nexport function migrationWorkflowResourceName(namespace: string, migrationNumber: number): string {\n  return `tailordb-migration--${namespace}--${formatMigrationNumber(migrationNumber)}`;\n}\n\n/**\n * Upload the bundled migration script to the function registry.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param name - Function registry name\n * @param code - Bundled script content\n * @param appName - Owning application name for the resource's labels\n * @param appId - Owning application id, when known\n */\nasync function uploadMigrationFunction(\n  client: OperatorClient,\n  workspaceId: string,\n  name: string,\n  code: string,\n  appName: string,\n  appId: string | undefined,\n): Promise<void> {\n  const buffer = Buffer.from(code, \"utf-8\");\n  const info = {\n    workspaceId,\n    name,\n    description: \"Temporary function for a TailorDB migration\",\n    sizeBytes: BigInt(buffer.length),\n    contentHash: crypto.createHash(\"sha256\").update(code, \"utf-8\").digest(\"hex\"),\n  };\n\n  /** @yields {MessageInitShape<typeof CreateFunctionRegistryRequestSchema>} Info header followed by content chunks */\n  async function* stream(): AsyncIterable<\n    MessageInitShape<typeof CreateFunctionRegistryRequestSchema>\n  > {\n    yield { payload: { case: \"info\" as const, value: info } };\n    for (let i = 0; i < buffer.length; i += CHUNK_SIZE) {\n      yield {\n        payload: {\n          case: \"chunk\" as const,\n          value: buffer.subarray(i, Math.min(i + CHUNK_SIZE, buffer.length)),\n        },\n      };\n    }\n  }\n\n  await client.createFunctionRegistry(stream());\n  await writeMetadataLabelsDirect(\n    client,\n    await buildMetaRequest({\n      trn: resourceTrn(workspaceId, \"function_registry\", name),\n      appName,\n      appId,\n    }),\n  );\n}\n\n/**\n * Remove the temporary resources created for a migration.\n *\n * Teardown is best effort: a failure here must not mask the migration's own\n * outcome, so every removal is attempted and an unexpected failure is reported\n * as a warning rather than raised.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param name - Shared resource name\n * @param workflowId - Created workflow id, when it was created\n */\nasync function teardown(\n  client: OperatorClient,\n  workspaceId: string,\n  name: string,\n  workflowId: string | undefined,\n): Promise<void> {\n  const steps: [string, () => Promise<unknown>][] = [\n    ...(workflowId\n      ? ([[\"workflow\", () => client.deleteWorkflow({ workspaceId, workflowId })]] as [\n          string,\n          () => Promise<unknown>,\n        ][])\n      : []),\n    [\n      \"job function\",\n      () => client.deleteWorkflowJobFunction({ workspaceId, jobFunctionName: name }),\n    ],\n    [\"function\", () => client.deleteFunctionRegistry({ workspaceId, name })],\n  ];\n\n  for (const [label, run] of steps) {\n    try {\n      await run();\n    } catch (error) {\n      // An already-absent resource means teardown's goal is met; anything else\n      // leaves a resource behind and has to stay diagnosable.\n      if (isNotFoundError(error)) continue;\n      logger.warn(\n        `Could not remove the temporary migration ${label} '${name}': ` +\n          `${error instanceof Error ? error.message : String(error)}. ` +\n          \"It is labeled as owned by this app and can be removed by a later deploy.\",\n      );\n    }\n  }\n}\n\n/**\n * Remove any leftovers from an earlier interrupted run of this migration.\n *\n * The resource name is stable per migration and `createFunctionRegistry` is\n * create-only, so a retry would otherwise fail on a name collision. Deleting\n * first makes the create path idempotent across retries.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param name - Shared resource name\n */\nasync function reclaimLeftovers(\n  client: OperatorClient,\n  workspaceId: string,\n  name: string,\n): Promise<void> {\n  const workflowId = await findMigrationWorkflowId(client, workspaceId, name);\n  await teardown(client, workspaceId, name, workflowId);\n}\n\n/**\n * Find the temporary workflow created for this migration, if it still exists.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param name - Shared resource name\n * @returns Workflow id, or undefined when no such workflow exists\n */\nasync function findMigrationWorkflowId(\n  client: OperatorClient,\n  workspaceId: string,\n  name: string,\n): Promise<string | undefined> {\n  try {\n    const { workflow } = await client.getWorkflowByName({ workspaceId, workflowName: name });\n    return workflow?.id;\n  } catch (error) {\n    if (isNotFoundError(error)) return undefined;\n    throw error;\n  }\n}\n\n/**\n * Execute a migration script as a temporary workflow and wait for completion.\n *\n * Unlike synchronous script execution, only the start call is bound by the\n * request deadline; the migration itself runs as a workflow job.\n * @param {LongRunningMigrationOptions} options - Execution options\n * @returns {Promise<LongRunningMigrationResult>} Execution result\n */\nexport async function executeMigrationAsWorkflow(\n  options: LongRunningMigrationOptions,\n): Promise<LongRunningMigrationResult> {\n  const { client, workspaceId, code, namespace, migrationNumber, invoker, appName, appId } =\n    options;\n  const name = migrationWorkflowResourceName(namespace, migrationNumber);\n  const pollInterval = options.pollIntervalMs ?? POLL_INTERVAL_MS;\n\n  let workflowId: string | undefined;\n  try {\n    await reclaimLeftovers(client, workspaceId, name);\n    await uploadMigrationFunction(client, workspaceId, name, code, appName, appId);\n\n    const { jobFunction } = await client.createWorkflowJobFunction({\n      workspaceId,\n      jobFunctionName: name,\n      scriptRef: name,\n      publishExecutionEvents: false,\n    });\n    await writeMetadataLabelsDirect(\n      client,\n      await buildMetaRequest({\n        trn: resourceTrn(workspaceId, \"workflow_job_function\", name),\n        appName,\n        appId,\n      }),\n    );\n\n    const version = jobFunction?.version;\n    if (version === undefined) {\n      throw internalError(\n        `Temporary migration job function '${name}' was created without a version.`,\n      );\n    }\n\n    const { workflow } = await client.createWorkflow({\n      workspaceId,\n      workflowName: name,\n      mainJobFunctionName: name,\n      jobFunctions: { [name]: version },\n    });\n    workflowId = workflow?.id;\n    if (!workflowId) {\n      throw internalError(`Temporary migration workflow '${name}' was created without an id.`);\n    }\n    await writeMetadataLabelsDirect(\n      client,\n      await buildMetaRequest({\n        trn: resourceTrn(workspaceId, \"workflow\", name),\n        appName,\n        appId,\n      }),\n    );\n\n    const { executionId } = await client.startWorkflow({\n      workspaceId,\n      workflowId,\n      authInvoker: invoker,\n    });\n\n    return await waitForMigrationWorkflow(client, workspaceId, executionId, pollInterval);\n  } finally {\n    await teardown(client, workspaceId, name, workflowId);\n  }\n}\n\n/**\n * Poll a migration workflow execution until it reaches a terminal state.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param executionId - Workflow execution id\n * @param pollInterval - Poll interval in milliseconds\n * @returns Execution result\n */\nasync function waitForMigrationWorkflow(\n  client: OperatorClient,\n  workspaceId: string,\n  executionId: string,\n  pollInterval: number,\n): Promise<LongRunningMigrationResult> {\n  // loop exits when the workflow execution reaches a terminal status\n  // oxlint-disable-next-line typescript/no-unnecessary-condition\n  while (true) {\n    const { execution } = await client.getWorkflowExecution({\n      workspaceId,\n      executionId,\n    });\n    if (!execution) {\n      throw CLIError({\n        code: \"WORKFLOW_EXECUTION_NOT_FOUND\",\n        message: `Migration workflow execution '${executionId}' not found.`,\n      });\n    }\n\n    if (execution.status === WorkflowExecution_Status.SUCCESS) {\n      const { logs } = await collectJobOutcomes(client, workspaceId, execution);\n      return { success: true, logs };\n    }\n    if (execution.status === WorkflowExecution_Status.FAILED) {\n      const outcomes = await collectJobOutcomes(client, workspaceId, execution);\n      return {\n        success: false,\n        logs: outcomes.logs,\n        error: extractFailureMessage(outcomes),\n      };\n    }\n\n    await new Promise((resolve) => setTimeout(resolve, pollInterval));\n  }\n}\n\n/**\n * Collect the logs and failure reasons of every job in a workflow execution.\n *\n * Workflow executions carry neither logs nor the error a job threw; both live\n * on the job's corresponding function execution.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param execution - Workflow execution to read jobs from\n * @returns Concatenated job logs and the reasons the jobs failed\n */\nasync function collectJobOutcomes(\n  client: OperatorClient,\n  workspaceId: string,\n  execution: WorkflowExecution,\n): Promise<{ logs: string; failures: string[] }> {\n  const outcomes = await Promise.all(\n    execution.jobExecutions.map(async (job) => {\n      if (!job.executionId) return undefined;\n      try {\n        const { execution: functionExecution } = await client.getFunctionExecution({\n          workspaceId,\n          executionId: job.executionId,\n        });\n        if (!functionExecution) return undefined;\n        // The script's own error is reported as structured error info, or as\n        // the execution result; logs only carry what the script printed.\n        const failure =\n          functionExecution.error?.message.trim() || functionExecution.result.trim() || \"\";\n        return { logs: functionExecution.logs, failure };\n      } catch {\n        return undefined;\n      }\n    }),\n  );\n\n  return {\n    logs: outcomes\n      .map((outcome) => outcome?.logs)\n      .filter(Boolean)\n      .join(\"\\n\"),\n    failures: outcomes\n      .map((outcome) => outcome?.failure)\n      .filter((failure): failure is string => !!failure),\n  };\n}\n\n/**\n * Derive a failure message from the jobs' failure reasons, falling back to the\n * last log line mentioning an error and then to a generic message.\n * @param outcomes - Collected job logs and failure reasons\n * @returns Failure message\n */\nfunction extractFailureMessage(outcomes: { logs: string; failures: string[] }): string {\n  const failure = outcomes.failures.at(-1);\n  if (failure) return failure;\n\n  const lastErrorLine = outcomes.logs\n    .split(\"\\n\")\n    .filter((line) => /error/i.test(line))\n    .at(-1);\n  return lastErrorLine?.trim() || \"Migration workflow execution failed.\";\n}\n","/**\n * Migration execution service for TailorDB migrations\n *\n * Handles detection and execution of pending migration scripts. Every migration\n * runs as a temporary workflow job so its duration is not bound by the\n * synchronous function-execution deadline.\n */\n\nimport * as fs from \"node:fs\";\nimport { create } from \"@bufbuild/protobuf\";\nimport {\n  AuthInvokerSchema,\n  type AuthInvoker,\n} from \"@tailor-platform/tailor-proto/auth_resource_pb\";\nimport { bundleMigrationScript } from \"#/cli/commands/tailordb/migrate/bundler\";\nimport { type NamespaceWithMigrations } from \"#/cli/commands/tailordb/migrate/config\";\nimport { formatMigrationScriptCommand } from \"#/cli/commands/tailordb/migrate/hints\";\nimport {\n  loadDiff,\n  getMigrationFiles,\n  getMigrationFilePath,\n  formatMigrationNumber,\n} from \"#/cli/commands/tailordb/migrate/snapshot\";\nimport {\n  type PendingMigration,\n  MIGRATION_HISTORY_LABEL_KEY,\n  MIGRATION_LABEL_KEY,\n  parseMigrationLabelNumber,\n  sanitizeMigrationLabel,\n} from \"#/cli/commands/tailordb/migrate/types\";\nimport { isNotFoundError, type OperatorClient } from \"#/cli/shared/client\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger, styles } from \"#/cli/shared/logger\";\nimport { spinner } from \"#/cli/shared/spinner\";\nimport { resourceTrn, writeMetadataLabelsDirect } from \"../label\";\nimport { executeMigrationAsWorkflow } from \"./migration-workflow\";\nimport type { TailorDBServiceConfig } from \"#/types/tailordb.generated\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\ninterface MigrationExecutionOptions {\n  client: OperatorClient;\n  workspaceId: string;\n  invoker: AuthInvoker;\n  env: Record<string, string | number | boolean>;\n  configDir: string;\n  appName: string;\n  appId: string | undefined;\n}\n\n/**\n * Context for migration execution with per-namespace configuration\n */\nexport interface MigrationContext {\n  client: OperatorClient;\n  workspaceId: string;\n  authNamespace: string;\n  machineUsers: string[] | undefined;\n  dbConfig: Record<string, TailorDBServiceConfig | undefined>;\n  env: Record<string, string | number | boolean>;\n  configDir: string;\n  /** Application name, used to label a migration's temporary resources. */\n  appName: string;\n  /** Application id, used to label a migration's temporary resources. */\n  appId: string | undefined;\n}\n\ninterface ExecutionResult {\n  namespace: string;\n  migrationNumber: number;\n  success: boolean;\n  logs?: string;\n  error?: string;\n}\n\n// ============================================================================\n// Migration Detection\n// ============================================================================\n\n/**\n * Get the current migration label from TailorDB Service metadata\n * @param {OperatorClient} client - Operator client instance\n * @param {string} workspaceId - Workspace ID\n * @param {string} namespace - TailorDB namespace\n * @returns {Promise<number>} Current migration number (0 if none)\n */\nasync function getCurrentMigrationNumber(\n  client: OperatorClient,\n  workspaceId: string,\n  namespace: string,\n): Promise<number> {\n  try {\n    const trn = resourceTrn(workspaceId, \"tailordb\", namespace);\n\n    const { metadata } = await client.getMetadata({ trn });\n\n    const label = metadata?.labels[MIGRATION_LABEL_KEY];\n\n    if (!label) {\n      return 0;\n    }\n    const num = parseMigrationLabelNumber(label);\n    return num ?? 0;\n  } catch (error) {\n    if (isNotFoundError(error)) {\n      return 0;\n    }\n    throw error;\n  }\n}\n\n/**\n * Detect pending migrations that need to be executed\n * @param {OperatorClient} client - Operator client instance\n * @param {string} workspaceId - Workspace ID\n * @param {NamespaceWithMigrations[]} namespacesWithMigrations - Namespaces with migrations config\n * @param {string} [configPath] - Config file path, included in remediation guidance when provided\n * @param {ReadonlyMap<string, number>} [currentMigrationOverrides] - Confirmed current migration numbers to use instead of remote metadata\n * @returns {Promise<PendingMigration[]>} List of pending migrations\n */\nexport async function detectPendingMigrations(\n  client: OperatorClient,\n  workspaceId: string,\n  namespacesWithMigrations: NamespaceWithMigrations[],\n  configPath?: string,\n  currentMigrationOverrides?: ReadonlyMap<string, number>,\n): Promise<PendingMigration[]> {\n  const pendingMigrations: PendingMigration[] = [];\n\n  for (const { namespace, migrationsDir } of namespacesWithMigrations) {\n    // Get current applied migration number\n    const currentMigration =\n      currentMigrationOverrides?.get(namespace) ??\n      (await getCurrentMigrationNumber(client, workspaceId, namespace));\n\n    // Get all migration files\n    const migrationFiles = getMigrationFiles(migrationsDir);\n\n    // Find migrations that haven't been applied yet\n    for (const file of migrationFiles) {\n      if (file.number <= currentMigration) {\n        continue;\n      }\n\n      // Check for diff file (all migrations must have a diff)\n      const diffPath = getMigrationFilePath(migrationsDir, file.number, \"diff\");\n      if (!fs.existsSync(diffPath)) {\n        continue;\n      }\n\n      // Load the diff to inspect breaking/warning classification\n      const diff = loadDiff(diffPath);\n\n      // The migration script is executed when migrate.ts exists on disk.\n      // Breaking changes hard-require a script unless the user recorded an\n      // explicit skip acknowledgment; warnings (e.g. field_removed) may\n      // optionally have one added via `tailordb migration script <num>`.\n      const scriptPath = getMigrationFilePath(migrationsDir, file.number, \"migrate\");\n      const hasScript = fs.existsSync(scriptPath);\n      if (diff.requiresMigrationScript && !hasScript && !diff.scriptSkipped) {\n        const commandOptions = { migrationNumber: file.number, namespace, configPath };\n        throw CLIError({\n          code: \"MIGRATION_SCRIPT_REQUIRED\",\n          message: `Migration ${namespace}/${formatMigrationNumber(file.number)} requires a migration script but migrate.ts was not found.`,\n          suggestion: `Add a script: ${formatMigrationScriptCommand(commandOptions)}\\nOr record that no script is needed: ${formatMigrationScriptCommand({ ...commandOptions, noScript: true })}`,\n        });\n      }\n      if (diff.scriptSkipped) {\n        const migrationLabel = `${namespace}/${formatMigrationNumber(file.number)}`;\n        if (hasScript) {\n          throw CLIError({\n            code: \"MIGRATION_SCRIPT_SKIP_CONFLICT\",\n            message: `Migration ${migrationLabel} has both a --no-script skip acknowledgment and migrate.ts.`,\n            suggestion: `Keep the script and clear the stale acknowledgment: ${formatMigrationScriptCommand({ migrationNumber: file.number, namespace, configPath })}\\nOr keep the skip: delete migrate.ts`,\n          });\n        }\n        logger.info(\n          `Migration ${migrationLabel} runs without a script (skip acknowledged at ${diff.scriptSkipped.acknowledgedAt}: ${diff.scriptSkipped.reason})`,\n        );\n      }\n\n      pendingMigrations.push({\n        number: file.number,\n        scriptPath,\n        hasScript,\n        diffPath,\n        namespace,\n        migrationsDir,\n        diff,\n      });\n    }\n  }\n\n  // Sort by namespace and migration number\n  return pendingMigrations.toSorted((a, b) => {\n    if (a.namespace !== b.namespace) {\n      return a.namespace.localeCompare(b.namespace);\n    }\n    return a.number - b.number;\n  });\n}\n\n// ============================================================================\n// Migration Execution\n// ============================================================================\n\n/**\n * Execute a single migration script\n * @param {MigrationExecutionOptions} options - Execution options\n * @param {PendingMigration} migration - Migration to execute\n * @returns {Promise<ExecutionResult>} Execution result\n */\nasync function executeSingleMigration(\n  options: MigrationExecutionOptions,\n  migration: PendingMigration,\n): Promise<ExecutionResult> {\n  const { client, workspaceId, invoker, env, configDir, appName, appId } = options;\n\n  // Bundle the migration script\n  const bundleResult = await bundleMigrationScript(\n    migration.scriptPath,\n    migration.namespace,\n    migration.number,\n    env,\n    configDir,\n  );\n\n  const result = await executeMigrationAsWorkflow({\n    client,\n    workspaceId,\n    code: bundleResult.bundledCode,\n    namespace: migration.namespace,\n    migrationNumber: migration.number,\n    invoker,\n    appName,\n    appId,\n  });\n\n  return {\n    namespace: migration.namespace,\n    migrationNumber: migration.number,\n    success: result.success,\n    logs: result.logs,\n    error: result.error,\n  };\n}\n\n/**\n * Update the migration label on TailorDB Service metadata\n * @param {OperatorClient} client - Operator client instance\n * @param {string} workspaceId - Workspace ID\n * @param {string} namespace - TailorDB namespace\n * @param {number} migrationNumber - Migration number to set\n * @param historyId - Optional migration history ID to set atomically with the checkpoint\n * @returns {Promise<void>}\n */\nexport async function updateMigrationLabel(\n  client: OperatorClient,\n  workspaceId: string,\n  namespace: string,\n  migrationNumber: number,\n  historyId?: string,\n): Promise<void> {\n  const trn = resourceTrn(workspaceId, \"tailordb\", namespace);\n\n  await writeMetadataLabelsDirect(client, {\n    trn,\n    labels: {\n      [MIGRATION_LABEL_KEY]: sanitizeMigrationLabel(migrationNumber),\n      ...(historyId ? { [MIGRATION_HISTORY_LABEL_KEY]: historyId } : {}),\n    },\n    remove: historyId ? undefined : [MIGRATION_HISTORY_LABEL_KEY],\n  });\n}\n\n/**\n * Execute all pending migrations, grouping by namespace and using appropriate machine user\n * @param {MigrationContext} context - Migration context with per-namespace configuration\n * @param {PendingMigration[]} migrations - Migrations to execute\n * @returns {Promise<void>}\n */\nexport async function executeMigrations(\n  context: MigrationContext,\n  migrations: PendingMigration[],\n): Promise<void> {\n  // Run migrate.ts whenever the file exists on disk. Required for breaking changes,\n  // optional for warning-tier changes (e.g. field_removed).\n  const migrationsWithScripts = migrations.filter((m) => m.hasScript);\n\n  if (migrationsWithScripts.length === 0) {\n    return;\n  }\n\n  // Group migrations by namespace\n  const migrationsByNamespace = groupMigrationsByNamespace(migrationsWithScripts);\n\n  // Execute migrations for each namespace with appropriate machine user\n  for (const [namespace, namespaceMigrations] of migrationsByNamespace) {\n    const dbConfig = context.dbConfig[namespace];\n    const migrationConfig = dbConfig?.migration;\n\n    // Get machine user name for this namespace\n    const machineUserName = getMigrationMachineUser(migrationConfig, context.machineUsers);\n    if (!machineUserName) {\n      throw CLIError({\n        code: \"MACHINE_USER_REQUIRED\",\n        message: `No machine user available for migration execution in namespace '${namespace}'.`,\n        suggestion:\n          \"Either configure 'migration.machineUser' in db config or define machine users in auth config.\",\n      });\n    }\n\n    const invoker = create(AuthInvokerSchema, {\n      namespace: context.authNamespace,\n      machineUserName,\n    });\n\n    const options: MigrationExecutionOptions = {\n      client: context.client,\n      workspaceId: context.workspaceId,\n      invoker,\n      env: context.env,\n      configDir: context.configDir,\n      appName: context.appName,\n      appId: context.appId,\n    };\n\n    logger.info(`Using machine user: ${styles.bold(machineUserName)} for namespace '${namespace}'`);\n\n    for (const migration of namespaceMigrations) {\n      const migrationLabel = `${migration.namespace}/${formatMigrationNumber(migration.number)}`;\n      const sp = spinner().start(\n        `Executing migration ${migrationLabel} (this can take a while)...`,\n      );\n\n      const result = await executeSingleMigration(options, migration);\n\n      if (result.success) {\n        sp.succeed(`Migration ${migrationLabel} completed successfully`);\n\n        // Show logs if any\n        if (result.logs && result.logs.trim()) {\n          logger.log(`Logs:\\n${result.logs}`);\n        }\n      } else {\n        sp.fail(`Migration ${migrationLabel} failed`);\n        if (result.logs) {\n          logger.error(`Logs:\\n${result.logs}`);\n        }\n        throw CLIError({ code: \"MIGRATION_FAILED\", message: result.error ?? \"Migration failed\" });\n      }\n    }\n  }\n}\n\n/**\n * Get the machine user name for migration execution\n *\n * Priority:\n * 1. machineUser from migration config (if set)\n * 2. First machine user from auth config\n * @param {object | undefined} migrationConfig - Migration config for namespace\n * @param {string[] | undefined} machineUsers - Machine users from auth config\n * @returns {string | undefined} Machine user name or undefined if none available\n */\nexport function getMigrationMachineUser(\n  migrationConfig: { machineUser?: string } | undefined,\n  machineUsers: string[] | undefined,\n): string | undefined {\n  // Priority 1: Explicit config\n  if (migrationConfig?.machineUser) {\n    return migrationConfig.machineUser;\n  }\n\n  // Priority 2: First machine user from auth\n  if (machineUsers && machineUsers.length > 0) {\n    return machineUsers[0];\n  }\n\n  return undefined;\n}\n\n/**\n * Group migrations by namespace\n * @param {PendingMigration[]} migrations - Migrations to group\n * @returns {Map<string, PendingMigration[]>} Migrations grouped by namespace\n */\nexport function groupMigrationsByNamespace(\n  migrations: PendingMigration[],\n): Map<string, PendingMigration[]> {\n  const grouped = new Map<string, PendingMigration[]>();\n  for (const migration of migrations) {\n    const existing = grouped.get(migration.namespace) ?? [];\n    existing.push(migration);\n    grouped.set(migration.namespace, existing);\n  }\n  return grouped;\n}\n","/**\n * Pre-migration field config adjustments\n *\n * The Pre-phase sends a \"relaxed\" version of the target schema so that\n * `migrate.ts` scripts can still operate on the previous shape of the data.\n * This module handles the field-level adjustments:\n *\n * - `field_removed`: re-insert the removed field so migrate.ts can read it\n *   (the physical drop happens in Post-phase).\n * - `field_added` with `required: true`: relax to `required: false`.\n * - `field_modified` optional→required, unique constraint added, enum\n *   value removed: keep the looser side until Post-phase. Members removed\n *   from a nested field are re-inserted so migrate.ts can read them, and the\n *   new member of a confirmed nested rename is relaxed to optional until the\n *   copy script has filled it.\n * - `field_renamed`: keep the old field (readable by migrate.ts) and relax\n *   the new field's required/unique constraints until Post-phase.\n * - `field_type_modified`: keep the complete previous field config until\n *   Post-phase so migrate.ts runs against the previous type contract.\n *\n * and the table-level index adjustments:\n *\n * - `index_added` with `unique: true`: withhold the index until Post-phase.\n * - `index_modified` that gains a unique constraint or re-points a unique\n *   index at different fields: keep the previous definition until Post-phase.\n *\n * Table-level deletions (`table_removed`) and renames (`table_renamed`) are\n * handled by the deploy flow rather than via this module: the old table is\n * retained until Post-phase, and a renamed table's new table is created with\n * its full constraints in the Pre-phase (the copy script writes complete\n * rows, so nothing needs relaxing).\n *\n * Post-phase then sends the final schema, after migrate.ts has had a chance\n * to fix up data.\n */\n\nimport { assertDefined } from \"#/utils/assert\";\nimport { collectNestedMemberChanges } from \"./nested-members\";\nimport { isBreakingIndexChange } from \"./snapshot\";\nimport {\n  convertFieldConfigToProto,\n  convertIndexToProto,\n  processNestedFieldsFromSnapshot,\n} from \"./snapshot-manifest\";\nimport type {\n  DiffChange,\n  FieldDiffChange,\n  FieldModifiedChange,\n  IndexDiffChange,\n  MigrationDiff,\n  NestedMemberRename,\n  TableScriptsModifiedChange,\n} from \"./diff-calculator\";\nimport type {\n  SnapshotFieldConfig,\n  SnapshotIndexConfig,\n  TailorDBSnapshotType,\n} from \"./snapshot-types\";\nimport type { PendingMigration } from \"./types\";\nimport type { MessageInitShape } from \"@bufbuild/protobuf\";\nimport type {\n  TailorDBType_FieldConfigSchema,\n  TailorDBType_IndexSchema,\n} from \"@tailor-platform/tailor-proto/tailordb_resource_pb\";\n\nfunction defineRecordEntry<T>(record: Record<string, T>, key: string, value: T): void {\n  Object.defineProperty(record, key, {\n    value,\n    enumerable: true,\n    writable: true,\n    configurable: true,\n  });\n}\n\n/**\n * Diff change kinds that require pre-migration schema adjustments.\n */\nconst PRE_MIGRATION_FIELD_KINDS = new Set<DiffChange[\"kind\"]>([\n  \"field_added\",\n  \"field_modified\",\n  \"field_type_modified\",\n  \"field_removed\",\n  \"field_renamed\",\n]);\n\n/**\n * Type guard: is the change a field-level change that needs pre-migration\n * schema adjustment?\n * @param {DiffChange} change - Diff change to test\n * @returns {boolean} True if the change is a field-level change\n */\nfunction isPreMigrationFieldChange(change: DiffChange): change is FieldDiffChange {\n  return PRE_MIGRATION_FIELD_KINDS.has(change.kind);\n}\n\n/**\n * Map of pre-migration field changes: tableName -> fieldName -> change.\n *\n * Includes both breaking changes (required-add, unique-add, enum value\n * removal) and warning changes (field_removed). The Pre-phase needs to\n * adjust the schema for both so that migrate.ts can still see the previous\n * shape.\n */\nexport type PreMigrationChangesMap = Map<string, Map<string, FieldDiffChange>>;\n\n/**\n * Create the table snapshot used to build a Pre-phase manifest.\n *\n * This adjustment happens before manifest generation because field hooks and\n * validators are aggregated into table-level scripts by the manifest builder.\n * Replacing only the generated field proto would leave those scripts on the\n * target field contract while migrate.ts still runs against the previous one.\n * @param snapshotType - Final snapshot state for this migration\n * @param typeChanges - Field changes for this table, keyed by field name\n * @param typeScriptsChange - Table-level scripts changed by the same migration\n * @returns A snapshot with Pre-phase field contracts\n */\nexport function createPreMigrationSnapshotType(\n  snapshotType: TailorDBSnapshotType,\n  typeChanges: Map<string, FieldDiffChange>,\n  typeScriptsChange?: TableScriptsModifiedChange,\n): TailorDBSnapshotType {\n  const fields = structuredClone(snapshotType.fields);\n  let hasFieldTypeChange = false;\n\n  for (const [fieldName, change] of typeChanges) {\n    if (change.kind !== \"field_type_modified\") continue;\n    hasFieldTypeChange = true;\n    defineRecordEntry(fields, fieldName, structuredClone(change.before));\n  }\n\n  const preSnapshotType = { ...snapshotType, fields };\n  if (!hasFieldTypeChange || !typeScriptsChange) return preSnapshotType;\n\n  const {\n    typeHookExpr: _targetHook,\n    typeValidateExpr: _targetValidate,\n    ...withoutTypeScripts\n  } = preSnapshotType;\n  return {\n    ...withoutTypeScripts,\n    ...(typeScriptsChange.before.typeHookExpr && {\n      typeHookExpr: structuredClone(typeScriptsChange.before.typeHookExpr),\n    }),\n    ...(typeScriptsChange.before.typeValidateExpr !== undefined && {\n      typeValidateExpr: typeScriptsChange.before.typeValidateExpr,\n    }),\n  };\n}\n\n/**\n * Build a map of field changes that require pre-migration schema adjustment.\n * @param {PendingMigration[]} pendingMigrations - Pending migrations to scan\n * @returns {PreMigrationChangesMap} Map of changes keyed by tableName/fieldName\n */\nexport function buildPreMigrationChangesMap(\n  pendingMigrations: PendingMigration[],\n): PreMigrationChangesMap {\n  return buildPreMigrationChangesMapFromDiffs(pendingMigrations.map((m) => m.diff));\n}\n\n/**\n * {@link buildPreMigrationChangesMap} over the diffs themselves.\n * @param diffs - Migration diffs to scan\n * @returns Map of changes keyed by tableName/fieldName\n */\nexport function buildPreMigrationChangesMapFromDiffs(\n  diffs: readonly MigrationDiff[],\n): PreMigrationChangesMap {\n  const map: PreMigrationChangesMap = new Map();\n  for (const diff of diffs) {\n    for (const change of diff.changes) {\n      if (!isPreMigrationFieldChange(change)) continue;\n      if (!change.fieldName) continue;\n      const perType = map.get(change.tableName) ?? new Map<string, FieldDiffChange>();\n      perType.set(change.fieldName, change);\n      map.set(change.tableName, perType);\n    }\n  }\n  return map;\n}\n\n/**\n * Apply pre-migration schema adjustments to a single field map in place.\n *\n * The fields map is the proto-shape `TailorDBType.schema.fields` that will\n * be sent in the Pre-phase. We mutate it so that:\n *\n * - Removed fields are re-inserted using their pre-migration config.\n * - Newly added required fields are relaxed to optional.\n * - Modified fields keep the looser side of unique/required/enum, members\n *   removed from a nested field are re-inserted, and the new member of a\n *   confirmed nested rename is relaxed to optional.\n *\n * @param {Record<string, MessageInitShape<typeof TailorDBType_FieldConfigSchema>>} fields - Field map to adjust (mutated in place)\n * @param {Map<string, FieldDiffChange>} typeChanges - Changes for this table, keyed by fieldName\n */\nexport function applyPreMigrationFieldAdjustments(\n  fields: Record<string, MessageInitShape<typeof TailorDBType_FieldConfigSchema>>,\n  typeChanges: Map<string, FieldDiffChange>,\n): void {\n  relaxFieldsForPreMigration(fields, typeChanges, {\n    toField: convertFieldConfigToProto,\n    adjustNestedMembers: (field, change) => {\n      restoreRemovedNestedMembers(field, change.before, change.after);\n      relaxRenamedNestedMembers(field, change.memberRenames ?? []);\n    },\n  });\n}\n\n/**\n * {@link applyPreMigrationFieldAdjustments} on snapshot-shaped fields, for\n * describing the Pre-phase schema outside a deploy. Nested members are left\n * as the target declares them: the snapshot consumers read a nested field as\n * one value.\n * @param fields - Snapshot field map to adjust (mutated in place)\n * @param typeChanges - Changes for this table, keyed by fieldName\n */\nexport function applyPreMigrationFieldAdjustmentsToSnapshot(\n  fields: Record<string, SnapshotFieldConfig>,\n  typeChanges: Map<string, FieldDiffChange>,\n): void {\n  relaxFieldsForPreMigration(fields, typeChanges, {\n    toField: (config) => structuredClone(config),\n  });\n}\n\n/** The properties the Pre-phase relaxes, shared by the proto and snapshot field shapes. */\ninterface PreMigrationField {\n  required?: boolean;\n  unique?: boolean;\n  allowedValues?: { value?: string; description?: string }[];\n}\n\ninterface PreMigrationFieldStrategy<F extends PreMigrationField> {\n  /** Build the field to re-insert from its snapshot config. */\n  toField: (config: SnapshotFieldConfig) => F;\n  /** Apply nested-member relaxations to a modified field. */\n  adjustNestedMembers?: (field: F, change: FieldModifiedChange) => void;\n}\n\nfunction relaxFieldsForPreMigration<F extends PreMigrationField>(\n  fields: Record<string, F>,\n  typeChanges: Map<string, FieldDiffChange>,\n  strategy: PreMigrationFieldStrategy<F>,\n): void {\n  for (const [fieldName, change] of typeChanges) {\n    if (change.kind === \"field_removed\") {\n      defineRecordEntry(fields, fieldName, strategy.toField(change.before));\n      continue;\n    }\n\n    if (change.kind === \"field_renamed\") {\n      // Expand the rename into \"keep the old field + relax the new field\":\n      // the copy script reads the old field while both coexist, and the\n      // Post-phase drops the old field and enforces the new field's\n      // constraints. Unique is always deferred because stored values of a\n      // previously removed field with the new name may still contain\n      // duplicates until the copy overwrites them.\n      defineRecordEntry(fields, change.previousFieldName, strategy.toField(change.before));\n      const newField: PreMigrationField | undefined = fields[fieldName];\n      if (newField) {\n        if (change.after.required) newField.required = false;\n        if (change.after.unique ?? false) newField.unique = false;\n      }\n      continue;\n    }\n\n    const field = fields[fieldName];\n    if (!field) continue;\n\n    const relaxed: PreMigrationField = field;\n\n    if (change.kind === \"field_added\") {\n      if (change.after.required) {\n        relaxed.required = false;\n      }\n      continue;\n    }\n\n    if (change.kind === \"field_type_modified\") {\n      defineRecordEntry(fields, fieldName, strategy.toField(change.before));\n      continue;\n    }\n\n    const { before, after } = change;\n\n    strategy.adjustNestedMembers?.(field, change);\n\n    if (!before.required && after.required) {\n      relaxed.required = false;\n    }\n\n    if (!(before.unique ?? false) && (after.unique ?? false)) {\n      relaxed.unique = false;\n    }\n\n    // Snapshots omit allowedValues when an enum has no values left.\n    const beforeAllowed = before.allowedValues ?? [];\n    const afterAllowed = after.allowedValues ?? [];\n    const afterValues = new Set(afterAllowed.map((v) => v.value));\n    const removedValues = beforeAllowed.filter((v) => !afterValues.has(v.value));\n    if (removedValues.length > 0) {\n      const valueMap = new Map<string, string>();\n      for (const v of beforeAllowed) {\n        valueMap.set(v.value, v.description ?? \"\");\n      }\n      for (const v of afterAllowed) {\n        if (!valueMap.has(v.value)) {\n          valueMap.set(v.value, v.description ?? \"\");\n        }\n      }\n      relaxed.allowedValues = Array.from(valueMap.entries()).map(([value, description]) => ({\n        value,\n        description,\n      }));\n    }\n  }\n}\n\ntype ProtoFieldConfig = MessageInitShape<typeof TailorDBType_FieldConfigSchema>;\n\n/**\n * Look up a member of a Pre-phase proto field by its path relative to the field.\n * @param {ProtoFieldConfig} field - Top-level proto field\n * @param {readonly string[]} path - Member path, e.g. `[\"geo\", \"lat\"]`\n * @returns {ProtoFieldConfig | undefined} The member, or undefined when any segment is missing\n */\nfunction getProtoNestedMember(\n  field: ProtoFieldConfig,\n  path: readonly string[],\n): ProtoFieldConfig | undefined {\n  return path.reduce<ProtoFieldConfig | undefined>(\n    (current, segment) => current?.fields?.[segment],\n    field,\n  );\n}\n\n/**\n * Re-insert members removed from a nested field so migrate.ts can still read\n * them; the Post-phase drops them.\n * @param {ProtoFieldConfig} field - Pre-phase proto field to adjust (mutated in place)\n * @param {SnapshotFieldConfig} before - Field configuration before the change\n * @param {SnapshotFieldConfig} after - Field configuration after the change\n */\nfunction restoreRemovedNestedMembers(\n  field: ProtoFieldConfig,\n  before: SnapshotFieldConfig,\n  after: SnapshotFieldConfig,\n): void {\n  for (const change of collectNestedMemberChanges(before, after)) {\n    if (change.kind !== \"removed\") continue;\n    const memberPath = change.path.join(\".\");\n    const parentMembers = assertDefined(\n      getProtoNestedMember(field, change.path.slice(0, -1))?.fields,\n      `parent of removed nested member \"${memberPath}\" missing from the Pre-phase field`,\n    );\n    const memberName = assertDefined(change.path.at(-1), \"removed nested member path is empty\");\n    const restored = processNestedFieldsFromSnapshot({ [memberName]: change.before });\n    defineRecordEntry(\n      parentMembers,\n      memberName,\n      assertDefined(restored[memberName], `restored nested member \"${memberPath}\" missing`),\n    );\n  }\n}\n\n/**\n * Relax the new member of each confirmed nested rename to optional and\n * non-unique; the Post-phase enforces both after the copy script has filled\n * it. The manifest currently sends every nested member as non-unique, so the\n * unique relaxation only guards a manifest that starts sending it.\n * @param {ProtoFieldConfig} field - Pre-phase proto field to adjust (mutated in place)\n * @param {readonly NestedMemberRename[]} memberRenames - Confirmed renames inside the field\n */\nfunction relaxRenamedNestedMembers(\n  field: ProtoFieldConfig,\n  memberRenames: readonly NestedMemberRename[],\n): void {\n  for (const rename of memberRenames) {\n    const member = getProtoNestedMember(field, rename.path);\n    if (member?.required) member.required = false;\n    if (member?.unique) member.unique = false;\n  }\n}\n\n/**\n * Map of pre-migration index changes needing relaxation:\n * tableName -> indexName -> change.\n */\nexport type PreMigrationIndexChangesMap = Map<string, Map<string, IndexDiffChange>>;\n\n/**\n * Build a map of table-level index changes that require pre-migration schema\n * adjustment (the breaking ones — see {@link isBreakingIndexChange}).\n * @param {PendingMigration[]} pendingMigrations - Pending migrations to scan\n * @returns {PreMigrationIndexChangesMap} Map of changes keyed by tableName/indexName\n */\nexport function buildPreMigrationIndexChangesMap(\n  pendingMigrations: PendingMigration[],\n): PreMigrationIndexChangesMap {\n  return buildPreMigrationIndexChangesMapFromDiffs(pendingMigrations.map((m) => m.diff));\n}\n\n/**\n * {@link buildPreMigrationIndexChangesMap} over the diffs themselves.\n * @param diffs - Migration diffs to scan\n * @returns Map of changes keyed by tableName/indexName\n */\nexport function buildPreMigrationIndexChangesMapFromDiffs(\n  diffs: readonly MigrationDiff[],\n): PreMigrationIndexChangesMap {\n  const map: PreMigrationIndexChangesMap = new Map();\n  for (const diff of diffs) {\n    for (const change of diff.changes) {\n      if (change.kind !== \"index_added\" && change.kind !== \"index_modified\") continue;\n      const before = change.kind === \"index_modified\" ? change.before : undefined;\n      if (!isBreakingIndexChange(change.tableName, change.indexName, before, change.after)) {\n        continue;\n      }\n      const perType = map.get(change.tableName) ?? new Map<string, IndexDiffChange>();\n      perType.set(change.indexName, change);\n      map.set(change.tableName, perType);\n    }\n  }\n  return map;\n}\n\n/**\n * Apply pre-migration schema adjustments to a table's index map in place.\n *\n * The indexes map is the proto-shape `TailorDBType.schema.indexes` that will\n * be sent in the Pre-phase. We mutate it so that:\n *\n * - Newly added unique indexes are withheld until Post-phase.\n * - Modified indexes keep their previous definition until Post-phase.\n *\n * @param {Record<string, MessageInitShape<typeof TailorDBType_IndexSchema>>} indexes - Index map to adjust (mutated in place)\n * @param {Map<string, IndexDiffChange>} typeIndexChanges - Changes for this table, keyed by indexName\n */\nexport function applyPreMigrationIndexAdjustments(\n  indexes: Record<string, MessageInitShape<typeof TailorDBType_IndexSchema>>,\n  typeIndexChanges: Map<string, IndexDiffChange>,\n): void {\n  relaxIndexesForPreMigration(indexes, typeIndexChanges, convertIndexToProto);\n}\n\n/**\n * {@link applyPreMigrationIndexAdjustments} on snapshot-shaped indexes.\n * @param indexes - Snapshot index map to adjust (mutated in place)\n * @param typeIndexChanges - Changes for this table, keyed by indexName\n */\nexport function applyPreMigrationIndexAdjustmentsToSnapshot(\n  indexes: Record<string, SnapshotIndexConfig>,\n  typeIndexChanges: Map<string, IndexDiffChange>,\n): void {\n  relaxIndexesForPreMigration(indexes, typeIndexChanges, (index) => structuredClone(index));\n}\n\nfunction relaxIndexesForPreMigration<I>(\n  indexes: Record<string, I>,\n  typeIndexChanges: Map<string, IndexDiffChange>,\n  toIndex: (config: SnapshotIndexConfig) => I,\n): void {\n  for (const [indexName, change] of typeIndexChanges) {\n    if (change.kind === \"index_added\") {\n      delete indexes[indexName];\n      continue;\n    }\n    if (change.kind === \"index_modified\") {\n      defineRecordEntry(indexes, indexName, toIndex(change.before));\n    }\n  }\n}\n","import { type MessageInitShape } from \"@bufbuild/protobuf\";\nimport {\n  applyPreMigrationFieldAdjustments,\n  applyPreMigrationIndexAdjustments,\n  buildPreMigrationChangesMap,\n  buildPreMigrationIndexChangesMap,\n  createPreMigrationSnapshotType,\n} from \"#/cli/commands/tailordb/migrate/pre-migration-schema\";\nimport {\n  reconstructSnapshotFromMigrations,\n  formatMigrationNumber,\n  INITIAL_SCHEMA_NUMBER,\n  type SchemaSnapshot,\n} from \"#/cli/commands/tailordb/migrate/snapshot\";\nimport { generateTailorDBTypeManifestFromSnapshot } from \"#/cli/commands/tailordb/migrate/snapshot-manifest\";\nimport { handleOptionalToRequiredError } from \"#/cli/commands/tailordb/migrate/types\";\nimport { fetchAllTolerant, type OperatorClient } from \"#/cli/shared/client\";\nimport { CLIError, toError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport type {\n  FieldDiffChange,\n  TableScriptsModifiedChange,\n} from \"#/cli/commands/tailordb/migrate/diff-calculator\";\nimport type { TailorDBDeployInput } from \"#/cli/commands/tailordb/migrate/schema-checks\";\nimport type { PendingMigration } from \"#/cli/commands/tailordb/migrate/types\";\nimport type { TailorDBChangeSet } from \"./plan\";\nimport type { TailorDBTypeSchema } from \"@tailor-platform/tailor-proto/tailordb_resource_pb\";\n\ntype MigrationTableSettings = {\n  bulkUpsert: boolean;\n  publishRecordEvents: boolean;\n  disableGqlOperations?: {\n    create: boolean;\n    update: boolean;\n    delete: boolean;\n    read: boolean;\n  };\n  tailordbType?: MessageInitShape<typeof TailorDBTypeSchema>;\n};\n\nexport type MigrationRestrictionState = Map<string, Map<string, MigrationTableSettings>>;\n\n/**\n * Capture the settings and table names active immediately before migration writes.\n * @param client - Operator client instance\n * @param workspaceId - Target workspace ID\n * @param namespaceNames - Migrating namespaces to inspect\n * @returns Settings keyed by namespace and table name\n */\nexport async function captureMigrationRestrictionState(\n  client: OperatorClient,\n  workspaceId: string,\n  namespaceNames: ReadonlySet<string>,\n): Promise<MigrationRestrictionState> {\n  const state: MigrationRestrictionState = new Map();\n  for (const namespaceName of namespaceNames) {\n    const types = await fetchAllTolerant(async (pageToken, maxPageSize) => {\n      const { tailordbTypes, nextPageToken } = await client.listTailorDBTypes({\n        workspaceId,\n        namespaceName,\n        pageToken,\n        pageSize: maxPageSize,\n      });\n      return [tailordbTypes, nextPageToken];\n    });\n    const settingsByTable = new Map<string, MigrationTableSettings>();\n    for (const type of types) {\n      const settings = type.schema?.settings;\n      if (!type.name) continue;\n      settingsByTable.set(type.name, {\n        bulkUpsert: settings?.bulkUpsert ?? false,\n        publishRecordEvents: settings?.publishRecordEvents ?? false,\n        // Defensive: the generated client always populates these bools, so the\n        // fallbacks only guard a hand-built client and keep the shape identical\n        // to resolveMigrationSnapshotSettings, whose settings come from a\n        // MessageInitShape that declares the fields optional.\n        // oxlint-disable typescript/no-unnecessary-condition\n        ...(settings?.disableGqlOperations && {\n          disableGqlOperations: {\n            create: settings.disableGqlOperations.create ?? false,\n            update: settings.disableGqlOperations.update ?? false,\n            delete: settings.disableGqlOperations.delete ?? false,\n            read: settings.disableGqlOperations.read ?? false,\n          },\n        }),\n        // oxlint-enable typescript/no-unnecessary-condition\n        tailordbType: structuredClone(type),\n      });\n    }\n    state.set(namespaceName, settingsByTable);\n  }\n  return state;\n}\n\n/**\n * Get the set of table names affected by a migration\n * @param {PendingMigration} migration - Pending migration\n * @returns {Set<string>} Set of affected table names\n */\nfunction getAffectedTableNames(migration: PendingMigration): Set<string> {\n  const tableNames = new Set<string>();\n  for (const change of migration.diff.changes) {\n    tableNames.add(change.tableName);\n  }\n  return tableNames;\n}\n\n/**\n * Get the set of table names to be deleted by a migration. A renamed table's\n * old name is included: the old table survives the Pre-phase and the script\n * (which copies its rows into the new table), then is dropped here.\n * @param {PendingMigration} migration - Pending migration\n * @returns {Set<string>} Set of table names to delete\n */\nexport function getDeletedTableNames(migration: PendingMigration): Set<string> {\n  const tableNames = new Set<string>();\n  for (const change of migration.diff.changes) {\n    if (change.kind === \"table_removed\") {\n      tableNames.add(change.tableName);\n    } else if (change.kind === \"table_renamed\") {\n      tableNames.add(change.previousTableName);\n    }\n  }\n  return tableNames;\n}\n\n/**\n * Track which tables have been created/updated across migrations\n */\nexport const processedTables = {\n  created: new Set<string>(),\n  updated: new Set<string>(),\n  gqlPermissionsProcessed: new Set<string>(),\n  reset() {\n    this.created.clear();\n    this.updated.clear();\n    this.gqlPermissionsProcessed.clear();\n  },\n};\n\n/**\n * Snapshot cache for per-migration schema lookups during a single apply run.\n *\n * Only the initial baseline `0000/schema.json` is stored on disk; later migrations\n * ship `diff.json` only. To get the schema state AFTER migration N we replay the\n * initial snapshot through all diffs up to N via `reconstructSnapshotFromMigrations`.\n * Results are memoized per (namespace, migration number) for the apply run.\n */\nexport const migrationSnapshotCache = {\n  cache: new Map<string, SchemaSnapshot>(),\n  reset() {\n    this.cache.clear();\n  },\n  load(migration: PendingMigration): SchemaSnapshot {\n    const key = `${migration.namespace}/${migration.number}`;\n    let snapshot = this.cache.get(key);\n    if (!snapshot) {\n      const reconstructed = reconstructSnapshotFromMigrations(\n        migration.migrationsDir,\n        migration.number,\n      );\n      if (!reconstructed) {\n        throw CLIError({\n          code: \"MIGRATION_HISTORY_INVALID\",\n          message: `Cannot reconstruct snapshot for ${migration.namespace} migration ${migration.number}: no migrations found in ${migration.migrationsDir}`,\n        });\n      }\n      snapshot = reconstructed;\n      this.cache.set(key, snapshot);\n    }\n    return snapshot;\n  },\n};\n\nfunction buildSnapshotTypeManifest(\n  migration: PendingMigration,\n  tableName: string,\n  tailorDBInputs: ReadonlyArray<TailorDBDeployInput>,\n  typeChanges?: Map<string, FieldDiffChange>,\n): MessageInitShape<typeof TailorDBTypeSchema> | undefined {\n  const snapshot = migrationSnapshotCache.load(migration);\n  const snapshotType = snapshot.tables[tableName];\n  if (!snapshotType) return undefined;\n  const input = tailorDBInputs.find((i) => i.namespace === migration.namespace);\n  const typeScriptsChange = migration.diff.changes.find(\n    (change): change is TableScriptsModifiedChange =>\n      change.kind === \"table_scripts_modified\" && change.tableName === tableName,\n  );\n  const manifestSnapshotType = typeChanges\n    ? createPreMigrationSnapshotType(snapshotType, typeChanges, typeScriptsChange)\n    : snapshotType;\n  return generateTailorDBTypeManifestFromSnapshot(manifestSnapshotType, {\n    // A migration script's own record writes would publish from a shape that is\n    // mid-migration, to executors still registered from the previous deploy.\n    // `restoreMigrationRestrictions` turns it back on once they have settled.\n    // Overrides a declared `publishEvents: true`, which `subscribed` cannot.\n    suppressRecordEvents: true,\n    suppressGqlOperations: true,\n    namespaceGqlOperations: input?.config.gqlOperations,\n  });\n}\n\n/**\n * Await every promise to settle, then throw the first rejection. Unlike\n * `Promise.all`, this never leaves sibling operations in flight after a failure,\n * so a following rollback cannot race with still-pending DDL.\n * @param promises - Promises (or already-resolved values) to await\n * @returns {Promise<void>} Resolves once all settle; rejects with the first failure\n */\nasync function awaitAllSettledOrThrow(\n  promises: ReadonlyArray<Promise<unknown> | undefined>,\n): Promise<void> {\n  const results = await Promise.allSettled(\n    promises.filter((promise): promise is Promise<unknown> => promise !== undefined),\n  );\n  const rejected = results.find((r): r is PromiseRejectedResult => r.status === \"rejected\");\n  if (rejected) {\n    throw rejected.reason;\n  }\n}\n\n/**\n * Execute pre-migration phase for a single migration\n * @param {OperatorClient} client - Operator client instance\n * @param {TailorDBChangeSet} changeSet - TailorDB change set\n * @param {PendingMigration} migration - Single pending migration\n * @param tailorDBInputs - Deploy inputs, used to resolve namespace gqlOperations for the snapshot\n * @param attemptedTables - Tables whose schema this migration attempted to create or update\n * @returns {Promise<void>} Promise that resolves when pre-migration phase completes\n */\nexport async function executeSingleMigrationPrePhase(\n  client: OperatorClient,\n  changeSet: TailorDBChangeSet,\n  migration: PendingMigration,\n  tailorDBInputs: ReadonlyArray<TailorDBDeployInput>,\n  attemptedTables: Set<string>,\n): Promise<void> {\n  // Build pre-migration changes maps for this single migration. Includes both\n  // breaking changes (required-add, unique-add, enum value removal) and the\n  // warning-tier field_removed, since the Pre-phase relaxes both, plus the\n  // breaking table-level index changes.\n  const preMigrationChanges = buildPreMigrationChangesMap([migration]);\n  const preMigrationIndexChanges = buildPreMigrationIndexChangesMap([migration]);\n  const affectedTables = getAffectedTableNames(migration);\n  const createdBeforeMigration = new Set(processedTables.created);\n\n  for (const create of changeSet.type.creates) {\n    const tableName = create.request.tailordbType?.name;\n    if (!tableName || !affectedTables.has(tableName) || createdBeforeMigration.has(tableName)) {\n      continue;\n    }\n    const typeChanges = preMigrationChanges.get(tableName);\n    const snapshotType = buildSnapshotTypeManifest(\n      migration,\n      tableName,\n      tailorDBInputs,\n      typeChanges,\n    );\n    if (!snapshotType) continue;\n\n    const clonedRequest = structuredClone(create.request);\n    clonedRequest.tailordbType = snapshotType;\n\n    if (typeChanges && typeChanges.size > 0 && clonedRequest.tailordbType.schema?.fields) {\n      applyPreMigrationFieldAdjustments(clonedRequest.tailordbType.schema.fields, typeChanges);\n    }\n    const indexChanges = preMigrationIndexChanges.get(tableName);\n    if (indexChanges && indexChanges.size > 0 && clonedRequest.tailordbType.schema?.indexes) {\n      applyPreMigrationIndexAdjustments(clonedRequest.tailordbType.schema.indexes, indexChanges);\n    }\n\n    processedTables.created.add(tableName);\n    attemptedTables.add(tableName);\n    await client.createTailorDBType(clonedRequest);\n  }\n\n  for (const create of changeSet.type.creates) {\n    const tableName = create.request.tailordbType?.name;\n    if (!tableName || !affectedTables.has(tableName) || !createdBeforeMigration.has(tableName)) {\n      continue;\n    }\n    const typeChanges = preMigrationChanges.get(tableName);\n    const snapshotType = buildSnapshotTypeManifest(\n      migration,\n      tableName,\n      tailorDBInputs,\n      typeChanges,\n    );\n    if (!snapshotType) continue;\n\n    const clonedTypeRequest = structuredClone(snapshotType);\n    if (typeChanges && typeChanges.size > 0 && clonedTypeRequest.schema?.fields) {\n      applyPreMigrationFieldAdjustments(clonedTypeRequest.schema.fields, typeChanges);\n    }\n    const indexChanges = preMigrationIndexChanges.get(tableName);\n    if (indexChanges && indexChanges.size > 0 && clonedTypeRequest.schema?.indexes) {\n      applyPreMigrationIndexAdjustments(clonedTypeRequest.schema.indexes, indexChanges);\n    }\n\n    processedTables.updated.add(tableName);\n    attemptedTables.add(tableName);\n    await client.updateTailorDBType({\n      workspaceId: create.request.workspaceId,\n      namespaceName: create.request.namespaceName,\n      tailordbType: clonedTypeRequest,\n    });\n  }\n\n  for (const update of changeSet.type.updates) {\n    const tableName = update.request.tailordbType?.name;\n    if (!tableName || !affectedTables.has(tableName)) continue;\n    const typeChanges = preMigrationChanges.get(tableName);\n    const snapshotType = buildSnapshotTypeManifest(\n      migration,\n      tableName,\n      tailorDBInputs,\n      typeChanges,\n    );\n    if (!snapshotType) continue;\n\n    const clonedRequest = structuredClone(update.request);\n    clonedRequest.tailordbType = snapshotType;\n\n    if (typeChanges && typeChanges.size > 0 && clonedRequest.tailordbType.schema?.fields) {\n      applyPreMigrationFieldAdjustments(clonedRequest.tailordbType.schema.fields, typeChanges);\n    }\n    const indexChanges = preMigrationIndexChanges.get(tableName);\n    if (indexChanges && indexChanges.size > 0 && clonedRequest.tailordbType.schema?.indexes) {\n      applyPreMigrationIndexAdjustments(clonedRequest.tailordbType.schema.indexes, indexChanges);\n    }\n\n    processedTables.updated.add(tableName);\n    attemptedTables.add(tableName);\n    await client.updateTailorDBType(clonedRequest);\n  }\n\n  const currentTableNames = new Set(Object.keys(migrationSnapshotCache.load(migration).tables));\n  const permissionKey = (tableName: string) => `${migration.namespace}/${tableName}`;\n  const gqlPermissionCreatesForNamespace = changeSet.gqlPermission.creates.filter(\n    (create) =>\n      create.request.namespaceName === migration.namespace &&\n      currentTableNames.has(create.name) &&\n      !processedTables.gqlPermissionsProcessed.has(permissionKey(create.name)),\n  );\n  const gqlPermissionUpdatesForNamespace = changeSet.gqlPermission.updates.filter(\n    (update) =>\n      update.request.namespaceName === migration.namespace &&\n      currentTableNames.has(update.name) &&\n      !processedTables.gqlPermissionsProcessed.has(permissionKey(update.name)),\n  );\n  if (gqlPermissionCreatesForNamespace.length + gqlPermissionUpdatesForNamespace.length > 0) {\n    const gqlPermissionTypeNames = new Set(\n      gqlPermissionCreatesForNamespace.map((create) => create.name),\n    );\n    const missingTypeCreates = changeSet.type.creates.filter((create) => {\n      const tableName = create.request.tailordbType?.name;\n      const namespaceName = create.request.namespaceName;\n      return (\n        namespaceName === migration.namespace &&\n        tableName &&\n        gqlPermissionTypeNames.has(tableName) &&\n        !processedTables.created.has(tableName)\n      );\n    });\n    if (missingTypeCreates.length > 0) {\n      for (const create of missingTypeCreates) {\n        const tableName = create.request.tailordbType?.name;\n        if (!tableName) continue;\n        const snapshotType = buildSnapshotTypeManifest(migration, tableName, tailorDBInputs);\n        if (!snapshotType) continue;\n        processedTables.created.add(tableName);\n        attemptedTables.add(tableName);\n        const clonedRequest = structuredClone(create.request);\n        clonedRequest.tailordbType = snapshotType;\n        await client.createTailorDBType(clonedRequest);\n      }\n    }\n    await awaitAllSettledOrThrow([\n      ...gqlPermissionCreatesForNamespace.map((create) =>\n        client.createTailorDBGQLPermission(create.request),\n      ),\n      ...gqlPermissionUpdatesForNamespace.map((update) =>\n        client.updateTailorDBGQLPermission(update.request),\n      ),\n    ]);\n    for (const typeName of [\n      ...gqlPermissionCreatesForNamespace.map((create) => create.name),\n      ...gqlPermissionUpdatesForNamespace.map((update) => update.name),\n    ]) {\n      processedTables.gqlPermissionsProcessed.add(permissionKey(typeName));\n    }\n  }\n}\n\n/**\n * Track which tables/permissions have been deleted across migrations\n */\nexport const deletedResources = {\n  types: new Set<string>(),\n  gqlPermissions: new Set<string>(),\n  reset() {\n    this.types.clear();\n    this.gqlPermissions.clear();\n  },\n};\n\nexport async function rollbackSingleMigrationAfterFailure(\n  client: OperatorClient,\n  migration: PendingMigration,\n  workspaceId: string,\n  tailorDBInputs: ReadonlyArray<TailorDBDeployInput>,\n  attemptedTables: ReadonlySet<string>,\n): Promise<void> {\n  try {\n    await rollbackSingleMigrationPrePhase(\n      client,\n      migration,\n      workspaceId,\n      tailorDBInputs,\n      attemptedTables,\n    );\n  } catch (rollbackError) {\n    logger.warn(\n      `Failed to roll back migration ${migration.namespace}/${formatMigrationNumber(migration.number)}: ` +\n        `${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`,\n    );\n  }\n}\n\n/**\n * Execute post-migration phase for a single migration: Apply final tables (with required: true)\n * @param {OperatorClient} client - Operator client instance\n * @param {TailorDBChangeSet} changeSet - TailorDB change set\n * @param {PendingMigration} migration - Single pending migration\n * @param tailorDBInputs - Deploy inputs, used to resolve namespace gqlOperations for the snapshot\n * @param attemptedTables - Tables whose schema this migration attempted to create or update\n * @returns {Promise<void>} Promise that resolves when post-migration phase completes\n */\nexport async function executeSingleMigrationPostPhase(\n  client: OperatorClient,\n  changeSet: TailorDBChangeSet,\n  migration: PendingMigration,\n  tailorDBInputs: ReadonlyArray<TailorDBDeployInput>,\n  attemptedTables: Set<string>,\n): Promise<void> {\n  // Re-use the pre-migration changes maps to know which tables were touched in\n  // this migration (so we send the post-phase final-schema update for them).\n  const preMigrationChanges = buildPreMigrationChangesMap([migration]);\n  const preMigrationIndexChanges = buildPreMigrationIndexChangesMap([migration]);\n  const adjustedTypes = new Set([\n    ...preMigrationChanges.keys(),\n    ...preMigrationIndexChanges.keys(),\n  ]);\n  const affectedTables = getAffectedTableNames(migration);\n\n  // Tables - apply schema as of migration N (= snapshot[N]) with all breaking\n  // changes enforced. The prePhase sent the same schema with breaking fields\n  // relaxed; here we send it again without relaxation so required/unique/etc.\n  // take effect after the data script has reconciled records.\n  try {\n    // For newly created tables that had pre-migration adjustments in this migration, send update with snapshot[N] values\n    for (const create of changeSet.type.creates) {\n      const tableName = create.request.tailordbType?.name;\n      if (!tableName || !affectedTables.has(tableName) || !adjustedTypes.has(tableName)) {\n        continue;\n      }\n      const snapshotType = buildSnapshotTypeManifest(migration, tableName, tailorDBInputs);\n      if (!snapshotType) continue;\n      attemptedTables.add(tableName);\n      await client.updateTailorDBType({\n        workspaceId: create.request.workspaceId,\n        namespaceName: create.request.namespaceName,\n        tailordbType: snapshotType,\n      });\n    }\n\n    // For updated tables affected by this migration, send update with snapshot[N] values\n    for (const update of changeSet.type.updates) {\n      const tableName = update.request.tailordbType?.name;\n      if (!tableName || !affectedTables.has(tableName) || !adjustedTypes.has(tableName)) {\n        continue;\n      }\n      const snapshotType = buildSnapshotTypeManifest(migration, tableName, tailorDBInputs);\n      if (!snapshotType) continue;\n      attemptedTables.add(tableName);\n      await client.updateTailorDBType({\n        workspaceId: update.request.workspaceId,\n        namespaceName: update.request.namespaceName,\n        tailordbType: snapshotType,\n      });\n    }\n  } catch (error) {\n    handleOptionalToRequiredError(error, [\n      \"This error occurred during post-migration phase. Please check your migration script.\",\n      \"Ensure all existing records have values for fields being changed to required.\",\n    ]);\n  }\n}\n\n/**\n * Rewrite tables that can publish records or accept GraphQL mutations, with\n * migration restrictions applied or removed from the given snapshot.\n *\n * Writes the snapshot's schema rather than the config's, so this never enforces\n * a change whose migration has not run — the same reason the per-migration\n * phases build from a checkpoint.\n * @param client - Operator client instance\n * @param params - Namespace, snapshot, subscriber set, and direction\n */\ntype RewriteRestrictedTablesParams = {\n  workspaceId: string;\n  namespaceName: string;\n  snapshot: SchemaSnapshot;\n  input: TailorDBDeployInput;\n  executorUsedTables: ReadonlySet<string>;\n  settingsState?: ReadonlyMap<string, MigrationTableSettings>;\n  restricted: boolean;\n  continueOnError?: boolean;\n};\n\nfunction acceptsMigrationWrites(settings: MigrationTableSettings): boolean {\n  const operations = settings.disableGqlOperations;\n  return (\n    settings.publishRecordEvents ||\n    settings.bulkUpsert ||\n    operations?.create !== true ||\n    operations.update !== true ||\n    operations.delete !== true\n  );\n}\n\nasync function rewriteRestrictedTables(\n  client: OperatorClient,\n  params: RewriteRestrictedTablesParams,\n): Promise<void> {\n  const {\n    workspaceId,\n    namespaceName,\n    snapshot,\n    input,\n    executorUsedTables,\n    settingsState,\n    restricted,\n    continueOnError = false,\n  } = params;\n  let firstError: Error | undefined;\n  const tableNames = new Set([...Object.keys(snapshot.tables), ...(settingsState?.keys() ?? [])]);\n  for (const tableName of tableNames) {\n    try {\n      const snapshotType = snapshot.tables[tableName];\n      const activeSettings = settingsState?.get(tableName);\n      if (settingsState && !activeSettings) continue;\n      if (restricted && (!activeSettings || !acceptsMigrationWrites(activeSettings))) continue;\n      const tailordbType = snapshotType\n        ? restricted\n          ? generateTailorDBTypeManifestFromSnapshot(snapshotType, {\n              suppressRecordEvents: true,\n              suppressGqlOperations: true,\n              namespaceGqlOperations: input.config.gqlOperations,\n            })\n          : generateTailorDBTypeManifestFromSnapshot(snapshotType, {\n              subscribed: executorUsedTables.has(tableName),\n              namespaceGqlOperations: input.config.gqlOperations,\n            })\n        : activeSettings?.tailordbType\n          ? structuredClone(activeSettings.tailordbType)\n          : undefined;\n      if (!tailordbType?.schema) continue;\n      tailordbType.schema.settings ??= {};\n      const settings = tailordbType.schema.settings;\n      if (restricted) {\n        settings.bulkUpsert = false;\n        settings.publishRecordEvents = false;\n        settings.disableGqlOperations = {\n          create: true,\n          update: true,\n          delete: true,\n          read: true,\n        };\n      }\n      if (!restricted && activeSettings) {\n        settings.bulkUpsert = activeSettings.bulkUpsert;\n        settings.publishRecordEvents = activeSettings.publishRecordEvents;\n        settings.disableGqlOperations = activeSettings.disableGqlOperations\n          ? { ...activeSettings.disableGqlOperations }\n          : undefined;\n      }\n      await client.updateTailorDBType({ workspaceId, namespaceName, tailordbType });\n    } catch (error) {\n      if (!continueOnError) throw error;\n      firstError ??= error instanceof Error ? error : toError(error);\n    }\n  }\n  if (firstError !== undefined) throw firstError;\n}\n\n/**\n * Resolve the settings represented by a committed migration snapshot.\n *\n * Intermediate snapshots may intentionally conflict with executors from the\n * final deployment. They still need restorable settings if a later migration\n * fails, so explicit snapshot values win without re-running that final-state\n * conflict check.\n * @param snapshot - Committed schema snapshot\n * @param input - TailorDB deploy input for the namespace\n * @param executorUsedTables - Tables an enabled executor in this deploy subscribes to\n * @returns Settings keyed by table name\n */\nexport function resolveMigrationSnapshotSettings(\n  snapshot: SchemaSnapshot,\n  input: TailorDBDeployInput,\n  executorUsedTables: ReadonlySet<string>,\n): Map<string, MigrationTableSettings> {\n  const settingsByTable = new Map<string, MigrationTableSettings>();\n  for (const [tableName, snapshotType] of Object.entries(snapshot.tables)) {\n    const settings = generateTailorDBTypeManifestFromSnapshot(snapshotType, {\n      subscribed: false,\n      namespaceGqlOperations: input.config.gqlOperations,\n    }).schema?.settings;\n    if (!settings) continue;\n    settingsByTable.set(tableName, {\n      bulkUpsert: settings.bulkUpsert ?? false,\n      publishRecordEvents:\n        snapshotType.settings?.publishEvents ?? executorUsedTables.has(tableName),\n      ...(settings.disableGqlOperations && {\n        disableGqlOperations: {\n          create: settings.disableGqlOperations.create ?? false,\n          update: settings.disableGqlOperations.update ?? false,\n          delete: settings.disableGqlOperations.delete ?? false,\n          read: settings.disableGqlOperations.read ?? false,\n        },\n      }),\n    });\n  }\n  return settingsByTable;\n}\n\n/**\n * Stop record event publishing and GraphQL mutations across each migrating namespace.\n *\n * The per-migration phases only rewrite tables some pending diff names, so a\n * data-only migration — an empty diff carrying only a script — would leave the\n * whole namespace unrestricted while its script runs. Restrictions therefore\n * use the schema in place before the namespace's first migration.\n * @param client - Operator client instance\n * @param snapshots - Schema in place before each namespace's first pending migration\n * @param restrictionState - Settings and tables active before migration writes\n * @param tailorDBInputs - TailorDB deploy inputs for the run\n * @param executorUsedTables - Tables an enabled executor subscribes to\n * @param workspaceId - Target workspace ID\n */\nexport async function applyMigrationRestrictions(\n  client: OperatorClient,\n  snapshots: ReadonlyMap<string, SchemaSnapshot>,\n  restrictionState: MigrationRestrictionState,\n  tailorDBInputs: ReadonlyArray<TailorDBDeployInput>,\n  executorUsedTables: ReadonlySet<string>,\n  workspaceId: string,\n): Promise<void> {\n  for (const [namespaceName, snapshot] of snapshots) {\n    const input = tailorDBInputs.find((entry) => entry.namespace === namespaceName);\n    if (!input) continue;\n    await rewriteRestrictedTables(client, {\n      workspaceId,\n      namespaceName,\n      snapshot,\n      input,\n      executorUsedTables,\n      settingsState: restrictionState.get(namespaceName) ?? new Map(),\n      restricted: true,\n    });\n  }\n}\n\n/**\n * Restore normal event publishing and GraphQL operations after migrations.\n *\n * Uses the latest schema that completed its post-phase in each namespace. If a\n * later migration fails, this avoids applying schema changes that never settled.\n *\n * Callers must run this even when the migration loop throws because a committed\n * checkpoint drops its migration from the next run's pending set.\n * @param client - Operator client instance\n * @param snapshots - Latest schema that settled in each migrating namespace\n * @param settingsToRestore - Settings for the latest confirmed checkpoint, including exact active settings for snapshot-external tables\n * @param tailorDBInputs - TailorDB deploy inputs for the run\n * @param executorUsedTables - Tables an enabled executor subscribes to\n * @param workspaceId - Target workspace ID\n */\nexport async function restoreMigrationRestrictions(\n  client: OperatorClient,\n  snapshots: ReadonlyMap<string, SchemaSnapshot>,\n  settingsToRestore: MigrationRestrictionState | undefined,\n  tailorDBInputs: ReadonlyArray<TailorDBDeployInput>,\n  executorUsedTables: ReadonlySet<string>,\n  workspaceId: string,\n): Promise<void> {\n  let firstError: Error | undefined;\n  for (const [namespaceName, snapshot] of snapshots) {\n    const input = tailorDBInputs.find((entry) => entry.namespace === namespaceName);\n    if (!input) continue;\n    try {\n      await rewriteRestrictedTables(client, {\n        workspaceId,\n        namespaceName,\n        snapshot,\n        input,\n        executorUsedTables,\n        settingsState: settingsToRestore?.get(namespaceName),\n        restricted: false,\n        continueOnError: true,\n      });\n    } catch (error) {\n      firstError ??= error instanceof Error ? error : toError(error);\n    }\n  }\n  if (firstError !== undefined) throw firstError;\n}\n\nexport async function executeSingleMigrationPostPhaseDeletions(\n  client: OperatorClient,\n  changeSet: TailorDBChangeSet,\n  migration: PendingMigration,\n): Promise<void> {\n  const deletedTableNames = getDeletedTableNames(migration);\n  if (deletedTableNames.size > 0) {\n    const gqlPermissionsToDelete = changeSet.gqlPermission.deletes.filter((del) => {\n      const permKey = `${del.request.namespaceName}/${del.name}`;\n      if (deletedResources.gqlPermissions.has(permKey)) return false;\n      const tableName = del.name;\n      return deletedTableNames.has(tableName);\n    });\n    for (const del of gqlPermissionsToDelete) {\n      await client.deleteTailorDBGQLPermission(del.request);\n      deletedResources.gqlPermissions.add(`${del.request.namespaceName}/${del.name}`);\n    }\n\n    const typesToDelete = changeSet.type.deletes.filter((del) => {\n      const tableName = del.name;\n      if (!tableName || deletedResources.types.has(tableName)) return false;\n      return deletedTableNames.has(tableName);\n    });\n    for (const del of typesToDelete) {\n      await client.deleteTailorDBType(del.request);\n      deletedResources.types.add(del.name);\n    }\n  }\n}\n\n/**\n * Revert a single migration's Pre-phase DDL to the prior checkpoint's schema.\n * @param client - Operator client instance\n * @param migration - The migration whose Pre-phase DDL must be reverted\n * @param workspaceId - Workspace ID\n * @param tailorDBInputs - Deploy inputs, used to resolve namespace gqlOperations for the snapshot\n * @param attemptedTables - Tables whose schema this migration attempted to create or update\n * @returns {Promise<void>} Promise that resolves when rollback attempts complete\n */\nasync function rollbackSingleMigrationPrePhase(\n  client: OperatorClient,\n  migration: PendingMigration,\n  workspaceId: string,\n  tailorDBInputs: ReadonlyArray<TailorDBDeployInput>,\n  attemptedTables: ReadonlySet<string>,\n): Promise<void> {\n  // The baseline migration has no prior checkpoint to revert to.\n  if (migration.number <= INITIAL_SCHEMA_NUMBER) return;\n  if (attemptedTables.size === 0) return;\n\n  const priorSnapshot = reconstructSnapshotFromMigrations(\n    migration.migrationsDir,\n    migration.number - 1,\n  );\n  // Without the prior snapshot, pre-existing and new tables are indistinguishable;\n  // deleting them all would be destructive, so leave the schema untouched.\n  if (!priorSnapshot) {\n    logger.warn(\n      `Cannot roll back migration ${migration.namespace}/${formatMigrationNumber(migration.number)}: ` +\n        `prior snapshot (migration ${formatMigrationNumber(migration.number - 1)}) could not be reconstructed. ` +\n        \"Leaving schema as-is; manual repair may be required.\",\n    );\n    return;\n  }\n  const input = tailorDBInputs.find((i) => i.namespace === migration.namespace);\n\n  logger.warn(\n    `Migration ${migration.namespace}/${formatMigrationNumber(migration.number)} failed; ` +\n      \"rolling back its pre-migration schema changes.\",\n  );\n\n  // Restore pre-existing tables before deleting new ones, so no restored table\n  // still references a new table (e.g. a foreign key retargeted at a renamed\n  // table) at the moment that table is deleted.\n  const restoredTables = [...attemptedTables].flatMap((tableName) => {\n    const priorTable = priorSnapshot.tables[tableName];\n    return priorTable ? [{ tableName, priorTable }] : [];\n  });\n  const newTables = [...attemptedTables].filter((tableName) => !priorSnapshot.tables[tableName]);\n\n  for (const { tableName, priorTable } of restoredTables) {\n    try {\n      const manifest = generateTailorDBTypeManifestFromSnapshot(priorTable, {\n        suppressRecordEvents: true,\n        suppressGqlOperations: true,\n        namespaceGqlOperations: input?.config.gqlOperations,\n      });\n      await client.updateTailorDBType({\n        workspaceId,\n        namespaceName: migration.namespace,\n        tailordbType: manifest,\n      });\n    } catch (rollbackError) {\n      logger.warn(\n        `Failed to roll back table '${tableName}' in namespace '${migration.namespace}': ` +\n          `${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`,\n      );\n    }\n  }\n\n  for (const tableName of newTables) {\n    try {\n      // New table: its GQL permission must go first (table deletion does not\n      // cascade). The permission may not exist, so the delete is best-effort.\n      await client\n        .deleteTailorDBGQLPermission({\n          workspaceId,\n          namespaceName: migration.namespace,\n          typeName: tableName,\n        })\n        .catch(() => undefined);\n      await client.deleteTailorDBType({\n        workspaceId,\n        namespaceName: migration.namespace,\n        tailordbTypeName: tableName,\n      });\n    } catch (rollbackError) {\n      logger.warn(\n        `Failed to roll back table '${tableName}' in namespace '${migration.namespace}': ` +\n          `${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`,\n      );\n    }\n  }\n}\n","/**\n * Schema validation checks shared between `deploy` and\n * `tailordb migration validate`.\n *\n * These checks are read-only: they compare local table definitions, the\n * migration snapshot history, and the remote schema without mutating any\n * state.\n */\n\nimport { resourceTrn } from \"#/cli/commands/deploy/label\";\nimport { fetchAllTolerant, type OperatorClient } from \"#/cli/shared/client\";\nimport { logger } from \"#/cli/shared/logger\";\nimport {\n  hasChanges,\n  formatMigrationDiff,\n  formatDiffSummary,\n  type MigrationDiff,\n} from \"./diff-calculator\";\nimport { fetchRemoteMigrationState } from \"./remote-state\";\nimport {\n  reconstructSnapshotFromMigrations,\n  compareLocalTypesWithSnapshot,\n  compareRemoteWithSnapshot,\n  formatMigrationNumber,\n  formatSchemaDrifts,\n  createSnapshotType,\n  createSnapshotFromRemoteTypes,\n  getLatestMigrationNumber,\n  MISSING_REMOTE_SCRIPT_HASH_SUFFIX,\n  type RemoteGqlPermission,\n  type SchemaSnapshot,\n  type SnapshotGqlOperations,\n  type SnapshotSettings,\n  type TailorDBSnapshotType,\n  type NormalizedSchemaSnapshot,\n} from \"./snapshot\";\nimport {\n  type RebaselinePendingInfo,\n  type RemoteSchemaVerificationResult,\n  type SchemaDrift,\n} from \"./types\";\nimport type { TailorDBService } from \"#/cli/services/tailordb/service\";\nimport type { LoadedConfig } from \"#/cli/shared/config-loader\";\nimport type { TailorDBServiceConfig } from \"#/types/tailordb.generated\";\nimport type { NamespaceWithMigrations } from \"./config\";\nimport type { TailorDBType as ProtoTailorDBType } from \"@tailor-platform/tailor-proto/tailordb_resource_pb\";\n\n/**\n * Canonical input shape consumed by every TailorDB plan/proto step.\n * The deploy pipeline funnels `TailorDBService` through `createSnapshotType` so\n * that comparison, manifest generation and migration drift checks all read the\n * same snapshot-shaped data, keeping platform-side normalization (e.g. decimal\n * scale) in one place.\n */\nexport type TailorDBDeployInput = {\n  namespace: string;\n  config: TailorDBServiceConfig;\n  types: Record<string, TailorDBSnapshotType>;\n};\n\n/**\n * Convert a runtime TailorDBService to the snapshot-shaped deploy input.\n * @param service - Loaded TailorDB service (after `loadTypes()`)\n * @returns The canonical snapshot-shaped deploy input for downstream plan/apply phases.\n */\nexport function toTailorDBDeployInput(service: TailorDBService): TailorDBDeployInput {\n  const types: Record<string, TailorDBSnapshotType> = {};\n  for (const [tableName, type] of Object.entries(service.types)) {\n    types[tableName] = createSnapshotType(type);\n  }\n  return {\n    namespace: service.namespace,\n    config: service.config,\n    types,\n  };\n}\n\n// ============================================================================\n// Remote Schema Verification\n// ============================================================================\n\n/**\n * Fetch all TailorDB tables from remote for a namespace\n * @param {OperatorClient} client - Operator client instance\n * @param {string} workspaceId - Workspace ID\n * @param {string} namespace - TailorDB namespace\n * @returns {Promise<ProtoTailorDBType[]>} Remote TailorDB tables\n */\nasync function fetchRemoteTypes(\n  client: OperatorClient,\n  workspaceId: string,\n  namespace: string,\n): Promise<ProtoTailorDBType[]> {\n  return fetchAllTolerant(async (pageToken, maxPageSize) => {\n    const { tailordbTypes, nextPageToken } = await client.listTailorDBTypes({\n      workspaceId,\n      namespaceName: namespace,\n      pageToken,\n      pageSize: maxPageSize,\n    });\n    return [tailordbTypes, nextPageToken];\n  });\n}\n\nasync function fetchRemoteGqlPermissions(\n  client: OperatorClient,\n  workspaceId: string,\n  namespace: string,\n): Promise<RemoteGqlPermission[]> {\n  return fetchAllTolerant(async (pageToken, maxPageSize) => {\n    const { permissions, nextPageToken } = await client.listTailorDBGQLPermissions({\n      workspaceId,\n      namespaceName: namespace,\n      pageToken,\n      pageSize: maxPageSize,\n    });\n    return [permissions, nextPageToken];\n  });\n}\n\n/**\n * Fetch a namespace's deployed schema as a normalized snapshot.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param namespace - TailorDB namespace\n * @returns The deployed schema snapshot\n */\nexport async function fetchRemoteSchemaSnapshot(\n  client: OperatorClient,\n  workspaceId: string,\n  namespace: string,\n): Promise<NormalizedSchemaSnapshot> {\n  const [remoteTypes, remoteGqlPermissions] = await Promise.all([\n    fetchRemoteTypes(client, workspaceId, namespace),\n    fetchRemoteGqlPermissions(client, workspaceId, namespace),\n  ]);\n  return createSnapshotFromRemoteTypes(remoteTypes, namespace, remoteGqlPermissions);\n}\n\ntype RemoteTailorDBSettings = NonNullable<NonNullable<ProtoTailorDBType[\"schema\"]>[\"settings\"]>;\ntype DeployGqlOperations = SnapshotGqlOperations | \"query\" | undefined;\n\nfunction definedWhenNotEmpty<T extends object>(value: T): T | undefined {\n  return Object.keys(value).length > 0 ? value : undefined;\n}\n\nfunction namespaceConfig(\n  config: LoadedConfig,\n  tailorDBInputs: ReadonlyArray<TailorDBDeployInput>,\n  namespace: string,\n): TailorDBServiceConfig | undefined {\n  const inputConfig = tailorDBInputs.find((input) => input.namespace === namespace)?.config;\n  return inputConfig ?? (config.db?.[namespace] as TailorDBServiceConfig | undefined);\n}\n\nfunction namespaceGqlOperations(\n  config: LoadedConfig,\n  tailorDBInputs: ReadonlyArray<TailorDBDeployInput>,\n  namespace: string,\n): DeployGqlOperations {\n  return namespaceConfig(config, tailorDBInputs, namespace)?.gqlOperations;\n}\n\nconst GQL_OPERATION_KEYS = [\"create\", \"update\", \"delete\", \"read\"] as const;\n\nfunction configuredDisabledGqlOperations(\n  operations: DeployGqlOperations,\n): SnapshotGqlOperations | undefined {\n  if (!operations) return undefined;\n  if (operations === \"query\") {\n    return { create: false, update: false, delete: false };\n  }\n\n  const disabled: SnapshotGqlOperations = {};\n  for (const key of GQL_OPERATION_KEYS) {\n    if (operations[key] === false) disabled[key] = false;\n  }\n\n  return definedWhenNotEmpty(disabled);\n}\n\nfunction appliedConfiguredDisabledGqlOperations(\n  remoteDisabled: RemoteTailorDBSettings[\"disableGqlOperations\"] | undefined,\n  configuredDisabled: SnapshotGqlOperations | undefined,\n): SnapshotGqlOperations | undefined {\n  if (!remoteDisabled || !configuredDisabled) return undefined;\n\n  const disabled: SnapshotGqlOperations = {};\n  for (const key of GQL_OPERATION_KEYS) {\n    if (configuredDisabled[key] === false && remoteDisabled[key]) disabled[key] = false;\n  }\n\n  return definedWhenNotEmpty(disabled);\n}\n\nfunction deployComparableSnapshot(\n  snapshot: SchemaSnapshot,\n  remoteTypes: ReadonlyArray<ProtoTailorDBType>,\n  gqlOperations: DeployGqlOperations,\n): SchemaSnapshot {\n  const remoteTablesByName = new Map(remoteTypes.map((type) => [type.name, type]));\n  const configuredDisabled = configuredDisabledGqlOperations(gqlOperations);\n  const tables: Record<string, TailorDBSnapshotType> = {};\n\n  for (const [tableName, type] of Object.entries(snapshot.tables)) {\n    const settings: SnapshotSettings = { ...type.settings };\n    const remoteSettings = remoteTablesByName.get(tableName)?.schema?.settings;\n\n    if (type.settings?.publishEvents === undefined && remoteSettings?.publishRecordEvents) {\n      settings.publishEvents = true;\n    }\n\n    if (type.settings?.gqlOperations === undefined) {\n      const disabled = appliedConfiguredDisabledGqlOperations(\n        remoteSettings?.disableGqlOperations,\n        configuredDisabled,\n      );\n      if (disabled) settings.gqlOperations = disabled;\n    }\n\n    const comparableType = { ...type };\n    const comparableSettings = definedWhenNotEmpty(settings);\n    if (comparableSettings) {\n      comparableType.settings = comparableSettings;\n    } else {\n      delete comparableType.settings;\n    }\n    tables[tableName] = comparableType;\n  }\n\n  return { ...snapshot, tables };\n}\n\n/**\n * Verify remote schema matches the expected snapshot state\n * @param {OperatorClient} client - Operator client instance\n * @param {string} workspaceId - Workspace ID\n * @param {NamespaceWithMigrations[]} namespacesWithMigrations - Namespaces with migration config\n * @param {LoadedConfig} config - Loaded application config\n * @param {ReadonlyArray<TailorDBDeployInput>} tailorDBInputs - Deploy inputs for namespace defaults\n * @returns {Promise<RemoteSchemaVerificationResult[]>} Verification results per namespace\n */\nexport async function verifyRemoteSchema(\n  client: OperatorClient,\n  workspaceId: string,\n  namespacesWithMigrations: NamespaceWithMigrations[],\n  config: LoadedConfig,\n  tailorDBInputs: ReadonlyArray<TailorDBDeployInput>,\n): Promise<RemoteSchemaVerificationResult[]> {\n  const results: RemoteSchemaVerificationResult[] = [];\n\n  for (const { namespace, migrationsDir } of namespacesWithMigrations) {\n    // Get current remote migration number\n    const remoteState = await fetchRemoteMigrationState(\n      client,\n      resourceTrn(workspaceId, \"tailordb\", namespace),\n    );\n    const { metadataExists, number: remoteMigrationNumber } = remoteState;\n\n    if (\n      remoteState.historyIdInvalid ||\n      (remoteMigrationNumber === null && remoteState.historyId !== null)\n    ) {\n      results.push({\n        namespace,\n        remoteMigrationNumber: remoteMigrationNumber ?? 0,\n        drifts: [],\n        hasDrift: false,\n        checkpointMissingLocal: true,\n      });\n      continue;\n    }\n\n    // If no migration label exists, this is likely a first apply - skip verification\n    // Remote verification only makes sense when there's an established migration history\n    if (remoteMigrationNumber === null) {\n      results.push({\n        namespace,\n        remoteMigrationNumber: 0,\n        drifts: [],\n        hasDrift: false,\n        skipped: metadataExists ? \"no_migration_label\" : \"not_deployed\",\n      });\n      continue;\n    }\n\n    const latestMigrationNumber = getLatestMigrationNumber(migrationsDir);\n    const baselineSnapshot = reconstructSnapshotFromMigrations(migrationsDir, 0);\n    const rebaseline = baselineSnapshot?.rebaseline;\n    const historyMatchesCurrent = rebaseline\n      ? remoteState.historyId === rebaseline.historyId\n      : remoteState.historyId === null;\n    const historyMatchesReplaced = rebaseline\n      ? remoteState.historyId === rebaseline.replacedHistoryId\n      : false;\n    const checkpointRepair =\n      rebaseline &&\n      historyMatchesReplaced &&\n      remoteMigrationNumber === rebaseline.replacedLatestMigration\n        ? ({\n            from: remoteMigrationNumber,\n            to: 0,\n            fromHistoryId: remoteState.historyId,\n            toHistoryId: rebaseline.historyId,\n          } as const)\n        : undefined;\n    const checkpointMissingLocal =\n      (!historyMatchesCurrent && !checkpointRepair) ||\n      (remoteMigrationNumber > latestMigrationNumber && !checkpointRepair);\n    if (checkpointMissingLocal) {\n      const rebaselinePending =\n        rebaseline &&\n        historyMatchesReplaced &&\n        remoteMigrationNumber < rebaseline.replacedLatestMigration\n          ? { replacedLatestMigration: rebaseline.replacedLatestMigration }\n          : undefined;\n      results.push({\n        namespace,\n        remoteMigrationNumber,\n        drifts: [],\n        hasDrift: false,\n        checkpointMissingLocal: true,\n        ...(rebaselinePending ? { rebaselinePending } : {}),\n      });\n      continue;\n    }\n    const expectedMigrationNumber = checkpointRepair?.to ?? remoteMigrationNumber;\n\n    // Reconstruct the snapshot that the remote schema must match.\n    const expectedSnapshot = reconstructSnapshotFromMigrations(\n      migrationsDir,\n      expectedMigrationNumber,\n    );\n    if (!expectedSnapshot) {\n      // No snapshots exist - skip verification\n      results.push({\n        namespace,\n        remoteMigrationNumber,\n        drifts: [],\n        hasDrift: false,\n        skipped: \"no_snapshot\",\n      });\n      continue;\n    }\n\n    // Fetch remote tables\n    const [remoteTypes, remoteGqlPermissions] = await Promise.all([\n      fetchRemoteTypes(client, workspaceId, namespace),\n      fetchRemoteGqlPermissions(client, workspaceId, namespace),\n    ]);\n    const expectedDeploySnapshot = deployComparableSnapshot(\n      expectedSnapshot,\n      remoteTypes,\n      namespaceGqlOperations(config, tailorDBInputs, namespace),\n    );\n\n    // Compare remote with expected snapshot\n    const drifts = compareRemoteWithSnapshot(\n      remoteTypes,\n      expectedDeploySnapshot,\n      remoteGqlPermissions,\n    );\n\n    results.push({\n      namespace,\n      remoteMigrationNumber,\n      drifts,\n      hasDrift: drifts.length > 0,\n      ...(checkpointRepair && drifts.length === 0 ? { checkpointRepair } : {}),\n    });\n  }\n\n  return results;\n}\n\n/**\n * Minimal per-namespace drift shape needed to detect the v1-origin\n * missing-script-hash pattern, shared by callers that hold either a full\n * {@link RemoteSchemaVerificationResult} or a validation report's subset of it.\n */\ninterface DriftGuidanceInput {\n  hasDrift: boolean;\n  drifts: readonly SchemaDrift[];\n}\n\nfunction isMissingRemoteScriptHashDrift(drift: SchemaDrift): boolean {\n  return (\n    drift.kind === \"script_mismatch\" && drift.details.endsWith(MISSING_REMOTE_SCRIPT_HASH_SUFFIX)\n  );\n}\n\n/**\n * Detect the pattern left by a v1-deployed environment: the v1 CLI never wrote\n * script hashes, so every drift reports a missing hash rather than an actual\n * schema difference.\n * @param {readonly DriftGuidanceInput[]} driftResults - Per-namespace verification results\n * @returns {boolean} True when every reported drift is a missing-script-hash drift\n */\nfunction isLikelyPreV2ScriptHashDrift(driftResults: readonly DriftGuidanceInput[]): boolean {\n  const withDrift = driftResults.filter((result) => result.hasDrift);\n  return (\n    withDrift.length > 0 &&\n    withDrift.every(\n      (result) => result.drifts.length > 0 && result.drifts.every(isMissingRemoteScriptHashDrift),\n    )\n  );\n}\n\n/**\n * Log common causes of remote schema drift and how to resolve them\n * @param {readonly DriftGuidanceInput[]} [driftResults] - Per-namespace verification results, used to add a targeted hint for the v1-origin missing-hash pattern\n * @returns {void}\n */\nexport function logRemoteDriftGuidance(driftResults?: readonly DriftGuidanceInput[]): void {\n  logger.info(\"This may indicate:\");\n  logger.info(\"  - Another developer applied different migrations\", { mode: \"plain\" });\n  logger.info(\"  - Manual schema changes were made directly\", { mode: \"plain\" });\n  logger.info(\"  - Migration history is out of sync\", { mode: \"plain\" });\n  logger.newline();\n  logger.info(\"To resolve:\");\n  logger.info(\"  - Run 'tailor tailordb migration status' to compare local vs remote.\", {\n    mode: \"plain\",\n  });\n  logger.info(\"  - If remote is correct, update local tables and run 'migration generate'.\", {\n    mode: \"plain\",\n  });\n  logger.info(\n    \"  - If local migration history is correct, run 'migration sync <N>' to overwrite remote.\",\n    { mode: \"plain\" },\n  );\n  logger.info(\"  - If only bookkeeping is stale, run 'migration set <N>'.\", { mode: \"plain\" });\n  if (driftResults && isLikelyPreV2ScriptHashDrift(driftResults)) {\n    logger.newline();\n    logger.info(\n      `Every listed drift is '${MISSING_REMOTE_SCRIPT_HASH_SUFFIX}'. Run 'migration sync <N>' above to add the missing hashes.`,\n    );\n  }\n}\n\n/**\n * Minimal per-namespace shape needed to report a missing remote checkpoint, shared by callers\n * that hold either a full {@link RemoteSchemaVerificationResult} or a validation report's subset.\n */\ninterface CheckpointMissingGuidanceInput {\n  namespace: string;\n  remoteMigrationNumber: number;\n  rebaselinePending?: RebaselinePendingInfo;\n}\n\ntype RebaselinePendingGuidanceInput = CheckpointMissingGuidanceInput & {\n  rebaselinePending: RebaselinePendingInfo;\n};\n\nfunction hasRebaselinePending(\n  result: CheckpointMissingGuidanceInput,\n): result is RebaselinePendingGuidanceInput {\n  return result.rebaselinePending !== undefined;\n}\n\n/**\n * Log recovery guidance for namespaces whose remote migration checkpoint is not in the local\n * migration history, singling out the specific \"fell behind before a rebaseline\" cause when\n * present.\n * @param {readonly CheckpointMissingGuidanceInput[]} results - Namespaces with a missing checkpoint\n * @returns {void}\n */\nexport function logMissingCheckpointGuidance(\n  results: readonly CheckpointMissingGuidanceInput[],\n): void {\n  const pending = results.filter(hasRebaselinePending);\n  if (pending.length > 0) {\n    for (const result of pending) {\n      const target = formatMigrationNumber(result.rebaselinePending.replacedLatestMigration);\n      const current = formatMigrationNumber(result.remoteMigrationNumber);\n      logger.info(\n        `${result.namespace} fell behind before 'migration rebaseline' ran: every environment was required to already be at migration ${target} before the rebaseline, but this environment is at ${current}.`,\n      );\n    }\n    logger.newline();\n    logger.info(\"To recover:\");\n    logger.info(\n      \"  1. Restore the pre-rebaseline migrations/ directory from git history (the commit before 'migration rebaseline' ran; rebaseline preserves committed files there).\",\n      { mode: \"plain\" },\n    );\n    logger.info(\n      \"  2. Deploy this environment against that restored history until its checkpoint reaches the migration named above, running any migrate.ts scripts it still needs.\",\n      { mode: \"plain\" },\n    );\n    logger.info(\n      \"  3. Switch back to the current migration files and deploy again — the automatic checkpoint reset to the new baseline then applies.\",\n      { mode: \"plain\" },\n    );\n  }\n  if (pending.length < results.length) {\n    if (pending.length > 0) logger.newline();\n    logger.info(\n      \"Pull the latest migration files, or run 'tailor tailordb migration status' to compare.\",\n    );\n  }\n}\n\n/**\n * Format remote schema verification results for display\n * @param {RemoteSchemaVerificationResult[]} results - Verification results\n * @returns {string} Formatted results string\n */\nexport function formatRemoteVerificationResults(results: RemoteSchemaVerificationResult[]): string {\n  const lines: string[] = [];\n\n  for (const result of results) {\n    if (!result.hasDrift) continue;\n\n    lines.push(`Namespace: ${result.namespace}`);\n    lines.push(`  Remote migration: ${formatMigrationNumber(result.remoteMigrationNumber)}`);\n    lines.push(`  Differences:`);\n    lines.push(formatSchemaDrifts(result.drifts));\n    lines.push(\"\");\n  }\n\n  return lines.join(\"\\n\");\n}\n\n// ============================================================================\n// Local Migration Diff Check\n// ============================================================================\n\nexport interface MigrationCheckResult {\n  namespace: string;\n  migrationsDir: string;\n  hasDiff: boolean;\n  diff?: MigrationDiff;\n}\n\n/**\n * Check if there are schema differences between migration snapshots and local definitions\n * @param {ReadonlyMap<string, Record<string, TailorDBSnapshotType>>} typesByNamespace - Snapshot-shaped local tables by namespace\n * @param {NamespaceWithMigrations[]} namespacesWithMigrations - Namespaces with migrations config\n * @returns {Promise<MigrationCheckResult[]>} Results for each namespace\n */\nexport async function checkMigrationDiffs(\n  typesByNamespace: ReadonlyMap<string, Record<string, TailorDBSnapshotType>>,\n  namespacesWithMigrations: NamespaceWithMigrations[],\n): Promise<MigrationCheckResult[]> {\n  const results: MigrationCheckResult[] = [];\n\n  for (const { namespace, migrationsDir } of namespacesWithMigrations) {\n    const localTypes = typesByNamespace.get(namespace);\n    if (!localTypes) {\n      continue;\n    }\n\n    // Returns null when the migrations directory is missing or empty;\n    // throws when existing migration files are invalid.\n    const previousSnapshot = reconstructSnapshotFromMigrations(migrationsDir);\n\n    if (!previousSnapshot) {\n      // No snapshots yet - user should run migrate generate first\n      results.push({\n        namespace,\n        migrationsDir,\n        hasDiff: true,\n        diff: undefined, // Indicates no snapshot exists\n      });\n      continue;\n    }\n\n    // Compare with local tables\n    const diff = compareLocalTypesWithSnapshot(previousSnapshot, localTypes, namespace);\n\n    results.push({\n      namespace,\n      migrationsDir,\n      hasDiff: hasChanges(diff),\n      diff: hasChanges(diff) ? diff : undefined,\n    });\n  }\n\n  return results;\n}\n\n/**\n * Format migration check results for display\n * @param {MigrationCheckResult[]} results - Migration check results\n * @returns {string} Formatted results string\n */\nexport function formatMigrationCheckResults(results: MigrationCheckResult[]): string {\n  const lines: string[] = [];\n\n  for (const result of results) {\n    if (!result.hasDiff) {\n      continue;\n    }\n\n    lines.push(`Namespace: ${result.namespace}`);\n\n    if (!result.diff) {\n      lines.push(\"  No migration snapshot found. Run 'tailor tailordb migration generate' first.\");\n    } else {\n      lines.push(`  ${formatDiffSummary(result.diff)}`);\n      lines.push(\"\");\n      lines.push(formatMigrationDiff(result.diff));\n    }\n    lines.push(\"\");\n  }\n\n  return lines.join(\"\\n\");\n}\n","import * as path from \"pathe\";\nimport {\n  getNamespacesWithMigrations,\n  type NamespaceWithMigrations,\n} from \"#/cli/commands/tailordb/migrate/config\";\nimport { captureMigrationFileState } from \"#/cli/commands/tailordb/migrate/file-state\";\nimport {\n  checkMigrationDiffs,\n  formatMigrationCheckResults,\n  formatRemoteVerificationResults,\n  logMissingCheckpointGuidance,\n  logRemoteDriftGuidance,\n  verifyRemoteSchema,\n  type TailorDBDeployInput,\n} from \"#/cli/commands/tailordb/migrate/schema-checks\";\nimport {\n  reconstructSnapshotFromMigrations,\n  assertValidMigrationFiles,\n  formatMigrationNumber,\n  type TailorDBSnapshotType,\n} from \"#/cli/commands/tailordb/migrate/snapshot\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { detectPendingMigrations } from \"./migration\";\nimport type {\n  MigrationCheckpointRepair,\n  PendingMigration,\n} from \"#/cli/commands/tailordb/migrate/types\";\nimport type { OperatorClient } from \"#/cli/shared/client\";\nimport type { LoadedConfig } from \"#/cli/shared/config-loader\";\n\nexport type ValidateAndDetectResult = {\n  pendingMigrations: PendingMigration[];\n  checkpointRepairs: MigrationCheckpointRepair[];\n  namespacesWithMigrations: NamespaceWithMigrations[];\n  migrationFileState: Record<string, string>;\n  migrationHistoryIds: Record<string, string | null>;\n};\n\nexport function migrationFileStatesEqual(\n  planned: Readonly<Record<string, string>>,\n  current: Readonly<Record<string, string>>,\n): boolean {\n  const plannedNamespaces = Object.keys(planned).toSorted();\n  const currentNamespaces = Object.keys(current).toSorted();\n  return (\n    plannedNamespaces.length === currentNamespaces.length &&\n    plannedNamespaces.every(\n      (namespace, index) =>\n        namespace === currentNamespaces[index] && planned[namespace] === current[namespace],\n    )\n  );\n}\n\n/**\n * Validate migration files and detect pending migrations\n * @param {OperatorClient} client - Operator client instance\n * @param {string} workspaceId - Workspace ID\n * @param {ReadonlyMap<string, Record<string, TailorDBSnapshotType>>} typesByNamespace - Tables by namespace\n * @param {LoadedConfig} config - Loaded application config (includes path)\n * @param {boolean} noSchemaCheck - Whether to skip schema diff check\n * @param {ReadonlyArray<TailorDBDeployInput>} tailorDBInputs - Deploy inputs for namespace defaults\n * @returns {Promise<ValidateAndDetectResult>} Pending migrations and namespaces that have migration directories configured\n */\nexport async function validateAndDetectMigrations(\n  client: OperatorClient,\n  workspaceId: string,\n  typesByNamespace: ReadonlyMap<string, Record<string, TailorDBSnapshotType>>,\n  config: LoadedConfig,\n  noSchemaCheck: boolean,\n  tailorDBInputs: ReadonlyArray<TailorDBDeployInput>,\n): Promise<ValidateAndDetectResult> {\n  const configDir = path.dirname(config.path);\n  const namespacesWithMigrations = getNamespacesWithMigrations(config, configDir);\n  let pendingMigrations: PendingMigration[] = [];\n  let checkpointRepairs: MigrationCheckpointRepair[] = [];\n  const migrationHistoryIds = Object.create(null) as Record<string, string | null>;\n\n  if (namespacesWithMigrations.length > 0) {\n    // Validate migration file integrity (sequential numbers, no gaps, no duplicates)\n    for (const { namespace, migrationsDir } of namespacesWithMigrations) {\n      assertValidMigrationFiles(migrationsDir, namespace);\n      migrationHistoryIds[namespace] =\n        reconstructSnapshotFromMigrations(migrationsDir)?.rebaseline?.historyId ?? null;\n    }\n\n    // Check for schema diffs if not skipped\n    if (!noSchemaCheck) {\n      // 1. Check local tables vs local snapshot (existing check)\n      const migrationResults = await checkMigrationDiffs(\n        typesByNamespace,\n        namespacesWithMigrations,\n      );\n      const hasDiffs = migrationResults.some((r) => r.hasDiff);\n\n      if (hasDiffs) {\n        logger.error(\"Schema changes detected that are not in migration files:\");\n        logger.log(formatMigrationCheckResults(migrationResults));\n        logger.newline();\n        logger.info(\"Run 'tailor tailordb migration generate' to create migration files.\");\n        logger.info(\"Or use '--no-schema-check' to skip this check.\");\n        throw CLIError({\n          code: \"MIGRATION_SCHEMA_CHECK_FAILED\",\n          message: \"Schema migration check failed\",\n          suggestion:\n            \"Run 'tailor tailordb migration generate' to create migration files, or use --no-schema-check to skip this check.\",\n        });\n      }\n\n      // 2. Check remote schema vs local snapshot (new check)\n      const remoteVerificationResults = await verifyRemoteSchema(\n        client,\n        workspaceId,\n        namespacesWithMigrations,\n        config,\n        tailorDBInputs,\n      );\n      checkpointRepairs = remoteVerificationResults.flatMap((result) =>\n        result.checkpointRepair\n          ? [{ namespace: result.namespace, ...result.checkpointRepair }]\n          : [],\n      );\n      const missingCheckpointResults = remoteVerificationResults.filter(\n        (result) => result.checkpointMissingLocal,\n      );\n      if (missingCheckpointResults.length > 0) {\n        logger.error(\"Remote migration checkpoint is not in the local migration history:\");\n        for (const result of missingCheckpointResults) {\n          logger.log(\n            `  ${result.namespace}: ${formatMigrationNumber(result.remoteMigrationNumber)}`,\n          );\n        }\n        logger.newline();\n        logMissingCheckpointGuidance(missingCheckpointResults);\n        throw CLIError({\n          code: \"MIGRATION_CHECKPOINT_UNKNOWN\",\n          message: \"Remote migration checkpoint verification failed\",\n        });\n      }\n      const hasRemoteDrift = remoteVerificationResults.some((r) => r.hasDrift);\n\n      if (hasRemoteDrift) {\n        logger.error(\"Remote schema drift detected:\");\n        logger.log(formatRemoteVerificationResults(remoteVerificationResults));\n        logger.newline();\n        logRemoteDriftGuidance(remoteVerificationResults);\n        logger.newline();\n        logger.info(\"Use '--no-schema-check' to skip this check (not recommended).\");\n        throw CLIError({\n          code: \"MIGRATION_REMOTE_DRIFT\",\n          message: \"Remote schema verification failed\",\n        });\n      }\n      for (const repair of checkpointRepairs) {\n        logger.warn(\n          `Remote migration checkpoint for ${repair.namespace} will be reset to 0000 after confirmation (${formatMigrationNumber(repair.from)} → 0000); the remote schema already matches the local baseline.`,\n        );\n      }\n    }\n\n    // Detect pending migrations (migration scripts that haven't been executed yet)\n    const currentMigrationOverrides = new Map(\n      checkpointRepairs.map((repair) => [repair.namespace, repair.to]),\n    );\n    pendingMigrations = await detectPendingMigrations(\n      client,\n      workspaceId,\n      namespacesWithMigrations,\n      config.path,\n      currentMigrationOverrides,\n    );\n\n    if (pendingMigrations.length > 0) {\n      logger.newline();\n\n      // Classify migrations by whether a migrate.ts will run for them.\n      const withScripts = pendingMigrations.filter((m) => m.hasScript);\n      const withoutScripts = pendingMigrations.filter((m) => !m.hasScript);\n\n      logger.info(`${pendingMigrations.length} pending migration(s) will be applied:`);\n      if (withoutScripts.length > 0) {\n        logger.info(\n          `  • ${withoutScripts.length} schema change(s) (applied automatically with schema deployment)`,\n          { mode: \"plain\" },\n        );\n      }\n      if (withScripts.length > 0) {\n        logger.info(\n          `  • ${withScripts.length} data migration(s) (requires migration script execution)`,\n          { mode: \"plain\" },\n        );\n      }\n    }\n  }\n\n  return {\n    pendingMigrations,\n    checkpointRepairs,\n    namespacesWithMigrations,\n    migrationFileState: captureMigrationFileState(namespacesWithMigrations),\n    migrationHistoryIds,\n  };\n}\n","import * as path from \"pathe\";\nimport {\n  getNamespacesWithMigrations,\n  type NamespaceWithMigrations,\n} from \"#/cli/commands/tailordb/migrate/config\";\nimport { captureMigrationFileState } from \"#/cli/commands/tailordb/migrate/file-state\";\nimport { fetchRemoteMigrationState } from \"#/cli/commands/tailordb/migrate/remote-state\";\nimport {\n  reconstructSnapshotFromMigrations,\n  formatMigrationNumber,\n  getLatestMigrationNumber,\n  getMigrationFiles,\n  type SchemaSnapshot,\n  type TailorDBSnapshotType,\n} from \"#/cli/commands/tailordb/migrate/snapshot\";\nimport { generateTailorDBTypeManifestFromSnapshot } from \"#/cli/commands/tailordb/migrate/snapshot-manifest\";\nimport { handleOptionalToRequiredError } from \"#/cli/commands/tailordb/migrate/types\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { withSpan } from \"#/cli/telemetry/index\";\nimport { resourceTrn, writeMetadataLabels } from \"../label\";\nimport { executeMigrations, updateMigrationLabel, type MigrationContext } from \"./migration\";\nimport {\n  applyMigrationRestrictions,\n  captureMigrationRestrictionState,\n  deletedResources,\n  executeSingleMigrationPostPhase,\n  executeSingleMigrationPostPhaseDeletions,\n  executeSingleMigrationPrePhase,\n  restoreMigrationRestrictions,\n  getDeletedTableNames,\n  migrationSnapshotCache,\n  processedTables,\n  resolveMigrationSnapshotSettings,\n  rollbackSingleMigrationAfterFailure,\n} from \"./migration-execution\";\nimport {\n  migrationFileStatesEqual,\n  validateAndDetectMigrations,\n  type ValidateAndDetectResult,\n} from \"./migration-validation\";\nimport type { PendingMigration } from \"#/cli/commands/tailordb/migrate/types\";\nimport type { OperatorClient } from \"#/cli/shared/client\";\nimport type { TailorDBServiceConfig } from \"#/types/tailordb.generated\";\nimport type { ApplyPhase } from \"../types\";\nimport type { planTailorDB, TailorDBChangeSet, TailorDBPlanResult } from \"./plan\";\n\n/**\n * Reconcile each namespace's migration checkpoint and history ID to\n * the working tree after a create-update apply.\n *\n * This records the initial baseline (`0000`), which is deployed via the normal\n * flow and never bumps the label itself, and keeps the label `<= working_tree_max`\n * after a `--no-schema-check` deploy from an older revision. Namespaces without a\n * baseline are skipped so no phantom label is written.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param namespacesWithMigrations - Namespaces that have migration directories configured\n * @param migrationHistoryIds - Migration history ID captured during preflight for each namespace\n */\nasync function reconcileMigrationLabels(\n  client: OperatorClient,\n  workspaceId: string,\n  namespacesWithMigrations: NamespaceWithMigrations[],\n  migrationHistoryIds: Readonly<Record<string, string | null>>,\n): Promise<void> {\n  for (const { namespace, migrationsDir } of namespacesWithMigrations) {\n    if (getMigrationFiles(migrationsDir).length === 0) {\n      continue;\n    }\n    const targetVersion = getLatestMigrationNumber(migrationsDir);\n    const historyId = migrationHistoryIds[namespace] ?? null;\n    const remoteState = await fetchRemoteMigrationState(\n      client,\n      resourceTrn(workspaceId, \"tailordb\", namespace),\n    ).catch(() => null);\n    const currentVersion = remoteState?.number ?? null;\n    if (remoteState && currentVersion === targetVersion && remoteState.historyId === historyId) {\n      continue;\n    }\n    await updateMigrationLabel(\n      client,\n      workspaceId,\n      namespace,\n      targetVersion,\n      historyId ?? undefined,\n    );\n    if (remoteState) {\n      logger.info(\n        `Migration label for namespace ${namespace} reconciled: ${describeMigrationCheckpoint(currentVersion)} → ${formatMigrationNumber(targetVersion)}.`,\n      );\n    } else {\n      logger.info(\n        `Migration label for namespace ${namespace} reconciled to ${formatMigrationNumber(targetVersion)}.`,\n      );\n    }\n  }\n}\n\n/**\n * Build migration execution context for script-based migrations.\n * @param client - Operator client instance\n * @param migrationContext - Planned TailorDB context\n * @param migrationsRequiringScripts - Migrations that require scripts\n * @returns Migration context for script execution\n */\nfunction buildMigrationContextForScripts(\n  client: OperatorClient,\n  migrationContext: Awaited<ReturnType<typeof planTailorDB>>[\"context\"],\n  migrationsRequiringScripts: PendingMigration[],\n): MigrationContext {\n  const authService = migrationContext.application.authService;\n  if (!authService) {\n    throw CLIError({\n      code: \"AUTH_CONFIG_REQUIRED\",\n      message: \"Auth configuration is required to execute migration scripts.\",\n    });\n  }\n\n  const dbConfigMap: Record<string, TailorDBServiceConfig | undefined> = {};\n  for (const migration of migrationsRequiringScripts) {\n    if (!(migration.namespace in dbConfigMap)) {\n      dbConfigMap[migration.namespace] = migrationContext.config.db?.[migration.namespace] as\n        | TailorDBServiceConfig\n        | undefined;\n    }\n  }\n\n  return {\n    client,\n    workspaceId: migrationContext.workspaceId,\n    authNamespace: authService.config.name,\n    machineUsers: authService.config.machineUsers\n      ? Object.keys(authService.config.machineUsers)\n      : undefined,\n    dbConfig: dbConfigMap,\n    env: migrationContext.config.env ?? {},\n    configDir: path.dirname(migrationContext.config.path),\n    appName: migrationContext.application.name,\n    appId: migrationContext.application.id,\n  };\n}\n\nasync function validateTailorDBMigrationState(\n  client: OperatorClient,\n  result: TailorDBPlanResult,\n): Promise<ValidateAndDetectResult> {\n  const { context } = result;\n  if (context.migrationTestBaselines) {\n    const currentMigrationFileState = captureMigrationFileState(\n      getNamespacesWithMigrations(context.config, path.dirname(context.config.path)),\n    );\n    if (!migrationFileStatesEqual(context.migrationFileState, currentMigrationFileState)) {\n      throw CLIError({\n        code: \"DEPLOY_PLAN_STALE\",\n        message: \"Migration files changed after deployment planning.\",\n        suggestion: \"Run the migration test again to create a fresh plan.\",\n      });\n    }\n    return {\n      pendingMigrations: [],\n      checkpointRepairs: [],\n      namespacesWithMigrations: [],\n      migrationFileState: currentMigrationFileState,\n      migrationHistoryIds: {},\n    };\n  }\n  const typesByNamespace = new Map<string, Record<string, TailorDBSnapshotType>>();\n  for (const tailordb of context.tailorDBInputs) {\n    typesByNamespace.set(tailordb.namespace, tailordb.types);\n  }\n\n  const validation = await validateAndDetectMigrations(\n    client,\n    context.workspaceId,\n    typesByNamespace,\n    context.config,\n    context.noSchemaCheck,\n    context.tailorDBInputs,\n  );\n  const approvedRepairs = context.checkpointRepairs;\n  const repairPlanChanged =\n    approvedRepairs.length !== validation.checkpointRepairs.length ||\n    validation.checkpointRepairs.some(\n      (repair) =>\n        !approvedRepairs.some(\n          (approved) =>\n            approved.namespace === repair.namespace &&\n            approved.from === repair.from &&\n            approved.fromHistoryId === repair.fromHistoryId &&\n            approved.toHistoryId === repair.toHistoryId,\n        ),\n    );\n  if (repairPlanChanged) {\n    throw CLIError({\n      code: \"DEPLOY_PLAN_STALE\",\n      message: \"Remote migration checkpoint repair changed after deployment planning.\",\n      suggestion: \"Run the deployment again to review the updated repair.\",\n    });\n  }\n  if (!migrationFileStatesEqual(context.migrationFileState, validation.migrationFileState)) {\n    throw CLIError({\n      code: \"DEPLOY_PLAN_STALE\",\n      message: \"Migration files changed after deployment planning.\",\n      suggestion: \"Run the deployment again to create a fresh plan.\",\n    });\n  }\n  return validation;\n}\n\n/**\n * Revalidate migration state before the deployment enters any mutation phase.\n * @param client - Operator client instance\n * @param result - Planned TailorDB changes\n */\nexport async function preflightTailorDB(\n  client: OperatorClient,\n  result: TailorDBPlanResult,\n): Promise<void> {\n  await validateTailorDBMigrationState(client, result);\n}\n\nfunction includeUndeletedTables(\n  snapshot: SchemaSnapshot,\n  previousSnapshot: SchemaSnapshot | undefined,\n  migration: PendingMigration,\n): SchemaSnapshot {\n  const undeletedTables = [...getDeletedTableNames(migration)].flatMap((tableName) => {\n    const table = previousSnapshot?.tables[tableName];\n    return table ? [[tableName, table] as const] : [];\n  });\n  return {\n    ...snapshot,\n    tables: {\n      ...snapshot.tables,\n      ...Object.fromEntries(undeletedTables),\n    },\n  };\n}\n\nfunction describeMigrationCheckpoint(number: number | null | undefined): string {\n  return number == null ? \"<unset>\" : formatMigrationNumber(number);\n}\n\n/**\n * Apply TailorDB-related changes for the given phase.\n * @param client - Operator client instance\n * @param result - Planned TailorDB changes\n * @param phase - Apply phase (defaults to \"create-update\")\n */\nexport async function applyTailorDB(\n  client: OperatorClient,\n  result: Awaited<ReturnType<typeof planTailorDB>>,\n  phase: Exclude<ApplyPhase, \"delete\"> = \"create-update\",\n): Promise<void> {\n  const { changeSet, context: migrationContext } = result;\n\n  if (phase === \"create-update\") {\n    // Plan-time validation makes dry runs fail fast. Repeat the full validation\n    // at the apply boundary because migration files, remote checkpoints, or the\n    // remote schema may have changed while waiting for confirmation.\n    const { pendingMigrations, checkpointRepairs, namespacesWithMigrations, migrationHistoryIds } =\n      await validateTailorDBMigrationState(client, result);\n\n    for (const repair of checkpointRepairs) {\n      await updateMigrationLabel(\n        client,\n        migrationContext.workspaceId,\n        repair.namespace,\n        repair.to,\n        repair.toHistoryId,\n      );\n      logger.info(\n        `Migration checkpoint for namespace ${repair.namespace} reset: ${formatMigrationNumber(repair.from)} → 0000.`,\n      );\n    }\n\n    if (pendingMigrations.length > 0) {\n      // Migration flow: Execute each migration sequentially (pre -> script -> post)\n      // This ensures intermediate states are properly handled when scripts depend on them\n\n      // Reset tracking state for this migration run\n      processedTables.reset();\n      deletedResources.reset();\n      migrationSnapshotCache.reset();\n\n      const migratingNamespaces = new Set(pendingMigrations.map((m) => m.namespace));\n      const restrictionState = await captureMigrationRestrictionState(\n        client,\n        migrationContext.workspaceId,\n        migratingNamespaces,\n      );\n\n      // Step 1: Create/update services once at the beginning (services don't need per-migration handling)\n      await executeServicesCreation(client, changeSet);\n\n      // Step 1.5: The migration loop below only touches the types named by\n      // some pending migration's diff; changes planned for every other\n      // namespace must go through the normal flow or they would be silently\n      // dropped. A migrating namespace's planned creates that already exist\n      // in the schema state before its first pending migration — the whole\n      // baseline on a fresh-workspace replay, and every table when the\n      // pending migration is data-only — are equally dropped by the loop and\n      // run here too, built from that snapshot so scripts see the checkpoint\n      // state rather than the final schema. Updates of types no pending diff\n      // names stay skipped: applying the final schema outside the\n      // per-migration phases could enforce a change whose migration has not\n      // run. Snapshot-backed creates run before the loop so scripts see the\n      // checkpoint world. Under --no-schema-check, planned tables absent from\n      // every snapshot are deferred until migrations settle. Deletes are\n      // irreversible and stay last (Step 5).\n      const isOutsideMigrations = (namespaceName: string | undefined) =>\n        namespaceName !== undefined && !migratingNamespaces.has(namespaceName);\n      const firstPendingByNamespace = new Map<string, PendingMigration>();\n      const pendingDeletedTables = new Map<string, Set<string>>();\n      const pendingSnapshotTableKeys = new Set<string>();\n      for (const migration of pendingMigrations) {\n        const first = firstPendingByNamespace.get(migration.namespace);\n        if (!first || migration.number < first.number) {\n          firstPendingByNamespace.set(migration.namespace, migration);\n        }\n        const deleted = pendingDeletedTables.get(migration.namespace) ?? new Set<string>();\n        for (const tableName of getDeletedTableNames(migration)) deleted.add(tableName);\n        pendingDeletedTables.set(migration.namespace, deleted);\n        for (const tableName of Object.keys(migrationSnapshotCache.load(migration).tables)) {\n          pendingSnapshotTableKeys.add(`${migration.namespace}/${tableName}`);\n        }\n      }\n      const preMigrationSnapshots = new Map<string, SchemaSnapshot>();\n      for (const [namespace, first] of firstPendingByNamespace) {\n        const snapshot = reconstructSnapshotFromMigrations(first.migrationsDir, first.number - 1);\n        if (!snapshot) {\n          throw CLIError({\n            code: \"MIGRATION_HISTORY_INVALID\",\n            message: `Cannot reconstruct the schema state before migration ${formatMigrationNumber(first.number)} for namespace \"${namespace}\"`,\n          });\n        }\n        preMigrationSnapshots.set(namespace, snapshot);\n      }\n\n      const deferredTypeKeys = new Set<string>();\n      const deferredGqlPermissionKeys = new Set(\n        [...changeSet.gqlPermission.creates, ...changeSet.gqlPermission.updates]\n          .filter((permission) => {\n            const namespaceName = permission.request.namespaceName;\n            return (\n              migrationContext.noSchemaCheck &&\n              namespaceName !== undefined &&\n              migratingNamespaces.has(namespaceName) &&\n              !pendingSnapshotTableKeys.has(`${namespaceName}/${permission.name}`)\n            );\n          })\n          .map((permission) => `${permission.request.namespaceName}/${permission.name}`),\n      );\n\n      try {\n        for (const create of changeSet.type.creates) {\n          const namespaceName = create.request.namespaceName;\n          if (isOutsideMigrations(namespaceName)) {\n            await client.createTailorDBType(create.request);\n            continue;\n          }\n          const tableName = create.request.tailordbType?.name;\n          if (!namespaceName || !tableName) continue;\n          const priorTable = preMigrationSnapshots.get(namespaceName)?.tables[tableName];\n          if (!priorTable) {\n            if (\n              migrationContext.noSchemaCheck &&\n              !pendingSnapshotTableKeys.has(`${namespaceName}/${tableName}`)\n            ) {\n              deferredTypeKeys.add(`${namespaceName}/${tableName}`);\n            }\n            continue;\n          }\n          // A type some pending migration removes or renames away is created\n          // only when its re-adding migration runs; materializing it early\n          // would erase the removal boundary (the plan holds no delete entry\n          // for a name its final state keeps).\n          if (pendingDeletedTables.get(namespaceName)?.has(tableName)) continue;\n          const input = migrationContext.tailorDBInputs.find((i) => i.namespace === namespaceName);\n          // Recorded so the pre-phase GQL-permission fallback does not create\n          // the type a second time.\n          processedTables.created.add(tableName);\n          await client.createTailorDBType({\n            workspaceId: create.request.workspaceId,\n            namespaceName,\n            tailordbType: generateTailorDBTypeManifestFromSnapshot(priorTable, {\n              suppressRecordEvents: true,\n              suppressGqlOperations: true,\n              namespaceGqlOperations: input?.config.gqlOperations,\n            }),\n          });\n        }\n        for (const update of changeSet.type.updates) {\n          if (!isOutsideMigrations(update.request.namespaceName)) continue;\n          await client.updateTailorDBType(update.request);\n        }\n      } catch (error) {\n        handleOptionalToRequiredError(error, [\n          \"Run 'tailor tailordb migration generate' to create migration files.\",\n          \"Migration scripts allow you to handle existing data before applying the schema change.\",\n        ]);\n      }\n      await Promise.all([\n        ...changeSet.gqlPermission.creates\n          .filter((create) => isOutsideMigrations(create.request.namespaceName))\n          .map((create) => client.createTailorDBGQLPermission(create.request)),\n        ...changeSet.gqlPermission.updates\n          .filter((update) => isOutsideMigrations(update.request.namespaceName))\n          .map((update) => client.updateTailorDBGQLPermission(update.request)),\n      ]);\n\n      const migrationsRequiringScripts = pendingMigrations.filter((m) => m.hasScript);\n\n      // Step 2: Build migration context for script execution (if any migrations require scripts)\n      const migrationCtx =\n        migrationsRequiringScripts.length > 0\n          ? buildMigrationContextForScripts(client, migrationContext, migrationsRequiringScripts)\n          : undefined;\n\n      // Step 3: Execute each migration sequentially: pre -> script -> post\n      if (migrationsRequiringScripts.length > 0) {\n        logger.info(`Executing ${migrationsRequiringScripts.length} data migration(s)...`);\n        logger.newline();\n      }\n\n      const restorationSnapshots = new Map(preMigrationSnapshots);\n      const restorationSettings = new Map(restrictionState);\n      const restorationCheckpoints = new Map<\n        string,\n        { number: number | null; historyId: string | null }\n      >(\n        [...firstPendingByNamespace].map(([namespaceName, firstMigration]) => [\n          namespaceName,\n          {\n            number: firstMigration.number > 0 ? firstMigration.number - 1 : null,\n            historyId: migrationHistoryIds[namespaceName] ?? null,\n          },\n        ]),\n      );\n      let migrationFailure: { error: unknown } | undefined;\n      try {\n        // A committed checkpoint drops its migration from the next run's pending set.\n        await applyMigrationRestrictions(\n          client,\n          preMigrationSnapshots,\n          restrictionState,\n          migrationContext.tailorDBInputs,\n          migrationContext.executorUsedTables,\n          migrationContext.workspaceId,\n        );\n        for (const migration of pendingMigrations) {\n          const attemptedTables = new Set<string>();\n          try {\n            // Pre-migration phase: Create/update tables with breaking fields as optional\n            await withSpan(\"apply.tailorDB.migration.prePhase\", () =>\n              executeSingleMigrationPrePhase(\n                client,\n                changeSet,\n                migration,\n                migrationContext.tailorDBInputs,\n                attemptedTables,\n              ),\n            );\n\n            // Script execution (only if migrate.ts exists for this migration)\n            if (migration.hasScript && migrationCtx) {\n              await withSpan(\"apply.tailorDB.migration.script\", () =>\n                executeMigrations(migrationCtx, [migration]),\n              );\n            }\n          } catch (error) {\n            await rollbackSingleMigrationAfterFailure(\n              client,\n              migration,\n              migrationContext.workspaceId,\n              migrationContext.tailorDBInputs,\n              attemptedTables,\n            );\n            throw error;\n          }\n\n          try {\n            await withSpan(\"apply.tailorDB.migration.postPhase\", () =>\n              executeSingleMigrationPostPhase(\n                client,\n                changeSet,\n                migration,\n                migrationContext.tailorDBInputs,\n                attemptedTables,\n              ),\n            );\n          } catch (error) {\n            await rollbackSingleMigrationAfterFailure(\n              client,\n              migration,\n              migrationContext.workspaceId,\n              migrationContext.tailorDBInputs,\n              attemptedTables,\n            );\n            throw error;\n          }\n\n          const previousRestorationSnapshot = restorationSnapshots.get(migration.namespace);\n          const previousRestorationSettings = restorationSettings.get(migration.namespace);\n          const postMigrationSnapshot = migrationSnapshotCache.load(migration);\n          restorationSnapshots.set(migration.namespace, postMigrationSnapshot);\n          const expectedHistoryId = migrationHistoryIds[migration.namespace] ?? null;\n\n          try {\n            await updateMigrationLabel(\n              client,\n              migrationContext.workspaceId,\n              migration.namespace,\n              migration.number,\n              expectedHistoryId ?? undefined,\n            );\n          } catch (error) {\n            let remoteState: Awaited<ReturnType<typeof fetchRemoteMigrationState>>;\n            try {\n              remoteState = await fetchRemoteMigrationState(\n                client,\n                resourceTrn(migrationContext.workspaceId, \"tailordb\", migration.namespace),\n              );\n            } catch (readbackError) {\n              logger.warn(\n                `Could not verify migration checkpoint ${migration.namespace}/${formatMigrationNumber(migration.number)} after its update failed: ` +\n                  `${readbackError instanceof Error ? readbackError.message : String(readbackError)}. ` +\n                  \"Leaving the post-migration schema unchanged to avoid rolling back a committed checkpoint.\",\n              );\n              throw error;\n            }\n\n            const remoteMigrationNumber = remoteState.number ?? undefined;\n            const differentHistoryAtCheckpoint =\n              remoteState.historyIdInvalid || remoteState.historyId !== expectedHistoryId;\n            const concurrentCheckpoint = differentHistoryAtCheckpoint\n              ? `${describeMigrationCheckpoint(remoteState.number)} in a different migration history`\n              : remoteMigrationNumber !== undefined && remoteMigrationNumber > migration.number\n                ? formatMigrationNumber(remoteMigrationNumber)\n                : undefined;\n            if (concurrentCheckpoint !== undefined) {\n              restorationSnapshots.delete(migration.namespace);\n              throw CLIError({\n                code: \"MIGRATION_CHECKPOINT_CONFLICT\",\n                message:\n                  `Migration checkpoint ${migration.namespace}/${formatMigrationNumber(migration.number)} advanced concurrently to ${concurrentCheckpoint}. ` +\n                  \"Leaving the post-migration schema unchanged and aborting this deployment.\",\n                cause: error,\n              });\n            }\n\n            if (remoteMigrationNumber !== migration.number) {\n              restorationSnapshots.set(\n                migration.namespace,\n                includeUndeletedTables(\n                  postMigrationSnapshot,\n                  previousRestorationSnapshot,\n                  migration,\n                ),\n              );\n              logger.warn(\n                `Migration checkpoint ${migration.namespace}/${formatMigrationNumber(migration.number)} could not be confirmed after its update failed; remote remains at ${describeMigrationCheckpoint(remoteMigrationNumber)}. ` +\n                  \"Leaving the post-migration schema unchanged to avoid rolling back a concurrent deployment. Repair the checkpoint before retrying.\",\n              );\n              throw error;\n            }\n          }\n\n          restorationCheckpoints.set(migration.namespace, {\n            number: migration.number,\n            historyId: expectedHistoryId,\n          });\n\n          const input = migrationContext.tailorDBInputs.find(\n            (entry) => entry.namespace === migration.namespace,\n          );\n          if (input) {\n            const committedSettings = resolveMigrationSnapshotSettings(\n              postMigrationSnapshot,\n              input,\n              migrationContext.executorUsedTables,\n            );\n            for (const [tableName, settings] of previousRestorationSettings ?? []) {\n              if (!previousRestorationSnapshot?.tables[tableName]) {\n                committedSettings.set(tableName, settings);\n              }\n            }\n            restorationSettings.set(migration.namespace, committedSettings);\n          }\n\n          try {\n            await executeSingleMigrationPostPhaseDeletions(client, changeSet, migration);\n          } catch (error) {\n            logger.warn(\n              `Migration checkpoint ${migration.namespace}/${formatMigrationNumber(migration.number)} was committed, but post-checkpoint cleanup failed. ` +\n                \"The leftover resources remain locked. Remove them manually before the next deployment; remote schema verification will fail closed until then.\",\n            );\n            throw error;\n          }\n        }\n\n        if (migrationsRequiringScripts.length > 0) {\n          logger.newline();\n          logger.success(`All data migrations completed successfully.`);\n        }\n      } catch (error) {\n        migrationFailure = { error };\n      }\n\n      for (const [namespaceName, expectedCheckpoint] of restorationCheckpoints) {\n        try {\n          const remoteState = await fetchRemoteMigrationState(\n            client,\n            resourceTrn(migrationContext.workspaceId, \"tailordb\", namespaceName),\n          );\n          const checkpointStillOwned =\n            remoteState.number === expectedCheckpoint.number &&\n            !remoteState.historyIdInvalid &&\n            remoteState.historyId === expectedCheckpoint.historyId;\n          if (checkpointStillOwned) continue;\n\n          restorationSnapshots.delete(namespaceName);\n          const concurrencyError = CLIError({\n            code: \"MIGRATION_CHECKPOINT_CONFLICT\",\n            message:\n              `Migration checkpoint ${namespaceName}/${describeMigrationCheckpoint(expectedCheckpoint.number)} advanced concurrently to ${describeMigrationCheckpoint(remoteState.number)}. ` +\n              \"Skipping restoration for this namespace and aborting this deployment.\",\n          });\n          if (migrationFailure) {\n            logger.warn(\n              `${concurrencyError.message} The original migration error is reported below.`,\n            );\n          } else {\n            migrationFailure = { error: concurrencyError };\n          }\n        } catch (checkpointReadError) {\n          restorationSnapshots.delete(namespaceName);\n          const ownershipError = CLIError({\n            code: \"MIGRATION_CHECKPOINT_UNVERIFIED\",\n            message:\n              `Could not verify ownership of migration checkpoint ${namespaceName}/${describeMigrationCheckpoint(expectedCheckpoint.number)} before restoring table settings: ` +\n              `${checkpointReadError instanceof Error ? checkpointReadError.message : String(checkpointReadError)}. ` +\n              \"Skipping restoration for this namespace and aborting this deployment.\",\n          });\n          if (migrationFailure) {\n            logger.warn(\n              `${ownershipError.message} The original migration error is reported below.`,\n            );\n          } else {\n            migrationFailure = { error: ownershipError };\n          }\n        }\n      }\n\n      try {\n        await restoreMigrationRestrictions(\n          client,\n          restorationSnapshots,\n          restorationSettings,\n          migrationContext.tailorDBInputs,\n          migrationContext.executorUsedTables,\n          migrationContext.workspaceId,\n        );\n      } catch (restorationError) {\n        if (!migrationFailure) throw restorationError;\n        logger.warn(\n          `Could not restore every TailorDB table after the migration failed: ${\n            restorationError instanceof Error ? restorationError.message : String(restorationError)\n          }. The original migration error is reported below.`,\n        );\n      }\n      if (migrationFailure) throw migrationFailure.error;\n\n      for (const create of changeSet.type.creates) {\n        const namespaceName = create.request.namespaceName;\n        const tableName = create.request.tailordbType?.name;\n        if (!namespaceName || !tableName) continue;\n        if (!deferredTypeKeys.has(`${namespaceName}/${tableName}`)) continue;\n        await client.createTailorDBType(create.request);\n      }\n      await Promise.all([\n        ...changeSet.gqlPermission.creates\n          .filter((create) =>\n            deferredGqlPermissionKeys.has(`${create.request.namespaceName}/${create.name}`),\n          )\n          .map((create) => client.createTailorDBGQLPermission(create.request)),\n        ...changeSet.gqlPermission.updates\n          .filter((update) =>\n            deferredGqlPermissionKeys.has(`${update.request.namespaceName}/${update.name}`),\n          )\n          .map((update) => client.updateTailorDBGQLPermission(update.request)),\n      ]);\n\n      // Step 4: Delete remaining GQL permissions that weren't deleted with their tables\n      const remainingGqlPermissionDeletes = changeSet.gqlPermission.deletes.filter((del) => {\n        const permKey = `${del.request.namespaceName}/${del.name}`;\n        return !deletedResources.gqlPermissions.has(permKey);\n      });\n      if (remainingGqlPermissionDeletes.length > 0) {\n        await Promise.all(\n          remainingGqlPermissionDeletes.map((del) =>\n            client.deleteTailorDBGQLPermission(del.request),\n          ),\n        );\n      }\n\n      // Step 5: Delete tables outside the migrating namespaces (their GQL\n      // permissions were just removed above; migration postPhases never see them)\n      await Promise.all(\n        changeSet.type.deletes\n          .filter(\n            (del) =>\n              isOutsideMigrations(del.request.namespaceName) &&\n              !deletedResources.types.has(del.name),\n          )\n          .map((del) => client.deleteTailorDBType(del.request)),\n      );\n\n      // Step 6: Write table metadata, which the migration phases above do not.\n      // Tables inside migrating namespaces only exist once their phases have run,\n      // so this waits until every table in the change set is present. Skipping it\n      // would leave a cross-config dependency record unwritten on any deploy that\n      // carries a migration, and the owner's next solo deploy would turn\n      // publishing off without asking.\n      await Promise.all(\n        [...changeSet.type.creates, ...changeSet.type.updates, ...changeSet.type.unchanged]\n          .filter((entry) => entry.metaRequest && !deletedResources.types.has(entry.name))\n          .flatMap((entry) =>\n            entry.metaRequest ? [writeMetadataLabels(client, entry.metaRequest)] : [],\n          ),\n      );\n    } else {\n      // Normal create-update flow without migrations\n      // Services\n      await Promise.all([\n        ...changeSet.service.creates.map(async (create) => {\n          await client.createTailorDBService(create.request);\n          await writeMetadataLabels(client, create.metaRequest);\n        }),\n        ...changeSet.service.updates.map((update) =>\n          writeMetadataLabels(client, update.metaRequest),\n        ),\n      ]);\n\n      // Tables. An unchanged table still gets its labels written, because its\n      // dependency records can change while its schema does not.\n      try {\n        for (const create of changeSet.type.creates) {\n          await client.createTailorDBType(create.request);\n          await writeMetadataLabels(client, create.metaRequest);\n        }\n        for (const update of changeSet.type.updates) {\n          await client.updateTailorDBType(update.request);\n          await writeMetadataLabels(client, update.metaRequest);\n        }\n        await Promise.all(\n          changeSet.type.unchanged.flatMap((entry) =>\n            entry.metaRequest ? [writeMetadataLabels(client, entry.metaRequest)] : [],\n          ),\n        );\n      } catch (error) {\n        handleOptionalToRequiredError(error, [\n          \"Run 'tailor tailordb migration generate' to create migration files.\",\n          \"Migration scripts allow you to handle existing data before applying the schema change.\",\n        ]);\n      }\n\n      // GQLPermissions\n      await Promise.all([\n        ...changeSet.gqlPermission.creates.map((create) =>\n          client.createTailorDBGQLPermission(create.request),\n        ),\n        ...changeSet.gqlPermission.updates.map((update) =>\n          client.updateTailorDBGQLPermission(update.request),\n        ),\n      ]);\n\n      // Delete resources (only when no migrations occurred)\n      // Migrations already handle deletions in post-migration phase\n      await Promise.all(\n        changeSet.gqlPermission.deletes.map((del) =>\n          client.deleteTailorDBGQLPermission(del.request),\n        ),\n      );\n      await Promise.all(\n        changeSet.type.deletes.map((del) => client.deleteTailorDBType(del.request)),\n      );\n    }\n\n    // Skip when pending migrations ran: each already bumped the label, and\n    // re-pinning to working_tree_max could mask one left intentionally pending\n    // (e.g. a missing script). --no-schema-check always re-pins to repair drift.\n    if (\n      namespacesWithMigrations.length > 0 &&\n      (migrationContext.noSchemaCheck || pendingMigrations.length === 0)\n    ) {\n      await reconcileMigrationLabels(\n        client,\n        migrationContext.workspaceId,\n        namespacesWithMigrations,\n        migrationHistoryIds,\n      );\n    }\n  } else if (phase === \"delete-resources\") {\n    // Delete GQL permissions first, then tables\n    await Promise.all(\n      changeSet.gqlPermission.deletes.map((del) => client.deleteTailorDBGQLPermission(del.request)),\n    );\n    await Promise.all(changeSet.type.deletes.map((del) => client.deleteTailorDBType(del.request)));\n  } else {\n    // Services only\n    await Promise.all(\n      changeSet.service.deletes.map((del) => client.deleteTailorDBService(del.request)),\n    );\n  }\n}\n\n/**\n * Execute services creation (called once at the beginning of migration flow)\n * @param {OperatorClient} client - Operator client instance\n * @param {TailorDBChangeSet} changeSet - TailorDB change set\n * @returns {Promise<void>} Promise that resolves when services are created\n */\nasync function executeServicesCreation(\n  client: OperatorClient,\n  changeSet: TailorDBChangeSet,\n): Promise<void> {\n  await Promise.all([\n    ...changeSet.service.creates.map(async (create) => {\n      await client.createTailorDBService(create.request);\n      await writeMetadataLabels(client, create.metaRequest);\n    }),\n    ...changeSet.service.updates.map((update) => writeMetadataLabels(client, update.metaRequest)),\n  ]);\n}\n","import { type ChangeSet, type HasName } from \"../change-set\";\nimport { ACTION_SYMBOLS, type DisplayAction, type GroupedDisplayEntry } from \"../grouped-display\";\n\ntype TailorDBDisplayEntry = GroupedDisplayEntry;\n\ntype NamespacedItem = HasName & { request?: { namespaceName?: string } };\n\nfunction itemKey(item: NamespacedItem): string {\n  return `${item.request?.namespaceName ?? \"\"}/${item.name}`;\n}\n\nfunction collectTailorDBDisplayEntries(\n  action: DisplayAction,\n  typeItems: ReadonlyArray<NamespacedItem>,\n  gqlPermissionItems: ReadonlyArray<NamespacedItem>,\n): TailorDBDisplayEntry[] {\n  const typeKeys = new Set(typeItems.map(itemKey));\n  const gqlPermissionKeys = new Set(gqlPermissionItems.map(itemKey));\n  const typeEntries = typeItems.map((item) => ({\n    action,\n    symbol: ACTION_SYMBOLS[action],\n    name: item.name,\n    labels: gqlPermissionKeys.has(itemKey(item)) ? [\"table\", \"gqlPermission\"] : [\"table\"],\n    namespace: item.request?.namespaceName,\n  }));\n  const gqlPermissionOnlyEntries = gqlPermissionItems\n    .filter((item) => !typeKeys.has(itemKey(item)))\n    .map((item) => ({\n      action,\n      symbol: ACTION_SYMBOLS[action],\n      name: item.name,\n      labels: [\"gqlPermission\"],\n      namespace: item.request?.namespaceName,\n    }));\n\n  return [...typeEntries, ...gqlPermissionOnlyEntries];\n}\n\n/**\n * Format TailorDB table and gqlPermission changes as grouped dry-run entries.\n * @param typeChangeSet - TailorDB table changes\n * @param gqlPermissionChangeSet - TailorDB gqlPermission changes\n * @returns Display entries for TailorDB resource output\n */\nexport function formatTailorDBResourceChangeEntries(\n  typeChangeSet: Pick<\n    ChangeSet<HasName, HasName, HasName>,\n    \"creates\" | \"updates\" | \"deletes\" | \"replaces\"\n  >,\n  gqlPermissionChangeSet: Pick<\n    ChangeSet<HasName, HasName, HasName>,\n    \"creates\" | \"updates\" | \"deletes\" | \"replaces\"\n  >,\n): TailorDBDisplayEntry[] {\n  return [\n    ...collectTailorDBDisplayEntries(\n      \"create\",\n      typeChangeSet.creates,\n      gqlPermissionChangeSet.creates,\n    ),\n    ...collectTailorDBDisplayEntries(\n      \"delete\",\n      typeChangeSet.deletes,\n      gqlPermissionChangeSet.deletes,\n    ),\n    ...collectTailorDBDisplayEntries(\n      \"update\",\n      typeChangeSet.updates,\n      gqlPermissionChangeSet.updates,\n    ),\n    ...collectTailorDBDisplayEntries(\n      \"replace\",\n      typeChangeSet.replaces,\n      gqlPermissionChangeSet.replaces,\n    ),\n  ];\n}\n","import { type MessageInitShape } from \"@bufbuild/protobuf\";\nimport { TailorDBTypeSchema } from \"@tailor-platform/tailor-proto/tailordb_resource_pb\";\nimport { areNormalizedEqual, normalizeProtoConfig, toComparableProtoJson } from \"../compare\";\nimport type { TailorDBDeployInput } from \"#/cli/commands/tailordb/migrate/schema-checks\";\n\nfunction normalizeComparableTailorDBService(service: {\n  namespace?: string;\n  defaultTimezone?: string;\n}) {\n  return normalizeProtoConfig({\n    namespace: service.namespace,\n    defaultTimezone: service.defaultTimezone || \"UTC\",\n  });\n}\n\nexport function areTailorDBServicesEqual(\n  existing: {\n    namespace?: { name?: string };\n    defaultTimezone?: string;\n  },\n  desired: Readonly<TailorDBDeployInput>,\n): boolean {\n  return areNormalizedEqual(\n    normalizeComparableTailorDBService({\n      namespace: existing.namespace?.name,\n      defaultTimezone: existing.defaultTimezone,\n    }),\n    normalizeComparableTailorDBService({\n      namespace: desired.namespace,\n      defaultTimezone: \"UTC\",\n    }),\n  );\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n  return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nconst tailordbCompareKnownDefaults = {\n  /**\n   * Platform returns this object with explicit false flags even when the SDK omitted\n   * gqlOperations entirely. Treat the all-false object as \"unset\" for diff purposes.\n   */\n  disableGqlOperations: {\n    create: false,\n    update: false,\n    delete: false,\n    read: false,\n  },\n  /**\n   * Some remote validate expressions are emitted as an empty string when the SDK did\n   * not define a script. Local manifests omit the field entirely.\n   */\n  emptyExpression: \"\",\n  /**\n   * Proto bigint-backed values can round-trip as numbers locally and strings remotely.\n   * Canonicalize them to strings at compare time.\n   */\n  numericStringPaths: new Set([\n    \"schema.fields.*.serial.start\",\n    \"schema.fields.*.serial.maxValue\",\n    \"schema.settings.defaultQueryLimitSize\",\n    \"schema.settings.maxBulkUpsertSize\",\n  ]),\n} as const;\n\nexport function normalizeComparableTailorDBType(type: MessageInitShape<typeof TailorDBTypeSchema>) {\n  const canonical = toComparableProtoJson(TailorDBTypeSchema, type);\n  const normalized = normalizeProtoConfig(canonical) as {\n    name?: string;\n    schema?: {\n      description?: string;\n      fields?: Record<string, unknown>;\n      relationships?: Record<string, unknown>;\n      settings?: Record<string, unknown>;\n      indexes?: Record<string, unknown>;\n      files?: Record<string, unknown>;\n      permission?: Record<string, unknown>;\n      typeHook?: Record<string, unknown>;\n      typeValidate?: Record<string, unknown>;\n    };\n  } | null;\n  return normalizeTailorDBCompareValue(\n    {\n      name: normalized?.name ?? \"\",\n      schema: {\n        description: normalized?.schema?.description ?? \"\",\n        fields: normalized?.schema?.fields ?? {},\n        relationships: normalized?.schema?.relationships ?? {},\n        settings: normalized?.schema?.settings ?? {},\n        indexes: normalized?.schema?.indexes ?? {},\n        files: normalized?.schema?.files ?? {},\n        permission: normalized?.schema?.permission ?? {},\n        // Hooks/validators are sent as table-level scripts; include them so a\n        // changed hook or validator is detected as an update.\n        typeHook: normalized?.schema?.typeHook ?? {},\n        typeValidate: normalized?.schema?.typeValidate ?? {},\n      },\n    },\n    [],\n  );\n}\n\nfunction isPermissionPolicyArrayPath(path: readonly (string | number)[]): boolean {\n  return (\n    path.length === 3 &&\n    path[0] === \"schema\" &&\n    path[1] === \"permission\" &&\n    (path[2] === \"create\" || path[2] === \"read\" || path[2] === \"update\" || path[2] === \"delete\")\n  );\n}\n\nfunction normalizeTailorDBCompareValue(\n  value: unknown,\n  path: readonly (string | number)[],\n): unknown {\n  if (value === undefined || value === null) {\n    return value;\n  }\n\n  if (typeof value === \"boolean\") {\n    if (path.at(-1) === \"optionalOnCreate\" && value === false) {\n      return undefined;\n    }\n    return value;\n  }\n\n  if (typeof value === \"number\" || typeof value === \"bigint\" || typeof value === \"string\") {\n    if (matchesNumericStringPath(path) && isNumericLikeValue(value)) {\n      return String(value);\n    }\n    if (\n      (path.at(-1) === \"expr\" || path.at(-1) === \"description\") &&\n      value === tailordbCompareKnownDefaults.emptyExpression\n    ) {\n      return undefined;\n    }\n    return value;\n  }\n\n  if (Array.isArray(value)) {\n    const items = value\n      .map((item, index) => normalizeTailorDBCompareValue(item, [...path, index]))\n      .filter((item) => item !== undefined);\n    // Field-level validators are no longer emitted by the SDK (they are aggregated\n    // into table-level type_validate). The platform still returns an empty `validate`\n    // array per field; treat it as unset so it matches the omitted local value.\n    if (items.length === 0 && path.at(-1) === \"validate\") {\n      return undefined;\n    }\n    // The platform evaluates permission policies order-insensitively (any\n    // matching deny wins over any matching allow), while committed migration\n    // snapshots can record the same policies in a different order than the\n    // current config parse — so compare each action's policies as a set.\n    if (isPermissionPolicyArrayPath(path)) {\n      return items.toSorted((a, b) => (JSON.stringify(a) < JSON.stringify(b) ? -1 : 1));\n    }\n    return items;\n  }\n\n  if (!isPlainObject(value)) {\n    return value;\n  }\n\n  const normalizedEntries = Object.entries(value)\n    .map(\n      ([key, entryValue]) =>\n        [key, normalizeTailorDBCompareValue(entryValue, [...path, key])] as const,\n    )\n    .filter(([, entryValue]) => entryValue !== undefined);\n\n  const normalizedObject = Object.fromEntries(normalizedEntries);\n\n  if (path.at(-1) === \"fields\" && Object.keys(normalizedObject).length === 0) {\n    return undefined;\n  }\n\n  if (\n    path.at(-1) === \"disableGqlOperations\" &&\n    (Object.keys(normalizedObject).length === 0 ||\n      areNormalizedEqual(normalizedObject, tailordbCompareKnownDefaults.disableGqlOperations))\n  ) {\n    return undefined;\n  }\n\n  return normalizedObject;\n}\n\nfunction matchesNumericStringPath(path: readonly (string | number)[]): boolean {\n  const pathKey = path.map((segment) => String(segment)).join(\".\");\n  return [...tailordbCompareKnownDefaults.numericStringPaths].some((pattern) => {\n    const patternParts = pattern.split(\".\");\n    const pathParts = pathKey.split(\".\");\n    if (patternParts.length !== pathParts.length) {\n      return false;\n    }\n    return patternParts.every((part, index) => part === \"*\" || part === pathParts[index]);\n  });\n}\n\nfunction isNumericLikeValue(value: string | number | bigint): boolean {\n  return typeof value === \"number\" || typeof value === \"bigint\" || /^-?\\d+$/.test(value);\n}\n\nexport function normalizeComparableGqlPermission(permission: unknown) {\n  const normalized = normalizeProtoConfig(permission) as {\n    policies?: Array<{\n      actions?: number[];\n      conditions?: unknown[];\n      permit?: number;\n      description?: string;\n    }>;\n  } | null;\n  return {\n    policies: (normalized?.policies ?? []).map((policy) => ({\n      ...policy,\n      actions: (policy.actions ?? []).toSorted((left, right) => left - right),\n    })),\n  };\n}\n","import { type MessageInitShape } from \"@bufbuild/protobuf\";\nimport {\n  type CreateTailorDBGQLPermissionRequestSchema,\n  type CreateTailorDBServiceRequestSchema,\n  type CreateTailorDBTypeRequestSchema,\n  type DeleteTailorDBGQLPermissionRequestSchema,\n  type DeleteTailorDBServiceRequestSchema,\n  type DeleteTailorDBTypeRequestSchema,\n  type UpdateTailorDBGQLPermissionRequestSchema,\n  type UpdateTailorDBTypeRequestSchema,\n} from \"@tailor-platform/tailor-proto/tailordb_pb\";\nimport * as path from \"pathe\";\nimport { getNamespacesWithMigrations } from \"#/cli/commands/tailordb/migrate/config\";\nimport { captureMigrationFileState } from \"#/cli/commands/tailordb/migrate/file-state\";\nimport {\n  toTailorDBDeployInput,\n  type TailorDBDeployInput,\n} from \"#/cli/commands/tailordb/migrate/schema-checks\";\nimport { type TailorDBSnapshotType } from \"#/cli/commands/tailordb/migrate/snapshot\";\nimport {\n  generateTailorDBTypeManifestFromSnapshot,\n  protoGqlPermission,\n} from \"#/cli/commands/tailordb/migrate/snapshot-manifest\";\nimport { byName } from \"#/cli/shared/apply-concurrency\";\nimport { fetchAllTolerant, type OperatorClient } from \"#/cli/shared/client\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport {\n  assertNoPublishEventsConflict,\n  publishEventsConflict,\n  subscribesToEvents,\n} from \"#/cli/shared/publish-events\";\nimport { createChangeSet } from \"../change-set\";\nimport { areNormalizedEqual } from \"../compare\";\nimport {\n  addDependencyRecords,\n  buildMetaRequest,\n  type DependentAppsByResource,\n  eventSourceKey,\n  hasMatchingSdkVersion,\n  type MetadataLabelWrite,\n  resourceTrn,\n  tailorDBTypeTrn,\n} from \"../label\";\nimport {\n  fetchExistingResourcesWithLabels,\n  trackDesiredResourceOwnership,\n  trackRemainingResourceOwner,\n} from \"../owned-resource\";\nimport {\n  areTailorDBServicesEqual,\n  normalizeComparableGqlPermission,\n  normalizeComparableTailorDBType,\n} from \"./compare\";\nimport { validateAndDetectMigrations } from \"./migration-validation\";\nimport type { OwnerConflict, UnmanagedResource } from \"../confirm\";\nimport type { PlanContext } from \"../types\";\n\nexport type TailorDBPlanResult = Awaited<ReturnType<typeof planTailorDB>>;\n\nexport type TailorDBChangeSet = TailorDBPlanResult[\"changeSet\"];\n\n/**\n * Plan TailorDB-related changes based on current and desired state.\n * @param context - Planning context\n * @returns Planned changes\n */\nexport async function planTailorDB(context: PlanContext) {\n  const {\n    client,\n    workspaceId,\n    application,\n    forRemoval,\n    config,\n    noSchemaCheck,\n    forceApplyAll = false,\n  } = context;\n  const tailordbs: TailorDBDeployInput[] = [];\n  const migrationTestSnapshots =\n    context.migrationTestSnapshots ??\n    (context.migrationTestBaselines\n      ? new Map(\n          [...context.migrationTestBaselines].map(([namespace, baseline]) => [\n            namespace,\n            baseline.snapshot,\n          ]),\n        )\n      : undefined);\n  if (!forRemoval) {\n    for (const tailordb of application.tailorDBServices) {\n      await tailordb.loadTypes();\n      const input = toTailorDBDeployInput(tailordb);\n      const snapshot = migrationTestSnapshots?.get(tailordb.namespace);\n      tailordbs.push(snapshot ? { ...input, types: snapshot.tables } : input);\n    }\n  }\n  const executors = forRemoval\n    ? []\n    : Object.values((await application.executorService?.loadExecutors()) ?? {});\n  const executorUsedTables = new Set(context.executorUsedTailorDBTables ?? []);\n  for (const executor of executors) {\n    if (!subscribesToEvents(executor)) continue;\n    if (executor.trigger.kind === \"tailordb\") {\n      executorUsedTables.add(executor.trigger.tableName);\n    }\n  }\n\n  // Validate migrations at plan time so a missing migration script fails the\n  // deploy (including --dry-run) before any resource is applied.\n  const typesByNamespace = new Map<string, Record<string, TailorDBSnapshotType>>();\n  for (const tailordb of tailordbs) {\n    typesByNamespace.set(tailordb.namespace, tailordb.types);\n  }\n  const migrationTestBaselines = context.migrationTestBaselines;\n  if (migrationTestSnapshots) {\n    for (const namespace of migrationTestSnapshots.keys()) {\n      if (!tailordbs.some((tailordb) => tailordb.namespace === namespace)) {\n        throw CLIError({\n          code: \"MIGRATION_TEST_SNAPSHOT_INVALID\",\n          message: `Migration test snapshot targets unknown TailorDB namespace \"${namespace}\".`,\n        });\n      }\n    }\n    const namespaceByType = new Map<string, string>();\n    for (const tailordb of tailordbs) {\n      for (const tableName of Object.keys(tailordb.types)) {\n        const existingNamespace = namespaceByType.get(tableName);\n        if (existingNamespace) {\n          throw CLIError({\n            code: \"MIGRATION_TEST_SNAPSHOT_INVALID\",\n            message: `Migration test snapshot has duplicate TailorDB table name \"${tableName}\" in namespaces \"${existingNamespace}\" and \"${tailordb.namespace}\".`,\n          });\n        }\n        namespaceByType.set(tableName, tailordb.namespace);\n      }\n    }\n  }\n  const migrationConfig = getNamespacesWithMigrations(config, path.dirname(config.path));\n  const { namespacesWithMigrations, migrationFileState, checkpointRepairs } = forRemoval\n    ? { namespacesWithMigrations: [], migrationFileState: {}, checkpointRepairs: [] }\n    : migrationTestBaselines\n      ? {\n          namespacesWithMigrations: migrationConfig,\n          migrationFileState: captureMigrationFileState(migrationConfig),\n          checkpointRepairs: [],\n        }\n      : await validateAndDetectMigrations(\n          client,\n          workspaceId,\n          typesByNamespace,\n          config,\n          noSchemaCheck ?? false,\n          tailordbs,\n        );\n\n  const {\n    changeSet: serviceChangeSet,\n    conflicts,\n    unmanaged,\n    resourceOwners,\n  } = await planServices(client, workspaceId, application.name, application.id, tailordbs);\n  const deletedServices = serviceChangeSet.deletes.map((del) => del.name);\n  const [typeChangeSet, gqlPermissionChangeSet] = await Promise.all([\n    planTypes(\n      client,\n      workspaceId,\n      tailordbs,\n      executorUsedTables,\n      deletedServices,\n      undefined,\n      forceApplyAll,\n      {\n        appName: application.name,\n        appId: application.id,\n        dependentApps: context.dependentApps,\n        runAppIds: context.runAppIds,\n      },\n    ),\n    planGqlPermissions(client, workspaceId, tailordbs, deletedServices, forceApplyAll),\n  ]);\n\n  // Apply table DDL in a stable, name-sorted order so the create burst (capped\n  // by the operator client's concurrency limiter) is reproducible across runs.\n  typeChangeSet.creates.sort(byName);\n  typeChangeSet.updates.sort(byName);\n  typeChangeSet.deletes.sort(byName);\n\n  return {\n    changeSet: {\n      service: serviceChangeSet,\n      type: typeChangeSet,\n      gqlPermission: gqlPermissionChangeSet,\n    },\n    conflicts,\n    unmanaged,\n    resourceOwners,\n    context: {\n      workspaceId,\n      application,\n      tailorDBInputs: tailordbs,\n      executorUsedTables,\n      config,\n      noSchemaCheck: noSchemaCheck ?? false,\n      ...(migrationTestBaselines ? { migrationTestBaselines } : {}),\n      namespacesWithMigrations,\n      migrationFileState,\n      checkpointRepairs,\n    },\n  };\n}\n\ntype CreateService = {\n  name: string;\n  request: MessageInitShape<typeof CreateTailorDBServiceRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype UpdateService = {\n  name: string;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype DeleteService = {\n  name: string;\n  request: MessageInitShape<typeof DeleteTailorDBServiceRequestSchema>;\n};\n\nasync function planServices(\n  client: OperatorClient,\n  workspaceId: string,\n  appName: string,\n  appId: string | undefined,\n  tailordbs: ReadonlyArray<TailorDBDeployInput>,\n) {\n  const changeSet = createChangeSet<CreateService, UpdateService, DeleteService>(\n    \"TailorDB services\",\n  );\n  const conflicts: OwnerConflict[] = [];\n  const unmanaged: UnmanagedResource[] = [];\n  const resourceOwners = new Set<string>();\n\n  const existingServices = await fetchExistingResourcesWithLabels({\n    client,\n    fetchPage: async (pageToken, maxPageSize) => {\n      const { tailordbServices, nextPageToken } = await client.listTailorDBServices({\n        workspaceId,\n        pageToken,\n        pageSize: maxPageSize,\n      });\n      return [tailordbServices, nextPageToken];\n    },\n    getName: (resource) => resource.namespace?.name,\n    getTrn: (name) => resourceTrn(workspaceId, \"tailordb\", name),\n  });\n\n  for (const tailordb of tailordbs) {\n    const existing = existingServices[tailordb.namespace];\n    const metaRequest = await buildMetaRequest({\n      trn: resourceTrn(workspaceId, \"tailordb\", tailordb.namespace),\n      appName,\n      appId,\n    });\n    if (existing) {\n      const owned = trackDesiredResourceOwnership({\n        labels: existing.allLabels,\n        ownerLabel: existing.label,\n        appName,\n        appId,\n        resourceType: \"TailorDB service\",\n        resourceName: tailordb.namespace,\n        conflicts,\n        unmanaged,\n      });\n\n      if (\n        owned &&\n        hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) &&\n        areTailorDBServicesEqual(existing.resource, tailordb)\n      ) {\n        changeSet.unchanged.push({ name: tailordb.namespace });\n      } else {\n        changeSet.updates.push({\n          name: tailordb.namespace,\n          metaRequest,\n        });\n      }\n      delete existingServices[tailordb.namespace];\n    } else {\n      changeSet.creates.push({\n        name: tailordb.namespace,\n        request: {\n          workspaceId,\n          namespaceName: tailordb.namespace,\n          // Keep generated TailorDB services aligned with Terraform defaults.\n          defaultTimezone: \"UTC\",\n        },\n        metaRequest,\n      });\n    }\n  }\n  Object.entries(existingServices).forEach(([namespaceName]) => {\n    const entry = existingServices[namespaceName];\n    const owned = trackRemainingResourceOwner({\n      labels: entry?.allLabels,\n      ownerLabel: entry?.label,\n      appName,\n      appId,\n      resourceOwners,\n    });\n    if (owned) {\n      changeSet.deletes.push({\n        name: namespaceName,\n        request: {\n          workspaceId,\n          namespaceName,\n        },\n      });\n    }\n  });\n\n  return { changeSet, conflicts, unmanaged, resourceOwners };\n}\n\ntype CreateType = {\n  name: string;\n  request: MessageInitShape<typeof CreateTailorDBTypeRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype UpdateType = {\n  name: string;\n  request: MessageInitShape<typeof UpdateTailorDBTypeRequestSchema>;\n  metaRequest: MetadataLabelWrite;\n};\n\n/**\n * A table whose schema is unchanged but whose dependency records may not be. The\n * plan shows it as unchanged; apply still writes its labels.\n */\ntype UnchangedType = {\n  name: string;\n  metaRequest?: MetadataLabelWrite;\n};\n\n/** What planTypes needs to record dependencies on each table. */\ntype TypeRecordInputs = {\n  appName?: string;\n  appId?: string;\n  dependentApps?: DependentAppsByResource;\n  runAppIds?: ReadonlySet<string>;\n};\n\ntype DeleteType = {\n  name: string;\n  request: MessageInitShape<typeof DeleteTailorDBTypeRequestSchema>;\n};\n\nasync function planTypes(\n  client: OperatorClient,\n  workspaceId: string,\n  tailordbs: ReadonlyArray<TailorDBDeployInput>,\n  executorUsedTables: ReadonlySet<string>,\n  deletedServices: ReadonlyArray<string>,\n  filteredTypesByNamespace?: Map<string, Record<string, TailorDBSnapshotType>>,\n  forceApplyAll = false,\n  records: TypeRecordInputs = {},\n) {\n  const changeSet = createChangeSet<CreateType, UpdateType, DeleteType, never, UnchangedType>(\n    \"TailorDB tables\",\n  );\n  const { appName, appId, dependentApps, runAppIds } = records;\n\n  /**\n   * Build one table's metadata write, carrying the dependency records that belong\n   * to it. The table is what publishes record events, so the record lives there.\n   * @param namespace - Namespace holding the table\n   * @param tableName - Table name\n   * @param explicitPublishEvents - `publishEvents` declared on the table, if any\n   * @returns The table's metadata write\n   */\n  const typeMetaRequest = async (\n    namespace: string,\n    tableName: string,\n    explicitPublishEvents: boolean | undefined,\n  ) => {\n    const trn = tailorDBTypeTrn(workspaceId, namespace, tableName);\n    return addDependencyRecords(await buildMetaRequest({ trn, appName: appName ?? \"\", appId }), {\n      key: eventSourceKey.tailorDBType(namespace, tableName),\n      dependentApps,\n      runAppIds,\n      pinned: explicitPublishEvents !== undefined,\n    });\n  };\n\n  const fetchTypes = (namespaceName: string) => {\n    return fetchAllTolerant(async (pageToken, maxPageSize) => {\n      const { tailordbTypes, nextPageToken } = await client.listTailorDBTypes({\n        workspaceId,\n        namespaceName,\n        pageToken,\n        pageSize: maxPageSize,\n      });\n      return [tailordbTypes, nextPageToken];\n    });\n  };\n\n  // Reject a conflicting opt-out before any request, not partway through.\n  for (const tailordb of tailordbs) {\n    const types = filteredTypesByNamespace?.get(tailordb.namespace) ?? tailordb.types;\n    for (const [tableName, type] of Object.entries(types)) {\n      assertNoPublishEventsConflict({\n        explicit: type.settings?.publishEvents,\n        subscribed: executorUsedTables.has(tableName),\n        conflict: publishEventsConflict.tailorDBType(tableName),\n      });\n    }\n  }\n\n  for (const tailordb of tailordbs) {\n    const existingTypes = await fetchTypes(tailordb.namespace);\n    const existingTypesMap = new Map(existingTypes.map((type) => [type.name, type]));\n\n    // Use filtered tables if provided, otherwise use local tables\n    const types = filteredTypesByNamespace?.get(tailordb.namespace) ?? tailordb.types;\n    const typeMeta = (tableName: string) =>\n      typeMetaRequest(tailordb.namespace, tableName, types[tableName]?.settings?.publishEvents);\n\n    for (const [tableName, tailordbTypeSnapshot] of Object.entries(types)) {\n      const tailordbType = generateTailorDBTypeManifestFromSnapshot(tailordbTypeSnapshot, {\n        subscribed: executorUsedTables.has(tableName),\n        namespaceGqlOperations: tailordb.config.gqlOperations,\n      });\n      const existingType = existingTypesMap.get(tableName);\n      if (existingType) {\n        if (\n          !forceApplyAll &&\n          areNormalizedEqual(\n            normalizeComparableTailorDBType(existingType),\n            normalizeComparableTailorDBType(tailordbType),\n          )\n        ) {\n          // The schema matches, but the records may not, so the labels still go.\n          changeSet.unchanged.push({ name: tableName, metaRequest: await typeMeta(tableName) });\n        } else {\n          changeSet.updates.push({\n            name: tableName,\n            request: {\n              workspaceId,\n              namespaceName: tailordb.namespace,\n              tailordbType,\n            },\n            metaRequest: await typeMeta(tableName),\n          });\n        }\n        existingTypesMap.delete(tableName);\n      } else {\n        changeSet.creates.push({\n          name: tableName,\n          request: {\n            workspaceId,\n            namespaceName: tailordb.namespace,\n            tailordbType,\n          },\n          metaRequest: await typeMeta(tableName),\n        });\n      }\n    }\n    existingTypesMap.forEach((_type, name) => {\n      changeSet.deletes.push({\n        name,\n        request: {\n          workspaceId,\n          namespaceName: tailordb.namespace,\n          tailordbTypeName: name,\n        },\n      });\n    });\n  }\n  for (const namespaceName of deletedServices) {\n    const existingTypes = await fetchTypes(namespaceName);\n    existingTypes.forEach((typ) => {\n      changeSet.deletes.push({\n        name: typ.name,\n        request: {\n          workspaceId,\n          namespaceName,\n          tailordbTypeName: typ.name,\n        },\n      });\n    });\n  }\n  return changeSet;\n}\n\ntype CreateGqlPermission = {\n  name: string;\n  request: MessageInitShape<typeof CreateTailorDBGQLPermissionRequestSchema>;\n};\n\ntype UpdateGqlPermission = {\n  name: string;\n  request: MessageInitShape<typeof UpdateTailorDBGQLPermissionRequestSchema>;\n};\n\ntype DeleteGqlPermission = {\n  name: string;\n  request: MessageInitShape<typeof DeleteTailorDBGQLPermissionRequestSchema>;\n};\n\nasync function planGqlPermissions(\n  client: OperatorClient,\n  workspaceId: string,\n  tailordbs: ReadonlyArray<TailorDBDeployInput>,\n  deletedServices: ReadonlyArray<string>,\n  forceApplyAll = false,\n) {\n  const changeSet = createChangeSet<CreateGqlPermission, UpdateGqlPermission, DeleteGqlPermission>(\n    \"TailorDB gqlPermissions\",\n  );\n\n  const fetchGqlPermissions = (namespaceName: string) => {\n    return fetchAllTolerant(async (pageToken, maxPageSize) => {\n      const { permissions, nextPageToken } = await client.listTailorDBGQLPermissions({\n        workspaceId,\n        namespaceName,\n        pageToken,\n        pageSize: maxPageSize,\n      });\n      return [permissions, nextPageToken];\n    });\n  };\n\n  for (const tailordb of tailordbs) {\n    const existingGqlPermissions = await fetchGqlPermissions(tailordb.namespace);\n    const existingNameSet = new Set<string>();\n    existingGqlPermissions.forEach((gqlPermission) => {\n      existingNameSet.add(gqlPermission.typeName);\n    });\n\n    const types = tailordb.types;\n    for (const [tableName, typeEntry] of Object.entries(types)) {\n      const gqlPermission = typeEntry.permissions?.gql;\n      if (!gqlPermission) {\n        continue;\n      }\n      const desiredPermission = protoGqlPermission(gqlPermission);\n      const existingPermission = existingGqlPermissions.find(\n        (entry) => entry.typeName === tableName,\n      );\n      if (existingNameSet.has(tableName)) {\n        if (\n          !forceApplyAll &&\n          existingPermission &&\n          areNormalizedEqual(\n            normalizeComparableGqlPermission(existingPermission.permission),\n            normalizeComparableGqlPermission(desiredPermission),\n          )\n        ) {\n          changeSet.unchanged.push({ name: tableName });\n        } else {\n          changeSet.updates.push({\n            name: tableName,\n            request: {\n              workspaceId,\n              namespaceName: tailordb.namespace,\n              typeName: tableName,\n              permission: desiredPermission,\n            },\n          });\n        }\n        existingNameSet.delete(tableName);\n      } else {\n        changeSet.creates.push({\n          name: tableName,\n          request: {\n            workspaceId,\n            namespaceName: tailordb.namespace,\n            typeName: tableName,\n            permission: desiredPermission,\n          },\n        });\n      }\n    }\n    existingNameSet.forEach((name) => {\n      changeSet.deletes.push({\n        name,\n        request: {\n          workspaceId,\n          namespaceName: tailordb.namespace,\n          typeName: name,\n        },\n      });\n    });\n  }\n  for (const namespaceName of deletedServices) {\n    const existingGqlPermissions = await fetchGqlPermissions(namespaceName);\n    existingGqlPermissions.forEach((gqlPermission) => {\n      changeSet.deletes.push({\n        name: gqlPermission.typeName,\n        request: {\n          workspaceId,\n          namespaceName,\n          typeName: gqlPermission.typeName,\n        },\n      });\n    });\n  }\n  return changeSet;\n}\n","import { Code, ConnectError } from \"@connectrpc/connect\";\nimport { parseDuration } from \"#/cli/shared/args\";\nimport { type OperatorClient, fetchAll } from \"#/cli/shared/client\";\nimport { CLIError, toError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { publishEventsConflict, resolvePublishEvents } from \"#/cli/shared/publish-events\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { createChangeSet, type ChangeSet } from \"./change-set\";\nimport { areNormalizedEqual } from \"./compare\";\nimport { workflowJobFunctionName } from \"./function-registry\";\nimport {\n  formatChangeEntriesWithFunctionRegistry,\n  type GroupedDisplayEntry,\n  type RelatedFunctionRegistryChanges,\n} from \"./grouped-display\";\nimport {\n  addDependencyRecords,\n  buildMetaRequest,\n  type DependentAppsByResource,\n  eventSourceKey,\n  hasMatchingSdkVersion,\n  type MetadataLabelWrite,\n  resourceTrn,\n  sdkNameLabelKey,\n  writeMetadataLabels,\n} from \"./label\";\nimport {\n  fetchExistingResourcesWithLabels,\n  trackDesiredResourceOwnership,\n  trackRemainingResourceOwner,\n} from \"./owned-resource\";\nimport type { ConcurrencyPolicy, Workflow, RetryPolicy } from \"#/types/workflow.generated\";\nimport type { OwnerConflict, UnmanagedResource } from \"./confirm\";\nimport type { ApplyPhase } from \"./phase\";\nimport type { MessageInitShape } from \"@bufbuild/protobuf\";\nimport type { CreateWorkflowRequestSchema } from \"@tailor-platform/tailor-proto/workflow_pb\";\nimport type {\n  ConcurrencyPolicySchema,\n  RetryPolicySchema,\n  WorkflowJobFunctionSummary,\n} from \"@tailor-platform/tailor-proto/workflow_resource_pb\";\n\n/**\n * Apply workflow changes for the given phase.\n * @param client - Operator client instance\n * @param result - Planned workflow changes\n * @param phase - Apply phase\n * @returns Promise that resolves when workflows are applied\n */\nexport async function applyWorkflow(\n  client: OperatorClient,\n  result: Awaited<ReturnType<typeof planWorkflow>>,\n  phase: Extract<ApplyPhase, \"create-update\" | \"delete\"> = \"create-update\",\n) {\n  const { changeSet, appName, appId } = result;\n  if (phase === \"create-update\") {\n    // Register job functions used by any workflow, returns map of job name to version\n    const jobFunctionVersions = await registerJobFunctions(\n      client,\n      changeSet,\n      appName,\n      appId,\n      result.unchangedWorkflowJobNames,\n      result.jobFunctionPublishEvents,\n    );\n\n    // Create and update workflows in parallel\n    // Each workflow only gets the job function versions it actually uses\n    await Promise.all([\n      ...changeSet.creates.map(async (create) => {\n        const filteredVersions = filterJobFunctionVersions(\n          jobFunctionVersions,\n          create.usedJobNames,\n        );\n        const shape = buildWorkflowValidationShape(create.workspaceId, create.workflow);\n        await client.createWorkflow({\n          workspaceId: shape.workspaceId,\n          workflowName: shape.workflowName,\n          mainJobFunctionName: shape.mainJobFunctionName,\n          retryPolicy: shape.retryPolicy,\n          concurrencyPolicy: shape.concurrencyPolicy,\n          jobFunctions: filteredVersions,\n          publishExecutionEvents: shape.publishExecutionEvents,\n        });\n        await writeMetadataLabels(client, create.metaRequest);\n      }),\n      ...changeSet.updates.map(async (update) => {\n        const filteredVersions = filterJobFunctionVersions(\n          jobFunctionVersions,\n          update.usedJobNames,\n        );\n        const shape = buildWorkflowValidationShape(update.workspaceId, update.workflow);\n        await client.updateWorkflow({\n          workspaceId: shape.workspaceId,\n          workflowName: shape.workflowName,\n          mainJobFunctionName: shape.mainJobFunctionName,\n          retryPolicy: shape.retryPolicy,\n          concurrencyPolicy: shape.concurrencyPolicy,\n          jobFunctions: filteredVersions,\n          publishExecutionEvents: shape.publishExecutionEvents,\n        });\n        await writeMetadataLabels(client, update.metaRequest);\n      }),\n      // An unchanged workflow still gets its labels written, because its dependency\n      // records can change while its definition does not.\n      ...changeSet.unchanged.flatMap((entry) =>\n        entry.metaRequest ? [writeMetadataLabels(client, entry.metaRequest)] : [],\n      ),\n    ]);\n  } else {\n    await deleteAllSettled(\n      changeSet.deletes.map((del) => ({\n        resourceType: \"workflow\",\n        resourceName: del.name,\n        run: () =>\n          client.deleteWorkflow({\n            workspaceId: del.workspaceId,\n            workflowId: del.workflowId,\n          }),\n      })),\n    );\n\n    await deleteAllSettled(\n      result.jobFunctionDeletes.map((del) => ({\n        resourceType: \"workflow job function\",\n        resourceName: del.jobFunctionName,\n        run: () =>\n          client.deleteWorkflowJobFunction({\n            workspaceId: del.workspaceId,\n            jobFunctionName: del.jobFunctionName,\n          }),\n      })),\n    );\n  }\n}\n\ntype DeleteOperation = {\n  resourceType: string;\n  resourceName: string;\n  run: () => Promise<unknown>;\n};\n\nasync function deleteAllSettled(operations: readonly DeleteOperation[]) {\n  const results = await Promise.allSettled(operations.map((operation) => operation.run()));\n  const errors: Error[] = [];\n  results.forEach((result, index) => {\n    if (result.status === \"fulfilled\") {\n      return;\n    }\n    const operation = assertDefined(operations[index], \"operation missing at index\");\n    const error = result.reason;\n    if (error instanceof ConnectError && error.code === Code.NotFound) {\n      return;\n    }\n    if (error instanceof ConnectError && error.code === Code.FailedPrecondition) {\n      logger.warn(\n        `Skipped deleting ${operation.resourceType} \"${operation.resourceName}\" because it is still referenced.`,\n      );\n      return;\n    }\n    errors.push(toError(error));\n  });\n  const firstError = errors[0];\n  if (firstError) {\n    throw firstError;\n  }\n}\n\n/**\n * Filter job function versions to only include those used by a workflow\n * @param allVersions - Map of job function names to versions\n * @param usedJobNames - Job names used by the workflow\n * @returns Filtered job function versions\n */\nfunction filterJobFunctionVersions(\n  allVersions: { [key: string]: bigint },\n  usedJobNames: string[],\n): { [key: string]: bigint } {\n  const filtered: { [key: string]: bigint } = {};\n  for (const jobName of usedJobNames) {\n    if (allVersions[jobName] !== undefined) {\n      filtered[jobName] = allVersions[jobName];\n    }\n  }\n  return filtered;\n}\n\n/**\n * Register job functions used by any workflow.\n * Only registers jobs that are actually used (based on usedJobNames in changeSet).\n * Uses create for new jobs and update for existing jobs.\n * Sets metadata on used JobFunctions.\n * @param client - Operator client instance\n * @param changeSet - Workflow change set\n * @param appName - Application name\n * @param appId - Application ID used for job function metadata when available\n * @param unchangedWorkflowJobNames - Job function names used by unchanged workflows\n * @param jobFunctionPublishEvents - Resolved `publishExecutionEvents` keyed by job function name\n * @returns Map of job function names to versions\n */\nasync function registerJobFunctions(\n  client: OperatorClient,\n  changeSet: ChangeSet<CreateWorkflow, UpdateWorkflow, DeleteWorkflow>,\n  appName: string,\n  appId: string | undefined,\n  unchangedWorkflowJobNames: ReadonlySet<string> = new Set(),\n  jobFunctionPublishEvents: ReadonlyMap<string, boolean> = new Map(),\n): Promise<{ [key: string]: bigint }> {\n  const jobFunctionVersions: { [key: string]: bigint } = {};\n\n  // Get workspaceId from the first workflow\n  const firstWorkflow = changeSet.creates[0] || changeSet.updates[0] || changeSet.deletes[0];\n  if (!firstWorkflow) {\n    return jobFunctionVersions;\n  }\n\n  const { workspaceId } = firstWorkflow;\n\n  // Collect all job names used by any workflow\n  const allUsedJobNames = new Set<string>();\n  unchangedWorkflowJobNames.forEach((jobName) => allUsedJobNames.add(jobName));\n  for (const item of [...changeSet.creates, ...changeSet.updates]) {\n    for (const jobName of item.usedJobNames) {\n      allUsedJobNames.add(jobName);\n    }\n  }\n  // Fetch existing job functions with their names\n  const existingJobFunctions = await fetchAll(async (pageToken, maxPageSize) => {\n    const response = await client.listWorkflowJobFunctions({\n      workspaceId,\n      pageToken,\n      pageSize: maxPageSize,\n    });\n    return [response.jobFunctions.map((j) => j.name), response.nextPageToken];\n  });\n  const existingJobNamesSet = new Set(existingJobFunctions);\n\n  if (changeSet.creates.length > 0 || changeSet.updates.length > 0) {\n    // Register job functions in parallel\n    // Use create for new jobs, update for existing jobs\n    const results = await Promise.all(\n      Array.from(allUsedJobNames).map(async (jobName) => {\n        const isExisting = existingJobNamesSet.has(jobName);\n        const request = {\n          workspaceId,\n          jobFunctionName: jobName,\n          scriptRef: workflowJobFunctionName(jobName),\n          publishExecutionEvents: jobFunctionPublishEvents.get(jobName) ?? false,\n        };\n        const response = isExisting\n          ? await client.updateWorkflowJobFunction(request)\n          : await client.createWorkflowJobFunction(request);\n\n        // Set metadata to mark this JobFunction as owned by this app\n        await writeMetadataLabels(\n          client,\n          await buildMetaRequest({\n            trn: resourceTrn(workspaceId, \"workflow_job_function\", jobName),\n            appName,\n            appId,\n          }),\n        );\n\n        return { jobName, version: response.jobFunction?.version };\n      }),\n    );\n\n    for (const { jobName, version } of results) {\n      if (version) {\n        jobFunctionVersions[jobName] = version;\n      }\n    }\n  }\n\n  return jobFunctionVersions;\n}\n\ntype CreateWorkflow = {\n  name: string;\n  workspaceId: string;\n  workflow: Workflow;\n  usedJobNames: string[];\n  metaRequest: MetadataLabelWrite;\n};\n\ntype UpdateWorkflow = {\n  name: string;\n  workspaceId: string;\n  workflow: Workflow;\n  usedJobNames: string[];\n  metaRequest: MetadataLabelWrite;\n};\n\ntype DeleteWorkflow = {\n  name: string;\n  workspaceId: string;\n  workflowId: string;\n  usedJobNames: string[];\n  deletableJobNames: string[];\n};\n\ntype DeleteWorkflowJobFunction = {\n  workspaceId: string;\n  jobFunctionName: string;\n};\n\nfunction parseDurationToProto(duration: string): { seconds: bigint; nanos: number } {\n  const ms = parseDuration(duration);\n  const seconds = Math.floor(ms / 1000);\n  const nanos = (ms % 1000) * 1_000_000;\n  return { seconds: BigInt(seconds), nanos };\n}\n\nfunction toRetryPolicy(policy: RetryPolicy): MessageInitShape<typeof RetryPolicySchema> {\n  return {\n    maxRetries: policy.maxRetries,\n    initialBackoff: parseDurationToProto(policy.initialBackoff),\n    maxBackoff: parseDurationToProto(policy.maxBackoff),\n    backoffMultiplier: policy.backoffMultiplier,\n  };\n}\n\nfunction toConcurrencyPolicy(\n  policy: ConcurrencyPolicy,\n): MessageInitShape<typeof ConcurrencyPolicySchema> {\n  return {\n    maxConcurrentExecutions: policy.maxConcurrentExecutions,\n  };\n}\n\n/** Plan-time init shape for Create/UpdateWorkflowRequest (jobFunctions excluded). */\nexport type WorkflowValidationShape = Omit<\n  MessageInitShape<typeof CreateWorkflowRequestSchema>,\n  \"jobFunctions\"\n>;\n\n/**\n * Build the plan-time validation init shape for a workflow.\n * @param workspaceId - Workspace ID\n * @param workflow - Parsed workflow object\n * @returns Init shape suitable for validating against CreateWorkflowRequestSchema and UpdateWorkflowRequestSchema\n */\nexport function buildWorkflowValidationShape(\n  workspaceId: string,\n  workflow: Workflow,\n): WorkflowValidationShape {\n  return {\n    workspaceId,\n    workflowName: workflow.name,\n    mainJobFunctionName: workflow.mainJob.name,\n    ...(workflow.retryPolicy && { retryPolicy: toRetryPolicy(workflow.retryPolicy) }),\n    ...(workflow.concurrencyPolicy && {\n      concurrencyPolicy: toConcurrencyPolicy(workflow.concurrencyPolicy),\n    }),\n    publishExecutionEvents: workflow.publishEvents ?? false,\n  };\n}\n\n/** Executors subscribing to one granularity level of workflow execution events. */\nexport type WorkflowEventSubscribers = {\n  /** Workflow names named by executor triggers. */\n  workflowNames: ReadonlySet<string>;\n};\n\n/**\n * A workflow whose definition is unchanged but whose dependency records may not\n * be. The plan shows it as unchanged; apply still writes its labels.\n */\ntype UnchangedWorkflow = {\n  name: string;\n  metaRequest?: MetadataLabelWrite;\n};\n\n/** Inputs deciding which workflows and job functions publish execution events. */\nexport type WorkflowEventPublishing = {\n  /** Subscribers of `workflow.workflow_execution.*` events. */\n  execution?: WorkflowEventSubscribers;\n  /** Subscribers of `workflow.workflow_execution.job_execution.*` events. */\n  jobExecution?: WorkflowEventSubscribers;\n  /** `publishEvents` declared on jobs, keyed by job name. */\n  jobPublishEvents?: ReadonlyMap<string, boolean>;\n  /** Dependents the run resolved, keyed by resource. */\n  dependentApps?: DependentAppsByResource;\n  /** Stable ids of every application taking part in the run. */\n  runAppIds?: ReadonlySet<string>;\n};\n\nconst NO_EVENT_SUBSCRIBERS: WorkflowEventSubscribers = {\n  workflowNames: new Set(),\n};\n\nfunction isSubscribed(subscribers: WorkflowEventSubscribers, workflowName: string): boolean {\n  return subscribers.workflowNames.has(workflowName);\n}\n\ntype ResolveJobPublishEventsParams = {\n  workflows: Record<string, Workflow>;\n  mainJobDeps: Record<string, string[]>;\n  subscribers: WorkflowEventSubscribers;\n  explicit: ReadonlyMap<string, boolean>;\n};\n\n/**\n * Job names the given workflows' subscriptions enable.\n *\n * A job execution trigger names a workflow rather than a job, so the value is\n * resolved per job name over the union of the workflows that run it: a job two\n * workflows share stays on while either one is subscribed. Whoever asks whether a\n * job still publishes has to apply that same union, which is why this is shared\n * rather than restated — the two answering it differently is what let a shared\n * job be reported as turning off while a peer subscription kept it on.\n * @param params - Workflows, the jobs each runs, and which are subscribed\n * @param params.workflows - Workflows whose job sets are considered\n * @param params.mainJobDeps - Job names each workflow runs, keyed by its main job\n * @param params.isSubscribed - Whether a workflow's jobs are subscribed in this run\n * @returns Job names those subscriptions enable\n */\nexport function subscribedWorkflowJobNames(params: {\n  workflows: Iterable<{ name: string; mainJob: { name: string } }>;\n  mainJobDeps: Record<string, string[]>;\n  isSubscribed: (workflowName: string) => boolean;\n}): ReadonlySet<string> {\n  const { workflows, mainJobDeps, isSubscribed } = params;\n  const jobNames = new Set<string>();\n  for (const workflow of workflows) {\n    if (!isSubscribed(workflow.name)) continue;\n    // A missing entry gets a fuller diagnostic from planWorkflow's own loop.\n    for (const jobName of mainJobDeps[workflow.mainJob.name] ?? []) {\n      jobNames.add(jobName);\n    }\n  }\n  return jobNames;\n}\n\n/**\n * Resolve `publishExecutionEvents` for every job function used by a workflow.\n *\n * A job execution trigger names a workflow rather than a job, so a subscription\n * opts in every job that workflow runs.\n * @param params - Workflows, their job dependencies, subscribers, and explicit job flags\n * @returns Resolved flags keyed by job function name\n */\nfunction resolveJobPublishEvents(params: ResolveJobPublishEventsParams): Map<string, boolean> {\n  const { workflows, mainJobDeps, subscribers, explicit } = params;\n  const usedJobNames = new Set<string>();\n  for (const workflow of Object.values(workflows)) {\n    // A missing entry gets a fuller diagnostic from planWorkflow's own loop.\n    for (const jobName of mainJobDeps[workflow.mainJob.name] ?? []) {\n      usedJobNames.add(jobName);\n    }\n  }\n  const subscribedJobNames = subscribedWorkflowJobNames({\n    workflows: Object.values(workflows),\n    mainJobDeps,\n    isSubscribed: (workflowName) => isSubscribed(subscribers, workflowName),\n  });\n\n  const resolved = new Map<string, boolean>();\n  for (const jobName of usedJobNames) {\n    resolved.set(\n      jobName,\n      resolvePublishEvents({\n        explicit: explicit.get(jobName),\n        subscribed: subscribedJobNames.has(jobName),\n        conflict: publishEventsConflict.workflowJob(jobName),\n      }),\n    );\n  }\n  return resolved;\n}\n\n/**\n * Collect job functions whose remote publishing flag no longer matches the plan.\n * @param existing - Existing job functions keyed by name\n * @param resolved - Resolved `publishExecutionEvents` keyed by job function name\n * @returns Job function names needing re-registration\n */\nfunction collectStaleJobFunctionNames(\n  existing: ReadonlyMap<string, ExistingJobFunction>,\n  resolved: ReadonlyMap<string, boolean>,\n): Set<string> {\n  const stale = new Set<string>();\n  for (const [jobName, publishEvents] of resolved) {\n    const remote = existing.get(jobName);\n    if (remote && remote.publishExecutionEvents !== publishEvents) {\n      stale.add(jobName);\n    }\n  }\n  return stale;\n}\n\n/**\n * Plan workflow changes and job functions based on current and desired state.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param appName - Application name\n * @param appId - Application ID used for workflow metadata when available\n * @param workflows - Parsed workflows\n * @param mainJobDeps - Main job dependencies by workflow\n * @param unchangedJobFunctions - Job functions already proven unchanged by function registry plan\n * @param eventPublishing - Executor subscriptions and explicit job flags driving execution event publishing\n * @returns Planned workflow changes\n */\nexport async function planWorkflow(\n  client: OperatorClient,\n  workspaceId: string,\n  appName: string,\n  appId: string | undefined,\n  workflows: Record<string, Workflow>,\n  mainJobDeps: Record<string, string[]>,\n  unchangedJobFunctions: ReadonlySet<string> = new Set<string>(),\n  eventPublishing: WorkflowEventPublishing = {},\n) {\n  const changeSet = createChangeSet<\n    CreateWorkflow,\n    UpdateWorkflow,\n    DeleteWorkflow,\n    never,\n    UnchangedWorkflow\n  >(\"Workflows\");\n  const conflicts: OwnerConflict[] = [];\n  const unmanaged: UnmanagedResource[] = [];\n  const resourceOwners = new Set<string>();\n  const unchangedWorkflowJobNames = new Set<string>();\n  const retainedWorkflowJobNames = new Set<string>();\n\n  const executionSubscribers = eventPublishing.execution ?? NO_EVENT_SUBSCRIBERS;\n  const { dependentApps, runAppIds } = eventPublishing;\n  // A workflowJobExecution subscription records on the workflow, so the workflow's\n  // own declaration does not settle whether its records still matter. Dropping\n  // them while a job it runs leaves publishEvents unset would delete the only\n  // signal fetchMissingDependentApps looks for on that workflow.\n  const everyJobDeclaresPublishEvents = (workflowName: string): boolean => {\n    const jobNames = mainJobDeps[workflows[workflowName]?.mainJob.name ?? \"\"] ?? [];\n    const explicit = eventPublishing.jobPublishEvents ?? new Map<string, boolean>();\n    return jobNames.length > 0 && jobNames.every((jobName) => explicit.has(jobName));\n  };\n  const existingJobFunctions = await fetchExistingJobFunctions(client, workspaceId);\n  const jobFunctionPublishEvents = resolveJobPublishEvents({\n    workflows,\n    mainJobDeps,\n    subscribers: eventPublishing.jobExecution ?? NO_EVENT_SUBSCRIBERS,\n    explicit: eventPublishing.jobPublishEvents ?? new Map<string, boolean>(),\n  });\n  const staleJobFunctionNames = collectStaleJobFunctionNames(\n    existingJobFunctions,\n    jobFunctionPublishEvents,\n  );\n\n  const existingWorkflows = await fetchExistingResourcesWithLabels({\n    client,\n    fetchPage: async (pageToken, pageSize) => {\n      const response = await client.listWorkflows({\n        workspaceId,\n        pageToken,\n        pageSize,\n      });\n      return [response.workflows, response.nextPageToken];\n    },\n    getName: (resource) => resource.name,\n    getTrn: (name) => resourceTrn(workspaceId, \"workflow\", name),\n  });\n\n  for (const workflow of Object.values(workflows)) {\n    const existing = existingWorkflows[workflow.name];\n    const metaRequest = addDependencyRecords(\n      await buildMetaRequest({\n        trn: resourceTrn(workspaceId, \"workflow\", workflow.name),\n        appName,\n        appId,\n      }),\n      {\n        key: eventSourceKey.workflow(workflow.name),\n        dependentApps,\n        runAppIds,\n        pinned: workflow.publishEvents !== undefined,\n      },\n    );\n    // The jobs' value is driven by workflowJobExecution subscribers, independently\n    // of the workflow's own, so its records live in their own namespace here.\n    addDependencyRecords(metaRequest, {\n      key: eventSourceKey.workflowJobs(workflow.name),\n      dependentApps,\n      runAppIds,\n      pinned: everyJobDeclaresPublishEvents(workflow.name),\n      scope: \"jobs\",\n    });\n    // Get jobs used by this workflow from mainJobDeps\n    const usedJobNames = mainJobDeps[workflow.mainJob.name];\n    if (!usedJobNames) {\n      throw CLIError({\n        code: \"WORKFLOW_MAIN_JOB_NOT_FOUND\",\n        message: `Job \"${workflow.mainJob.name}\" (mainJob of workflow \"${workflow.name}\") was not found.`,\n        details:\n          \"Possible causes:\\n - The job is not exported as a named export\\n - The file containing the job is not included in workflow.files glob pattern\",\n        suggestion: `Export the job: export const ${workflow.mainJob.name} = createWorkflowJob({ name: \"${workflow.mainJob.name}\", ... })`,\n      });\n    }\n    usedJobNames.forEach((jobName) => retainedWorkflowJobNames.add(jobName));\n\n    const desiredWorkflow: Workflow = {\n      ...workflow,\n      publishEvents: resolvePublishEvents({\n        explicit: workflow.publishEvents,\n        subscribed: isSubscribed(executionSubscribers, workflow.name),\n        conflict: publishEventsConflict.workflow(workflow.name),\n      }),\n    };\n\n    if (existing) {\n      const owned = trackDesiredResourceOwnership({\n        labels: existing.allLabels,\n        ownerLabel: existing.label,\n        appName,\n        appId,\n        resourceType: \"Workflow\",\n        resourceName: workflow.name,\n        conflicts,\n        unmanaged,\n      });\n\n      if (\n        owned &&\n        hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) &&\n        canTreatWorkflowAsUnchanged({\n          existing: existing.resource,\n          workflow: desiredWorkflow,\n          usedJobNames,\n          unchangedJobFunctions,\n          staleJobFunctionNames,\n        })\n      ) {\n        // The definition matches, but the records may not, so the labels still go.\n        changeSet.unchanged.push({ name: workflow.name, metaRequest });\n        for (const jobName of usedJobNames) {\n          unchangedWorkflowJobNames.add(jobName);\n        }\n      } else {\n        changeSet.updates.push({\n          name: workflow.name,\n          workspaceId,\n          workflow: desiredWorkflow,\n          usedJobNames,\n          metaRequest,\n        });\n      }\n      delete existingWorkflows[workflow.name];\n    } else {\n      changeSet.creates.push({\n        name: workflow.name,\n        workspaceId,\n        workflow: desiredWorkflow,\n        usedJobNames,\n        metaRequest,\n      });\n    }\n  }\n\n  const deleteWorkflows: DeleteWorkflow[] = [];\n  Object.values(existingWorkflows).forEach((existing) => {\n    if (!existing) {\n      return;\n    }\n    const owned = trackRemainingResourceOwner({\n      labels: existing.allLabels,\n      ownerLabel: existing.label,\n      appName,\n      appId,\n      resourceOwners,\n    });\n    const usedJobNames = getExistingWorkflowJobNames(existing.resource);\n    if (owned) {\n      deleteWorkflows.push({\n        name: existing.resource.name,\n        workspaceId,\n        workflowId: existing.resource.id,\n        usedJobNames,\n        deletableJobNames: [],\n      });\n    } else {\n      usedJobNames.forEach((jobName) => retainedWorkflowJobNames.add(jobName));\n    }\n  });\n\n  const jobFunctionDeletes = await planWorkflowJobFunctionDeletes({\n    client,\n    workspaceId,\n    appName,\n    appId,\n    existingJobFunctionNames: [...existingJobFunctions.keys()],\n    retainedWorkflowJobNames,\n    resourceOwners,\n  });\n  const deletableJobNames = new Set(jobFunctionDeletes.map((del) => del.jobFunctionName));\n\n  for (const del of deleteWorkflows) {\n    changeSet.deletes.push({\n      ...del,\n      deletableJobNames: del.usedJobNames.filter(\n        (jobName) => !retainedWorkflowJobNames.has(jobName) && deletableJobNames.has(jobName),\n      ),\n    });\n  }\n\n  return {\n    changeSet,\n    conflicts,\n    unmanaged,\n    resourceOwners,\n    appName,\n    appId,\n    unchangedWorkflowJobNames,\n    jobFunctionDeletes,\n    jobFunctionPublishEvents,\n  };\n}\n\n/** Existing job function as reported by the platform's job function listing. */\ntype ExistingJobFunction = Pick<WorkflowJobFunctionSummary, \"name\" | \"publishExecutionEvents\">;\n\nasync function fetchExistingJobFunctions(\n  client: OperatorClient,\n  workspaceId: string,\n): Promise<ReadonlyMap<string, ExistingJobFunction>> {\n  const jobFunctions = await fetchAll(async (pageToken, maxPageSize) => {\n    const response = await client.listWorkflowJobFunctions({\n      workspaceId,\n      pageToken,\n      pageSize: maxPageSize,\n    });\n    return [response.jobFunctions, response.nextPageToken];\n  });\n  return new Map(jobFunctions.map((jobFunction) => [jobFunction.name, jobFunction]));\n}\n\ntype PlanWorkflowJobFunctionDeletesParams = {\n  client: OperatorClient;\n  workspaceId: string;\n  appName: string;\n  appId: string | undefined;\n  existingJobFunctionNames: readonly string[];\n  retainedWorkflowJobNames: ReadonlySet<string>;\n  resourceOwners: Set<string>;\n};\n\nasync function planWorkflowJobFunctionDeletes(\n  params: PlanWorkflowJobFunctionDeletesParams,\n): Promise<DeleteWorkflowJobFunction[]> {\n  const {\n    client,\n    workspaceId,\n    appName,\n    appId,\n    existingJobFunctionNames,\n    retainedWorkflowJobNames,\n    resourceOwners,\n  } = params;\n  const candidates = existingJobFunctionNames.filter(\n    (jobName) => !retainedWorkflowJobNames.has(jobName),\n  );\n  const owned = await Promise.all(\n    candidates.map(async (jobFunctionName) => {\n      const { metadata } = await client.getMetadata({\n        trn: resourceTrn(workspaceId, \"workflow_job_function\", jobFunctionName),\n      });\n      // Record the owner of what is skipped, so remove can say it left something\n      // behind instead of reporting that it deleted everything.\n      return trackRemainingResourceOwner({\n        labels: metadata?.labels,\n        ownerLabel: metadata?.labels[sdkNameLabelKey],\n        appName,\n        appId,\n        resourceOwners,\n      })\n        ? { workspaceId, jobFunctionName }\n        : undefined;\n    }),\n  );\n  return owned.filter((item): item is DeleteWorkflowJobFunction => item !== undefined);\n}\n\ntype WorkflowDisplayEntry = GroupedDisplayEntry;\n\n/**\n * Format workflow changes for grouped dry-run display.\n * @param changeSet - Workflow changes\n * @param workflowJobFunctionChanges - Related function registry changes for workflow jobs\n * @returns Display entries for workflow output\n */\nexport function formatWorkflowChangeEntries(\n  changeSet: Pick<\n    ChangeSet<CreateWorkflow, UpdateWorkflow, DeleteWorkflow>,\n    \"creates\" | \"updates\" | \"deletes\" | \"replaces\"\n  >,\n  workflowJobFunctionChanges?: RelatedFunctionRegistryChanges,\n): WorkflowDisplayEntry[] {\n  return formatChangeEntriesWithFunctionRegistry(\n    \"workflow\",\n    changeSet,\n    workflowJobFunctionChanges,\n    (item) =>\n      \"usedJobNames\" in item\n        ? item.usedJobNames.map((jobName) => workflowJobFunctionName(jobName))\n        : [],\n  );\n}\n\ntype ExistingWorkflowResource = {\n  mainJobFunctionName?: string;\n  retryPolicy?: {\n    maxRetries?: number;\n    backoffMultiplier?: number;\n    initialBackoff?: { seconds?: bigint; nanos?: number };\n    maxBackoff?: { seconds?: bigint; nanos?: number };\n  };\n  concurrencyPolicy?: {\n    maxConcurrentExecutions?: number;\n  };\n  jobFunctions?: Record<string, string | bigint>;\n  publishExecutionEvents?: boolean;\n};\n\ntype CanTreatWorkflowAsUnchangedParams = {\n  existing: ExistingWorkflowResource;\n  workflow: Workflow;\n  usedJobNames: string[];\n  unchangedJobFunctions: ReadonlySet<string>;\n  staleJobFunctionNames: ReadonlySet<string>;\n};\n\nfunction canTreatWorkflowAsUnchanged(params: CanTreatWorkflowAsUnchangedParams) {\n  const { existing, workflow, usedJobNames, unchangedJobFunctions, staleJobFunctionNames } = params;\n  if (!usedJobNames.every((jobName) => unchangedJobFunctions.has(jobName))) {\n    return false;\n  }\n  // Job functions are only re-registered while applying a workflow create/update.\n  if (usedJobNames.some((jobName) => staleJobFunctionNames.has(jobName))) {\n    return false;\n  }\n  return areWorkflowsEqual(existing, workflow, usedJobNames);\n}\n\nfunction areWorkflowsEqual(\n  existing: ExistingWorkflowResource,\n  workflow: Workflow,\n  usedJobNames: readonly string[],\n) {\n  return (\n    existing.mainJobFunctionName === workflow.mainJob.name &&\n    (existing.publishExecutionEvents ?? false) === (workflow.publishEvents ?? false) &&\n    areNormalizedEqual(\n      normalizeComparableExistingWorkflowRetryPolicy(existing.retryPolicy),\n      normalizeComparableWorkflowRetryPolicy(workflow.retryPolicy),\n    ) &&\n    areNormalizedEqual(\n      normalizeComparableConcurrencyPolicy(existing.concurrencyPolicy),\n      normalizeComparableConcurrencyPolicy(workflow.concurrencyPolicy),\n    ) &&\n    areNormalizedEqual(\n      normalizeComparableWorkflowJobNames(existing.jobFunctions),\n      normalizeComparableWorkflowJobNames(usedJobNames),\n    )\n  );\n}\n\nfunction normalizeComparableExistingWorkflowRetryPolicy(\n  policy:\n    | {\n        maxRetries?: number;\n        backoffMultiplier?: number;\n        initialBackoff?: { seconds?: bigint; nanos?: number };\n        maxBackoff?: { seconds?: bigint; nanos?: number };\n      }\n    | undefined,\n) {\n  if (!policy) {\n    return undefined;\n  }\n\n  return normalizeRetryPolicyForCompare({\n    maxRetries: policy.maxRetries ?? 0,\n    backoffMultiplier: policy.backoffMultiplier ?? 0,\n    initialBackoff: {\n      seconds: policy.initialBackoff?.seconds ?? 0n,\n      nanos: policy.initialBackoff?.nanos ?? 0,\n    },\n    maxBackoff: {\n      seconds: policy.maxBackoff?.seconds ?? 0n,\n      nanos: policy.maxBackoff?.nanos ?? 0,\n    },\n  });\n}\n\nfunction normalizeComparableWorkflowRetryPolicy(policy: RetryPolicy | undefined) {\n  if (!policy) {\n    return undefined;\n  }\n\n  return normalizeRetryPolicyForCompare({\n    maxRetries: policy.maxRetries,\n    backoffMultiplier: policy.backoffMultiplier,\n    initialBackoff: parseDurationToProto(policy.initialBackoff),\n    maxBackoff: parseDurationToProto(policy.maxBackoff),\n  });\n}\n\nfunction normalizeComparableConcurrencyPolicy(\n  policy: { maxConcurrentExecutions?: number } | undefined,\n) {\n  if (!policy || !policy.maxConcurrentExecutions) {\n    return undefined;\n  }\n  return { maxConcurrentExecutions: policy.maxConcurrentExecutions };\n}\n\nfunction normalizeComparableWorkflowJobNames(\n  jobFunctions: Record<string, string | bigint> | readonly string[] | undefined,\n) {\n  return Array.isArray(jobFunctions)\n    ? jobFunctions.toSorted()\n    : Object.keys(jobFunctions ?? {}).toSorted();\n}\n\nfunction getExistingWorkflowJobNames(existing: {\n  mainJobFunctionName?: string;\n  jobFunctions?: Record<string, string | bigint>;\n}) {\n  const jobNames = new Set(Object.keys(existing.jobFunctions ?? {}));\n  if (existing.mainJobFunctionName) {\n    jobNames.add(existing.mainJobFunctionName);\n  }\n  return [...jobNames].toSorted();\n}\n\nfunction normalizeRetryPolicyForCompare(policy: {\n  maxRetries: number;\n  backoffMultiplier: number;\n  initialBackoff: { seconds: bigint | number; nanos: number };\n  maxBackoff: { seconds: bigint | number; nanos: number };\n}) {\n  return {\n    maxRetries: policy.maxRetries,\n    backoffMultiplier: policy.backoffMultiplier,\n    initialBackoff: {\n      seconds: String(policy.initialBackoff.seconds),\n      nanos: policy.initialBackoff.nanos,\n    },\n    maxBackoff: {\n      seconds: String(policy.maxBackoff.seconds),\n      nanos: policy.maxBackoff.nanos,\n    },\n  };\n}\n","import {\n  EXECUTION_POLICY_KEY_WILDCARD_MESSAGE,\n  toPlatformExecutionPolicyKey as toPlatformKey,\n} from \"@tailor-platform/shared/workflow-policy\";\nimport { type OperatorClient } from \"#/cli/shared/client\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { WorkflowJobFunctionExecutionPolicySchema } from \"#/parser/service/workflow/schema\";\nimport { createChangeSet } from \"./change-set\";\nimport { areNormalizedEqual } from \"./compare\";\nimport {\n  buildMetaRequest,\n  hasMatchingSdkVersion,\n  type MetadataLabelWrite,\n  resourceTrn,\n  writeMetadataLabels,\n} from \"./label\";\nimport {\n  fetchExistingResourcesWithLabels,\n  trackDesiredResourceOwnership,\n  trackRemainingResourceOwner,\n} from \"./owned-resource\";\nimport type { ExecutionPolicyInstance } from \"#/configure/services/workflow/execution-policy.types\";\nimport type { OwnerConflict, UnmanagedResource } from \"./confirm\";\nimport type { ApplyPhase } from \"./phase\";\nimport type { MessageInitShape } from \"@bufbuild/protobuf\";\nimport type { ConcurrencyPolicySchema } from \"@tailor-platform/tailor-proto/workflow_resource_pb\";\n\ntype CreatePolicy = {\n  name: string;\n  workspaceId: string;\n  policy: ExecutionPolicyInstance;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype UpdatePolicy = {\n  name: string;\n  workspaceId: string;\n  policy: ExecutionPolicyInstance;\n  metaRequest: MetadataLabelWrite;\n};\n\ntype DeletePolicy = {\n  name: string;\n  workspaceId: string;\n};\n\ntype ReplacePolicy = {\n  name: string;\n  workspaceId: string;\n  policy: ExecutionPolicyInstance;\n  metaRequest: MetadataLabelWrite;\n};\n\nfunction toConcurrencyPolicyInit(\n  policy: ExecutionPolicyInstance[\"concurrencyPolicy\"],\n): MessageInitShape<typeof ConcurrencyPolicySchema> | undefined {\n  if (!policy) return undefined;\n  return { maxConcurrentExecutions: policy.maxConcurrentExecutions };\n}\n\nfunction normalizeComparableConcurrency(\n  policy: { maxConcurrentExecutions?: number } | undefined,\n): { maxConcurrentExecutions: number } | undefined {\n  if (!policy || !policy.maxConcurrentExecutions) return undefined;\n  return { maxConcurrentExecutions: policy.maxConcurrentExecutions };\n}\n\n/**\n * The declared key prefix, regardless of variant. `ExecutionPolicyWildcardInstance`\n * omits `key` from its public type to force callers through `keyFor()`, but\n * the underlying value always carries it when produced by\n * `defineWorkflowExecutionPolicy()` or `defineWorkflowExecutionPolicies()`.\n * @param policy - Declared policy from the config\n * @returns The declared key prefix\n */\nfunction declaredKey(policy: ExecutionPolicyInstance): string {\n  if (policy.matchType === \"exact\") return policy.key;\n  const key = (policy as unknown as { key?: string }).key;\n  if (typeof key !== \"string\") {\n    throw CLIError({\n      code: \"WORKFLOW_EXECUTION_POLICY_INVALID\",\n      message: `Invalid workflow execution policy \"${policy.name}\": prefix policies must be created via defineWorkflowExecutionPolicy() or defineWorkflowExecutionPolicies(), not a hand-constructed object.`,\n    });\n  }\n  return key;\n}\n\n/**\n * The literal key the platform registers for a declared policy: `key` with a\n * trailing `*` appended when `matchType` is `\"prefix\"`.\n * @param policy - Declared policy from the config\n * @returns The platform-facing execution policy key\n */\nexport function toPlatformExecutionPolicyKey(policy: ExecutionPolicyInstance): string {\n  return toPlatformKey(declaredKey(policy), policy.matchType);\n}\n\n/**\n * Validate a declared execution policy against the parser schema. Throws with\n * a descriptive error when `name` or the platform-facing key violates the\n * platform grammar.\n * @param policy - Declared policy from the config\n */\nfunction validatePolicy(policy: ExecutionPolicyInstance): void {\n  if (declaredKey(policy).endsWith(\"*\")) {\n    throw CLIError({\n      code: \"WORKFLOW_EXECUTION_POLICY_INVALID\",\n      message: `Invalid workflow execution policy \"${policy.name}\": ${EXECUTION_POLICY_KEY_WILDCARD_MESSAGE}`,\n    });\n  }\n  const parsed = WorkflowJobFunctionExecutionPolicySchema.safeParse({\n    name: policy.name,\n    key: toPlatformExecutionPolicyKey(policy),\n    concurrencyPolicy: policy.concurrencyPolicy,\n  });\n  if (!parsed.success) {\n    throw CLIError({\n      code: \"WORKFLOW_EXECUTION_POLICY_INVALID\",\n      message: `Invalid workflow execution policy \"${policy.name}\": ${parsed.error.issues.map((issue) => issue.message).join(\"; \")}`,\n    });\n  }\n}\n\n/**\n * Plan workflow job function execution policy changes based on desired\n * declarations and current remote state.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param appName - Application name\n * @param appId - Application ID for ownership metadata\n * @param declared - Policies declared in the config (property name → instance)\n * @returns Planned execution policy changes\n */\nexport async function planWorkflowJobFunctionExecutionPolicy(\n  client: OperatorClient,\n  workspaceId: string,\n  appName: string,\n  appId: string | undefined,\n  declared: Record<string, ExecutionPolicyInstance>,\n) {\n  const changeSet = createChangeSet<CreatePolicy, UpdatePolicy, DeletePolicy, ReplacePolicy>(\n    \"Workflow execution policies\",\n  );\n  const conflicts: OwnerConflict[] = [];\n  const unmanaged: UnmanagedResource[] = [];\n  const resourceOwners = new Set<string>();\n\n  const declaredList = Object.values(declared);\n  for (const policy of declaredList) {\n    validatePolicy(policy);\n  }\n\n  const existing = await fetchExistingResourcesWithLabels({\n    client,\n    fetchPage: async (pageToken, pageSize) => {\n      const response = await client.listWorkflowJobFunctionExecutionPolicies({\n        workspaceId,\n        pageToken,\n        pageSize,\n      });\n      return [response.policies, response.nextPageToken];\n    },\n    getName: (resource) => resource.name,\n    getTrn: (name) => resourceTrn(workspaceId, \"workflow_job_function_execution_policy\", name),\n  });\n\n  const seenNames = new Set<string>();\n  for (const policy of declaredList) {\n    if (seenNames.has(policy.name)) {\n      throw CLIError({\n        code: \"WORKFLOW_EXECUTION_POLICY_DUPLICATE\",\n        message: `Duplicate workflow execution policy name \"${policy.name}\". Each policy must have a unique name within the workspace.`,\n      });\n    }\n    seenNames.add(policy.name);\n\n    const currentTrn = resourceTrn(\n      workspaceId,\n      \"workflow_job_function_execution_policy\",\n      policy.name,\n    );\n    const metaRequest = await buildMetaRequest({ trn: currentTrn, appName, appId });\n    const found = existing[policy.name];\n\n    if (found) {\n      const owned = trackDesiredResourceOwnership({\n        labels: found.allLabels,\n        ownerLabel: found.label,\n        appName,\n        appId,\n        resourceType: \"Workflow execution policy\",\n        resourceName: policy.name,\n        conflicts,\n        unmanaged,\n      });\n\n      const remoteKey = found.resource.executionPolicyKey;\n      const desiredKey = toPlatformExecutionPolicyKey(policy);\n      const remoteConcurrency = normalizeComparableConcurrency(found.resource.concurrencyPolicy);\n      const desiredConcurrency = normalizeComparableConcurrency(policy.concurrencyPolicy);\n      const unchanged =\n        owned &&\n        hasMatchingSdkVersion(found.allLabels, metaRequest.labels) &&\n        remoteKey === desiredKey &&\n        areNormalizedEqual(remoteConcurrency, desiredConcurrency);\n\n      if (unchanged) {\n        changeSet.unchanged.push({ name: policy.name });\n      } else if (remoteKey !== desiredKey) {\n        // execution_policy_key is immutable after create; the platform requires\n        // a delete-then-create in the same apply pass. Handled as `replaces`\n        // (not delete + create) so the create phase does not race the delete.\n        changeSet.replaces.push({ name: policy.name, workspaceId, policy, metaRequest });\n      } else {\n        changeSet.updates.push({ name: policy.name, workspaceId, policy, metaRequest });\n      }\n      delete existing[policy.name];\n    } else {\n      changeSet.creates.push({ name: policy.name, workspaceId, policy, metaRequest });\n    }\n  }\n\n  for (const [name, remaining] of Object.entries(existing)) {\n    if (!remaining) continue;\n    const owned = trackRemainingResourceOwner({\n      labels: remaining.allLabels,\n      ownerLabel: remaining.label,\n      appName,\n      appId,\n      resourceOwners,\n    });\n    if (owned) {\n      changeSet.deletes.push({ name, workspaceId });\n    }\n  }\n\n  return { changeSet, conflicts, unmanaged, resourceOwners };\n}\n\n/**\n * Apply planned workflow execution policy changes for the given phase.\n * @param client - Operator client instance\n * @param plan - Result of `planWorkflowJobFunctionExecutionPolicy`\n * @param phase - Apply phase\n * @returns Promise that resolves when policies are applied\n */\nexport async function applyWorkflowJobFunctionExecutionPolicy(\n  client: OperatorClient,\n  plan: Awaited<ReturnType<typeof planWorkflowJobFunctionExecutionPolicy>>,\n  phase: Extract<ApplyPhase, \"create-update\" | \"delete\"> = \"create-update\",\n): Promise<void> {\n  const { changeSet } = plan;\n  if (phase === \"create-update\") {\n    await Promise.all([\n      // Replacements delete-then-create the same name (execution_policy_key is\n      // immutable); each replace runs sequentially so the create never races\n      // its own delete and hits AlreadyExists.\n      ...changeSet.replaces.map(async (replace) => {\n        await client.deleteWorkflowJobFunctionExecutionPolicy({\n          workspaceId: replace.workspaceId,\n          executionPolicyName: replace.name,\n        });\n        await client.createWorkflowJobFunctionExecutionPolicy({\n          workspaceId: replace.workspaceId,\n          executionPolicyName: replace.policy.name,\n          executionPolicyKey: toPlatformExecutionPolicyKey(replace.policy),\n          concurrencyPolicy: toConcurrencyPolicyInit(replace.policy.concurrencyPolicy),\n        });\n        await writeMetadataLabels(client, replace.metaRequest);\n      }),\n      ...changeSet.creates.map(async (create) => {\n        await client.createWorkflowJobFunctionExecutionPolicy({\n          workspaceId: create.workspaceId,\n          executionPolicyName: create.policy.name,\n          executionPolicyKey: toPlatformExecutionPolicyKey(create.policy),\n          concurrencyPolicy: toConcurrencyPolicyInit(create.policy.concurrencyPolicy),\n        });\n        await writeMetadataLabels(client, create.metaRequest);\n      }),\n      ...changeSet.updates.map(async (update) => {\n        await client.updateWorkflowJobFunctionExecutionPolicy({\n          workspaceId: update.workspaceId,\n          executionPolicyName: update.policy.name,\n          concurrencyPolicy: toConcurrencyPolicyInit(update.policy.concurrencyPolicy),\n        });\n        await writeMetadataLabels(client, update.metaRequest);\n      }),\n    ]);\n  } else {\n    await Promise.all(\n      changeSet.deletes.map((del) =>\n        client.deleteWorkflowJobFunctionExecutionPolicy({\n          workspaceId: del.workspaceId,\n          executionPolicyName: del.name,\n        }),\n      ),\n    );\n  }\n}\n","import { withSpan } from \"#/cli/telemetry/index\";\nimport { applyAIGateway, type planAIGateway } from \"./aigateway\";\nimport { applyApplication, type planApplication } from \"./application\";\nimport { applyAuth, type planAuth } from \"./auth\";\nimport { applyExecutor, type planExecutor } from \"./executor\";\nimport { applyFunctionRegistry, type planFunctionRegistry } from \"./function-registry\";\nimport { applyIdP, type planIdP } from \"./idp\";\nimport { withMetadataWriteBatch } from \"./label\";\nimport { applyPipeline, type planPipeline } from \"./resolver\";\nimport { applySecretManager, type planSecretManager } from \"./secret-manager\";\nimport { applyStaticWebsite, type planStaticWebsite } from \"./staticwebsite\";\nimport { applyTailorDB, preflightTailorDB, type planTailorDB } from \"./tailordb\";\nimport { applyWorkflow, type planWorkflow } from \"./workflow\";\nimport {\n  applyWorkflowJobFunctionExecutionPolicy,\n  type planWorkflowJobFunctionExecutionPolicy,\n} from \"./workflow-execution-policy\";\nimport type { Application } from \"#/cli/services/application\";\nimport type { OperatorClient } from \"#/cli/shared/client\";\n\nexport type PlannedDeployment = {\n  readonly application: Readonly<Application>;\n  readonly functionRegistry: Awaited<ReturnType<typeof planFunctionRegistry>>;\n  readonly tailorDB: Awaited<ReturnType<typeof planTailorDB>>;\n  readonly staticWebsite: Awaited<ReturnType<typeof planStaticWebsite>>;\n  readonly aiGateway: Awaited<ReturnType<typeof planAIGateway>>;\n  readonly idp: Awaited<ReturnType<typeof planIdP>>;\n  readonly auth: Awaited<ReturnType<typeof planAuth>>;\n  readonly pipeline: Awaited<ReturnType<typeof planPipeline>>;\n  readonly app: Awaited<ReturnType<typeof planApplication>>;\n  readonly executor: Awaited<ReturnType<typeof planExecutor>>;\n  readonly workflow: Awaited<ReturnType<typeof planWorkflow>>;\n  readonly workflowExecutionPolicy: Awaited<\n    ReturnType<typeof planWorkflowJobFunctionExecutionPolicy>\n  >;\n  readonly secretManager: Awaited<ReturnType<typeof planSecretManager>>;\n};\n\nexport type PlanResults = Omit<PlannedDeployment, \"application\">;\n\nexport function deploymentPlanResults(deployment: PlannedDeployment): PlanResults {\n  const { application: _application, ...results } = deployment;\n  return results;\n}\n\n/**\n * Apply planned deploy changes for one or more applications.\n * @param client - Operator client instance\n * @param workspaceId - Target workspace ID\n * @param deployments - Planned deployments to apply\n */\nexport async function applyDeploymentPlans(\n  client: OperatorClient,\n  workspaceId: string,\n  deployments: ReadonlyArray<PlannedDeployment>,\n): Promise<void> {\n  const forEachDeployment = async (\n    apply: (deployment: PlannedDeployment) => Promise<unknown>,\n  ): Promise<void> => {\n    for (const deployment of deployments) {\n      await apply(deployment);\n    }\n  };\n\n  const step = (\n    name: string,\n    apply: (deployment: PlannedDeployment) => Promise<unknown>,\n  ): Promise<void> => withSpan(name, () => forEachDeployment(apply));\n\n  await withSpan(\"apply.preflight\", async () => {\n    await forEachDeployment((d) => preflightTailorDB(client, d.tailorDB));\n  });\n\n  await withMetadataWriteBatch(client, async (applyClient) => {\n    await withSpan(\"apply.createUpdateServices\", async () => {\n      await step(\"apply.secretManager.createUpdate\", (d) =>\n        applySecretManager(applyClient, d.secretManager, \"create-update\", d.application),\n      );\n      await step(\"apply.functionRegistry.createUpdate\", (d) =>\n        applyFunctionRegistry(applyClient, workspaceId, d.functionRegistry, \"create-update\"),\n      );\n      await step(\"apply.staticWebsite.createUpdate\", (d) =>\n        applyStaticWebsite(applyClient, d.staticWebsite, \"create-update\"),\n      );\n      await step(\"apply.aiGateway.createUpdate\", (d) =>\n        applyAIGateway(applyClient, d.aiGateway, \"create-update\"),\n      );\n      await step(\"apply.idp.createUpdate\", (d) => applyIdP(applyClient, d.idp, \"create-update\"));\n      await step(\"apply.auth.createUpdatePrerequisites\", (d) =>\n        applyAuth(applyClient, d.auth, \"create-update-prerequisites\"),\n      );\n      await step(\"apply.tailorDB.createUpdate\", (d) =>\n        applyTailorDB(applyClient, d.tailorDB, \"create-update\"),\n      );\n      await step(\"apply.auth.createUpdateDependents\", (d) =>\n        applyAuth(applyClient, d.auth, \"create-update-dependents\"),\n      );\n      await step(\"apply.pipeline.createUpdate\", (d) =>\n        applyPipeline(applyClient, d.pipeline, \"create-update\"),\n      );\n    });\n\n    await withSpan(\"apply.deleteSubgraphResources\", async () => {\n      await forEachDeployment((d) => applyPipeline(applyClient, d.pipeline, \"delete-resources\"));\n      await forEachDeployment((d) => applyAuth(applyClient, d.auth, \"delete-resources\"));\n      await forEachDeployment((d) => applyIdP(applyClient, d.idp, \"delete-resources\"));\n    });\n\n    await withSpan(\"apply.createUpdateApplication\", async () => {\n      await forEachDeployment((d) => applyApplication(applyClient, d.app, \"create-update\"));\n    });\n\n    await withSpan(\"apply.createUpdateDependentServices\", async () => {\n      await step(\"apply.executor.createUpdate\", (d) =>\n        applyExecutor(applyClient, d.executor, \"create-update\"),\n      );\n      // Execution policies must exist before workflow job functions that reference\n      // them by key, otherwise the runtime rejects the dispatch as an unknown key.\n      await step(\"apply.workflowExecutionPolicy.createUpdate\", (d) =>\n        applyWorkflowJobFunctionExecutionPolicy(\n          applyClient,\n          d.workflowExecutionPolicy,\n          \"create-update\",\n        ),\n      );\n      await step(\"apply.workflow.createUpdate\", (d) =>\n        applyWorkflow(applyClient, d.workflow, \"create-update\"),\n      );\n    });\n  });\n\n  await withSpan(\"apply.deleteDependentServices\", async () => {\n    await forEachDeployment((d) => applyWorkflow(client, d.workflow, \"delete\"));\n    await forEachDeployment((d) =>\n      applyWorkflowJobFunctionExecutionPolicy(client, d.workflowExecutionPolicy, \"delete\"),\n    );\n    await forEachDeployment((d) => applyExecutor(client, d.executor, \"delete\"));\n    await forEachDeployment((d) => applyStaticWebsite(client, d.staticWebsite, \"delete\"));\n    await forEachDeployment((d) => applyAIGateway(client, d.aiGateway, \"delete\"));\n    await forEachDeployment((d) =>\n      applySecretManager(client, d.secretManager, \"delete\", d.application),\n    );\n  });\n\n  await withSpan(\"apply.deleteApplication\", async () => {\n    await forEachDeployment((d) => applyApplication(client, d.app, \"delete\"));\n  });\n\n  await withSpan(\"apply.deleteSubgraphServices\", async () => {\n    await forEachDeployment((d) => applyPipeline(client, d.pipeline, \"delete-services\"));\n    await forEachDeployment((d) => applyAuth(client, d.auth, \"delete-services\"));\n    await forEachDeployment((d) => applyIdP(client, d.idp, \"delete-services\"));\n    await forEachDeployment((d) => applyTailorDB(client, d.tailorDB, \"delete-services\"));\n  });\n\n  await withSpan(\"apply.cleanup\", async () => {\n    await forEachDeployment((d) =>\n      applyFunctionRegistry(client, workspaceId, d.functionRegistry, \"delete\"),\n    );\n  });\n}\n","import { CLIError } from \"#/cli/shared/errors\";\nimport type { BuiltDeploymentTarget } from \"./deployment-target\";\n\nfunction setBundledScript(\n  target: Map<string, string>,\n  name: string,\n  code: string,\n  kind: string,\n): void {\n  if (target.has(name)) {\n    throw CLIError({\n      code: \"DEPLOY_DUPLICATE_RESOURCE_NAME\",\n      message: `Duplicate ${kind} bundle name \"${name}\" across config files.`,\n    });\n  }\n  target.set(name, code);\n}\n\nfunction addBundledScripts(\n  target: Map<string, string>,\n  source: ReadonlyMap<string, string>,\n  kind: string,\n): void {\n  for (const [name, code] of source) {\n    setBundledScript(target, name, code, kind);\n  }\n}\n\n/**\n * Merge per-config bundled scripts into one build-only result.\n * Resolver bundles are keyed by `namespace:resolverName`, so the same resolver\n * name in different namespaces never collides across configs.\n * @param targets - Built deployment targets to merge\n * @returns Combined bundled scripts across all targets\n */\nexport function mergeBundledScripts(\n  targets: ReadonlyArray<BuiltDeploymentTarget>,\n): BuiltDeploymentTarget[\"bundledScripts\"] {\n  const bundledScripts: BuiltDeploymentTarget[\"bundledScripts\"] = {\n    resolvers: new Map(),\n    executors: new Map(),\n    workflowJobs: new Map(),\n    authHooks: new Map(),\n  };\n\n  for (const target of targets) {\n    addBundledScripts(bundledScripts.resolvers, target.bundledScripts.resolvers, \"resolver\");\n    addBundledScripts(bundledScripts.executors, target.bundledScripts.executors, \"executor\");\n    addBundledScripts(\n      bundledScripts.workflowJobs,\n      target.bundledScripts.workflowJobs,\n      \"workflow job\",\n    );\n    addBundledScripts(bundledScripts.authHooks, target.bundledScripts.authHooks, \"auth hook\");\n  }\n\n  return bundledScripts;\n}\n","import { formatMigrationNumber } from \"#/cli/commands/tailordb/migrate/migration-number\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { styles, logger } from \"#/cli/shared/logger\";\nimport { prompt } from \"#/cli/shared/prompt\";\nimport ml from \"#/utils/multiline\";\nimport type { MigrationCheckpointRepair } from \"#/cli/commands/tailordb/migrate/types\";\n\nexport interface OwnerConflict {\n  resourceType: string;\n  resourceName: string;\n  currentOwner: string;\n}\n\nexport interface UnmanagedResource {\n  resourceType: string;\n  resourceName: string;\n}\n\nexport async function confirmMigrationCheckpointRepairs(\n  repairs: ReadonlyArray<MigrationCheckpointRepair>,\n  yes: boolean,\n): Promise<void> {\n  if (repairs.length === 0) return;\n\n  logger.warn(\n    \"TailorDB migration checkpoints and history IDs need to be updated before this deployment:\",\n  );\n  for (const repair of repairs.toSorted((a, b) => a.namespace.localeCompare(b.namespace))) {\n    logger.log(`  ${repair.namespace}:`);\n    logger.log(\n      `    Checkpoint: ${formatMigrationNumber(repair.from)} → ${formatMigrationNumber(repair.to)}`,\n    );\n    logger.log(\n      `    Migration history ID: ${repair.fromHistoryId ?? \"<unset>\"} → ${repair.toHistoryId}`,\n    );\n  }\n  logger.log(\"  The checkpoint reset itself changes only metadata.\");\n  logger.log(\"  This deployment may still apply pending schema or data migrations afterward.\");\n\n  if (yes) return;\n  const confirmed = await prompt.confirm({\n    message:\n      \"Reset these migration checkpoints, align their history IDs, and continue with the deployment?\",\n    default: false,\n  });\n  if (!confirmed) {\n    throw CLIError({\n      code: \"DEPLOY_CANCELLED\",\n      message: \"Apply cancelled: migration checkpoint reset was not confirmed.\",\n    });\n  }\n}\n\n/**\n * Confirm reassignment of resources when owner conflicts are detected.\n * Splits into three scenarios, each with its own prompt because the\n * user-facing meaning is different: the resource carries the same sdk-name and\n * an sdk-app-id the config does not match, either because the config now holds\n * a different id (regeneration) or because it holds none at all; or the\n * resource carries a different sdk-name (name mismatch).\n * @param conflicts - Detected owner conflicts\n * @param appName - Target application name\n * @param yes - Whether to auto-confirm without prompting\n * @param appId - Target application id, when the config resolves to one\n * @returns Promise that resolves when confirmation completes\n */\nexport async function confirmOwnerConflict(\n  conflicts: OwnerConflict[],\n  appName: string,\n  yes: boolean,\n  appId?: string,\n): Promise<void> {\n  if (conflicts.length === 0) return;\n\n  // Same sdk-name as the target app -> the resources carry an id this config\n  // does not: either a new one replaced it, or the config has none at all.\n  const idMismatches = conflicts.filter((c) => c.currentOwner === appName);\n  const nameMismatches = conflicts.filter((c) => c.currentOwner !== appName);\n\n  if (idMismatches.length > 0) {\n    await (appId\n      ? confirmIdRegeneration(idMismatches, appName, yes)\n      : confirmMissingConfigId(idMismatches, appName, yes));\n  }\n  if (nameMismatches.length > 0) {\n    await confirmNameMismatch(nameMismatches, appName, yes);\n  }\n}\n\nasync function confirmIdRegeneration(\n  conflicts: OwnerConflict[],\n  appName: string,\n  yes: boolean,\n): Promise<void> {\n  logIdMismatch(`Application id was regenerated for \"${appName}\":`, conflicts);\n\n  if (yes) {\n    logger.success(\"Re-tagging resources with the new id (--yes flag specified)...\", {\n      mode: \"plain\",\n    });\n    return;\n  }\n\n  const confirmed = await prompt.confirm({\n    message: `Re-tag these resources with the new id for \"${appName}\"?\\n${styles.dim(\"(The app id recorded for this config was removed since the previous deploy, so a new one was generated)\")}`,\n    default: false,\n  });\n  if (!confirmed) {\n    throw CLIError({\n      code: \"DEPLOY_CANCELLED\",\n      message: ml`\n      Apply cancelled. Resources remain tagged with the previous id.\n      To override, run again and confirm, or use --yes flag.\n    `,\n    });\n  }\n}\n\nfunction logIdMismatch(heading: string, conflicts: OwnerConflict[]): void {\n  logger.warn(heading);\n  logger.log(\"  These resources are tagged with an id from an earlier deploy.\");\n  logger.newline();\n  logger.log(`  ${styles.info(\"Resources\")}:`);\n  for (const c of conflicts) {\n    logger.log(`    • ${styles.bold(c.resourceType)} ${styles.info(`\"${c.resourceName}\"`)}`);\n  }\n}\n\nasync function confirmMissingConfigId(\n  conflicts: OwnerConflict[],\n  appName: string,\n  yes: boolean,\n): Promise<void> {\n  logIdMismatch(`No application id resolved for \"${appName}\":`, conflicts);\n\n  if (yes) {\n    logger.success(\"Managing these resources by name (--yes flag specified)...\", { mode: \"plain\" });\n    return;\n  }\n\n  const confirmed = await prompt.confirm({\n    message: `Drop that id and manage these resources by name for \"${appName}\"?\\n${styles.dim(\"(the config resolves without an 'id', so ownership falls back to the application name)\")}`,\n    default: false,\n  });\n  if (!confirmed) {\n    throw CLIError({\n      code: \"DEPLOY_CANCELLED\",\n      message: ml`\n      Apply cancelled. Resources remain tagged with their current id.\n      Restore the app id for this config (in .github/tailor.lock, or the config's 'id') to keep owning them by id, or run again and confirm to own them by name.\n    `,\n    });\n  }\n}\n\nasync function confirmNameMismatch(\n  conflicts: OwnerConflict[],\n  appName: string,\n  yes: boolean,\n): Promise<void> {\n  const currentOwners = [...new Set(conflicts.map((c) => c.currentOwner))];\n\n  logger.warn(\"Application name mismatch detected:\");\n\n  logger.log(\n    `  ${styles.warning(\"Current application(s)\")}: ${currentOwners.map((o) => styles.bold(`\"${o}\"`)).join(\", \")}`,\n  );\n  logger.log(`  ${styles.success(\"New application\")}:        ${styles.bold(`\"${appName}\"`)}`);\n  logger.newline();\n  logger.log(`  ${styles.info(\"Resources\")}:`);\n  for (const c of conflicts) {\n    logger.log(`    • ${styles.bold(c.resourceType)} ${styles.info(`\"${c.resourceName}\"`)}`);\n  }\n\n  if (yes) {\n    logger.success(\"Updating resources (--yes flag specified)...\", {\n      mode: \"plain\",\n    });\n    return;\n  }\n\n  const promptMessage =\n    currentOwners.length === 1\n      ? `Update these resources to be managed by \"${appName}\"?\\n${styles.dim(\"(Common when renaming your application)\")}`\n      : `Update these resources to be managed by \"${appName}\"?`;\n  const confirmed = await prompt.confirm({\n    message: promptMessage,\n    default: false,\n  });\n  if (!confirmed) {\n    throw CLIError({\n      code: \"DEPLOY_CANCELLED\",\n      message: ml`\n      Apply cancelled. Resources remain managed by their current applications.\n      To override, run again and confirm, or use --yes flag.\n    `,\n    });\n  }\n}\n\n/**\n * Confirm allowing tailor to manage previously unmanaged resources.\n * @param resources - Unmanaged resources\n * @param appName - Target application name\n * @param yes - Whether to auto-confirm without prompting\n * @returns Promise that resolves when confirmation completes\n */\nexport async function confirmUnmanagedResources(\n  resources: UnmanagedResource[],\n  appName: string,\n  yes: boolean,\n): Promise<void> {\n  if (resources.length === 0) return;\n\n  logger.warn(\"Existing resources not tracked by tailor were found:\");\n\n  logger.log(`  ${styles.info(\"Resources\")}:`);\n  for (const r of resources) {\n    logger.log(`    • ${styles.bold(r.resourceType)} ${styles.info(`\"${r.resourceName}\"`)}`);\n  }\n  logger.newline();\n  logger.log(\"  These resources may have been created by older SDK versions, Terraform, or CUE.\");\n  logger.log(\"  To continue, confirm that tailor should manage them.\");\n  logger.log(\n    \"  If they are managed by another tool (e.g., Terraform), cancel and manage them there instead.\",\n  );\n\n  if (yes) {\n    logger.success(`Adding to \"${appName}\" (--yes flag specified)...`, {\n      mode: \"plain\",\n    });\n    return;\n  }\n\n  const confirmed = await prompt.confirm({\n    message: `Allow tailor to manage these resources for \"${appName}\"?`,\n    default: false,\n  });\n  if (!confirmed) {\n    throw CLIError({\n      code: \"DEPLOY_CANCELLED\",\n      message: ml`\n      Apply cancelled. Resources remain unmanaged.\n      To override, run again and confirm, or use --yes flag.\n    `,\n    });\n  }\n}\n\nexport interface ImportantResourceDeletion {\n  resourceType: string;\n  resourceName: string;\n}\n\n/**\n * Confirm deletion of important resources.\n * @param resources - Resources scheduled for deletion\n * @param yes - Whether to auto-confirm without prompting\n * @returns Promise that resolves when confirmation completes\n */\nexport async function confirmImportantResourceDeletion(\n  resources: ImportantResourceDeletion[],\n  yes: boolean,\n): Promise<void> {\n  if (resources.length === 0) return;\n\n  logger.warn(\"The following resources will be deleted:\");\n\n  logger.log(`  ${styles.info(\"Resources\")}:`);\n  for (const r of resources) {\n    logger.log(`    • ${styles.bold(r.resourceType)} ${styles.error(`\"${r.resourceName}\"`)}`);\n  }\n  logger.newline();\n  logger.log(\n    styles.warning(\"  Deleting these resources will permanently remove all associated data.\"),\n  );\n\n  if (yes) {\n    logger.success(\"Deleting resources (--yes flag specified)...\", {\n      mode: \"plain\",\n    });\n    return;\n  }\n\n  const confirmed = await prompt.confirm({\n    message: \"Are you sure you want to delete these resources?\",\n    default: false,\n  });\n  if (!confirmed) {\n    throw CLIError({\n      code: \"DEPLOY_CANCELLED\",\n      message: ml`\n      Apply cancelled. Resources will not be deleted.\n      To override, run again and confirm, or use --yes flag.\n    `,\n    });\n  }\n}\n\n/** An application recorded as needing to take part in this deploy, but absent. */\nexport interface MissingDependentApp {\n  /**\n   * The resource whose value is applied differently without the dependent, named\n   * as messages name it, e.g. `TailorDB table \"Order\"`. Records live on the\n   * resource, so this identifies one of those rather than an application.\n   */\n  resource: string;\n  /** Stable id of the absent application. */\n  appId: string;\n  /** Why it has to take part in the same deploy. */\n  reason: string;\n}\n\n/**\n * Confirm continuing without an application recorded as a dependency.\n *\n * A previous deploy recorded that another config's executors make this config's\n * resources publish events. Applying this config alone resolves those flags from\n * a smaller set of executors, which turns publishing off.\n * @param missing - Recorded dependencies absent from this deploy\n * @param yes - Whether `--yes` was passed\n * @returns Promise that resolves when the deploy may continue\n */\nexport async function confirmMissingDependentApps(\n  missing: MissingDependentApp[],\n  yes: boolean,\n): Promise<void> {\n  if (missing.length === 0) return;\n\n  logger.warn(\"Applications recorded as depending on this deploy are missing:\");\n  for (const entry of missing) {\n    logger.log(\n      `    • application id ${styles.info(entry.appId)} depends on ${styles.bold(entry.resource)} (${entry.reason})`,\n    );\n  }\n  logger.newline();\n  logger.log(\"  Applying without them turns off event publishing on the resources above:\");\n  logger.log(\"  nothing in this deploy subscribes to them, so the value resolves to false.\");\n  logger.log(\"  To keep it, add their configs to --config, or set publishEvents on\");\n  logger.log(\"  the resources above.\");\n\n  if (yes) {\n    logger.warn(\"Continuing without them (--yes flag specified); applying turns publishing off.\");\n    return;\n  }\n\n  const confirmed = await prompt.confirm({\n    message: \"Continue without them?\",\n    default: false,\n  });\n  if (!confirmed) {\n    throw CLIError({\n      code: \"DEPLOY_CANCELLED\",\n      message: ml`\n      Apply cancelled. Add the missing configs to --config, or set publishEvents\n      explicitly on the resources that should keep publishing.\n    `,\n    });\n  }\n}\n","import { getOrNull } from \"#/cli/shared/client\";\nimport { eventSourceLabel } from \"#/cli/shared/publish-events\";\nimport {\n  type DependencyScope,\n  eventSourceKey,\n  recordedDependencies,\n  resolverTrn,\n  resourceTrn,\n  tailorDBTypeTrn,\n} from \"./label\";\nimport { subscribedWorkflowJobNames } from \"./workflow\";\nimport type { Application } from \"#/cli/services/application\";\nimport type { OperatorClient } from \"#/cli/shared/client\";\nimport type { MissingDependentApp } from \"./confirm\";\n\n/** One value this run would recompute, and where its records live. */\ntype RecomputedResource = {\n  /** TRN carrying the dependency records. */\n  trn: string;\n  /** Key the run's own subscriptions are recorded under. */\n  key: string;\n  /** Which of the resource's values this entry concerns. */\n  scope: DependencyScope;\n  /** How it is named in the confirmation, e.g. `Workflow \"nightly\"`. */\n  label: string;\n};\n\n/**\n * List the resources whose `publishEvents` this run recomputes.\n *\n * A resource that declares the value keeps it whatever the run covers, so no\n * absent config can change it and its records cannot matter. Skipping those is\n * what keeps a declared value from prompting forever.\n * @param workspaceId - Workspace being deployed to\n * @param application - Application whose resources are listed\n * @param jobsByWorkflow - Job names each workflow runs, keyed by its main job\n * @param subscribedKeys - Resources this run subscribes to, by resource key\n * @returns One entry per value that leaves `publishEvents` unset\n */\nfunction recomputedResources(\n  workspaceId: string,\n  application: Readonly<Application>,\n  jobsByWorkflow: Record<string, string[]>,\n  subscribedKeys: ReadonlySet<string>,\n): RecomputedResource[] {\n  const resources: RecomputedResource[] = [];\n\n  for (const service of application.tailorDBServices) {\n    for (const [tableName, type] of Object.entries(service.types)) {\n      if (type.settings.publishEvents === undefined) {\n        resources.push({\n          trn: tailorDBTypeTrn(workspaceId, service.namespace, tableName),\n          key: eventSourceKey.tailorDBType(service.namespace, tableName),\n          scope: \"resource\",\n          label: eventSourceLabel.tailorDBType(tableName),\n        });\n      }\n    }\n  }\n\n  for (const service of application.resolverServices) {\n    for (const resolver of Object.values(service.resolvers)) {\n      if (resolver.publishEvents === undefined) {\n        resources.push({\n          trn: resolverTrn(workspaceId, service.namespace, resolver.name),\n          key: eventSourceKey.resolver(service.namespace, resolver.name),\n          scope: \"resource\",\n          label: eventSourceLabel.resolver(resolver.name),\n        });\n      }\n    }\n  }\n\n  for (const idp of application.idpServices) {\n    if (idp.publishEvents === undefined) {\n      resources.push({\n        trn: resourceTrn(workspaceId, \"idp\", idp.name),\n        key: eventSourceKey.idp(idp.name),\n        scope: \"resource\",\n        label: eventSourceLabel.idpService(idp.name),\n      });\n    }\n  }\n\n  // A workflow carries two values: its own execution events and the ones its jobs\n  // publish. Different triggers drive them, so each is asked about on its own —\n  // a subscriber of one must not answer for the other.\n  const explicitByJob = new Map(\n    (application.workflowService?.jobs ?? []).map((job) => [job.name, job.publishEvents]),\n  );\n  const subscribedJobNames = subscribedWorkflowJobNames({\n    workflows: Object.values(application.workflowService?.workflows ?? {}),\n    mainJobDeps: jobsByWorkflow,\n    isSubscribed: (workflowName) => subscribedKeys.has(eventSourceKey.workflowJobs(workflowName)),\n  });\n  for (const workflow of Object.values(application.workflowService?.workflows ?? {})) {\n    const trn = resourceTrn(workspaceId, \"workflow\", workflow.name);\n    if (workflow.publishEvents === undefined) {\n      resources.push({\n        trn,\n        key: eventSourceKey.workflow(workflow.name),\n        scope: \"resource\",\n        label: eventSourceLabel.workflow(workflow.name),\n      });\n    }\n    // Only the jobs this workflow runs decide whether its job records matter, and\n    // only the ones no subscription in the run keeps on — `subscribedWorkflowJobNames`\n    // applies the same union the values themselves are resolved by.\n    const jobNames = jobsByWorkflow[workflow.mainJob.name] ?? [];\n    if (\n      jobNames.some(\n        (jobName) => explicitByJob.get(jobName) === undefined && !subscribedJobNames.has(jobName),\n      )\n    ) {\n      resources.push({\n        trn,\n        key: eventSourceKey.workflowJobs(workflow.name),\n        scope: \"jobs\",\n        label: eventSourceLabel.workflowJobs(workflow.name),\n      });\n    }\n  }\n\n  return resources;\n}\n\n/**\n * Read the applications recorded as depending on this config's resources but\n * absent from the current deploy.\n *\n * Records live on the resources rather than on the application, so this survives\n * the application being renamed and stops reporting a resource that is gone.\n *\n * A resource this run still subscribes to is skipped: its value resolves to `true`\n * from the run's own executors, so the absent config changes nothing about it and\n * asking would be asking about something that cannot happen. What is left over is\n * a resource that really does turn off.\n * @param params - Client, workspace, application, and the run's inputs\n * @param params.client - Operator client instance\n * @param params.workspaceId - Workspace being deployed to\n * @param params.application - Application being planned\n * @param params.runAppIds - Stable ids of every application in the run\n * @param params.subscribedKeys - Resources this run subscribes to, by resource key\n * @param params.jobsByWorkflow - Job names each workflow runs, keyed by its main job\n * @returns Recorded dependencies missing from the run\n */\nexport async function fetchMissingDependentApps(params: {\n  client: OperatorClient;\n  workspaceId: string;\n  application: Readonly<Application>;\n  runAppIds: ReadonlySet<string>;\n  subscribedKeys: ReadonlySet<string>;\n  jobsByWorkflow: Record<string, string[]>;\n}): Promise<MissingDependentApp[]> {\n  const { client, workspaceId, application, runAppIds, subscribedKeys, jobsByWorkflow } = params;\n  const found = await Promise.all(\n    recomputedResources(workspaceId, application, jobsByWorkflow, subscribedKeys)\n      .filter(({ key }) => !subscribedKeys.has(key))\n      .map(async ({ trn, scope, label }) => {\n        const metadata = await getOrNull(() => client.getMetadata({ trn }));\n        return recordedDependencies(metadata?.metadata?.labels, scope)\n          .filter((dependency) => !runAppIds.has(dependency.appId))\n          .map((dependency) => ({\n            resource: label,\n            appId: dependency.appId,\n            reason: dependency.reason,\n          }));\n      }),\n  );\n  return found.flat();\n}\n","import { z } from \"zod\";\n\n// strip unknown keys\nconst cacheOutputFileSchema = z.object({\n  outputPath: z.string(),\n  contentHash: z.string(),\n});\n\n// strip unknown keys\nconst cacheEntrySchema = z.object({\n  kind: z.literal(\"bundle\"),\n  inputHash: z.string(),\n  dependencyPaths: z.array(z.string()),\n  outputFiles: z.array(cacheOutputFileSchema),\n  createdAt: z.string(),\n});\n\n// strip unknown keys\nconst cacheManifestSchema = z.object({\n  version: z.literal(1),\n  sdkVersion: z.string(),\n  lockfileHash: z.string().optional(),\n  entries: z.record(z.string(), cacheEntrySchema),\n});\n\ntype CacheEntry = z.infer<typeof cacheEntrySchema>;\ntype CacheManifest = z.infer<typeof cacheManifestSchema>;\n\n/**\n * Runtime configuration for the caching subsystem.\n */\ntype CacheConfig = {\n  /** Directory where cache artifacts are stored. */\n  cacheDir: string;\n};\n\nexport { cacheManifestSchema };\nexport type { CacheConfig, CacheEntry, CacheManifest };\n","import * as fs from \"node:fs\";\nimport * as path from \"pathe\";\nimport { hashContent } from \"./hasher\";\nimport { cacheManifestSchema } from \"./types\";\nimport type { CacheConfig, CacheEntry, CacheManifest } from \"./types\";\n\n/**\n * Public interface for cache persistence operations.\n */\ntype CacheStore = {\n  /** Read manifest from disk, returning undefined if missing or invalid. */\n  loadManifest(): CacheManifest | undefined;\n  /** Return the current in-memory manifest, loading from disk on first access if not yet loaded. */\n  getCurrentManifest(): CacheManifest | undefined;\n  /** Persist manifest to disk using atomic write (temp file + rename). */\n  saveManifest(manifest: CacheManifest): void;\n  /** Retrieve a cache entry by key from the in-memory manifest. */\n  getEntry(key: string): CacheEntry | undefined;\n  /** Add or update a cache entry in the in-memory manifest. */\n  setEntry(key: string, entry: CacheEntry): void;\n  /** Remove a cache entry from the in-memory manifest. */\n  deleteEntry(key: string): void;\n  /** Store bundled code content directly into cache/bundles/. */\n  storeBundleContent(cacheKey: string, content: string): void;\n  /** Restore bundled code content from cache/bundles/. Returns undefined if not found. */\n  restoreBundleContent(cacheKey: string): string | undefined;\n  /** Delete the entire cache directory. */\n  clean(): void;\n};\n\nconst MANIFEST_FILENAME = \"manifest.json\";\nconst BUNDLES_DIR = \"bundles\";\n\n/**\n * Create a cache store for manifest persistence and bundle output storage.\n * @param config - Cache configuration specifying the cache directory\n * @returns A CacheStore instance\n */\nfunction createCacheStore(config: CacheConfig): CacheStore {\n  // Tri-state: null = not yet loaded, undefined = loaded but missing/invalid, CacheManifest = loaded\n  let cachedManifest: CacheManifest | undefined | null = null;\n\n  function manifestPath(): string {\n    return path.join(config.cacheDir, MANIFEST_FILENAME);\n  }\n\n  function bundlesDir(): string {\n    return path.join(config.cacheDir, BUNDLES_DIR);\n  }\n\n  function bundlePath(cacheKey: string): string {\n    return path.join(bundlesDir(), `${hashContent(cacheKey)}.js`);\n  }\n\n  function loadManifest(): CacheManifest | undefined {\n    try {\n      const raw = fs.readFileSync(manifestPath(), \"utf-8\");\n      const result = cacheManifestSchema.safeParse(JSON.parse(raw));\n\n      if (!result.success) {\n        cachedManifest = undefined;\n        return undefined;\n      }\n\n      cachedManifest = result.data;\n      return cachedManifest;\n    } catch {\n      // Missing file, parse error, etc.\n      cachedManifest = undefined;\n      return undefined;\n    }\n  }\n\n  function getCurrentManifest(): CacheManifest | undefined {\n    if (cachedManifest === null) {\n      loadManifest();\n    }\n    return cachedManifest ?? undefined;\n  }\n\n  function ensureManifestLoaded(): CacheManifest {\n    if (cachedManifest === null) {\n      loadManifest();\n    }\n    if (cachedManifest == null) {\n      cachedManifest = {\n        version: 1,\n        sdkVersion: \"\",\n        entries: {},\n      };\n    }\n    return cachedManifest;\n  }\n\n  function saveManifest(manifest: CacheManifest): void {\n    fs.mkdirSync(config.cacheDir, { recursive: true });\n\n    const target = manifestPath();\n    const tmpFile = path.join(config.cacheDir, `.manifest.${process.pid}.tmp`);\n\n    // Atomic write: write to temp file, then rename\n    try {\n      fs.writeFileSync(tmpFile, JSON.stringify(manifest, null, 2), \"utf-8\");\n      fs.renameSync(tmpFile, target);\n    } catch (e) {\n      try {\n        fs.rmSync(tmpFile, { force: true });\n      } catch {\n        // Ignore cleanup errors\n      }\n      throw e;\n    }\n\n    cachedManifest = manifest;\n  }\n\n  function getEntry(key: string): CacheEntry | undefined {\n    const manifest = ensureManifestLoaded();\n    return manifest.entries[key];\n  }\n\n  function setEntry(key: string, entry: CacheEntry): void {\n    const manifest = ensureManifestLoaded();\n    manifest.entries[key] = entry;\n  }\n\n  function deleteEntry(key: string): void {\n    const manifest = ensureManifestLoaded();\n    // eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- Cache entry removal by dynamic key\n    delete manifest.entries[key];\n  }\n\n  function storeBundleContent(cacheKey: string, content: string): void {\n    const dir = bundlesDir();\n    fs.mkdirSync(dir, { recursive: true });\n    fs.writeFileSync(bundlePath(cacheKey), content, \"utf-8\");\n  }\n\n  function restoreBundleContent(cacheKey: string): string | undefined {\n    try {\n      return fs.readFileSync(bundlePath(cacheKey), \"utf-8\");\n    } catch (e) {\n      if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n      throw e;\n    }\n  }\n\n  function clean(): void {\n    fs.rmSync(config.cacheDir, { recursive: true, force: true });\n    cachedManifest = null;\n  }\n\n  return {\n    loadManifest,\n    getCurrentManifest,\n    saveManifest,\n    getEntry,\n    setEntry,\n    deleteEntry,\n    storeBundleContent,\n    restoreBundleContent,\n    clean,\n  };\n}\n\nexport { createCacheStore };\nexport type { CacheStore };\n","import * as path from \"pathe\";\nimport { getDistDir } from \"#/cli/shared/dist-dir\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { createBundleCache, type BundleCache } from \"./bundle-cache\";\nimport { createCacheStore } from \"./store\";\n\n/**\n * Options for creating a CacheManager.\n */\ntype CacheManagerOptions = {\n  /** Whether caching is enabled. Defaults to true. */\n  enabled?: boolean;\n  /** Directory where cache artifacts are stored. Defaults to `<distDir>/cache`. */\n  cacheDir?: string;\n  /** Current SDK version for cache invalidation on upgrade. */\n  sdkVersion: string;\n  /** Hash of the lockfile for cache invalidation on dependency changes. */\n  lockfileHash?: string;\n};\n\n/**\n * Top-level facade that orchestrates cache operations.\n */\ntype CacheManager = {\n  readonly enabled: boolean;\n  readonly bundleCache: BundleCache;\n  /** Persist the cache manifest to disk. */\n  finalize(): void;\n};\n\n/**\n * Create a CacheManager that orchestrates cache operations.\n * @param options - Configuration for the cache manager\n * @returns A CacheManager instance\n */\nfunction createCacheManager(options: CacheManagerOptions): CacheManager {\n  const enabled = options.enabled ?? true;\n\n  if (!enabled) {\n    return {\n      enabled: false,\n      bundleCache: {\n        tryRestore() {\n          return undefined;\n        },\n        save() {\n          // no-op\n        },\n      },\n      finalize() {\n        // no-op\n      },\n    };\n  }\n\n  const cacheDir = options.cacheDir ?? path.resolve(getDistDir(), \"cache\");\n\n  const store = createCacheStore({ cacheDir });\n\n  // Load existing manifest and check SDK version / lockfile hash for cache invalidation\n  const existingManifest = store.loadManifest();\n  if (existingManifest) {\n    if (existingManifest.sdkVersion !== options.sdkVersion) {\n      logger.debug(\n        `Cache invalidated: SDK version changed from ${existingManifest.sdkVersion} to ${options.sdkVersion}`,\n      );\n      store.clean();\n    } else if (existingManifest.lockfileHash !== options.lockfileHash) {\n      logger.debug(\"Cache invalidated: lockfile changed\");\n      store.clean();\n    }\n  }\n\n  const bundleCache = createBundleCache(store);\n\n  return {\n    enabled: true,\n    bundleCache,\n    finalize() {\n      const currentManifest = store.getCurrentManifest() ?? {\n        version: 1 as const,\n        sdkVersion: options.sdkVersion,\n        lockfileHash: options.lockfileHash,\n        entries: {},\n      };\n      const latestManifest = store.loadManifest();\n      const manifest =\n        latestManifest?.sdkVersion === options.sdkVersion &&\n        latestManifest.lockfileHash === options.lockfileHash\n          ? {\n              ...latestManifest,\n              entries: {\n                ...latestManifest.entries,\n                ...currentManifest.entries,\n              },\n            }\n          : currentManifest;\n      manifest.sdkVersion = options.sdkVersion;\n      manifest.lockfileHash = options.lockfileHash;\n      store.saveManifest(manifest);\n    },\n  };\n}\n\nexport { createCacheManager };\n","import * as fs from \"node:fs\";\nimport * as path from \"pathe\";\nimport { logger } from \"#/cli/shared/logger\";\nimport ml from \"#/utils/multiline\";\nimport type { ResolvedEnvAppConfig } from \"#/cli/shared/config-loader\";\nimport type { AppConfig } from \"#/configure/config/types\";\n\ninterface AttributeTypeInfo {\n  type: string;\n  optional?: boolean;\n}\n\nexport interface AttributesConfig {\n  [key: string]: AttributeTypeInfo;\n}\n\nexport type AttributeListConfig = readonly string[];\n\ninterface ExtractedAttributes {\n  attributes?: AttributesConfig;\n  attributeList?: AttributeListConfig;\n  env?: Record<string, string | number | boolean>;\n  machineUserNames?: string[];\n  idpNames?: string[];\n  connectionNames?: string[];\n  aiGatewayNames?: string[];\n  authNamespaceNames?: string[];\n}\n\ntype AttributeFieldLike = {\n  type?: string;\n  metadata?: {\n    array?: boolean;\n    allowedValues?: Array<{ value: string }>;\n    required?: boolean;\n  };\n};\n\n/**\n * Extract attribute definitions from the app config for user-defined typing.\n * @param config - Application config to inspect\n * @returns Extracted attributes/list and env values\n * @internal\n */\nexport function extractAttributesFromConfig(config: AppConfig): ExtractedAttributes {\n  return collectAttributesFromConfig(config);\n}\n\n// Quote generated keys only when they aren't valid TypeScript identifiers — matches\n// the formatter (oxfmt) output so subsequent format passes are no-ops.\nconst isValidIdentifier = (s: string): boolean => /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(s);\n\n/**\n * Generate the contents of the user-defined type definition file.\n * @param attributes - Attribute configuration\n * @param attributeList - Attribute list configuration\n * @param env - Environment configuration\n * @param machineUserNames - Registered machine user names (used to narrow `invoker` strings)\n * @param idpNames - Registered IdP names (used to narrow `idpUser*Trigger({ idp })` strings)\n * @param connectionNames - Registered auth connection names (used to narrow `getConnectionToken()` strings)\n * @param aiGatewayNames - Registered AI Gateway names (used to narrow `aigateway.get()` strings)\n * @param authNamespaceNames - Registered auth namespace names (used to narrow `authNamespace` strings)\n * @returns Generated type definition source\n */\nexport function generateTypeDefinition(\n  attributes: AttributesConfig | undefined,\n  attributeList: AttributeListConfig | undefined,\n  env?: Record<string, string | number | boolean>,\n  machineUserNames?: readonly string[],\n  idpNames?: readonly string[],\n  connectionNames?: readonly string[],\n  aiGatewayNames?: readonly string[],\n  authNamespaceNames?: readonly string[],\n): string {\n  // Generate Attributes interface\n  // attributes values carry a type string representation (e.g., \"string\", \"boolean\", \"string[]\")\n  // and whether the underlying field is optional, so the key mirrors that optionality.\n  const attributeFields = attributes\n    ? Object.entries(attributes)\n        .map(([key, { type, optional }]) => `    ${key}${optional ? \"?\" : \"\"}: ${type};`)\n        .join(\"\\n\")\n    : \"\";\n\n  const attributesBody =\n    !attributes || Object.keys(attributes).length === 0\n      ? \"{}\"\n      : `{\n${attributeFields}\n  }`;\n\n  // Generate AttributeList type as a tuple of strings based on the length\n  const listType = attributeList ? `[${attributeList.map(() => \"string\").join(\", \")}]` : \"[]\";\n\n  // Use interface with __tuple marker for declaration merging and tuple type support\n  const listBody = `{\n    __tuple?: ${listType};\n  }`;\n\n  // Generate Env interface.\n  // Emit the value's type, never the value itself — a literal would leak the\n  // configured value into this generated file.\n  const envFields = env\n    ? Object.entries(env)\n        .map(\n          ([key, value]) =>\n            `    ${isValidIdentifier(key) ? key : JSON.stringify(key)}: ${typeof value};`,\n        )\n        .join(\"\\n\")\n    : \"\";\n\n  const envBody =\n    !env || Object.keys(env).length === 0\n      ? \"{}\"\n      : `{\n${envFields}\n  }`;\n\n  // Generate MachineUserNameRegistry interface.\n  const machineUserFields = machineUserNames?.length\n    ? machineUserNames\n        .map((name) => `    ${isValidIdentifier(name) ? name : JSON.stringify(name)}: true;`)\n        .join(\"\\n\")\n    : \"\";\n\n  const machineUserBody =\n    !machineUserNames || machineUserNames.length === 0\n      ? \"{}\"\n      : `{\n${machineUserFields}\n  }`;\n\n  // Generate IdpNameRegistry interface (same quoting rules as machine users).\n  const idpNameFields = idpNames?.length\n    ? idpNames\n        .map((name) => `    ${isValidIdentifier(name) ? name : JSON.stringify(name)}: true;`)\n        .join(\"\\n\")\n    : \"\";\n\n  const idpNameBody =\n    !idpNames || idpNames.length === 0\n      ? \"{}\"\n      : `{\n${idpNameFields}\n  }`;\n\n  // Generate ConnectionNameRegistry interface (same quoting rules as machine users).\n  const connectionNameFields = connectionNames?.length\n    ? connectionNames\n        .map((name) => `    ${isValidIdentifier(name) ? name : JSON.stringify(name)}: true;`)\n        .join(\"\\n\")\n    : \"\";\n\n  const connectionNameBody =\n    !connectionNames || connectionNames.length === 0\n      ? \"{}\"\n      : `{\n${connectionNameFields}\n  }`;\n\n  // Generate AIGatewayNameRegistry interface (same quoting rules as machine users).\n  const aiGatewayNameFields = aiGatewayNames?.length\n    ? aiGatewayNames\n        .map((name) => `    ${isValidIdentifier(name) ? name : JSON.stringify(name)}: true;`)\n        .join(\"\\n\")\n    : \"\";\n\n  const aiGatewayNameBody =\n    !aiGatewayNames || aiGatewayNames.length === 0\n      ? \"{}\"\n      : `{\n${aiGatewayNameFields}\n  }`;\n\n  // Generate AuthNamespaceNameRegistry interface (same quoting rules as machine users).\n  const authNamespaceNameFields = authNamespaceNames?.length\n    ? authNamespaceNames\n        .map((name) => `    ${isValidIdentifier(name) ? name : JSON.stringify(name)}: true;`)\n        .join(\"\\n\")\n    : \"\";\n\n  const authNamespaceNameBody =\n    !authNamespaceNames || authNamespaceNames.length === 0\n      ? \"{}\"\n      : `{\n${authNamespaceNameFields}\n  }`;\n\n  return ml /* ts */ `\n// This file is auto-generated by @tailor-platform/sdk\n// Do not edit this file manually\n// Regenerated automatically when running 'tailor deploy' or 'tailor generate'\n\ndeclare module \"@tailor-platform/sdk\" {\n  interface Attributes ${attributesBody}\n  interface AttributeList ${listBody}\n  interface Env ${envBody}\n  interface MachineUserNameRegistry ${machineUserBody}\n  interface IdpNameRegistry ${idpNameBody}\n  interface ConnectionNameRegistry ${connectionNameBody}\n  interface AIGatewayNameRegistry ${aiGatewayNameBody}\n  interface AuthNamespaceNameRegistry ${authNamespaceNameBody}\n}\n\nexport {};\n\n`;\n}\n\nfunction collectAttributesFromConfig(config: AppConfig): ExtractedAttributes {\n  // De-duplicate IdP names so duplicates in config don't emit duplicate\n  // `IdpNameRegistry` keys (which would be invalid TypeScript).\n  const idpNames = config.idp?.length ? [...new Set(config.idp.map((idp) => idp.name))] : undefined;\n\n  // De-duplicate AI Gateway names for the same reason.\n  const aiGatewayNames = config.aiGateways?.length\n    ? [...new Set(config.aiGateways.map((gateway) => gateway.name))]\n    : undefined;\n\n  const auth = config.auth;\n\n  // An application has exactly one auth namespace: its own `auth`, local or external.\n  const authNamespaceNames =\n    auth && typeof auth === \"object\" && typeof auth.name === \"string\" ? [auth.name] : undefined;\n\n  if (!auth || typeof auth !== \"object\") {\n    return { idpNames, aiGatewayNames, authNamespaceNames };\n  }\n\n  // Extract machine user names from auth.machineUsers (available regardless of userProfile vs. machineUserAttributes)\n  const machineUsersObj = (auth as { machineUsers?: Record<string, unknown> }).machineUsers;\n  const machineUserNames =\n    machineUsersObj && typeof machineUsersObj === \"object\"\n      ? Object.keys(machineUsersObj)\n      : undefined;\n\n  // Extract connection names from auth.connections (available regardless of userProfile vs. machineUserAttributes)\n  const connectionsObj = (auth as { connections?: Record<string, unknown> }).connections;\n  const connectionNames =\n    connectionsObj && typeof connectionsObj === \"object\" ? Object.keys(connectionsObj) : undefined;\n\n  const inferAttributeType = (field?: AttributeFieldLike): AttributeTypeInfo => {\n    const type = field?.type;\n    const metadata = field?.metadata;\n\n    // Default to string if no metadata\n    if (!metadata) {\n      return { type: \"string\" };\n    }\n\n    let typeStr = \"string\";\n\n    if (type === \"boolean\") {\n      typeStr = \"boolean\";\n    } else if (type === \"enum\" && metadata.allowedValues) {\n      // Generate union type from enum values\n      typeStr = metadata.allowedValues.map((v) => `\"${v.value}\"`).join(\" | \");\n    }\n\n    // Add array suffix if needed\n    if (metadata.array) {\n      typeStr = typeStr.includes(\" | \") ? `(${typeStr})[]` : `${typeStr}[]`;\n    }\n\n    return { type: typeStr, optional: metadata.required === false };\n  };\n\n  // Check if auth has userProfile with attributes/attributeList\n  if (\"userProfile\" in auth) {\n    const userProfile = (\n      auth as {\n        userProfile?: {\n          type?: {\n            fields?: Record<string, AttributeFieldLike>;\n          };\n          attributes?: Record<string, true>;\n          attributeList?: AttributeListConfig;\n        };\n      }\n    ).userProfile;\n\n    const selectedAttributes = userProfile?.attributes;\n    const fields = userProfile?.type?.fields;\n    const attributeList = userProfile?.attributeList;\n\n    // Convert attributes to AttributesConfig by inferring types from field metadata\n    const attributes: AttributesConfig | undefined = selectedAttributes\n      ? Object.keys(selectedAttributes).reduce((acc, key) => {\n          acc[key] = inferAttributeType(fields?.[key]);\n          return acc;\n        }, {} as AttributesConfig)\n      : undefined;\n\n    return {\n      attributes,\n      attributeList,\n      machineUserNames,\n      idpNames,\n      connectionNames,\n      aiGatewayNames,\n      authNamespaceNames,\n    };\n  }\n\n  if (\"machineUserAttributes\" in auth) {\n    const machineUserAttributes = (\n      auth as {\n        machineUserAttributes?: Record<string, AttributeFieldLike>;\n      }\n    ).machineUserAttributes;\n\n    if (!machineUserAttributes) {\n      return { machineUserNames, idpNames, connectionNames, aiGatewayNames, authNamespaceNames };\n    }\n\n    const attributes = Object.entries(machineUserAttributes).reduce((acc, [key, field]) => {\n      acc[key] = inferAttributeType(field);\n      return acc;\n    }, {} as AttributesConfig);\n\n    return {\n      attributes,\n      machineUserNames,\n      idpNames,\n      connectionNames,\n      aiGatewayNames,\n      authNamespaceNames,\n    };\n  }\n\n  return { machineUserNames, idpNames, connectionNames, aiGatewayNames, authNamespaceNames };\n}\n\n/**\n * Resolve the output path for the generated type definition file.\n *\n * When the `TAILOR_DTS_PATH` environment variable is set, the value is\n * used as the output path (resolved relative to cwd when relative).\n * Otherwise, the file is written next to the config file as `tailor.d.ts`.\n * @param configPath - Path to Tailor config file\n * @returns Absolute path to the type definition file\n */\nexport function resolveTypeDefinitionPath(configPath: string): string {\n  const envPath = process.env.TAILOR_DTS_PATH;\n  if (envPath) {\n    return path.resolve(envPath);\n  }\n  return path.join(path.dirname(path.resolve(configPath)), \"tailor.d.ts\");\n}\n\n/**\n * Options for generating user type definitions\n */\ninterface GenerateUserTypesOptions {\n  /** Application config with resolved `env` values */\n  config: ResolvedEnvAppConfig;\n  /** Path to Tailor config file */\n  configPath: string;\n}\n\n/**\n * Generate user type definitions from the app config and write them to disk.\n * @param options - Generation options\n * @returns Promise that resolves when types are generated\n */\nexport async function generateUserTypes(options: GenerateUserTypesOptions): Promise<void> {\n  const { config, configPath } = options;\n  try {\n    const {\n      attributes,\n      attributeList,\n      machineUserNames,\n      idpNames,\n      connectionNames,\n      aiGatewayNames,\n      authNamespaceNames,\n    } = extractAttributesFromConfig(config);\n    if (!attributes && !attributeList) {\n      logger.info(\"No attributes found in configuration\", { mode: \"plain\" });\n    }\n\n    if (attributes) {\n      logger.debug(`Extracted Attributes: ${JSON.stringify(attributes)}`);\n    }\n    if (attributeList) {\n      logger.debug(`Extracted AttributeList: ${JSON.stringify(attributeList)}`);\n    }\n    if (machineUserNames?.length) {\n      logger.debug(`Extracted MachineUserNames: ${JSON.stringify(machineUserNames)}`);\n    }\n    if (idpNames?.length) {\n      logger.debug(`Extracted IdpNames: ${JSON.stringify(idpNames)}`);\n    }\n    if (connectionNames?.length) {\n      logger.debug(`Extracted ConnectionNames: ${JSON.stringify(connectionNames)}`);\n    }\n    if (aiGatewayNames?.length) {\n      logger.debug(`Extracted AIGatewayNames: ${JSON.stringify(aiGatewayNames)}`);\n    }\n    if (authNamespaceNames?.length) {\n      logger.debug(`Extracted AuthNamespaceNames: ${JSON.stringify(authNamespaceNames)}`);\n    }\n\n    const env = config.env;\n    if (env) {\n      logger.debug(`Extracted Env: ${JSON.stringify(env)}`);\n    }\n\n    // Generate type definition\n    const typeDefContent = generateTypeDefinition(\n      attributes,\n      attributeList,\n      env,\n      machineUserNames,\n      idpNames,\n      connectionNames,\n      aiGatewayNames,\n      authNamespaceNames,\n    );\n    const outputPath = resolveTypeDefinitionPath(configPath);\n\n    // Write to file\n    fs.mkdirSync(path.dirname(outputPath), { recursive: true });\n    fs.writeFileSync(outputPath, typeDefContent);\n    const relativePath = path.relative(process.cwd(), outputPath);\n    logger.newline();\n    logger.success(`Generated type definitions: ${relativePath}`, {\n      mode: \"plain\",\n    });\n  } catch (error) {\n    logger.error(\"Error generating types\");\n    logger.error(String(error));\n    // Don't throw - this should not block apply/generate\n  }\n}\n","import * as fs from \"node:fs\";\nimport { parseSync } from \"oxc-parser\";\nimport { isCI } from \"std-env\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { parseBoolean } from \"#/cli/shared/parse-boolean\";\nimport { assertDefined } from \"#/utils/assert\";\nimport type { CallExpression, ObjectExpression, ObjectProperty } from \"@oxc-project/types\";\n\nconst SEPARATE_APP_HINT = \"To use this config for a separate app, delete it.\";\n\nexport interface EnsureConfigIdResult {\n  id: string;\n  injected: boolean;\n}\n\n/**\n * Warn when a command that decides resource ownership resolved a config\n * without an app id.\n *\n * Injection only reaches an inline `defineConfig({...})` call, so a config\n * that re-exports one from another file resolves without an id and nothing\n * says so. Ownership then falls back to the application name, and resources\n * tagged with an id from an earlier deploy read as another application's.\n * @param appId - Application id from the resolved config, when it has one\n */\nexport function warnMissingAppId(appId: string | undefined): void {\n  if (appId) return;\n  logger.warn(\"The config resolved without an 'id'.\");\n  logger.log(\n    \"  Resources tagged with an id from an earlier deploy read as another application's:\\n\" +\n      \"  deploy asks before taking them over, and remove leaves them in place. Only resources\\n\" +\n      \"  carrying no id are matched by application name.\\n\" +\n      \"  Add an 'id' to the object passed to defineConfig() — a config that re-exports it from\\n\" +\n      \"  another file cannot have one injected automatically. 'tailor deploy' can add it for you.\",\n  );\n}\n\ntype ASTNode = Record<string, unknown>;\n\n// The user-facing id is a plain UUID. A label-compatible prefix is added\n// at the metadata boundary in `cli/commands/deploy/label.ts`, so the\n// in-config value does not need to satisfy the platform label-value regex.\nexport const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\ninterface ConfigCallSite {\n  callExpr: CallExpression;\n  configObj: ObjectExpression | null;\n}\n\nfunction findDefineConfigCalls(node: unknown, results: ConfigCallSite[]): void {\n  if (!node || typeof node !== \"object\") return;\n  const n = node as ASTNode;\n\n  if (n.type === \"CallExpression\") {\n    const ce = n as unknown as CallExpression;\n    if (ce.callee.type === \"Identifier\" && ce.callee.name === \"defineConfig\") {\n      const arg = ce.arguments[0];\n      // callee may be a ComputedMemberExpression at runtime\n      // oxlint-disable-next-line typescript/no-unnecessary-condition\n      const configObj = arg && arg.type === \"ObjectExpression\" ? arg : null;\n      results.push({ callExpr: ce, configObj });\n    }\n  }\n\n  for (const key of Object.keys(n)) {\n    const child = n[key];\n    if (Array.isArray(child)) {\n      for (const c of child) findDefineConfigCalls(c, results);\n    } else if (child && typeof child === \"object\") {\n      findDefineConfigCalls(child, results);\n    }\n  }\n}\n\nfunction findIdProperties(obj: ObjectExpression): ObjectProperty[] {\n  const found: ObjectProperty[] = [];\n  for (const prop of obj.properties) {\n    if (prop.type !== \"Property\") continue;\n    const keyName =\n      prop.key.type === \"Identifier\"\n        ? prop.key.name\n        : prop.key.type === \"Literal\"\n          ? (prop.key as { value?: unknown }).value\n          : null;\n    if (keyName === \"id\") found.push(prop);\n  }\n  return found;\n}\n\nfunction findIdProperty(obj: ObjectExpression): ObjectProperty | null {\n  return findIdProperties(obj)[0] ?? null;\n}\n\nfunction namesId(node: ASTNode | undefined): boolean {\n  return (\n    (node?.type === \"Identifier\" && node.name === \"id\") ||\n    (node?.type === \"Literal\" && node.value === \"id\")\n  );\n}\n\n// `app.id`, `app[\"id\"]`, and `const { id } = app` all observe a removed property.\nfunction readsIdMember(node: unknown): boolean {\n  if (!node || typeof node !== \"object\") return false;\n  const n = node as ASTNode;\n  if (n.type === \"MemberExpression\" && namesId(n.property as ASTNode | undefined)) return true;\n  if (n.type === \"ObjectPattern\") {\n    const properties = n.properties as ASTNode[];\n    if (properties.some((p) => p.type === \"Property\" && namesId(p.key as ASTNode))) return true;\n  }\n  return Object.values(n).some((child) =>\n    Array.isArray(child) ? child.some(readsIdMember) : readsIdMember(child),\n  );\n}\n\n/**\n * Ensure `tailor.config.ts` has an `id` property on the `defineConfig({...})`\n * argument. Generates a UUID when missing and writes it back to the file.\n * Returns null when the file does not contain a `defineConfig()` call (e.g.\n * a wrapper that re-exports another config).\n * @param configPath - Absolute path to the config file\n * @returns Resolved id and whether it was newly injected, or null if skipped\n */\nexport async function ensureConfigId(configPath: string): Promise<EnsureConfigIdResult | null> {\n  const source = await fs.promises.readFile(configPath, \"utf-8\");\n  const { program } = parseSync(configPath, source);\n\n  const calls: ConfigCallSite[] = [];\n  findDefineConfigCalls(program, calls);\n\n  if (calls.length === 0) {\n    // Wrapper/re-export file: defineConfig is in another file. Nothing to do here.\n    return null;\n  }\n  if (calls.length > 1) {\n    throw CLIError({\n      code: \"CONFIG_ID_UNMANAGEABLE\",\n      message: `Multiple defineConfig() calls found in ${configPath}. Only one is supported.`,\n    });\n  }\n\n  const { configObj } = assertDefined(calls[0], \"defineConfig call site missing\");\n  if (!configObj) {\n    throw CLIError({\n      code: \"CONFIG_ID_UNMANAGEABLE\",\n      message: `defineConfig() argument must be an inline object literal in ${configPath} so the SDK can manage the 'id' field.`,\n    });\n  }\n\n  const idProp = findIdProperty(configObj);\n  if (idProp) {\n    const value = idProp.value;\n    if (value.type !== \"Literal\") {\n      throw CLIError({\n        code: \"CONFIG_ID_INVALID\",\n        message: `'id' field in ${configPath} must be a string literal.`,\n        suggestion: SEPARATE_APP_HINT,\n      });\n    }\n    const literalValue = (value as { value?: unknown }).value;\n    if (typeof literalValue !== \"string\" || literalValue === \"\") {\n      throw CLIError({\n        code: \"CONFIG_ID_INVALID\",\n        message: `'id' field in ${configPath} must be a non-empty string literal.`,\n        suggestion: SEPARATE_APP_HINT,\n      });\n    }\n    if (!uuidRegex.test(literalValue)) {\n      throw CLIError({\n        code: \"CONFIG_ID_INVALID\",\n        message: `'id' field in ${configPath} must be a UUID.`,\n        suggestion: SEPARATE_APP_HINT,\n      });\n    }\n    return { id: literalValue, injected: false };\n  }\n\n  const id = crypto.randomUUID();\n  const newSource = insertIdProperty(source, configObj, id);\n  await fs.promises.writeFile(configPath, newSource, \"utf-8\");\n\n  logger.info(`Generated app id and wrote to ${configPath}: ${id}`);\n\n  return { id, injected: true };\n}\n\n/**\n * Read the resolved `defineConfig({...})` `id` from a config file without\n * mutating it. Returns null when the file has no inline `defineConfig()` call\n * (wrapper/re-export config), and `{ id: null }` when the call exists but has\n * no usable `id` property.\n * @param configPath - Absolute path to the config file\n * @returns The existing id (or null when absent), or null for wrapper configs\n */\nasync function readConfigId(configPath: string): Promise<{ id: string | null } | null> {\n  const source = await fs.promises.readFile(configPath, \"utf-8\");\n  const { program } = parseSync(configPath, source);\n  const calls: ConfigCallSite[] = [];\n  findDefineConfigCalls(program, calls);\n  if (calls.length === 0) return null;\n  // Mirror ensureConfigId's shape validation so CI fails loudly on config\n  // shapes whose id it cannot reliably read.\n  if (calls.length > 1) {\n    throw CLIError({\n      code: \"CONFIG_ID_UNMANAGEABLE\",\n      message: `Multiple defineConfig() calls found in ${configPath}. Only one is supported.`,\n    });\n  }\n  const { configObj } = assertDefined(calls[0], \"defineConfig call site missing\");\n  if (!configObj) {\n    throw CLIError({\n      code: \"CONFIG_ID_UNMANAGEABLE\",\n      message: `defineConfig() argument must be an inline object literal in ${configPath} so the SDK can manage the 'id' field.`,\n    });\n  }\n  const idProp = findIdProperty(configObj);\n  if (!idProp || idProp.value.type !== \"Literal\") return { id: null };\n  const value = (idProp.value as { value?: unknown }).value;\n  return { id: typeof value === \"string\" && value !== \"\" ? value : null };\n}\n\n/**\n * Read-only CI check: the config must already carry a valid app id.\n * Wrapper/re-export configs (no inline defineConfig call) are exempt,\n * mirroring the local behavior where {@link ensureConfigId} no-ops.\n * @param configPath - Absolute path to the config file\n */\nasync function assertConfigIdInCI(configPath: string): Promise<void> {\n  const result = await readConfigId(configPath);\n  if (result === null) {\n    return;\n  }\n  if (!result.id) {\n    throw CLIError({\n      code: \"CONFIG_ID_REQUIRED_IN_CI\",\n      message: \"tailor.config.ts is missing an 'id'.\",\n      details:\n        \"CI does not auto-generate one (each run would be treated as a separate app and break resource ownership).\",\n      suggestion: \"Run 'tailor deploy' locally and commit the injected id.\",\n    });\n  }\n  // Keep CI and local behavior aligned: ensureConfigId() enforces the same\n  // format when injecting locally.\n  if (!uuidRegex.test(result.id)) {\n    throw CLIError({\n      code: \"CONFIG_ID_INVALID\",\n      message: `'id' in ${configPath} must be a UUID.`,\n      suggestion: SEPARATE_APP_HINT,\n    });\n  }\n}\n\n/**\n * Ensure the config has an app id for a deploy run.\n *\n * Locally, the id is auto-injected when missing (via {@link ensureConfigId}).\n * In CI, the id is never auto-injected — a missing id is a hard error, because\n * generating one per run would create a fresh app each time and break resource\n * ownership. CI dry-runs (plan) perform the same check read-only, so a\n * forgotten id fails at PR time instead of at deploy. Ephemeral pipelines that\n * intentionally deploy a fresh app per run (such as e2e harnesses) can opt\n * back into injection with `TAILOR_CI_ALLOW_ID_INJECTION=true`.\n * Local dry-run and build-only flows skip both injection and the check (no\n * on-disk side effects are expected, and build-only never talks to the\n * platform).\n * @param obj - Inputs\n * @param obj.configPath - Absolute path to the config file\n * @param obj.dryRun - Whether this is a dry-run\n * @param obj.buildOnly - Whether this is a build-only run\n */\nexport async function ensureConfigIdForDeploy(obj: {\n  configPath: string;\n  dryRun: boolean;\n  buildOnly: boolean;\n}): Promise<void> {\n  const { configPath, dryRun, buildOnly } = obj;\n  if (buildOnly) return;\n\n  const allowCIInjection = parseBoolean(process.env.TAILOR_CI_ALLOW_ID_INJECTION) === true;\n  const strictCI = isCI && !allowCIInjection;\n\n  if (dryRun) {\n    if (strictCI) {\n      await assertConfigIdInCI(configPath);\n    }\n    return;\n  }\n\n  if (strictCI) {\n    await assertConfigIdInCI(configPath);\n    return;\n  }\n\n  await ensureConfigId(configPath);\n}\n\nconst idComment =\n  \"// SDK-managed app id — do not edit, except when copying this config to a separate app.\";\n\nfunction insertIdProperty(source: string, configObj: ObjectExpression, id: string): string {\n  const idLiteral = `id: ${JSON.stringify(id)}`;\n  if (configObj.properties.length > 0) {\n    const firstProp = assertDefined(configObj.properties[0], \"first property missing\");\n    const lineStart = source.lastIndexOf(\"\\n\", firstProp.start - 1) + 1;\n    const indent = source.slice(lineStart, firstProp.start);\n    if (!/^[\\t ]*$/.test(indent)) {\n      // The first property shares its line with other code (single-line\n      // object literal): insert inline, where a `//` comment would swallow\n      // the rest of the line and reusing the prefix as indent would\n      // duplicate it.\n      return source.slice(0, firstProp.start) + `${idLiteral}, ` + source.slice(firstProp.start);\n    }\n    const insertion = `${idComment}\\n${indent}${idLiteral},\\n${indent}`;\n    return source.slice(0, firstProp.start) + insertion + source.slice(firstProp.start);\n  }\n  // Empty object: insert on its own lines so the `//` comment does not\n  // bleed into the closing `}` / `)`. Derive indent from the line that\n  // contains the opening brace.\n  const openBracePos = configObj.start + 1;\n  const braceLineStart = source.lastIndexOf(\"\\n\", configObj.start) + 1;\n  const baseIndent = source.slice(braceLineStart).match(/^[\\t ]*/)?.[0] ?? \"\";\n  const innerIndent = `${baseIndent}  `;\n  const insertion = `\\n${innerIndent}${idComment}\\n${innerIndent}${idLiteral},\\n${baseIndent}`;\n  return source.slice(0, openBracePos) + insertion + source.slice(openBracePos);\n}\n\nfunction removeIdProperty(\n  source: string,\n  configObj: ObjectExpression,\n  prop: ObjectProperty,\n): string {\n  const edited = removeIdPropertyText(source, prop);\n  if (configObj.properties.length > 1) return edited;\n  // The object became empty: collapse it unless it still holds a user comment.\n  const objectEnd = configObj.end - (source.length - edited.length);\n  const inner = edited.slice(configObj.start + 1, objectEnd - 1);\n  return inner.trim() === \"\"\n    ? `${edited.slice(0, configObj.start + 1)}${edited.slice(objectEnd - 1)}`\n    : edited;\n}\n\nfunction removeIdPropertyText(source: string, prop: ObjectProperty): string {\n  let end = prop.end;\n  const trailingComma = /^[\\t ]*,/.exec(source.slice(end));\n  if (trailingComma) end += trailingComma[0].length;\n\n  const lineStart = source.lastIndexOf(\"\\n\", prop.start - 1) + 1;\n  const newlineAfter = source.indexOf(\"\\n\", end);\n  const lineEnd = newlineAfter === -1 ? source.length : newlineAfter + 1;\n  const ownLine =\n    /^[\\t ]*$/.test(source.slice(lineStart, prop.start)) &&\n    /^[\\t \\r]*$/.test(source.slice(end, lineEnd).replace(/\\n$/, \"\"));\n  if (ownLine) {\n    let removeStart = lineStart;\n    if (lineStart > 1) {\n      const prevLineStart = source.lastIndexOf(\"\\n\", lineStart - 2) + 1;\n      if (source.slice(prevLineStart, lineStart).trim() === idComment) removeStart = prevLineStart;\n    }\n    return source.slice(0, removeStart) + source.slice(lineEnd);\n  }\n  if (trailingComma) {\n    const spacing = /^[\\t ]*/.exec(source.slice(end))?.[0].length ?? 0;\n    return source.slice(0, prop.start) + source.slice(end + spacing);\n  }\n  // Last property of a single-line object: the separator to drop is the one before it.\n  const before = source.slice(0, prop.start);\n  const separator = /,?[\\t ]*$/.exec(before)?.[0].length ?? 0;\n  return before.slice(0, before.length - separator) + source.slice(end);\n}\n\n/**\n * Remove the `id` property from the inline `defineConfig({...})` argument once\n * the id is recorded elsewhere (the inverse of {@link ensureConfigId}). The\n * injected `// SDK-managed app id` comment goes with it.\n *\n * Only edits a shape it can read back unambiguously: exactly one inline\n * `defineConfig({...})` call whose single `id` property is a string literal\n * equal to `expectedId` (UUIDs compare case-insensitively), no `.id` read\n * anywhere in the module that could observe the removal, and an edited source\n * that still parses. Returns false without touching the file otherwise, so the\n * caller can ask for a manual edit.\n * @param configPath - Absolute path to the config file\n * @param expectedId - The id the property must hold to be removed\n * @returns Whether the file was edited\n */\nexport async function removeConfigId(configPath: string, expectedId: string): Promise<boolean> {\n  const source = await fs.promises.readFile(configPath, \"utf-8\");\n  const { program } = parseSync(configPath, source);\n  const calls: ConfigCallSite[] = [];\n  findDefineConfigCalls(program, calls);\n  const configObj = calls.length === 1 ? calls[0]?.configObj : null;\n  if (!configObj || readsIdMember(program)) return false;\n\n  const idProps = findIdProperties(configObj);\n  const idProp = idProps.length === 1 ? idProps[0] : undefined;\n  if (!idProp || idProp.value.type !== \"Literal\") return false;\n  const value = (idProp.value as { value?: unknown }).value;\n  if (typeof value !== \"string\" || value.toLowerCase() !== expectedId.toLowerCase()) return false;\n\n  const edited = removeIdProperty(source, configObj, idProp);\n  if (parseSync(configPath, edited).errors.length > 0) return false;\n  await fs.promises.writeFile(configPath, edited, \"utf-8\");\n  return true;\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"pathe\";\nimport { isCI } from \"std-env\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { parseBoolean } from \"#/cli/shared/parse-boolean\";\nimport { canPrompt, prompt } from \"#/cli/shared/prompt\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { removeConfigId, uuidRegex } from \"./config-id-injector\";\n\n/** Lock file path, relative to the repository root. Created by `tailor setup`. */\nexport const TAILOR_LOCK_FILENAME = \".github/tailor.lock\";\n\n/**\n * Current lock schema version. Version 2 added `appIds`; a lock carrying it\n * must not be rewritten by a tool that would drop the section.\n */\nexport const TAILOR_LOCK_VERSION = 2;\n\nconst restoreHint =\n  \"The lock file is machine-owned; restore it from git \" +\n  `(git checkout -- ${TAILOR_LOCK_FILENAME}) and re-run setup.`;\n\n/** App ids recorded in the lock, keyed by repository-relative config path. */\nexport type AppIds = Readonly<Record<string, string>>;\n\n/** The `appIds` section of a repository's lock file. */\nexport type AppIdLock = {\n  /** Repository root: the directory that holds `.github/tailor.lock`. */\n  root: string;\n  appIds: AppIds;\n};\n\ntype RawLock = { version: number; appIds?: unknown } & Record<string, unknown>;\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n  return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isRepositoryRelativeKey(key: string): boolean {\n  if (key === \"\" || path.isAbsolute(key) || key.includes(\"\\\\\")) return false;\n  return key.split(\"/\").every((segment) => segment !== \"\" && segment !== \".\" && segment !== \"..\");\n}\n\nfunction assertSafeLockPath(root: string): void {\n  for (const relativePath of [\".github\", TAILOR_LOCK_FILENAME]) {\n    try {\n      if (fs.lstatSync(path.join(root, relativePath)).isSymbolicLink()) {\n        throw CLIError({\n          code: \"APP_ID_LOCK_INVALID\",\n          message: `Refusing to use ${TAILOR_LOCK_FILENAME}: \"${relativePath}\" is a symbolic link.`,\n        });\n      }\n    } catch (error) {\n      if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") continue;\n      throw error;\n    }\n  }\n}\n\n/**\n * Validate the `appIds` section of a lock file.\n *\n * Every key must be a repository-relative config path and every value a UUID.\n * Two configs must not share one id: that is the copied-config accident the\n * lock exists to prevent, so it is rejected instead of deployed.\n * @param value - The raw `appIds` value, or undefined when the lock has none\n * @returns The validated section (empty when absent)\n */\nexport function parseAppIds(value: unknown): AppIds {\n  if (value === undefined) return {};\n  if (!isPlainObject(value)) {\n    throw CLIError({\n      code: \"APP_ID_LOCK_INVALID\",\n      message: `${TAILOR_LOCK_FILENAME} has an invalid 'appIds' section: expected an object mapping config paths to app ids.`,\n      suggestion: restoreHint,\n    });\n  }\n  const owners = new Map<string, string>();\n  for (const [key, id] of Object.entries(value)) {\n    if (!isRepositoryRelativeKey(key)) {\n      throw CLIError({\n        code: \"APP_ID_LOCK_INVALID\",\n        message: `${TAILOR_LOCK_FILENAME} 'appIds' key \"${key}\" must be a repository-relative config path (no absolute paths, \"..\", or backslashes).`,\n        suggestion: restoreHint,\n      });\n    }\n    if (typeof id !== \"string\" || !uuidRegex.test(id)) {\n      throw CLIError({\n        code: \"APP_ID_LOCK_INVALID\",\n        message: `${TAILOR_LOCK_FILENAME} 'appIds' entry for \"${key}\" must be a UUID.`,\n        suggestion: restoreHint,\n      });\n    }\n    const owner = owners.get(id.toLowerCase());\n    if (owner !== undefined) {\n      throw CLIError({\n        code: \"APP_ID_CONFLICT\",\n        message: `${TAILOR_LOCK_FILENAME} records the same app id \"${id}\" for \"${owner}\" and \"${key}\".`,\n        suggestion:\n          \"Each config needs its own app id: delete the entry of the copied config so the next local deploy assigns a fresh one.\",\n      });\n    }\n    owners.set(id.toLowerCase(), key);\n  }\n  return value as AppIds;\n}\n\nfunction readRawLock(root: string): RawLock | null {\n  assertSafeLockPath(root);\n  const file = path.join(root, TAILOR_LOCK_FILENAME);\n  if (!fs.existsSync(file)) return null;\n  let text: string;\n  try {\n    text = fs.readFileSync(file, \"utf-8\");\n  } catch (cause) {\n    throw CLIError({\n      code: \"APP_ID_LOCK_UNREADABLE\",\n      message: `${TAILOR_LOCK_FILENAME} under ${root} could not be read.`,\n      cause,\n    });\n  }\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(text);\n  } catch (cause) {\n    throw CLIError({\n      code: \"APP_ID_LOCK_INVALID\",\n      message: `${TAILOR_LOCK_FILENAME} is not valid JSON.`,\n      suggestion: restoreHint,\n      cause,\n    });\n  }\n  if (!isPlainObject(parsed) || typeof parsed.version !== \"number\") {\n    throw CLIError({\n      code: \"APP_ID_LOCK_INVALID\",\n      message: `${TAILOR_LOCK_FILENAME} has no valid 'version' field.`,\n      suggestion: restoreHint,\n    });\n  }\n  if (parsed.version > TAILOR_LOCK_VERSION) {\n    throw CLIError({\n      code: \"APP_ID_LOCK_VERSION_UNSUPPORTED\",\n      message: `${TAILOR_LOCK_FILENAME} was written by a newer SDK (lock version ${String(parsed.version)}).`,\n      suggestion: \"Update @tailor-platform/sdk and @tailor-platform/sdk-plugin-setup to continue.\",\n    });\n  }\n  return parsed as RawLock;\n}\n\n/**\n * Read the `appIds` section of the lock file under a repository root.\n * @param root - Directory that holds `.github/tailor.lock`\n * @returns The lock, or null when the repository has none\n */\nexport function readAppIdLock(root: string): AppIdLock | null {\n  const raw = readRawLock(root);\n  if (raw === null) return null;\n  return { root, appIds: parseAppIds(raw.appIds) };\n}\n\n/**\n * Locate the lock file that governs a config: the nearest `.github/tailor.lock`\n * in the config's directory or one of its ancestors, without leaving the\n * repository the config belongs to. That is the root setup records against\n * when it runs from that directory.\n * @param configPath - Absolute path to the config file\n * @returns The lock, or null when no ancestor directory inside the repository has one\n */\nexport function findAppIdLock(configPath: string): AppIdLock | null {\n  let dir = path.dirname(configPath);\n  for (;;) {\n    if (fs.existsSync(path.join(dir, TAILOR_LOCK_FILENAME))) return readAppIdLock(dir);\n    const parent = path.dirname(dir);\n    if (parent === dir || fs.existsSync(path.join(dir, \".git\"))) return null;\n    dir = parent;\n  }\n}\n\n/**\n * The `appIds` key of a config: its path relative to the repository root, with\n * `/` separators.\n * @param root - Directory that holds `.github/tailor.lock`\n * @param configPath - Absolute path to the config file\n * @returns The lock key\n */\nexport function appIdLockKey(root: string, configPath: string): string {\n  const key = path.relative(root, configPath);\n  if (!isRepositoryRelativeKey(key)) {\n    throw CLIError({\n      code: \"CONFIG_OUTSIDE_REPOSITORY\",\n      message: `${configPath} is outside the repository that holds ${TAILOR_LOCK_FILENAME} (${root}).`,\n    });\n  }\n  return key;\n}\n\n/**\n * How a command may treat a config whose id is not yet recorded.\n *\n * - `write`: local runs that may record, adopt, or generate ids\n * - `read`: local read-only runs; a missing id is a warning\n * - `require`: CI; a missing id is an error, since a fresh id per run would\n *   make every run a separate application\n */\nexport type AppIdPlanMode = \"write\" | \"read\" | \"require\";\n\n/** One config to resolve: its path and the id its module evaluates to. */\nexport type AppIdEntryInput = {\n  configPath: string;\n  configId: string | undefined;\n};\n\n/** The resolved id of one config and where it came from. */\nexport type AppIdEntry = {\n  configPath: string;\n  key: string;\n  id: string | undefined;\n  source: \"lock\" | \"config\" | \"generated\" | \"none\";\n  /** The config still carries the id; remove it once the lock is written. */\n  removeConfigId: boolean;\n};\n\n/** The `appIds` section after resolving a batch of configs. */\nexport type AppIdPlan = {\n  appIds: Record<string, string>;\n  /** Whether `appIds` differs from the lock it was planned against. */\n  changed: boolean;\n  /** One entry per input, in input order. */\n  entries: AppIdEntry[];\n};\n\nexport type PlanAppIdsParams = {\n  lock: AppIdLock;\n  entries: readonly AppIdEntryInput[];\n  mode: AppIdPlanMode;\n};\n\nfunction warnConfigStillCarriesId(key: string): void {\n  logger.warn(\n    `${key} still carries an 'id' that is also recorded in ${TAILOR_LOCK_FILENAME}. ` +\n      \"Remove it from the config, or run 'tailor deploy' locally to move it; \" +\n      \"the lock is where the id lives now.\",\n  );\n}\n\nfunction warnUnrecordedConfigId(key: string): void {\n  logger.warn(\n    `The app id of ${key} is read from the config and not yet recorded in ${TAILOR_LOCK_FILENAME}. ` +\n      `Run 'tailor deploy' locally and commit ${TAILOR_LOCK_FILENAME}.`,\n  );\n}\n\nfunction warnMissingLockedAppId(key: string): void {\n  logger.warn(`No app id is recorded for ${key} in ${TAILOR_LOCK_FILENAME}.`);\n  logger.log(\n    \"  Resources tagged with an id from an earlier deploy read as another application's:\\n\" +\n      \"  deploy asks before taking them over, and remove leaves them in place. Only resources\\n\" +\n      \"  carrying no id are matched by application name. 'tailor deploy' records an id for you.\",\n  );\n}\n\nfunction rekeyInstructions(orphans: readonly string[]): string {\n  return (\n    `${TAILOR_LOCK_FILENAME} has entries whose config no longer exists: ${orphans.join(\", \")}. ` +\n    \"If an app directory was moved, re-key its entry to the new path under 'appIds' so the \" +\n    \"app keeps its id; delete the entries of removed apps.\"\n  );\n}\n\nfunction missingInCIError(keys: readonly string[], orphans: readonly string[]): Error {\n  let suggestion = `Run 'tailor deploy' locally and commit ${TAILOR_LOCK_FILENAME}.`;\n  if (orphans.length > 0) suggestion += ` ${rekeyInstructions(orphans)}`;\n  return CLIError({\n    code: \"CONFIG_ID_REQUIRED_IN_CI\",\n    message: `No app id is recorded for ${keys.join(\", \")} in ${TAILOR_LOCK_FILENAME}, and the config has no 'id'.`,\n    details:\n      \"CI does not generate one (each run would be treated as a separate app and break resource ownership).\",\n    suggestion,\n  });\n}\n\nasync function confirmMove(from: string, to: string): Promise<boolean> {\n  if (!canPrompt()) {\n    throw CLIError({\n      code: \"APP_ID_NOT_RECORDED\",\n      message: `No app id is recorded for ${to}.`,\n      suggestion: rekeyInstructions([from]),\n    });\n  }\n  logger.warn(\n    `${TAILOR_LOCK_FILENAME} records an app id for ${from}, which no longer exists, ` +\n      `and ${to} has none.`,\n  );\n  return prompt.confirm({\n    message: `Was ${from} moved to ${to}? Yes keeps its app id; no assigns a fresh one.`,\n    default: false,\n  });\n}\n\n/**\n * Decide the app id of every config in a batch against one lock file.\n *\n * Precedence per config: the lock entry, then the id the config evaluates to,\n * then a generated id. A config whose id disagrees with its lock entry is an\n * error, since neither value can be chosen mechanically. Reads nothing but the\n * lock passed in and the existence of the files its entries name; the caller\n * persists the returned `appIds`.\n * @param params - The lock, the configs to resolve, and the mode\n * @returns The resolved entries and the `appIds` section to persist\n */\nexport async function planAppIds(params: PlanAppIdsParams): Promise<AppIdPlan> {\n  const { lock, entries, mode } = params;\n  const appIds: Record<string, string> = { ...lock.appIds };\n  let changed = false;\n  const planned: Array<AppIdEntry | undefined> = entries.map(() => undefined);\n  const unresolved: Array<{ index: number; configPath: string; key: string }> = [];\n  // Every id in play, recorded or provisional, so two configs can never leave\n  // this plan sharing one even when nothing is persisted.\n  const claimed = new Map<string, string>(\n    Object.entries(appIds).map(([key, id]) => [id.toLowerCase(), key]),\n  );\n  const exists = (key: string): boolean => fs.existsSync(path.join(lock.root, key));\n\n  entries.forEach(({ configPath, configId }, index) => {\n    const key = appIdLockKey(lock.root, configPath);\n    const recorded = appIds[key];\n    if (recorded !== undefined) {\n      if (configId !== undefined && configId.toLowerCase() !== recorded.toLowerCase()) {\n        throw CLIError({\n          code: \"APP_ID_CONFLICT\",\n          message: `${TAILOR_LOCK_FILENAME} records app id \"${recorded}\" for ${key}, but the config's 'id' is \"${configId}\".`,\n          suggestion:\n            \"Neither can be chosen automatically: remove the 'id' from the config to keep the recorded id, or replace the recorded value with the config's id.\",\n        });\n      }\n      const removeConfigId = configId !== undefined && mode === \"write\";\n      if (configId !== undefined && !removeConfigId) warnConfigStillCarriesId(key);\n      planned[index] = { configPath, key, id: recorded, source: \"lock\", removeConfigId };\n      return;\n    }\n    if (configId !== undefined) {\n      if (!uuidRegex.test(configId)) {\n        throw CLIError({\n          code: \"CONFIG_ID_INVALID\",\n          message: `'id' in ${configPath} must be a UUID.`,\n          suggestion: \"To use this config for a separate app, delete it.\",\n        });\n      }\n      const owner = claimed.get(configId.toLowerCase());\n      const movedFrom = owner !== undefined && owner !== key && !exists(owner) ? owner : undefined;\n      if (owner !== undefined && owner !== key && movedFrom === undefined) {\n        throw CLIError({\n          code: \"APP_ID_CONFLICT\",\n          message: `${configPath} carries the app id already recorded for ${owner} in ${TAILOR_LOCK_FILENAME}.`,\n          suggestion:\n            \"If this config was copied from that app, delete its 'id' so it gets a fresh one.\",\n        });\n      }\n      claimed.set(configId.toLowerCase(), key);\n      const removeConfigId = mode === \"write\";\n      if (removeConfigId) {\n        if (movedFrom !== undefined) {\n          delete appIds[movedFrom];\n          logger.info(`Keeping the app id of ${movedFrom} for ${key}: ${configId}`);\n        }\n        appIds[key] = configId;\n        changed = true;\n      } else {\n        warnUnrecordedConfigId(key);\n      }\n      planned[index] = { configPath, key, id: configId, source: \"config\", removeConfigId };\n      return;\n    }\n    unresolved.push({ index, configPath, key });\n  });\n\n  const finish = (): AppIdPlan => ({\n    appIds,\n    changed,\n    entries: planned.map((entry) => assertDefined(entry, \"app id entry missing\")),\n  });\n  if (unresolved.length === 0) return finish();\n  if (mode === \"read\") {\n    for (const { index, configPath, key } of unresolved) {\n      warnMissingLockedAppId(key);\n      planned[index] = { configPath, key, id: undefined, source: \"none\", removeConfigId: false };\n    }\n    return finish();\n  }\n\n  const orphans = Object.keys(appIds).filter((key) => !exists(key));\n  const keys = [...new Set(unresolved.map(({ key }) => key))];\n  if (mode === \"require\") throw missingInCIError(keys, orphans);\n\n  let moved: { from: string; key: string } | undefined;\n  if (orphans.length === 1 && keys.length === 1) {\n    const from = assertDefined(orphans[0], \"orphan missing\");\n    const key = assertDefined(keys[0], \"key missing\");\n    if (await confirmMove(from, key)) moved = { from, key };\n  } else if (orphans.length > 0) {\n    throw CLIError({\n      code: \"APP_ID_NOT_RECORDED\",\n      message: `No app id is recorded for ${keys.join(\", \")}.`,\n      suggestion: rekeyInstructions(orphans),\n    });\n  }\n\n  for (const { index, configPath, key } of unresolved) {\n    const alreadyPlanned = appIds[key];\n    if (alreadyPlanned !== undefined) {\n      planned[index] = {\n        configPath,\n        key,\n        id: alreadyPlanned,\n        source: \"generated\",\n        removeConfigId: false,\n      };\n      continue;\n    }\n    let id: string;\n    if (moved?.key === key) {\n      id = assertDefined(appIds[moved.from], \"orphaned app id missing\");\n      delete appIds[moved.from];\n      logger.info(`Keeping the app id of ${moved.from} for ${key}: ${id}`);\n    } else {\n      id = crypto.randomUUID();\n      logger.info(`Generated app id for ${key}: ${id}`);\n    }\n    appIds[key] = id;\n    changed = true;\n    const source = moved?.key === key ? \"lock\" : \"generated\";\n    planned[index] = { configPath, key, id, source, removeConfigId: false };\n  }\n  return finish();\n}\n\nexport type WriteAppIdsParams = {\n  lock: AppIdLock;\n  appIds: AppIds;\n};\n\n/**\n * Write a planned `appIds` section into an existing lock file, leaving every\n * other field as it is. Only the entries the plan changed relative to the lock\n * it was planned against are applied, so a deploy of another app that wrote\n * the file in the meantime keeps its entry. Only `tailor setup` creates the\n * lock, so a missing file is an error rather than a reason to create one.\n * @param params - The lock the plan was made against and the planned section\n */\nexport function writeAppIds(params: WriteAppIdsParams): void {\n  const { lock, appIds } = params;\n  const raw = readRawLock(lock.root);\n  if (raw === null) {\n    throw CLIError({\n      code: \"APP_ID_LOCK_NOT_FOUND\",\n      message: `${TAILOR_LOCK_FILENAME} does not exist under ${lock.root}.`,\n      suggestion: \"Create it with 'tailor setup'.\",\n    });\n  }\n  const merged: Record<string, string> = { ...parseAppIds(raw.appIds) };\n  for (const key of Object.keys(lock.appIds)) {\n    if (!(key in appIds)) delete merged[key];\n  }\n  for (const [key, id] of Object.entries(appIds)) {\n    if (lock.appIds[key] !== id) merged[key] = id;\n  }\n  const next = { ...raw, version: TAILOR_LOCK_VERSION, appIds: merged };\n  fs.writeFileSync(\n    path.join(lock.root, TAILOR_LOCK_FILENAME),\n    `${JSON.stringify(next, null, 2)}\\n`,\n    \"utf-8\",\n  );\n}\n\n/** Result of {@link removeAdoptedConfigIds}. */\nexport type RemoveAdoptedConfigIdsResult = {\n  /** Whether at least one config file was edited. */\n  configEdited: boolean;\n};\n\n/**\n * Remove the `id` from every config whose id the plan moved into the lock.\n * Call it after the lock has been written, so the id is never held nowhere.\n * A config shape that cannot be edited is reported with a manual-edit hint.\n * @param plan - A plan produced in `write` mode\n * @returns Whether any config was edited\n */\nexport async function removeAdoptedConfigIds(\n  plan: AppIdPlan,\n): Promise<RemoveAdoptedConfigIdsResult> {\n  let configEdited = false;\n  const edited = new Set<string>();\n  for (const entry of plan.entries) {\n    if (!entry.removeConfigId || entry.id === undefined || edited.has(entry.configPath)) continue;\n    edited.add(entry.configPath);\n    if (await removeConfigId(entry.configPath, entry.id)) {\n      configEdited = true;\n      logger.info(`Moved the app id of ${entry.key} from the config into ${TAILOR_LOCK_FILENAME}.`);\n    } else {\n      logger.warn(\n        `The app id of ${entry.key} is recorded in ${TAILOR_LOCK_FILENAME}. Remove the 'id' from ` +\n          \"the object passed to defineConfig() by hand; the SDK could not edit \" +\n          `${entry.configPath} to do it.`,\n      );\n    }\n  }\n  return { configEdited };\n}\n\n/**\n * Resolve the app ids of a batch of configs against their lock, and in `write`\n * mode persist the outcome: the lock first, then the config edits.\n * @param params - The lock, the configs to resolve, and the mode\n * @returns The plan, whose entries carry the id of every config in input order\n */\nexport async function resolveLockedAppIds(params: PlanAppIdsParams): Promise<AppIdPlan> {\n  const plan = await planAppIds(params);\n  if (params.mode === \"write\") {\n    if (plan.changed) writeAppIds({ lock: params.lock, appIds: plan.appIds });\n    await removeAdoptedConfigIds(plan);\n  }\n  return plan;\n}\n\n/**\n * The plan mode for a deploy run: CI requires a recorded id unless\n * `TAILOR_CI_ALLOW_ID_INJECTION=true` opts into local behavior; local runs\n * write on a real deploy and only read on a dry-run.\n * @param dryRun - Whether this is a dry-run\n * @returns The mode to plan with\n */\nexport function appIdPlanModeForDeploy(dryRun: boolean): AppIdPlanMode {\n  const allowCIInjection = parseBoolean(process.env.TAILOR_CI_ALLOW_ID_INJECTION) === true;\n  if (isCI && !allowCIInjection) return \"require\";\n  return dryRun ? \"read\" : \"write\";\n}\n","import * as fs from \"node:fs\";\nimport { findUpSync } from \"find-up-simple\";\nimport * as path from \"pathe\";\nimport { hashFile } from \"#/cli/cache/hasher\";\nimport { createCacheManager } from \"#/cli/cache/manager\";\nimport { loadApplication, type Application } from \"#/cli/services/application\";\nimport { loadConfig } from \"#/cli/shared/config-loader\";\nimport { loadConfigPath } from \"#/cli/shared/context\";\nimport { CLIError, internalError } from \"#/cli/shared/errors\";\nimport { generateUserTypes } from \"#/cli/shared/type-generator\";\nimport { withSpan } from \"#/cli/telemetry/index\";\nimport { PluginManager } from \"#/plugin/manager\";\nimport { assertDefined } from \"#/utils/assert\";\nimport {\n  type AppIdLock,\n  appIdPlanModeForDeploy,\n  findAppIdLock,\n  resolveLockedAppIds,\n} from \"./app-id-lock\";\nimport { ensureConfigIdForDeploy, warnMissingAppId } from \"./config-id-injector\";\n\ntype LoadedDeployConfig = Awaited<ReturnType<typeof loadConfig>>;\n\ntype LoadDeployConfigParams = {\n  configPath: string | undefined;\n  dryRun: boolean;\n  buildOnly: boolean;\n};\n\ntype LoadDeployConfigsParams = Omit<LoadDeployConfigParams, \"configPath\"> & {\n  configPaths: ReadonlyArray<string | undefined>;\n};\n\ntype BuildDeploymentTargetParams = {\n  configPath: string | undefined;\n  loadedConfig?: LoadedDeployConfig;\n  dryRun: boolean;\n  buildOnly: boolean;\n  noCache: boolean;\n  packageVersion: string;\n  cacheDir: string;\n};\n\nexport type BuiltDeploymentTarget = {\n  config: Awaited<ReturnType<typeof loadConfig>>[\"config\"];\n  application: Application;\n  workflowBuildResult: Awaited<ReturnType<typeof loadApplication>>[\"workflowBuildResult\"];\n  httpAdapterBuildResult: Awaited<ReturnType<typeof loadApplication>>[\"httpAdapterBuildResult\"];\n  bundledScripts: Awaited<ReturnType<typeof loadApplication>>[\"bundledScripts\"];\n};\n\ntype BuildDeploymentTargetsParams = Omit<\n  BuildDeploymentTargetParams,\n  \"configPath\" | \"loadedConfig\"\n> & {\n  configPaths: ReadonlyArray<string | undefined>;\n  loadedConfigs?: ReadonlyArray<LoadedDeployConfig>;\n  buildTarget?: (params: BuildDeploymentTargetParams) => Promise<BuiltDeploymentTarget>;\n};\n/**\n * Parse the deploy config option into one or more config paths.\n * @param configPath - Raw `--config` option value\n * @returns Config paths, or one undefined entry to preserve default config lookup\n */\nexport function parseDeployConfigPaths(configPath?: string): Array<string | undefined> {\n  const rawConfigPath = configPath ?? process.env.TAILOR_PLATFORM_SDK_CONFIG_PATH;\n  if (rawConfigPath === undefined) {\n    return [undefined];\n  }\n\n  const configPaths = rawConfigPath.split(\",\").map((entry) => entry.trim());\n  if (configPaths.some((entry) => entry.length === 0)) {\n    throw CLIError({\n      code: \"DEPLOY_CONFIG_REQUIRED\",\n      message: \"--config must contain one or more non-empty config paths.\",\n      command: \"deploy\",\n    });\n  }\n  return configPaths;\n}\nasync function buildDeploymentTarget(\n  params: BuildDeploymentTargetParams,\n): Promise<BuiltDeploymentTarget> {\n  const { configPath, loadedConfig, dryRun, buildOnly, noCache, packageVersion, cacheDir } = params;\n  const { config, plugins } =\n    loadedConfig ??\n    assertDefined(\n      (await loadDeployConfigs({ configPaths: [configPath], dryRun, buildOnly }))[0],\n      \"loaded config missing\",\n    );\n\n  const configDir = path.dirname(config.path);\n  const lockfilePath =\n    findUpSync(\"pnpm-lock.yaml\", { cwd: configDir }) ??\n    findUpSync(\"package-lock.json\", { cwd: configDir }) ??\n    findUpSync(\"yarn.lock\", { cwd: configDir }) ??\n    findUpSync(\"bun.lock\", { cwd: configDir });\n  const cacheManager = createCacheManager({\n    enabled: !noCache,\n    cacheDir,\n    sdkVersion: packageVersion,\n    lockfileHash: lockfilePath ? hashFile(lockfilePath) : undefined,\n  });\n\n  let pluginManager: PluginManager | undefined;\n  if (plugins.length > 0) {\n    pluginManager = new PluginManager(plugins);\n  }\n\n  await withSpan(\"build.generateUserTypes\", () =>\n    generateUserTypes({ config, configPath: config.path }),\n  );\n\n  let application: Application;\n  let workflowBuildResult: Awaited<ReturnType<typeof loadApplication>>[\"workflowBuildResult\"];\n  let httpAdapterBuildResult: Awaited<ReturnType<typeof loadApplication>>[\"httpAdapterBuildResult\"];\n  let bundledScripts: Awaited<ReturnType<typeof loadApplication>>[\"bundledScripts\"];\n  try {\n    const result = await withSpan(\"build.loadApplication\", () =>\n      loadApplication({\n        config,\n        pluginManager,\n        bundleCache: cacheManager.bundleCache,\n      }),\n    );\n    application = result.application;\n    workflowBuildResult = result.workflowBuildResult;\n    httpAdapterBuildResult = result.httpAdapterBuildResult;\n    bundledScripts = result.bundledScripts;\n  } finally {\n    cacheManager.finalize();\n  }\n\n  return {\n    config,\n    application,\n    workflowBuildResult,\n    httpAdapterBuildResult,\n    bundledScripts,\n  };\n}\n\nfunction resolveExistingConfigPath(configPath: string | undefined): string | undefined {\n  const foundPath = loadConfigPath(configPath);\n  if (!foundPath) return undefined;\n\n  const resolvedPath = path.resolve(process.cwd(), foundPath);\n  return fs.existsSync(resolvedPath) ? resolvedPath : undefined;\n}\n\n// Configs governed by a lock file resolve their id after the module is loaded\n// (the lock is compared against the id the module evaluates to), so only\n// lock-less configs are prepared here.\nasync function prepareDeployConfigs(params: LoadDeployConfigsParams): Promise<void> {\n  const { configPaths, dryRun, buildOnly } = params;\n  if (buildOnly) return;\n  const resolvedPaths = new Set(\n    configPaths\n      .map(resolveExistingConfigPath)\n      .filter((configPath): configPath is string => configPath !== undefined),\n  );\n\n  await Promise.all(\n    [...resolvedPaths].map((configPath) =>\n      withSpan(\"build.prepareConfig\", async () => {\n        if (findAppIdLock(configPath) !== null) return;\n        await ensureConfigIdForDeploy({ configPath, dryRun, buildOnly });\n      }),\n    ),\n  );\n}\n\nasync function loadPreparedDeployConfig(\n  params: LoadDeployConfigParams,\n): Promise<LoadedDeployConfig> {\n  return withSpan(\"build.loadConfig\", () => loadConfig(params.configPath));\n}\n\ntype ResolveDeployAppIdsParams = {\n  loaded: ReadonlyArray<LoadedDeployConfig>;\n  dryRun: boolean;\n  buildOnly: boolean;\n};\n\nasync function resolveDeployAppIds(\n  params: ResolveDeployAppIdsParams,\n): Promise<LoadedDeployConfig[]> {\n  const { loaded, dryRun, buildOnly } = params;\n  // build-only never reaches the platform, so ownership does not apply.\n  if (buildOnly) return [...loaded];\n\n  const resolved = [...loaded];\n  const byLockRoot = new Map<string, { lock: AppIdLock; indexes: number[] }>();\n  loaded.forEach((entry, index) => {\n    const lock = findAppIdLock(entry.config.path);\n    if (lock === null) {\n      warnMissingAppId(entry.config.id);\n      return;\n    }\n    const group = byLockRoot.get(lock.root) ?? { lock, indexes: [] };\n    group.indexes.push(index);\n    byLockRoot.set(lock.root, group);\n  });\n\n  const mode = appIdPlanModeForDeploy(dryRun);\n  for (const { lock, indexes } of byLockRoot.values()) {\n    const plan = await resolveLockedAppIds({\n      lock,\n      mode,\n      entries: indexes.map((index) => {\n        const { config } = assertDefined(loaded[index], \"loaded config missing\");\n        return { configPath: config.path, configId: config.id };\n      }),\n    });\n    indexes.forEach((index, position) => {\n      const entry = assertDefined(loaded[index], \"loaded config missing\");\n      const id = assertDefined(plan.entries[position], \"planned app id entry missing\").id;\n      resolved[index] = { ...entry, config: { ...entry.config, id } };\n    });\n  }\n  return resolved;\n}\n\nexport async function loadDeployConfigs(\n  params: LoadDeployConfigsParams,\n): Promise<LoadedDeployConfig[]> {\n  await prepareDeployConfigs(params);\n  const loaded = await Promise.all(\n    params.configPaths.map((configPath) => loadPreparedDeployConfig({ ...params, configPath })),\n  );\n  return resolveDeployAppIds({ loaded, dryRun: params.dryRun, buildOnly: params.buildOnly });\n}\n\nexport async function buildDeploymentTargets(\n  params: BuildDeploymentTargetsParams,\n): Promise<BuiltDeploymentTarget[]> {\n  const {\n    configPaths,\n    loadedConfigs: providedLoadedConfigs,\n    buildTarget,\n    ...targetParams\n  } = params;\n  if (\n    providedLoadedConfigs !== undefined &&\n    (providedLoadedConfigs.length !== configPaths.length ||\n      configPaths.some((_, index) => providedLoadedConfigs[index] === undefined))\n  ) {\n    throw internalError(\"loadedConfigs must contain exactly one entry for every configPath\");\n  }\n  const loadedConfigs =\n    buildTarget === undefined && providedLoadedConfigs === undefined\n      ? await loadDeployConfigs({\n          configPaths,\n          dryRun: params.dryRun,\n          buildOnly: params.buildOnly,\n        })\n      : providedLoadedConfigs;\n  const build = buildTarget ?? buildDeploymentTarget;\n\n  return Promise.all(\n    configPaths.map((configPath, index) =>\n      build({\n        ...targetParams,\n        configPath,\n        loadedConfig: loadedConfigs?.[index],\n      }),\n    ),\n  );\n}\n","import { collectApplicationIdpNames } from \"./executor\";\nimport type { Application } from \"#/cli/services/application\";\n\nfunction addPossiblyAmbiguousNamespace(\n  namespaces: Map<string, string | undefined>,\n  key: string,\n  namespace: string,\n): void {\n  if (namespaces.has(key)) {\n    if (namespaces.get(key) !== namespace) {\n      namespaces.set(key, undefined);\n    }\n    return;\n  }\n  namespaces.set(key, namespace);\n}\n\ntype VisibleResource = {\n  visibilityKey: string;\n  resourceKey: string;\n};\n\ntype CollectVisibleResourcesParams<TResult> = {\n  application: Readonly<Application>;\n  applications: ReadonlyArray<Readonly<Application>>;\n  visibleKeysOf: (application: Readonly<Application>) => ReadonlySet<string>;\n  resourcesOf: (application: Readonly<Application>) => Iterable<VisibleResource>;\n  createResult: () => TResult;\n  addResource: (result: TResult, resourceKey: string, visibilityKey: string) => void;\n};\n\nfunction collectVisibleResources<TResult>(params: CollectVisibleResourcesParams<TResult>): TResult {\n  const { application, applications, visibleKeysOf, resourcesOf, createResult, addResource } =\n    params;\n  const visibleKeys = visibleKeysOf(application);\n  const result = createResult();\n  for (const candidate of applications) {\n    for (const resource of resourcesOf(candidate)) {\n      if (!visibleKeys.has(resource.visibilityKey)) {\n        continue;\n      }\n      addResource(result, resource.resourceKey, resource.visibilityKey);\n    }\n  }\n  return result;\n}\n\nfunction collectApplicationTailorDBNamespaces(\n  application: Readonly<Application>,\n): ReadonlySet<string> {\n  return new Set([\n    ...application.tailorDBServices.map((service) => service.namespace),\n    ...application.externalTailorDBNamespaces,\n  ]);\n}\n\nfunction* tailorDBTypeResources(application: Readonly<Application>): Iterable<VisibleResource> {\n  for (const service of application.tailorDBServices) {\n    for (const tableName of Object.keys(service.types)) {\n      yield { visibilityKey: service.namespace, resourceKey: tableName };\n    }\n  }\n}\n\nexport function collectVisibleTailorDBTypeNamespaces(\n  application: Readonly<Application>,\n  applications: ReadonlyArray<Readonly<Application>>,\n): ReadonlyMap<string, string | undefined> {\n  return collectVisibleResources({\n    application,\n    applications,\n    visibleKeysOf: collectApplicationTailorDBNamespaces,\n    resourcesOf: tailorDBTypeResources,\n    createResult: () => new Map<string, string | undefined>(),\n    addResource: addPossiblyAmbiguousNamespace,\n  });\n}\n\nfunction collectApplicationResolverNamespaces(\n  application: Readonly<Application>,\n): ReadonlySet<string> {\n  return new Set(\n    application.subgraphs\n      .filter((subgraph) => subgraph.Type === \"pipeline\")\n      .map((subgraph) => subgraph.Name),\n  );\n}\n\nfunction* idpNameResources(application: Readonly<Application>): Iterable<VisibleResource> {\n  for (const name of collectApplicationIdpNames(application)) {\n    yield { visibilityKey: name, resourceKey: name };\n  }\n}\n\nexport function collectVisibleIdpNames(\n  application: Readonly<Application>,\n  applications: ReadonlyArray<Readonly<Application>>,\n): ReadonlySet<string> {\n  return collectVisibleResources({\n    application,\n    applications,\n    visibleKeysOf: collectApplicationIdpNames,\n    resourcesOf: idpNameResources,\n    createResult: () => new Set<string>(),\n    addResource: (names, name) => {\n      names.add(name);\n    },\n  });\n}\n\nfunction* resolverResources(application: Readonly<Application>): Iterable<VisibleResource> {\n  for (const service of application.resolverServices) {\n    for (const resolver of Object.values(service.resolvers)) {\n      yield { visibilityKey: service.namespace, resourceKey: resolver.name };\n    }\n  }\n}\n\nexport function collectVisibleResolverNamespaces(\n  application: Readonly<Application>,\n  applications: ReadonlyArray<Readonly<Application>>,\n): ReadonlyMap<string, string | undefined> {\n  return collectVisibleResources({\n    application,\n    applications,\n    visibleKeysOf: collectApplicationResolverNamespaces,\n    resourcesOf: resolverResources,\n    createResult: () => new Map<string, string | undefined>(),\n    addResource: addPossiblyAmbiguousNamespace,\n  });\n}\n","import { CLIError } from \"#/cli/shared/errors\";\nimport {\n  eventSourceLabel,\n  publishEventsConflict,\n  subscribesToEvents,\n} from \"#/cli/shared/publish-events\";\nimport { collectApplicationIdpNames, findResolverNamespace } from \"./executor\";\nimport { dependedByAppLabelKey, eventSourceKey } from \"./label\";\nimport {\n  collectVisibleIdpNames,\n  collectVisibleResolverNamespaces,\n  collectVisibleTailorDBTypeNamespaces,\n} from \"./visible-resources\";\nimport type { Application } from \"#/cli/services/application\";\nimport type { Executor } from \"#/types/executor.generated\";\nimport type { BuiltDeploymentTarget } from \"./deployment-target\";\nimport type { DependentAppsByResource, DeployDependencyReason } from \"./label\";\nimport type { WorkflowEventSubscribers } from \"./workflow\";\n\n/**\n * Resolve which IdP an `idpUser` trigger subscribes to. A trigger that omits the\n * `idp` option means the only configured IdP; when several exist the target is\n * ambiguous and the apply pipeline throws a clearer error for it later.\n * @param application - Application declaring the executor\n * @param trigger - The executor's `idpUser` trigger\n * @returns The subscribed IdP name, or undefined when ambiguous\n */\nfunction subscribedIdpName(\n  application: Readonly<Application>,\n  trigger: { idp?: string | undefined },\n): string | undefined {\n  if (trigger.idp != null) {\n    return trigger.idp;\n  }\n  const idps = collectApplicationIdpNames(application);\n  if (idps.size !== 1) {\n    return undefined;\n  }\n  const [only] = idps;\n  return only;\n}\n\n/** What one executor's event trigger subscribes to, and who declares it. */\nexport type EventSubscription = {\n  /** Target declaring the executor. */\n  subscriber: BuiltDeploymentTarget;\n  /** Name of the subscribing executor, for error messages. */\n  executorName: string;\n  /** Target declaring the subscribed resource. */\n  owner: BuiltDeploymentTarget;\n  /** The subscribed resource, named as error messages name it. */\n  resource: string;\n  /** Stable identity of the subscribed resource, keying its dependency records. */\n  key: string | undefined;\n  /**\n   * Whether the owner declares `publishEvents` on the subscribed resource, which\n   * pins the value and leaves nothing for a dependency record to protect.\n   */\n  pinned: boolean;\n  /**\n   * Whether the executor is disabled. A disabled executor never runs, so it needs\n   * no events published — but its trigger is still deployed, so the subscription\n   * is still resolved to validate the name and to keep the dependency record.\n   */\n  disabled: boolean;\n  /** The executor's trigger, narrowed to a kind that names a publishing resource. */\n  trigger: PublishingTrigger;\n};\n\n/**\n * Build the error for a subscription whose resource no config in the run declares.\n *\n * The advice differs by cause: a config that declares the resource as owned\n * elsewhere is missing its peer from `--config`, while one that declares nothing\n * external is naming a resource that does not exist.\n * @param executorName - Name of the subscribing executor\n * @param lookup - How the subscribed resource is found\n * @param subscriber - Deployment target declaring the executor\n * @returns Error message\n */\nfunction missingOwnerMessage(\n  executorName: string,\n  lookup: EventSourceLookup,\n  subscriber: BuiltDeploymentTarget,\n): string {\n  const subject = `Executor \"${executorName}\" subscribes to ${lookup.resource}, which no config in this deploy declares.`;\n  const external = lookup.externalHint(subscriber);\n  if (external) {\n    return `${subject} This config declares ${external}, so add the config that owns it to --config.`;\n  }\n  if (\n    lookup.trigger.kind === \"workflowExecution\" ||\n    lookup.trigger.kind === \"workflowJobExecution\"\n  ) {\n    return (\n      `${subject} A workflow has no \"external\" declaration, unlike a TailorDB namespace or resolver, so ` +\n      `nothing in this config points at the one that owns it. Check the name, or add the config that ` +\n      `declares the workflow to --config.`\n    );\n  }\n  return `${subject} This config declares nothing external that could hold it, so check the name.`;\n}\n\n/**\n * Resolve every event subscription in the run to the config that declares the\n * subscribed resource.\n *\n * Doing this once keeps the flags the planners resolve and the cross-config\n * dependencies recorded on the application in agreement — both are read off the\n * same list.\n * @param targets - Built deployment targets in the run\n * @returns One entry per executor whose trigger names a publishing resource\n */\nexport function collectEventSubscriptions(\n  targets: ReadonlyArray<BuiltDeploymentTarget>,\n): EventSubscription[] {\n  const subscriptions: EventSubscription[] = [];\n  const applications = targets.map((target) => target.application);\n  for (const subscriber of targets) {\n    const executors = subscriber.application.executorService?.executors ?? {};\n    const visibility = collectSubscriberVisibility(subscriber, applications);\n    for (const executor of Object.values(executors)) {\n      const lookup = eventSourceLookup(executor, subscriber, visibility);\n      if (!lookup) {\n        continue;\n      }\n      const entry = {\n        subscriber,\n        executorName: executor.name,\n        resource: lookup.resource,\n        disabled: !subscribesToEvents(executor),\n        trigger: lookup.trigger,\n      };\n      if (lookup.declaredBy(subscriber)) {\n        subscriptions.push({\n          ...entry,\n          owner: subscriber,\n          pinned: lookup.pinned(subscriber),\n          key: lookup.keyIn(subscriber),\n        });\n        continue;\n      }\n      const peers = targets.filter(\n        (target) => target.config.path !== subscriber.config.path && lookup.declaredBy(target),\n      );\n      const owners = lookup.narrowOwners(peers);\n      // The subscriber sees the name in more than one namespace. Which one the\n      // trigger means is reported when the executor's namespace is resolved.\n      if (owners === \"ambiguous\") {\n        continue;\n      }\n      const [owner] = owners;\n      if (!owner) {\n        throw CLIError({\n          code: \"EVENT_SUBSCRIPTION_OWNER_NOT_FOUND\",\n          message: missingOwnerMessage(executor.name, lookup, subscriber),\n        });\n      }\n      subscriptions.push({\n        ...entry,\n        owner,\n        pinned: lookup.pinned(owner),\n        key: lookup.keyIn(owner),\n      });\n    }\n  }\n  return subscriptions;\n}\n\n/**\n * Key the resources this run subscribes to among the target's own.\n *\n * A resource with a subscriber that runs resolves to `true` from that subscriber\n * alone, so no absent config can change it. A disabled one resolves nothing, so\n * the resource does turn off and the records still have to be asked about.\n * @param subscriptions - Subscriptions resolved across the run\n * @param owner - Deployment target being planned\n * @returns Resource keys the run subscribes to\n */\nexport function subscribedResourceKeys(\n  subscriptions: ReadonlyArray<EventSubscription>,\n  owner: BuiltDeploymentTarget,\n): ReadonlySet<string> {\n  return new Set(\n    publishingSubscriptions(ownedSubscriptions(subscriptions, owner)).flatMap(\n      (subscription) => subscription.key ?? [],\n    ),\n  );\n}\n\n/**\n * Select the subscriptions pointing at resources the given target declares.\n * @param subscriptions - Subscriptions resolved across the run\n * @param owner - Deployment target being planned\n * @returns Subscriptions whose subscribed resource belongs to `owner`\n */\nexport function ownedSubscriptions(\n  subscriptions: ReadonlyArray<EventSubscription>,\n  owner: BuiltDeploymentTarget,\n): EventSubscription[] {\n  return subscriptions.filter(\n    (subscription) => subscription.owner.config.path === owner.config.path,\n  );\n}\n\n/**\n * Narrow subscriptions to the ones whose executor actually needs events.\n *\n * A disabled executor never runs, so it must not keep publishing enabled on the\n * resource it names. It stays in the subscription list all the same: its trigger\n * is still deployed, so the name still has to resolve to a declared resource, and\n * a cross-config dependency record still has to survive the executor being\n * disabled and re-enabled.\n * @param subscriptions - Subscriptions owned by the target being planned\n * @returns Subscriptions from executors that will run\n */\nfunction publishingSubscriptions(\n  subscriptions: ReadonlyArray<EventSubscription>,\n): ReadonlyArray<EventSubscription> {\n  return subscriptions.filter((subscription) => !subscription.disabled);\n}\n\n/**\n * Collect the TailorDB tables subscribed to among the given subscriptions.\n * @param subscriptions - Subscriptions owned by the target being planned\n * @returns Subscribed table names\n */\nexport function subscribedTailorDBTables(\n  subscriptions: ReadonlyArray<EventSubscription>,\n): ReadonlySet<string> {\n  return new Set(\n    publishingSubscriptions(subscriptions).flatMap((subscription) =>\n      subscription.trigger.kind === \"tailordb\" ? [subscription.trigger.tableName] : [],\n    ),\n  );\n}\n\n/**\n * Collect the resolvers subscribed to among the given subscriptions.\n * @param subscriptions - Subscriptions owned by the target being planned\n * @returns Subscribed resolver names\n */\nexport function subscribedResolvers(\n  subscriptions: ReadonlyArray<EventSubscription>,\n): ReadonlySet<string> {\n  return new Set(\n    publishingSubscriptions(subscriptions).flatMap((subscription) =>\n      subscription.trigger.kind === \"resolverExecuted\" ? [subscription.trigger.resolverName] : [],\n    ),\n  );\n}\n\n/**\n * Collect the IdPs subscribed to among the given subscriptions.\n * @param subscriptions - Subscriptions owned by the target being planned\n * @returns Subscribed IdP names\n */\nexport function subscribedIdps(\n  subscriptions: ReadonlyArray<EventSubscription>,\n): ReadonlySet<string> {\n  return new Set(\n    publishingSubscriptions(subscriptions).flatMap((subscription) =>\n      subscription.trigger.kind === \"idpUser\"\n        ? [\n            subscribedIdpName(subscription.subscriber.application, subscription.trigger) ?? [],\n          ].flat()\n        : [],\n    ),\n  );\n}\n\n/**\n * Collect the workflows subscribed to, per event granularity level.\n * @param subscriptions - Subscriptions owned by the target being planned\n * @returns Subscribers keyed by event granularity level\n */\nexport function subscribedWorkflows(subscriptions: ReadonlyArray<EventSubscription>): {\n  execution: WorkflowEventSubscribers;\n  jobExecution: WorkflowEventSubscribers;\n} {\n  const execution = { workflowNames: new Set<string>() };\n  const jobExecution = { workflowNames: new Set<string>() };\n  for (const { trigger } of publishingSubscriptions(subscriptions)) {\n    if (trigger.kind === \"workflowExecution\") {\n      execution.workflowNames.add(trigger.workflowName);\n    } else if (trigger.kind === \"workflowJobExecution\") {\n      jobExecution.workflowNames.add(trigger.workflowName);\n    }\n  }\n  return { execution, jobExecution };\n}\n\n/**\n * Collect the applications that have to take part in the same deploy for this\n * target's resources to be applied the same way.\n *\n * An executor in another config makes the resource it subscribes to publish\n * events, so deploying this config without that one would resolve the flag from\n * a smaller set of executors and turn publishing off.\n *\n * A resource that declares `publishEvents` keeps its value either way, so\n * recording a dependency for it would ask about a partial deploy that changes\n * nothing — and `prompt.confirm` rejects outright where it cannot ask, failing a\n * deploy that was never at risk. A disabled subscriber is dropped for the same\n * reason: it holds the flag at `false` already, so the owner deploying alone\n * changes nothing about it.\n *\n * Records are keyed by resource rather than by application: the resource is what\n * carries them, so a record survives the owner being renamed and disappears with\n * the resource itself.\n * @param subscriptions - Subscriptions owned by the target being planned\n * @returns Dependent application ids and reasons, keyed by resource\n */\nexport function collectDependentApps(\n  subscriptions: ReadonlyArray<EventSubscription>,\n): DependentAppsByResource {\n  const byResource = new Map<string, Map<string, DeployDependencyReason>>();\n  for (const { subscriber, owner, pinned, key } of publishingSubscriptions(subscriptions)) {\n    if (subscriber.config.path === owner.config.path || pinned || key === undefined) {\n      continue;\n    }\n    const appId = subscriber.application.id;\n    if (appId === undefined) {\n      continue;\n    }\n    const dependents = byResource.get(key) ?? new Map<string, DeployDependencyReason>();\n    dependents.set(appId, \"publish-events\");\n    byResource.set(key, dependents);\n  }\n  return byResource;\n}\n\n/**\n * Collect explicit `publishEvents` values declared on this target's workflow jobs.\n * @param target - Deployment target being planned\n * @returns Explicit flags keyed by job name\n */\nexport function collectWorkflowJobPublishEvents(\n  target: BuiltDeploymentTarget,\n): ReadonlyMap<string, boolean> {\n  const jobPublishEvents = new Map<string, boolean>();\n  for (const job of target.application.workflowService?.jobs ?? []) {\n    if (job.publishEvents !== undefined) {\n      jobPublishEvents.set(job.name, job.publishEvents);\n    }\n  }\n  return jobPublishEvents;\n}\n\n/** Executor trigger kinds that name a resource which publishes events. */\ntype PublishingTrigger = Extract<\n  Executor[\"trigger\"],\n  {\n    kind:\n      | \"tailordb\"\n      | \"resolverExecuted\"\n      | \"idpUser\"\n      | \"workflowExecution\"\n      | \"workflowJobExecution\";\n  }\n>;\n\n/**\n * What one subscribing config can see, in the same terms the executor's own\n * namespace resolution uses. A namespace maps to `undefined` when the subscriber\n * sees the name in more than one place.\n */\ntype SubscriberVisibility = {\n  tailorDBTypes: ReadonlyMap<string, string | undefined>;\n  resolvers: ReadonlyMap<string, string | undefined>;\n  idps: ReadonlySet<string>;\n};\n\nfunction collectSubscriberVisibility(\n  subscriber: BuiltDeploymentTarget,\n  applications: ReadonlyArray<Readonly<Application>>,\n): SubscriberVisibility {\n  return {\n    tailorDBTypes: collectVisibleTailorDBTypeNamespaces(subscriber.application, applications),\n    resolvers: collectVisibleResolverNamespaces(subscriber.application, applications),\n    idps: collectVisibleIdpNames(subscriber.application, applications),\n  };\n}\n\n/** Candidate owners the subscriber's view leaves, or that it cannot tell apart. */\ntype OwnerCandidates = BuiltDeploymentTarget[] | \"ambiguous\";\n\n/** How to find one event-publishing resource in a deployment target. */\ntype EventSourceLookup = {\n  /** Resource named in error messages, e.g. `TailorDB table \"Order\"`. */\n  resource: string;\n  /** The trigger, narrowed to a kind that names a publishing resource. */\n  trigger: PublishingTrigger;\n  /** Whether `target` declares the resource. */\n  declaredBy: (target: BuiltDeploymentTarget) => boolean | undefined;\n  /**\n   * Whether `target` declares `publishEvents` on the resource, so the value does\n   * not depend on which configs the run covers.\n   */\n  pinned: (target: BuiltDeploymentTarget) => boolean;\n  /**\n   * Stable identity of the subscribed resource inside its owner, used to key the\n   * dependency records. Undefined when the owner does not declare it after all.\n   */\n  keyIn: (owner: BuiltDeploymentTarget) => string | undefined;\n  /**\n   * Narrow peer configs to the ones the subscriber's own view resolves to.\n   *\n   * Matching on the name alone would count a same-named resource in a namespace\n   * the subscriber cannot see, and drop the subscription as ambiguous even though\n   * the executor resolves it to exactly one owner.\n   */\n  narrowOwners: (candidates: ReadonlyArray<BuiltDeploymentTarget>) => OwnerCandidates;\n  /**\n   * What `target` declares as owned elsewhere that could hold this resource,\n   * described for an error message. Undefined for a resource kind that cannot be\n   * referenced from another config at all.\n   */\n  externalHint: (target: BuiltDeploymentTarget) => string | undefined;\n};\n\n/**\n * TailorDB namespaces the config declares as owned elsewhere.\n * @param target - Deployment target declaring the executor\n * @returns Namespace names declared with `external: true`\n */\nfunction externalTailorDBNamespaces(target: BuiltDeploymentTarget): ReadonlyArray<string> {\n  return target.application.externalTailorDBNamespaces;\n}\n\nfunction externalSubgraphNames(\n  target: BuiltDeploymentTarget,\n  subgraphType: string,\n  localNames: ReadonlySet<string>,\n): string[] {\n  return target.application.subgraphs\n    .filter((subgraph) => subgraph.Type === subgraphType && !localNames.has(subgraph.Name))\n    .map((subgraph) => subgraph.Name);\n}\n\nfunction externalResolverNamespaces(target: BuiltDeploymentTarget): string[] {\n  const local = new Set(target.application.resolverServices.map((service) => service.namespace));\n  return externalSubgraphNames(target, \"pipeline\", local);\n}\n\nfunction externalIdpNames(target: BuiltDeploymentTarget): string[] {\n  const local = new Set(target.application.idpServices.map((idp) => idp.name));\n  return externalSubgraphNames(target, \"idp\", local);\n}\n\n/**\n * Describe the external declarations that could hold a missing resource.\n * @param kind - Resource kind named in the message, e.g. `TailorDB namespace`\n * @param names - External names the subscribing config declares\n * @returns A phrase for the error message, or undefined when it declares none\n */\nfunction describeExternal(kind: string, names: ReadonlyArray<string>): string | undefined {\n  if (names.length === 0) {\n    return undefined;\n  }\n  const plural = names.length === 1 ? kind : `${kind}s`;\n  return `external ${plural} ${names.map((name) => `\"${name}\"`).join(\", \")}`;\n}\n\nfunction declaresTailorDBType(\n  target: BuiltDeploymentTarget,\n  tableName: string,\n): boolean | undefined {\n  return (\n    target.application.tailorDBServices.some((service) => service.types[tableName]) || undefined\n  );\n}\n\nfunction declaresResolver(\n  target: BuiltDeploymentTarget,\n  resolverName: string,\n): boolean | undefined {\n  return (\n    target.application.resolverServices.some((service) =>\n      Object.values(service.resolvers).some((resolver) => resolver.name === resolverName),\n    ) || undefined\n  );\n}\n\nfunction declaresIdp(target: BuiltDeploymentTarget, idpName: string): boolean | undefined {\n  return target.application.idpServices.some((entry) => entry.name === idpName) || undefined;\n}\n\nfunction declaresWorkflow(\n  target: BuiltDeploymentTarget,\n  workflowName: string,\n): boolean | undefined {\n  const workflows = Object.values(target.application.workflowService?.workflows ?? {});\n  return workflows.some((entry) => entry.name === workflowName) || undefined;\n}\n\n// A resource that declares publishEvents keeps that value whatever the run covers,\n// so nothing about it needs recording. An explicit `false` with a subscriber is\n// rejected by assertNoPublishEventsConflict, which explains that case on its own.\nfunction pinsTailorDBType(target: BuiltDeploymentTarget, tableName: string): boolean {\n  for (const service of target.application.tailorDBServices) {\n    const type = service.types[tableName];\n    if (type) return type.settings.publishEvents !== undefined;\n  }\n  return false;\n}\n\n// Resolver names are only namespace-unique, so the namespace the subscriber sees\n// the name through is what decides which resolver's declared value applies.\n// Searching every namespace would let one namespace's declaration pin another's.\nfunction pinsResolverIn(\n  target: BuiltDeploymentTarget,\n  namespace: string,\n  resolverName: string,\n): boolean {\n  return target.application.resolverServices.some(\n    (service) =>\n      service.namespace === namespace &&\n      Object.values(service.resolvers).some(\n        (resolver) => resolver.name === resolverName && resolver.publishEvents !== undefined,\n      ),\n  );\n}\n\nfunction pinsIdp(target: BuiltDeploymentTarget, idpName: string): boolean {\n  return target.application.idpServices.some(\n    (entry) => entry.name === idpName && entry.publishEvents !== undefined,\n  );\n}\n\nfunction pinsWorkflow(target: BuiltDeploymentTarget, workflowName: string): boolean {\n  return Object.values(target.application.workflowService?.workflows ?? {}).some(\n    (entry) => entry.name === workflowName && entry.publishEvents !== undefined,\n  );\n}\n\n// A workflowJobExecution trigger enables publishing on the jobs the subscribed\n// workflow runs, so only those decide whether the value is declared. Reading the\n// whole config's jobs instead would call the value unset because some other\n// workflow leaves one unset, and `planWorkflow` writes the records per workflow.\nfunction pinsEveryJobOfWorkflow(target: BuiltDeploymentTarget, workflowName: string): boolean {\n  const workflow = Object.values(target.application.workflowService?.workflows ?? {}).find(\n    (entry) => entry.name === workflowName,\n  );\n  if (workflow === undefined) return false;\n  const jobNames = target.workflowBuildResult?.mainJobDeps[workflow.mainJob.name] ?? [];\n  const declared = collectWorkflowJobPublishEvents(target);\n  return jobNames.length > 0 && jobNames.every((jobName) => declared.has(jobName));\n}\n\nfunction tailorDBTypeNamespaceIn(\n  target: BuiltDeploymentTarget,\n  tableName: string,\n): string | undefined {\n  return target.application.tailorDBServices.find((service) => service.types[tableName])?.namespace;\n}\n\n// A namespaced resource is owned by whichever config declares it in the one\n// namespace the subscriber sees it through. An absent key means the subscriber\n// cannot see the name at all, which the missing-owner error explains.\nfunction narrowByVisibleNamespace(params: {\n  candidates: ReadonlyArray<BuiltDeploymentTarget>;\n  visible: ReadonlyMap<string, string | undefined>;\n  resourceKey: string;\n  declaresIn: (target: BuiltDeploymentTarget, namespace: string) => boolean;\n}): OwnerCandidates {\n  const { candidates, visible, resourceKey, declaresIn } = params;\n  if (!visible.has(resourceKey)) return [];\n  const namespace = visible.get(resourceKey);\n  if (namespace === undefined) return \"ambiguous\";\n  return candidates.filter((target) => declaresIn(target, namespace));\n}\n\nfunction declaresTailorDBTypeIn(\n  target: BuiltDeploymentTarget,\n  namespace: string,\n  tableName: string,\n): boolean {\n  return target.application.tailorDBServices.some(\n    (service) => service.namespace === namespace && Boolean(service.types[tableName]),\n  );\n}\n\nfunction declaresResolverIn(\n  target: BuiltDeploymentTarget,\n  namespace: string,\n  resolverName: string,\n): boolean {\n  return target.application.resolverServices.some(\n    (service) =>\n      service.namespace === namespace &&\n      Object.values(service.resolvers).some((resolver) => resolver.name === resolverName),\n  );\n}\n\n/**\n * Resolve how to find the resource an executor's event trigger subscribes to.\n * @param executor - Executor declared by the subscribing config\n * @param subscriber - Deployment target declaring the executor\n * @param visibility - What the subscribing config can see, by resource kind\n * @returns The lookup, or undefined for triggers with no publishing resource\n */\nfunction eventSourceLookup(\n  executor: Executor,\n  subscriber: BuiltDeploymentTarget,\n  visibility: SubscriberVisibility,\n): EventSourceLookup | undefined {\n  const { trigger } = executor;\n  switch (trigger.kind) {\n    case \"tailordb\":\n      return {\n        resource: publishEventsConflict.tailorDBType(trigger.tableName).resource,\n        trigger,\n        declaredBy: (target) => declaresTailorDBType(target, trigger.tableName),\n        pinned: (target) => pinsTailorDBType(target, trigger.tableName),\n        keyIn: (owner) => {\n          const namespace = tailorDBTypeNamespaceIn(owner, trigger.tableName);\n          return namespace && eventSourceKey.tailorDBType(namespace, trigger.tableName);\n        },\n        narrowOwners: (candidates) =>\n          narrowByVisibleNamespace({\n            candidates,\n            visible: visibility.tailorDBTypes,\n            resourceKey: trigger.tableName,\n            declaresIn: (target, namespace) =>\n              declaresTailorDBTypeIn(target, namespace, trigger.tableName),\n          }),\n        externalHint: (target) =>\n          describeExternal(\"TailorDB namespace\", externalTailorDBNamespaces(target)),\n      };\n    case \"resolverExecuted\": {\n      // The namespace the subscriber resolves the name through, in the same order\n      // the trigger itself resolves it: a locally declared resolver wins, and only\n      // then the namespaces the config sees. Reading it back off the owner by bare\n      // name would pick whichever namespace comes first instead, and reading only\n      // the visible map would call a local name ambiguous because an external\n      // namespace happens to hold it too.\n      const namespace =\n        findResolverNamespace(subscriber.application, trigger.resolverName) ??\n        visibility.resolvers.get(trigger.resolverName);\n      return {\n        resource: publishEventsConflict.resolver(trigger.resolverName).resource,\n        trigger,\n        declaredBy: (target) => declaresResolver(target, trigger.resolverName),\n        pinned: (target) =>\n          namespace !== undefined && pinsResolverIn(target, namespace, trigger.resolverName),\n        keyIn: () => namespace && eventSourceKey.resolver(namespace, trigger.resolverName),\n        narrowOwners: (candidates) =>\n          narrowByVisibleNamespace({\n            candidates,\n            visible: visibility.resolvers,\n            resourceKey: trigger.resolverName,\n            declaresIn: (target, namespace) =>\n              declaresResolverIn(target, namespace, trigger.resolverName),\n          }),\n        externalHint: (target) =>\n          describeExternal(\"resolver namespace\", externalResolverNamespaces(target)),\n      };\n    }\n    case \"idpUser\": {\n      const idpName = subscribedIdpName(subscriber.application, trigger);\n      if (idpName === undefined) {\n        return undefined;\n      }\n      return {\n        resource: publishEventsConflict.idpService(idpName).resource,\n        trigger,\n        declaredBy: (target) => declaresIdp(target, idpName),\n        pinned: (target) => pinsIdp(target, idpName),\n        keyIn: () => eventSourceKey.idp(idpName),\n        // IdP namespace names are unique across a run, so there is nothing to\n        // tell apart once the subscriber can see the name.\n        narrowOwners: (candidates) =>\n          visibility.idps.has(idpName)\n            ? candidates.filter((target) => declaresIdp(target, idpName))\n            : [],\n        // The trigger names the IdP, so the hint can be exact rather than a list.\n        externalHint: (target) =>\n          describeExternal(\n            \"IdP\",\n            externalIdpNames(target).filter((name) => name === idpName),\n          ),\n      };\n    }\n    case \"workflowExecution\":\n    case \"workflowJobExecution\":\n      return {\n        // A job trigger subscribes to the jobs' events, not the workflow's own, so\n        // naming the workflow would read as if its publishEvents were at stake.\n        resource:\n          trigger.kind === \"workflowExecution\"\n            ? eventSourceLabel.workflow(trigger.workflowName)\n            : eventSourceLabel.workflowJobs(trigger.workflowName),\n        trigger,\n        declaredBy: (target) => declaresWorkflow(target, trigger.workflowName),\n        pinned: (target) =>\n          trigger.kind === \"workflowExecution\"\n            ? pinsWorkflow(target, trigger.workflowName)\n            : pinsEveryJobOfWorkflow(target, trigger.workflowName),\n        keyIn: () =>\n          trigger.kind === \"workflowExecution\"\n            ? eventSourceKey.workflow(trigger.workflowName)\n            : eventSourceKey.workflowJobs(trigger.workflowName),\n        narrowOwners: (candidates) =>\n          candidates.filter((target) => declaresWorkflow(target, trigger.workflowName)),\n        // A workflow has no `external` declaration to check.\n        externalHint: () => undefined,\n      };\n    default:\n      return undefined;\n  }\n}\n/**\n * Reject a cross-config subscription whose dependency cannot be recorded.\n *\n * Records live on the subscribed resource, so there is always somewhere to put\n * one. What can be missing is the dependent's name: the record identifies it by\n * application id, and a subscriber that resolves without one cannot be recorded,\n * leaving the next deploy of the owner alone to turn publishing off unannounced.\n *\n * The check applies only to a run that writes: `--dry-run` leaves every id\n * uninjected, so demanding one there would reject configs a real deploy gives one.\n * @param subscriptions - Every event subscription resolved for the run\n * @param writes - Whether this run applies changes rather than only reporting them\n */\nexport function assertRecordableDependencies(\n  subscriptions: ReadonlyArray<EventSubscription>,\n  writes: boolean,\n): void {\n  for (const { subscriber, owner, executorName, resource, pinned } of publishingSubscriptions(\n    subscriptions,\n  )) {\n    if (subscriber.config.path === owner.config.path) continue;\n    if (pinned) continue;\n    if (!writes) continue;\n    const appId = subscriber.application.id;\n    // An id that cannot form a label key fails the same way as a missing one, and\n    // it has to fail here: the write happens partway through apply, once sibling\n    // resources have already been mutated.\n    if (appId !== undefined && dependedByAppLabelKey(appId) !== undefined) continue;\n    const cause =\n      appId === undefined\n        ? `${subscriber.config.path} resolves without an \"id\" — a config that re-exports ` +\n          `defineConfig() from another file never gets one`\n        : `${subscriber.config.path} resolves to the id \"${appId}\", which is not the lowercase ` +\n          `UUID deploy writes`;\n    const fix =\n      appId === undefined\n        ? `Call defineConfig() inline in ${subscriber.config.path} so deploy can manage its \"id\".`\n        : `Restore the generated value in ${subscriber.config.path}'s \"id\".`;\n    throw CLIError({\n      code: \"EVENT_SUBSCRIPTION_OWNER_UNRECORDED\",\n      message: `Executor \"${executorName}\" in ${subscriber.config.path} subscribes to ${resource} in ${owner.config.path}, which would enable event publishing on it for this deploy only. ${cause} — so deploy cannot record which config the dependency belongs to.`,\n      details: `Deploying ${owner.config.path} alone later would turn publishing back off without asking.`,\n      suggestion: fix,\n    });\n  }\n}\n","import { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { deploymentPlanResults, type PlannedDeployment, type PlanResults } from \"./apply-phases\";\nimport type { HasName } from \"./change-set\";\nimport type { ImportantResourceDeletion, OwnerConflict, UnmanagedResource } from \"./confirm\";\nimport type { BuiltDeploymentTarget } from \"./deployment-target\";\n\n/**\n * Decide which renamed-away applications should be deleted. Excludes the\n * deploy targets themselves: id regeneration alone keeps the name unchanged,\n * so deleting by name would destroy a live app.\n * @param params - Inputs for the computation\n * @param params.conflicts - Detected owner conflicts across all services\n * @param params.resourceOwners - App names that still own resources we don't manage\n * @param params.protectedAppNames - App names that must not be deleted\n * @returns Names of empty old applications that should be deleted\n */\nexport function computeRenamedAppDeletions(params: {\n  conflicts: ReadonlyArray<Pick<OwnerConflict, \"currentOwner\">>;\n  resourceOwners: ReadonlySet<string>;\n  protectedAppNames: ReadonlySet<string>;\n}): string[] {\n  const { conflicts, resourceOwners, protectedAppNames } = params;\n  const conflictOwners = new Set(conflicts.map((c) => c.currentOwner));\n  return [...conflictOwners].filter(\n    (owner) => !resourceOwners.has(owner) && !protectedAppNames.has(owner),\n  );\n}\n/**\n * Reject resource names that collide across configs. Each checked resource\n * type is workspace-global (its TRN is not qualified by namespace or app), so\n * a duplicate name would make two configs target the same platform resource:\n * one config's apply could overwrite the other's, or a fresh create could be\n * attempted twice. Resolver and auth-hook function names are namespace- or\n * app-qualified and are intentionally excluded.\n * @param targets - Built deployment targets to check\n */\nexport function assertUniqueGlobalResourceNames(\n  targets: ReadonlyArray<BuiltDeploymentTarget>,\n): void {\n  for (const check of DEPLOY_MANAGED_RESOURCE_DEFINITIONS) {\n    const seen = new Set<string>();\n    for (const target of targets) {\n      for (const name of check.namesOf(target)) {\n        if (seen.has(name)) {\n          throw CLIError({\n            code: \"DEPLOY_DUPLICATE_RESOURCE_NAME\",\n            message: `Duplicate ${check.resourceLabel} name \"${name}\" across config files. ${check.resourceLabel} names must be unique across all configs in a single deploy.`,\n          });\n        }\n        seen.add(name);\n      }\n    }\n  }\n}\ntype OwnershipTrackedPlan = {\n  conflicts: OwnerConflict[];\n  unmanaged: UnmanagedResource[];\n  resourceOwners: Set<string>;\n};\n\n/**\n * Every `PlanResults` entry carries ownership-tracking fields; deriving the\n * list from `results` itself (instead of naming each key) keeps these\n * collectors in sync with `PlannedDeployment` as resource types are added.\n * @param results - Plan results for a single deployment\n * @returns The ownership-tracking plan entries\n */\nfunction ownershipTrackedPlans(results: PlanResults): ReadonlyArray<OwnershipTrackedPlan> {\n  return Object.values(results);\n}\n\nexport function collectOwnerConflicts(results: PlanResults): OwnerConflict[] {\n  return ownershipTrackedPlans(results).flatMap((plan) => plan.conflicts);\n}\n\nexport function collectUnmanagedResources(results: PlanResults): UnmanagedResource[] {\n  return ownershipTrackedPlans(results).flatMap((plan) => plan.unmanaged);\n}\n\nfunction collectResourceOwners(results: PlanResults): Set<string> {\n  return new Set(ownershipTrackedPlans(results).flatMap((plan) => [...plan.resourceOwners]));\n}\n\nexport function collectImportantResourceDeletions(\n  results: PlanResults,\n): ImportantResourceDeletion[] {\n  const importantDeletions: ImportantResourceDeletion[] = [];\n  for (const del of results.tailorDB.changeSet.type.deletes) {\n    importantDeletions.push({\n      resourceType: \"TailorDB table\",\n      resourceName: del.name,\n    });\n  }\n  for (const del of results.staticWebsite.changeSet.deletes) {\n    importantDeletions.push({\n      resourceType: \"StaticWebsite\",\n      resourceName: del.name,\n    });\n  }\n  for (const del of results.aiGateway.changeSet.deletes) {\n    importantDeletions.push({\n      resourceType: \"AIGateway\",\n      resourceName: del.name,\n    });\n  }\n  for (const del of results.auth.changeSet.oauth2Client.deletes) {\n    importantDeletions.push({\n      resourceType: \"OAuth2 client\",\n      resourceName: del.name,\n    });\n  }\n  for (const replace of results.auth.changeSet.oauth2Client.replaces) {\n    importantDeletions.push({\n      resourceType: \"OAuth2 client (client type change)\",\n      resourceName: replace.name,\n    });\n  }\n  for (const del of results.auth.changeSet.connection.deletes) {\n    importantDeletions.push({\n      resourceType: \"Auth connection\",\n      resourceName: del.name,\n    });\n  }\n  for (const del of results.secretManager.vaultChangeSet.deletes) {\n    importantDeletions.push({\n      resourceType: \"Secret Manager vault\",\n      resourceName: del.name,\n    });\n  }\n  for (const del of results.secretManager.secretChangeSet.deletes) {\n    importantDeletions.push({\n      resourceType: \"Secret Manager secret\",\n      resourceName: del.name,\n    });\n  }\n  return importantDeletions;\n}\n\ntype WorkflowJobFunctionItem = { jobFunctionName: string };\ntype ManagedResourceItem = HasName | WorkflowJobFunctionItem;\n\ntype ManagedResourceChangeSet = {\n  creates: ManagedResourceItem[];\n  updates: ManagedResourceItem[];\n  deletes: ManagedResourceItem[];\n  replaces: ManagedResourceItem[];\n  unchanged: ManagedResourceItem[];\n};\n\ntype ManagedResourceGroup = {\n  changeSet: ManagedResourceChangeSet;\n  resourceType: string;\n  namespaceFields?: readonly string[];\n  namespaceOwnerResourceType?: string;\n  getName?: (item: ManagedResourceItem) => string;\n};\n\nfunction readResourceField(item: ManagedResourceItem, field: string): string | undefined {\n  const itemRecord = item as unknown as Record<string, unknown>;\n  for (const requestField of [\"request\", \"deleteRequest\", \"createRequest\"]) {\n    const request = itemRecord[requestField];\n    if (request && typeof request === \"object\" && field in request) {\n      const value = (request as Record<string, unknown>)[field];\n      return value == null ? undefined : String(value);\n    }\n  }\n\n  const value = itemRecord[field];\n  return value == null ? undefined : String(value);\n}\n\nfunction managedResourceName(group: ManagedResourceGroup, item: ManagedResourceItem): string {\n  if (group.getName) {\n    return group.getName(item);\n  }\n  return (item as HasName).name;\n}\n\nfunction managedResourceKey(group: ManagedResourceGroup, item: ManagedResourceItem): string {\n  const namespace = group.namespaceFields\n    ?.map((field) => readResourceField(item, field))\n    .find((value) => value !== undefined);\n  const name = managedResourceName(group, item);\n  return namespace !== undefined\n    ? `${group.resourceType}:${namespace}:${name}`\n    : `${group.resourceType}:${name}`;\n}\n\nfunction managedNamespaceOwnerKey(\n  group: ManagedResourceGroup,\n  item: ManagedResourceItem,\n): string | undefined {\n  if (!group.namespaceOwnerResourceType) {\n    return undefined;\n  }\n  const namespace = group.namespaceFields\n    ?.map((field) => readResourceField(item, field))\n    .find((value) => value !== undefined);\n  return namespace !== undefined ? `${group.namespaceOwnerResourceType}:${namespace}` : undefined;\n}\n\nfunction addManagedResourceClaims(\n  claims: Set<string>,\n  group: ManagedResourceGroup,\n  item: ManagedResourceItem,\n): void {\n  claims.add(managedResourceKey(group, item));\n  const namespaceOwnerKey = managedNamespaceOwnerKey(group, item);\n  if (namespaceOwnerKey) {\n    claims.add(namespaceOwnerKey);\n  }\n}\n\nfunction isManagedResourceClaimed(\n  claims: ReadonlySet<string>,\n  group: ManagedResourceGroup,\n  item: ManagedResourceItem,\n): boolean {\n  if (claims.has(managedResourceKey(group, item))) {\n    return true;\n  }\n  const namespaceOwnerKey = managedNamespaceOwnerKey(group, item);\n  return namespaceOwnerKey ? claims.has(namespaceOwnerKey) : false;\n}\n\nfunction retainDeletesNotClaimed(\n  group: ManagedResourceGroup,\n  otherClaims: ReadonlySet<string>,\n): void {\n  let writeIndex = 0;\n  for (const item of group.changeSet.deletes) {\n    if (isManagedResourceClaimed(otherClaims, group, item)) {\n      logger.debug(\n        `Skipping delete of ${managedResourceKey(group, item)}: still managed by another config in this deploy.`,\n      );\n      continue;\n    }\n    group.changeSet.deletes[writeIndex] = item;\n    writeIndex += 1;\n  }\n  group.changeSet.deletes.length = writeIndex;\n}\n\nfunction workflowJobFunctionItems(items: ReadonlyArray<ManagedResourceItem>): HasName[] {\n  const jobNames = new Set<string>();\n  for (const item of items) {\n    const usedJobNames = (item as unknown as { usedJobNames?: unknown }).usedJobNames;\n    if (!Array.isArray(usedJobNames)) {\n      continue;\n    }\n    for (const jobName of usedJobNames) {\n      if (typeof jobName === \"string\") {\n        jobNames.add(jobName);\n      }\n    }\n  }\n  return [...jobNames].map((name) => ({ name }));\n}\n\nfunction workflowJobFunctionResourceGroup(results: PlanResults): ManagedResourceGroup {\n  return {\n    changeSet: {\n      creates: workflowJobFunctionItems(results.workflow.changeSet.creates),\n      updates: workflowJobFunctionItems(results.workflow.changeSet.updates),\n      replaces: workflowJobFunctionItems(results.workflow.changeSet.replaces),\n      unchanged: [...results.workflow.unchangedWorkflowJobNames].map((name) => ({ name })),\n      deletes: results.workflow.jobFunctionDeletes,\n    },\n    resourceType: \"workflow_job_function\",\n    getName: (item) => (\"jobFunctionName\" in item ? item.jobFunctionName : item.name),\n  };\n}\n\nconst MANAGED_RESOURCE_NAMESPACE_FIELDS = [\n  \"namespaceName\",\n  \"authNamespace\",\n  \"vaultName\",\n  \"staticWebsiteName\",\n] as const;\n\ntype DeployManagedResourceDefinition = Omit<ManagedResourceGroup, \"changeSet\"> & {\n  resourceLabel: string;\n  namesOf: (target: BuiltDeploymentTarget) => Iterable<string>;\n  changeSetOf: (results: PlanResults) => ManagedResourceChangeSet;\n};\n\nconst DEPLOY_MANAGED_RESOURCE_DEFINITIONS: ReadonlyArray<DeployManagedResourceDefinition> = [\n  {\n    resourceLabel: \"Application\",\n    resourceType: \"application\",\n    namesOf: (target) => [target.application.name],\n    changeSetOf: (results) => results.app,\n  },\n  {\n    resourceLabel: \"Executor\",\n    resourceType: \"executor\",\n    namesOf: (target) =>\n      Object.values(target.application.executorService?.executors ?? {}).map(\n        (executor) => executor.name,\n      ),\n    changeSetOf: (results) => results.executor.changeSet,\n  },\n  {\n    resourceLabel: \"Workflow job\",\n    resourceType: \"workflow_job_function\",\n    namesOf: (target) => target.bundledScripts.workflowJobs.keys(),\n    changeSetOf: (results) => workflowJobFunctionResourceGroup(results).changeSet,\n    getName: (item) => (\"jobFunctionName\" in item ? item.jobFunctionName : item.name),\n  },\n  {\n    resourceLabel: \"Workflow\",\n    resourceType: \"workflow\",\n    namesOf: (target) =>\n      Object.values(target.application.workflowService?.workflows ?? {}).map(\n        (workflow) => workflow.name,\n      ),\n    changeSetOf: (results) => results.workflow.changeSet,\n  },\n  {\n    resourceLabel: \"Workflow execution policy\",\n    resourceType: \"workflow_job_function_execution_policy\",\n    namesOf: (target) =>\n      Object.values(target.config.workflow?.executionPolicies ?? {}).map((policy) => policy.name),\n    changeSetOf: (results) => results.workflowExecutionPolicy.changeSet,\n  },\n  {\n    resourceLabel: \"Auth connection\",\n    resourceType: \"auth.connection\",\n    namespaceFields: MANAGED_RESOURCE_NAMESPACE_FIELDS,\n    namespaceOwnerResourceType: \"auth.service\",\n    namesOf: (target) => Object.keys(target.application.authService?.connections ?? {}),\n    changeSetOf: (results) => results.auth.changeSet.connection,\n  },\n  {\n    resourceLabel: \"StaticWebsite\",\n    resourceType: \"staticwebsite\",\n    namesOf: (target) => target.application.staticWebsiteServices.map((service) => service.name),\n    changeSetOf: (results) => results.staticWebsite.changeSet,\n  },\n  {\n    resourceLabel: \"TailorDB namespace\",\n    resourceType: \"tailordb.service\",\n    namesOf: (target) => target.application.tailorDBServices.map((service) => service.namespace),\n    changeSetOf: (results) => results.tailorDB.changeSet.service,\n  },\n  {\n    resourceLabel: \"Auth namespace\",\n    resourceType: \"auth.service\",\n    namesOf: (target) => {\n      const name = target.application.authService?.config.name;\n      return name === undefined ? [] : [name];\n    },\n    changeSetOf: (results) => results.auth.changeSet.service,\n  },\n  {\n    resourceLabel: \"IdP namespace\",\n    resourceType: \"idp.service\",\n    namesOf: (target) => target.application.idpServices.map((idp) => idp.name),\n    changeSetOf: (results) => results.idp.changeSet.service,\n  },\n  {\n    resourceLabel: \"Resolver namespace\",\n    resourceType: \"pipeline.service\",\n    namesOf: (target) => target.application.resolverServices.map((service) => service.namespace),\n    changeSetOf: (results) => results.pipeline.changeSet.service,\n  },\n  {\n    resourceLabel: \"AIGateway\",\n    resourceType: \"aigateway\",\n    namesOf: (target) => target.application.aiGatewayServices.map((service) => service.name),\n    changeSetOf: (results) => results.aiGateway.changeSet,\n  },\n  {\n    resourceLabel: \"Secret Manager vault\",\n    resourceType: \"secret.vault\",\n    namesOf: (target) => target.application.secrets.map((vault) => vault.vaultName),\n    changeSetOf: (results) => results.secretManager.vaultChangeSet,\n  },\n];\n\nfunction managedResourceGroupFromDefinition(\n  definition: DeployManagedResourceDefinition,\n  results: PlanResults,\n): ManagedResourceGroup {\n  const { changeSetOf, namesOf: _namesOf, resourceLabel: _resourceLabel, ...group } = definition;\n  return {\n    ...group,\n    changeSet: changeSetOf(results),\n  };\n}\n\nfunction managedResourceGroups(results: PlanResults): ManagedResourceGroup[] {\n  return [\n    { changeSet: results.functionRegistry.changeSet, resourceType: \"function_registry\" },\n    ...DEPLOY_MANAGED_RESOURCE_DEFINITIONS.map((definition) =>\n      managedResourceGroupFromDefinition(definition, results),\n    ),\n    {\n      changeSet: results.tailorDB.changeSet.type,\n      resourceType: \"tailordb.type\",\n      namespaceFields: MANAGED_RESOURCE_NAMESPACE_FIELDS,\n      namespaceOwnerResourceType: \"tailordb.service\",\n    },\n    {\n      changeSet: results.tailorDB.changeSet.gqlPermission,\n      resourceType: \"tailordb.gql_permission\",\n      namespaceFields: MANAGED_RESOURCE_NAMESPACE_FIELDS,\n      namespaceOwnerResourceType: \"tailordb.service\",\n    },\n    {\n      changeSet: results.staticWebsite.customDomainChangeSet,\n      resourceType: \"staticwebsite.custom_domain\",\n      namespaceFields: MANAGED_RESOURCE_NAMESPACE_FIELDS,\n      namespaceOwnerResourceType: \"staticwebsite\",\n    },\n    {\n      changeSet: results.idp.changeSet.client,\n      resourceType: \"idp.client\",\n      namespaceFields: MANAGED_RESOURCE_NAMESPACE_FIELDS,\n      namespaceOwnerResourceType: \"idp.service\",\n    },\n    {\n      changeSet: results.auth.changeSet.idpConfig,\n      resourceType: \"auth.idp_config\",\n      namespaceFields: MANAGED_RESOURCE_NAMESPACE_FIELDS,\n      namespaceOwnerResourceType: \"auth.service\",\n    },\n    {\n      changeSet: results.auth.changeSet.userProfileConfig,\n      resourceType: \"auth.user_profile_config\",\n      namespaceFields: MANAGED_RESOURCE_NAMESPACE_FIELDS,\n      namespaceOwnerResourceType: \"auth.service\",\n    },\n    {\n      changeSet: results.auth.changeSet.tenantConfig,\n      resourceType: \"auth.tenant_config\",\n      namespaceFields: MANAGED_RESOURCE_NAMESPACE_FIELDS,\n      namespaceOwnerResourceType: \"auth.service\",\n    },\n    {\n      changeSet: results.auth.changeSet.machineUser,\n      resourceType: \"auth.machine_user\",\n      namespaceFields: MANAGED_RESOURCE_NAMESPACE_FIELDS,\n      namespaceOwnerResourceType: \"auth.service\",\n    },\n    {\n      changeSet: results.auth.changeSet.oauth2Client,\n      resourceType: \"auth.oauth2_client\",\n      namespaceFields: MANAGED_RESOURCE_NAMESPACE_FIELDS,\n      namespaceOwnerResourceType: \"auth.service\",\n    },\n    {\n      changeSet: results.auth.changeSet.authHook,\n      resourceType: \"auth.hook\",\n      namespaceFields: MANAGED_RESOURCE_NAMESPACE_FIELDS,\n      namespaceOwnerResourceType: \"auth.service\",\n    },\n    {\n      changeSet: results.auth.changeSet.scim,\n      resourceType: \"auth.scim\",\n      namespaceFields: MANAGED_RESOURCE_NAMESPACE_FIELDS,\n      namespaceOwnerResourceType: \"auth.service\",\n    },\n    {\n      changeSet: results.auth.changeSet.scimResource,\n      resourceType: \"auth.scim_resource\",\n      namespaceFields: MANAGED_RESOURCE_NAMESPACE_FIELDS,\n      namespaceOwnerResourceType: \"auth.service\",\n    },\n    {\n      changeSet: results.pipeline.changeSet.resolver,\n      resourceType: \"pipeline.resolver\",\n      namespaceFields: MANAGED_RESOURCE_NAMESPACE_FIELDS,\n      namespaceOwnerResourceType: \"pipeline.service\",\n    },\n    {\n      changeSet: results.secretManager.secretChangeSet,\n      resourceType: \"secret.secret\",\n      namespaceFields: MANAGED_RESOURCE_NAMESPACE_FIELDS,\n      namespaceOwnerResourceType: \"secret.vault\",\n    },\n  ];\n}\n\nexport function dropCrossDeploymentManagedDeletes(\n  deployments: ReadonlyArray<PlannedDeployment>,\n): void {\n  const groupsByDeployment = deployments.map((deployment) =>\n    managedResourceGroups(deploymentPlanResults(deployment)),\n  );\n  const claimsByDeployment = groupsByDeployment.map((groups) =>\n    groups.reduce((claims, group) => {\n      for (const item of [\n        ...group.changeSet.creates,\n        ...group.changeSet.updates,\n        ...group.changeSet.replaces,\n        ...group.changeSet.unchanged,\n      ]) {\n        addManagedResourceClaims(claims, group, item);\n      }\n      return claims;\n    }, new Set<string>()),\n  );\n\n  groupsByDeployment.forEach((groups, deploymentIndex) => {\n    const otherClaims = new Set<string>();\n    claimsByDeployment.forEach((claims, claimIndex) => {\n      if (claimIndex === deploymentIndex) {\n        return;\n      }\n      for (const claim of claims) {\n        otherClaims.add(claim);\n      }\n    });\n\n    for (const group of groups) {\n      retainDeletesNotClaimed(group, otherClaims);\n    }\n  });\n}\n\nexport function collectDeploymentResourceOwners(\n  deployments: ReadonlyArray<PlannedDeployment>,\n): Set<string> {\n  const owners = new Set<string>();\n  for (const deployment of deployments) {\n    for (const owner of collectResourceOwners(deploymentPlanResults(deployment))) {\n      owners.add(owner);\n    }\n  }\n  return owners;\n}\n","import { create } from \"@bufbuild/protobuf\";\nimport { GetMetadataResponseSchema } from \"@tailor-platform/tailor-proto/metadata_pb\";\nimport { fetchAllTolerant, type OperatorClient } from \"#/cli/shared/client\";\nimport { sdkAppIdLabelKey, sdkAppIdLabelValue, sdkNameLabelKey } from \"./label\";\nimport type { Metadata } from \"@tailor-platform/tailor-proto/metadata_resource_pb\";\n\ninterface MetadataLookupApplication {\n  name: string;\n  id?: string;\n}\n\ninterface CreateMetadataLookupClientParams {\n  client: OperatorClient;\n  workspaceId: string;\n  applications: ReadonlyArray<MetadataLookupApplication>;\n}\n\nfunction ownershipFilters(\n  applications: ReadonlyArray<MetadataLookupApplication>,\n): Record<string, string>[] {\n  const filters = new Map<string, Record<string, string>>();\n  for (const application of applications) {\n    filters.set(`${sdkNameLabelKey}\\0${application.name}`, {\n      [sdkNameLabelKey]: application.name,\n    });\n    if (application.id) {\n      const value = sdkAppIdLabelValue(application.id);\n      filters.set(`${sdkAppIdLabelKey}\\0${value}`, { [sdkAppIdLabelKey]: value });\n    }\n  }\n  return [...filters.values()];\n}\n\n/**\n * Create a client that resolves metadata from app-scoped list queries first.\n * List misses still delegate to `GetMetadata` because an exact label filter\n * cannot distinguish another owner from a resource with no SDK labels.\n * @param params - Metadata lookup inputs\n * @param params.client - Operator client instance\n * @param params.workspaceId - Target workspace ID\n * @param params.applications - Applications taking part in the deploy\n * @returns Operator client with cached metadata reads\n */\nexport async function createMetadataLookupClient(\n  params: CreateMetadataLookupClientParams,\n): Promise<OperatorClient> {\n  const { client, workspaceId, applications } = params;\n  const pages = await Promise.all(\n    ownershipFilters(applications).map((labels) =>\n      fetchAllTolerant(async (pageToken, maxPageSize) => {\n        const { results, nextPageToken } = await client.listMetadata({\n          workspaceId,\n          labels,\n          pageToken,\n          pageSize: maxPageSize,\n        });\n        return [results, nextPageToken];\n      }),\n    ),\n  );\n  const metadataByTrn = new Map<string, Metadata>();\n  for (const result of pages.flat()) {\n    if (result.metadata) metadataByTrn.set(result.trn, result.metadata);\n  }\n\n  const fallbackByTrn = new Map<string, ReturnType<OperatorClient[\"getMetadata\"]>>();\n  const getMetadata: OperatorClient[\"getMetadata\"] = (request, options) => {\n    const metadata = metadataByTrn.get(request.trn ?? \"\");\n    if (metadata) {\n      return Promise.resolve(create(GetMetadataResponseSchema, { metadata }));\n    }\n    const trn = request.trn ?? \"\";\n    let fallback = fallbackByTrn.get(trn);\n    if (!fallback) {\n      fallback = client.getMetadata(request, options);\n      fallbackByTrn.set(trn, fallback);\n    }\n    return fallback;\n  };\n\n  return new Proxy(client, {\n    get(target, property, receiver) {\n      return property === \"getMetadata\" ? getMetadata : Reflect.get(target, property, receiver);\n    },\n  });\n}\n","import { formatMigrationNumber } from \"#/cli/commands/tailordb/migrate/migration-number\";\nimport { logger, styles } from \"#/cli/shared/logger\";\nimport { deploymentPlanResults, type PlannedDeployment, type PlanResults } from \"./apply-phases\";\nimport { formatAuthHookChangeEntries } from \"./auth\";\nimport {\n  formatPlanSummary,\n  summarizeChangeSets,\n  type HasName,\n  type PlanSummary,\n} from \"./change-set\";\nimport { buildPlannedExecutorsByName, formatExecutorChangeEntries } from \"./executor\";\nimport { splitFunctionRegistryChanges } from \"./function-registry\";\nimport {\n  ACTION_SYMBOLS,\n  buildGroupedDisplayLines,\n  extractServiceActions,\n  formatChangeSetEntries,\n  type GroupedDisplayEntry,\n  type NamespaceAction,\n} from \"./grouped-display\";\nimport { formatResolverChangeEntries } from \"./resolver\";\nimport { formatTailorDBResourceChangeEntries } from \"./tailordb\";\nimport { formatWorkflowChangeEntries } from \"./workflow\";\ntype PrintPlanOptions = {\n  dryRun?: boolean;\n};\n\ntype JsonPlanPayload = {\n  summary: PlanSummary;\n  changes: Array<Pick<GroupedDisplayEntry, \"action\" | \"name\" | \"labels\" | \"namespace\">>;\n  warnings: Array<{\n    type: \"unmanaged\" | \"skippedSecret\";\n    resourceType: string;\n    name: string;\n  }>;\n  conflicts: Array<{\n    resourceType: string;\n    name: string;\n    currentOwner: string;\n  }>;\n};\n\ntype PlanReport = {\n  summary: PlanSummary;\n  json: JsonPlanPayload;\n  lines: string[];\n};\n\nfunction buildPlanReport(results: PlanResults): PlanReport {\n  const executorEntries = formatExecutorChangeEntries(\n    results.executor.changeSet,\n    buildPlannedExecutorsByName(results.executor.changeSet),\n    results.functionRegistry.executorFunctionChanges,\n  );\n  const resolverEntries = formatResolverChangeEntries(\n    results.pipeline.changeSet.resolver,\n    results.functionRegistry.resolverFunctionChanges,\n  );\n  const workflowEntries = formatWorkflowChangeEntries(\n    results.workflow.changeSet,\n    results.functionRegistry.workflowJobChanges,\n  );\n  const workflowExecutionPolicyEntries = formatChangeSetEntries(\n    results.workflowExecutionPolicy.changeSet,\n    [\"executionPolicy\"],\n  );\n  const authHookEntries = formatAuthHookChangeEntries(\n    results.auth.changeSet.authHook,\n    results.functionRegistry.authHookFunctionChanges,\n  );\n  const tailorDBResourceEntries = formatTailorDBResourceChangeEntries(\n    results.tailorDB.changeSet.type,\n    results.tailorDB.changeSet.gqlPermission,\n  );\n  const checkpointRepairEntries: GroupedDisplayEntry[] =\n    results.tailorDB.context.checkpointRepairs.map((repair) => ({\n      action: \"update\",\n      symbol: ACTION_SYMBOLS.update,\n      name: `migration checkpoint ${formatMigrationNumber(repair.from)} → ${formatMigrationNumber(repair.to)}`,\n      labels: [\"migrationCheckpoint\"],\n      namespace: repair.namespace,\n    }));\n  const tailorDBEntries: GroupedDisplayEntry[] = [\n    ...tailorDBResourceEntries,\n    ...checkpointRepairEntries,\n  ];\n  const pipelineEntries: GroupedDisplayEntry[] = [...resolverEntries];\n  const namespaceOf = (item: HasName) => {\n    if (\n      \"request\" in item &&\n      item.request &&\n      typeof item.request === \"object\" &&\n      \"namespaceName\" in item.request\n    ) {\n      return item.request.namespaceName as string;\n    }\n    if (\"namespaceName\" in item) {\n      return item.namespaceName as string;\n    }\n    return undefined;\n  };\n  const authNamespaceOf = (item: HasName) =>\n    \"request\" in item &&\n    item.request &&\n    typeof item.request === \"object\" &&\n    \"authNamespace\" in item.request\n      ? (item.request.authNamespace as string)\n      : undefined;\n  const idpEntries: GroupedDisplayEntry[] = [\n    ...formatChangeSetEntries(results.idp.changeSet.client, [\"client\"], namespaceOf),\n  ];\n  const authEntries: GroupedDisplayEntry[] = [\n    ...formatChangeSetEntries(results.auth.changeSet.idpConfig, [\"idpConfig\"], namespaceOf),\n    ...formatChangeSetEntries(\n      results.auth.changeSet.userProfileConfig,\n      [\"userProfileConfig\"],\n      namespaceOf,\n    ),\n    ...formatChangeSetEntries(results.auth.changeSet.tenantConfig, [\"tenantConfig\"], namespaceOf),\n    ...formatChangeSetEntries(results.auth.changeSet.machineUser, [\"machineUser\"], authNamespaceOf),\n    ...authHookEntries,\n    ...formatChangeSetEntries(results.auth.changeSet.oauth2Client, [\"oauth2Client\"], namespaceOf),\n    ...formatChangeSetEntries(results.auth.changeSet.scim, [\"scimConfig\"], namespaceOf),\n    ...formatChangeSetEntries(results.auth.changeSet.scimResource, [\"scimResource\"], namespaceOf),\n    ...formatChangeSetEntries(results.auth.changeSet.connection, [\"connection\"], namespaceOf),\n  ];\n\n  const { otherChanges: otherFunctionRegistryChanges } = splitFunctionRegistryChanges(\n    results.functionRegistry.changeSet,\n  );\n  const tailorDBServiceActions = extractServiceActions(results.tailorDB.changeSet.service);\n  const pipelineServiceActions = extractServiceActions(results.pipeline.changeSet.service);\n  const idpServiceActions = extractServiceActions(results.idp.changeSet.service);\n  const authServiceActions = extractServiceActions(results.auth.changeSet.service);\n\n  const allDisplayEntries = [\n    ...tailorDBEntries,\n    ...pipelineEntries,\n    ...executorEntries,\n    ...workflowEntries,\n    ...workflowExecutionPolicyEntries,\n    ...idpEntries,\n    ...authEntries,\n  ];\n  const allServiceActions = [\n    ...tailorDBServiceActions,\n    ...pipelineServiceActions,\n    ...idpServiceActions,\n    ...authServiceActions,\n  ];\n  const summary = summarizePlanResults(results, allDisplayEntries, allServiceActions);\n\n  const allUnmanaged = [\n    ...results.functionRegistry.unmanaged,\n    ...results.tailorDB.unmanaged,\n    ...results.staticWebsite.unmanaged,\n    ...results.aiGateway.unmanaged,\n    ...results.idp.unmanaged,\n    ...results.auth.unmanaged,\n    ...results.pipeline.unmanaged,\n    ...results.executor.unmanaged,\n    ...results.workflow.unmanaged,\n    ...results.secretManager.unmanaged,\n  ];\n  const allConflicts = [\n    ...results.functionRegistry.conflicts,\n    ...results.tailorDB.conflicts,\n    ...results.staticWebsite.conflicts,\n    ...results.aiGateway.conflicts,\n    ...results.idp.conflicts,\n    ...results.auth.conflicts,\n    ...results.pipeline.conflicts,\n    ...results.executor.conflicts,\n    ...results.workflow.conflicts,\n    ...results.secretManager.conflicts,\n  ];\n\n  const allEntries = [\n    ...allDisplayEntries,\n    ...tailorDBServiceActions.map(({ action, name }) => ({\n      action,\n      name,\n      labels: [\"tailorDB\"],\n      namespace: undefined,\n    })),\n    ...pipelineServiceActions.map(({ action, name }) => ({\n      action,\n      name,\n      labels: [\"pipeline\"],\n      namespace: undefined,\n    })),\n    ...idpServiceActions.map(({ action, name }) => ({\n      action,\n      name,\n      labels: [\"idp\"],\n      namespace: undefined,\n    })),\n    ...authServiceActions.map(({ action, name }) => ({\n      action,\n      name,\n      labels: [\"auth\"],\n      namespace: undefined,\n    })),\n    ...formatChangeSetEntries(otherFunctionRegistryChanges),\n    ...formatChangeSetEntries(results.staticWebsite.changeSet, [\"staticWebsite\"]),\n    ...formatChangeSetEntries(results.staticWebsite.customDomainChangeSet, [\"customDomain\"]),\n    ...formatChangeSetEntries(results.aiGateway.changeSet, [\"aiGateway\"]),\n    ...formatChangeSetEntries(results.app, [\"application\"]),\n    ...formatChangeSetEntries(results.secretManager.vaultChangeSet, [\"vault\"]),\n    ...formatChangeSetEntries(results.secretManager.secretChangeSet, [\"secret\"]),\n  ];\n  const changes = allEntries.map(({ action, name, labels, namespace }) => ({\n    action,\n    name,\n    labels,\n    namespace,\n  }));\n  const warnings = [\n    ...allUnmanaged.map(({ resourceType, resourceName }) => ({\n      type: \"unmanaged\" as const,\n      resourceType,\n      name: resourceName,\n    })),\n    ...results.secretManager.skippedSecrets.map((name) => ({\n      type: \"skippedSecret\" as const,\n      resourceType: \"secret\",\n      name,\n    })),\n  ];\n  const conflicts = allConflicts.map(({ resourceType, resourceName, currentOwner }) => ({\n    resourceType,\n    name: resourceName,\n    currentOwner,\n  }));\n\n  const allLines: string[] = [\n    ...buildGroupedDisplayLines(\n      results.functionRegistry.changeSet.title,\n      formatChangeSetEntries(otherFunctionRegistryChanges),\n    ),\n    ...results.staticWebsite.changeSet.lines(),\n    ...results.staticWebsite.customDomainChangeSet.lines(),\n    ...results.aiGateway.changeSet.lines(),\n    ...results.app.lines(),\n    ...buildGroupedDisplayLines(\"TailorDB\", tailorDBEntries, tailorDBServiceActions),\n    ...buildGroupedDisplayLines(\"Resolver\", pipelineEntries, pipelineServiceActions),\n    ...buildGroupedDisplayLines(\"Executor\", executorEntries),\n    ...buildGroupedDisplayLines(\"Workflow\", workflowEntries),\n    ...buildGroupedDisplayLines(\"IdP\", idpEntries, idpServiceActions),\n    ...buildGroupedDisplayLines(\"Auth\", authEntries, authServiceActions),\n    ...results.secretManager.vaultChangeSet.lines(),\n    ...results.secretManager.secretChangeSet.lines(),\n  ];\n\n  if (allUnmanaged.length > 0) {\n    allLines.push(styles.bold(\"Unmanaged resources (not in config):\"));\n    for (const { resourceType, resourceName } of allUnmanaged) {\n      allLines.push(`  ${styles.warning(\"⚠\")} ${styles.bold(resourceType)} \"${resourceName}\"`);\n    }\n  }\n\n  if (results.secretManager.skippedSecrets.length > 0) {\n    allLines.push(styles.bold(\"Secret Manager secrets (skipped - no value provided):\"));\n    for (const name of results.secretManager.skippedSecrets) {\n      allLines.push(`  ${styles.dim(\"○\")} ${name}`);\n    }\n  }\n\n  if (allConflicts.length > 0) {\n    allLines.push(styles.bold(\"Owner conflicts (will require confirmation on apply):\"));\n    for (const { resourceType, resourceName, currentOwner } of allConflicts) {\n      allLines.push(\n        `  ${styles.warning(\"!\")} ${styles.bold(resourceType)} \"${resourceName}\" — owned by \"${currentOwner}\"`,\n      );\n    }\n  }\n\n  allLines.push(formatPlanSummary(summary));\n\n  return {\n    summary,\n    json: { summary, changes, warnings, conflicts },\n    lines: allLines,\n  };\n}\n\n/**\n * Format and output the plan results, then return a summary of change counts.\n * In JSON dry-run mode a JSON payload is written to stdout. In all other modes\n * the human-readable diff goes to stdout (dry-run) or stderr (apply).\n * @param results - Planned results across all services\n * @param opts - Output options (dry-run mode flag)\n * @returns Aggregated plan summary counts\n */\nexport function printPlanResults(results: PlanResults, opts?: PrintPlanOptions): PlanSummary {\n  const report = buildPlanReport(results);\n\n  if (logger.jsonMode && opts?.dryRun) {\n    logger.out(report.json);\n    return report.summary;\n  }\n\n  const output = report.lines.join(\"\\n\");\n  if (opts?.dryRun) {\n    logger.out(output);\n  } else {\n    logger.log(output);\n  }\n\n  return report.summary;\n}\n\n/**\n * Summarize plan counts from display entries, service actions, and non-grouped changesets.\n * @param results - Planned apply results\n * @param displayEntries - All grouped display entries across sections\n * @param serviceActions - All service-level namespace actions\n * @returns Aggregated plan summary\n */\nexport function summarizePlanResults(\n  results: PlanResults,\n  displayEntries: ReadonlyArray<GroupedDisplayEntry>,\n  serviceActions: ReadonlyArray<NamespaceAction>,\n): PlanSummary {\n  const summary: PlanSummary = { create: 0, update: 0, delete: 0, replace: 0 };\n\n  // Count grouped display entries\n  for (const entry of displayEntries) {\n    summary[entry.action] += 1;\n  }\n\n  // Count service-level actions (shown as namespace headers)\n  for (const sa of serviceActions) {\n    summary[sa.action] += 1;\n  }\n\n  // Count non-grouped changesets (staticWebsite, app, secretManager, functionRegistry other)\n  const { otherChanges } = splitFunctionRegistryChanges(results.functionRegistry.changeSet);\n  const nonGrouped = summarizeChangeSets([\n    otherChanges,\n    results.staticWebsite.changeSet,\n    results.staticWebsite.customDomainChangeSet,\n    results.aiGateway.changeSet,\n    results.app,\n    results.secretManager.vaultChangeSet,\n    results.secretManager.secretChangeSet,\n  ]);\n  summary.create += nonGrouped.create;\n  summary.update += nonGrouped.update;\n  summary.delete += nonGrouped.delete;\n  summary.replace += nonGrouped.replace;\n\n  return summary;\n}\nfunction sumPlanSummaries(summaries: ReadonlyArray<PlanSummary>): PlanSummary {\n  return summaries.reduce<PlanSummary>(\n    (acc, summary) => ({\n      create: acc.create + summary.create,\n      update: acc.update + summary.update,\n      delete: acc.delete + summary.delete,\n      replace: acc.replace + summary.replace,\n    }),\n    { create: 0, update: 0, delete: 0, replace: 0 },\n  );\n}\n\nexport function printDeploymentPlans(\n  deployments: ReadonlyArray<PlannedDeployment>,\n  opts?: PrintPlanOptions,\n): PlanSummary {\n  if (logger.jsonMode && opts?.dryRun) {\n    const reports = deployments.map((deployment) =>\n      buildPlanReport(deploymentPlanResults(deployment)),\n    );\n    const summary = sumPlanSummaries(reports.map((report) => report.summary));\n    logger.out({\n      summary,\n      changes: reports.flatMap((report) => report.json.changes),\n      warnings: reports.flatMap((report) => report.json.warnings),\n      conflicts: reports.flatMap((report) => report.json.conflicts),\n    });\n    return summary;\n  }\n\n  const summaries = deployments.map((deployment) =>\n    printPlanResults(deploymentPlanResults(deployment), opts),\n  );\n  return sumPlanSummaries(summaries);\n}\n","import { create, createRegistry, type DescMessage } from \"@bufbuild/protobuf\";\nimport { pathToString, usedTypes } from \"@bufbuild/protobuf/reflect\";\nimport { createValidator, type Validator } from \"@bufbuild/protovalidate\";\nimport {\n  CreateAIGatewayRequestSchema,\n  UpdateAIGatewayRequestSchema,\n} from \"@tailor-platform/tailor-proto/aigateway_pb\";\nimport {\n  CreateApplicationRequestSchema,\n  UpdateApplicationRequestSchema,\n} from \"@tailor-platform/tailor-proto/application_pb\";\nimport {\n  CreateAuthConnectionRequestSchema,\n  UpdateAuthConnectionRequestSchema,\n  CreateAuthHookRequestSchema,\n  CreateAuthIDPConfigRequestSchema,\n  CreateAuthMachineUserRequestSchema,\n  CreateAuthOAuth2ClientRequestSchema,\n  CreateAuthSCIMConfigRequestSchema,\n  CreateAuthSCIMResourceRequestSchema,\n  CreateAuthServiceRequestSchema,\n  CreateTenantConfigRequestSchema,\n  CreateUserProfileConfigRequestSchema,\n  UpdateAuthHookRequestSchema,\n  UpdateAuthIDPConfigRequestSchema,\n  UpdateAuthMachineUserRequestSchema,\n  UpdateAuthOAuth2ClientRequestSchema,\n  UpdateAuthSCIMConfigRequestSchema,\n  UpdateAuthSCIMResourceRequestSchema,\n  UpdateAuthServiceRequestSchema,\n  UpdateTenantConfigRequestSchema,\n  UpdateUserProfileConfigRequestSchema,\n} from \"@tailor-platform/tailor-proto/auth_pb\";\nimport {\n  CreateExecutorExecutorRequestSchema,\n  UpdateExecutorExecutorRequestSchema,\n} from \"@tailor-platform/tailor-proto/executor_pb\";\nimport {\n  CreateIdPServiceRequestSchema,\n  UpdateIdPServiceRequestSchema,\n} from \"@tailor-platform/tailor-proto/idp_pb\";\nimport {\n  CreatePipelineResolverRequestSchema,\n  CreatePipelineServiceRequestSchema,\n  UpdatePipelineResolverRequestSchema,\n  UpdatePipelineServiceRequestSchema,\n} from \"@tailor-platform/tailor-proto/pipeline_pb\";\nimport {\n  CreateSecretManagerSecretRequestSchema,\n  CreateSecretManagerVaultRequestSchema,\n  UpdateSecretManagerSecretRequestSchema,\n} from \"@tailor-platform/tailor-proto/secret_manager_pb\";\nimport {\n  AddCustomDomainRequestSchema,\n  CreateStaticWebsiteRequestSchema,\n  UpdateStaticWebsiteRequestSchema,\n} from \"@tailor-platform/tailor-proto/staticwebsite_pb\";\nimport {\n  CreateTailorDBServiceRequestSchema,\n  CreateTailorDBTypeRequestSchema,\n  UpdateTailorDBTypeRequestSchema,\n} from \"@tailor-platform/tailor-proto/tailordb_pb\";\nimport {\n  CreateWorkflowJobFunctionExecutionPolicyRequestSchema,\n  CreateWorkflowJobFunctionRequestSchema,\n  CreateWorkflowRequestSchema,\n  UpdateWorkflowJobFunctionExecutionPolicyRequestSchema,\n  UpdateWorkflowRequestSchema,\n} from \"@tailor-platform/tailor-proto/workflow_pb\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger, styles } from \"#/cli/shared/logger\";\nimport { idpClientSecretName, idpClientVaultName } from \"./idp\";\nimport { secretCreateRequest, secretUpdateRequest, vaultCreateRequest } from \"./secret-manager\";\nimport { buildWorkflowValidationShape } from \"./workflow\";\nimport { toPlatformExecutionPolicyKey } from \"./workflow-execution-policy\";\nimport type { PlannedDeployment } from \"./apply-phases\";\n\n/** Plan results passed to validatePlan. */\nexport type ValidatePlanInput = Omit<PlannedDeployment, \"application\">;\n\ntype ViolationEntry = {\n  kind: string;\n  name: string;\n  action: \"create\" | \"update\" | \"replace\";\n  fieldPath: string;\n  message: string;\n};\n\ntype HasRequest = { name: string; request: unknown };\ntype HasCreateRequest = { name: string; createRequest: unknown };\ntype HasUpdateRequest = { name: string; updateRequest: unknown };\n\ntype ValidateItemsParams<Desc extends DescMessage> = {\n  schema: Desc;\n  kind: string;\n  action: \"create\" | \"update\" | \"replace\";\n  items: ReadonlyArray<HasRequest | HasCreateRequest | HasUpdateRequest>;\n  requestKey: \"request\" | \"createRequest\" | \"updateRequest\";\n  violations: ViolationEntry[];\n};\n\nconst validators = new Map<string, Validator>();\n\n// A validator's CEL environment snapshots its registry at construction, leaving types the\n// validator discovers later unresolvable in CEL. Message-level rules that name a\n// fully-qualified enum — AuthOAuth2Client's `browser_client_cannot_require_dpop` — then fail\n// with \"unresolved attribute\", so seed each schema's registry with its transitive types.\nfunction validatorFor(schema: DescMessage): Validator {\n  const cached = validators.get(schema.typeName);\n  if (cached) {\n    return cached;\n  }\n  const validator = createValidator({ registry: createRegistry(schema, ...usedTypes(schema)) });\n  validators.set(schema.typeName, validator);\n  return validator;\n}\n\nfunction validateItems<Desc extends DescMessage>(params: ValidateItemsParams<Desc>): void {\n  const { schema, kind, action, items, requestKey, violations } = params;\n  if (items.length === 0) {\n    return;\n  }\n  const validator = validatorFor(schema);\n  for (const item of items) {\n    const init = (item as Record<string, unknown>)[requestKey];\n    const msg = create(schema, init as never);\n    const result = validator.validate(schema, msg);\n    if (result.kind === \"invalid\") {\n      for (const v of result.violations) {\n        violations.push({\n          kind,\n          name: item.name,\n          action,\n          fieldPath: v.field.length > 0 ? pathToString(v.field) : \"(message)\",\n          message: v.message,\n        });\n      }\n    } else if (result.kind === \"error\") {\n      // Evaluator failures must not block deploys; the platform stays the authoritative validator.\n      logger.warn(`Could not validate ${kind} \"${item.name}\" (${action}): ${result.error.message}`);\n    }\n  }\n}\n\n/**\n * Validate all plan-time create/update requests against buf.validate constraints embedded in the\n * generated proto descriptors.\n *\n * Collections not validated: idp client, tailorDB gqlPermission, functionRegistry — no\n * buf.validate annotations.\n * Application cors, AIGateway cors, and IdP userAuthPolicy.allowedReturnOrigins receive\n * special handling: static-website URL placeholders are resolved at apply time, so the\n * relevant origin/URL constraints would false-positive on `<name>:url` entries\n * here. Application cors and AIGateway cors are dropped entirely, forgoing their\n * per-item URL/origin constraints for the whole list rather than substituting\n * placeholders; IdP `allowedReturnOrigins` instead substitutes placeholder entries\n * with a dummy origin so the per-item regex and the cross-field `enable_mfa requires\n * ≥1 origin` rule still get exercised on the rest of the payload.\n * Workflow jobFunctions map excluded: versions are registered at apply time (registerJobFunctions)\n * and the map field carries no min_items constraint. Job names are validated separately via\n * CreateWorkflowJobFunctionRequestSchema using usedJobNames from the workflow change set.\n * auth idpConfig.config (provider oneof) is absent at plan time for BuiltInIdP but carries no\n * required constraint — the request is validated as-is from the changeset.\n *\n * @param input - Plan results from the plan phase\n */\nexport async function validatePlan(input: ValidatePlanInput): Promise<void> {\n  const {\n    tailorDB,\n    staticWebsite,\n    aiGateway,\n    idp,\n    auth,\n    pipeline,\n    app,\n    executor,\n    workflow,\n    workflowExecutionPolicy,\n    secretManager,\n  } = input;\n\n  const violations: ViolationEntry[] = [];\n\n  function creates<Desc extends DescMessage>(\n    schema: Desc,\n    kind: string,\n    items: ReadonlyArray<HasRequest>,\n  ): void {\n    validateItems({\n      schema,\n      kind,\n      action: \"create\",\n      items,\n      requestKey: \"request\",\n      violations,\n    });\n  }\n\n  function updates<Desc extends DescMessage>(\n    schema: Desc,\n    kind: string,\n    items: ReadonlyArray<HasRequest>,\n  ): void {\n    validateItems({\n      schema,\n      kind,\n      action: \"update\",\n      items,\n      requestKey: \"request\",\n      violations,\n    });\n  }\n\n  function replaces<Desc extends DescMessage>(\n    schema: Desc,\n    kind: string,\n    items: ReadonlyArray<HasCreateRequest>,\n  ): void {\n    validateItems({\n      schema,\n      kind,\n      action: \"replace\",\n      items,\n      requestKey: \"createRequest\",\n      violations,\n    });\n  }\n\n  function inPlaceReplaces<Desc extends DescMessage>(\n    schema: Desc,\n    kind: string,\n    items: ReadonlyArray<HasUpdateRequest>,\n  ): void {\n    validateItems({\n      schema,\n      kind,\n      action: \"replace\",\n      items,\n      requestKey: \"updateRequest\",\n      violations,\n    });\n  }\n\n  // TailorDB service creates (UpdateService has no request field — only metaRequest)\n  creates(\n    CreateTailorDBServiceRequestSchema,\n    \"TailorDB service\",\n    tailorDB.changeSet.service.creates as HasRequest[],\n  );\n\n  creates(\n    CreateTailorDBTypeRequestSchema,\n    \"TailorDB table\",\n    tailorDB.changeSet.type.creates as HasRequest[],\n  );\n  updates(\n    UpdateTailorDBTypeRequestSchema,\n    \"TailorDB table\",\n    tailorDB.changeSet.type.updates as HasRequest[],\n  );\n\n  creates(\n    CreateStaticWebsiteRequestSchema,\n    \"StaticWebsite\",\n    staticWebsite.changeSet.creates as HasRequest[],\n  );\n  updates(\n    UpdateStaticWebsiteRequestSchema,\n    \"StaticWebsite\",\n    staticWebsite.changeSet.updates as HasRequest[],\n  );\n  creates(\n    AddCustomDomainRequestSchema,\n    \"StaticWebsite custom domain\",\n    staticWebsite.customDomainChangeSet.creates as HasRequest[],\n  );\n\n  // cors is excluded: static-website URL placeholders are resolved at apply time.\n  creates(\n    CreateAIGatewayRequestSchema,\n    \"AIGateway\",\n    (aiGateway.changeSet.creates as HasRequest[]).map((item) => ({\n      name: item.name,\n      request: { ...(item.request as Record<string, unknown>), cors: undefined },\n    })),\n  );\n  updates(\n    UpdateAIGatewayRequestSchema,\n    \"AIGateway\",\n    (aiGateway.changeSet.updates as HasRequest[]).map((item) => ({\n      name: item.name,\n      request: { ...(item.request as Record<string, unknown>), cors: undefined },\n    })),\n  );\n\n  // userAuthPolicy.allowedReturnOrigins: static-website URL placeholders\n  // (`<name>:url`) are resolved at apply time. Substitute them with a dummy\n  // origin so the per-item origin regex passes and the cross-field\n  // `enable_mfa requires ≥1 origin` rule still sees a non-empty list; real\n  // (non-placeholder) entries pass through unchanged.\n  const placeholderOriginReplacement = \"https://placeholder.invalid\";\n  const substituteIdpReturnOrigins = (item: HasRequest): HasRequest => {\n    const request = item.request as { userAuthPolicy?: Record<string, unknown> };\n    const origins = request.userAuthPolicy?.allowedReturnOrigins;\n    if (!Array.isArray(origins) || origins.length === 0) {\n      return item;\n    }\n    // Match the parser schema's placeholder shape exactly (a static-website\n    // slug followed by `:url`, no path/query/fragment). A broader regex would\n    // mask schema-rejected inputs that should still surface here as\n    // validation errors.\n    const substituted = origins.map((origin) =>\n      typeof origin === \"string\" && /^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]:url$/.test(origin)\n        ? placeholderOriginReplacement\n        : origin,\n    );\n    return {\n      ...item,\n      request: {\n        ...request,\n        userAuthPolicy: { ...request.userAuthPolicy, allowedReturnOrigins: substituted },\n      },\n    };\n  };\n  creates(\n    CreateIdPServiceRequestSchema,\n    \"IdP service\",\n    (idp.changeSet.service.creates as HasRequest[]).map(substituteIdpReturnOrigins),\n  );\n  updates(\n    UpdateIdPServiceRequestSchema,\n    \"IdP service\",\n    (idp.changeSet.service.updates as HasRequest[]).map(substituteIdpReturnOrigins),\n  );\n\n  // Validate Secret Manager vault/secret names derived from IdP client creates and updates.\n  // The client name itself may be valid while the derived vault/secret name exceeds 63 chars.\n  const idpClientVaultItems = [\n    ...idp.changeSet.client.creates.map((c) => ({\n      clientName: c.request.client?.name ?? \"\",\n      namespaceName: c.request.namespaceName ?? \"\",\n      workspaceId: c.request.workspaceId ?? \"\",\n    })),\n    ...idp.changeSet.client.updates.map((u) => ({\n      clientName: u.name,\n      namespaceName: u.namespaceName,\n      workspaceId: u.workspaceId,\n    })),\n  ];\n  creates(\n    CreateSecretManagerVaultRequestSchema,\n    \"IdP client secret\",\n    idpClientVaultItems.map((item) => ({\n      name: item.clientName,\n      request: {\n        workspaceId: item.workspaceId,\n        secretmanagerVaultName: idpClientVaultName(item.namespaceName, item.clientName),\n      },\n    })),\n  );\n  creates(\n    CreateSecretManagerSecretRequestSchema,\n    \"IdP client secret\",\n    idpClientVaultItems.map((item) => ({\n      name: item.clientName,\n      request: {\n        workspaceId: item.workspaceId,\n        secretmanagerVaultName: idpClientVaultName(item.namespaceName, item.clientName),\n        secretmanagerSecretName: idpClientSecretName(item.namespaceName, item.clientName),\n      },\n    })),\n  );\n\n  creates(\n    CreateAuthServiceRequestSchema,\n    \"Auth service\",\n    auth.changeSet.service.creates as HasRequest[],\n  );\n  updates(\n    UpdateAuthServiceRequestSchema,\n    \"Auth service\",\n    auth.changeSet.service.updates as HasRequest[],\n  );\n\n  creates(\n    CreateAuthIDPConfigRequestSchema,\n    \"Auth IDP config\",\n    auth.changeSet.idpConfig.creates as HasRequest[],\n  );\n  updates(\n    UpdateAuthIDPConfigRequestSchema,\n    \"Auth IDP config\",\n    auth.changeSet.idpConfig.updates as HasRequest[],\n  );\n\n  creates(\n    CreateUserProfileConfigRequestSchema,\n    \"Auth user profile config\",\n    auth.changeSet.userProfileConfig.creates as HasRequest[],\n  );\n  updates(\n    UpdateUserProfileConfigRequestSchema,\n    \"Auth user profile config\",\n    auth.changeSet.userProfileConfig.updates as HasRequest[],\n  );\n\n  creates(\n    CreateTenantConfigRequestSchema,\n    \"Auth tenant config\",\n    auth.changeSet.tenantConfig.creates as HasRequest[],\n  );\n  updates(\n    UpdateTenantConfigRequestSchema,\n    \"Auth tenant config\",\n    auth.changeSet.tenantConfig.updates as HasRequest[],\n  );\n\n  creates(\n    CreateAuthMachineUserRequestSchema,\n    \"Auth machine user\",\n    auth.changeSet.machineUser.creates as HasRequest[],\n  );\n  updates(\n    UpdateAuthMachineUserRequestSchema,\n    \"Auth machine user\",\n    auth.changeSet.machineUser.updates as HasRequest[],\n  );\n\n  creates(\n    CreateAuthHookRequestSchema,\n    \"Auth hook\",\n    auth.changeSet.authHook.creates as HasRequest[],\n  );\n  updates(\n    UpdateAuthHookRequestSchema,\n    \"Auth hook\",\n    auth.changeSet.authHook.updates as HasRequest[],\n  );\n\n  creates(\n    CreateAuthSCIMConfigRequestSchema,\n    \"Auth SCIM config\",\n    auth.changeSet.scim.creates as HasRequest[],\n  );\n  updates(\n    UpdateAuthSCIMConfigRequestSchema,\n    \"Auth SCIM config\",\n    auth.changeSet.scim.updates as HasRequest[],\n  );\n\n  creates(\n    CreateAuthSCIMResourceRequestSchema,\n    \"Auth SCIM resource\",\n    auth.changeSet.scimResource.creates as HasRequest[],\n  );\n  updates(\n    UpdateAuthSCIMResourceRequestSchema,\n    \"Auth SCIM resource\",\n    auth.changeSet.scimResource.updates as HasRequest[],\n  );\n\n  creates(\n    CreateAuthOAuth2ClientRequestSchema,\n    \"OAuth2 client\",\n    auth.changeSet.oauth2Client.creates as HasRequest[],\n  );\n  updates(\n    UpdateAuthOAuth2ClientRequestSchema,\n    \"OAuth2 client\",\n    auth.changeSet.oauth2Client.updates as HasRequest[],\n  );\n  replaces(\n    CreateAuthOAuth2ClientRequestSchema,\n    \"OAuth2 client\",\n    auth.changeSet.oauth2Client.replaces as HasCreateRequest[],\n  );\n\n  creates(\n    CreatePipelineServiceRequestSchema,\n    \"Pipeline service\",\n    pipeline.changeSet.service.creates as HasRequest[],\n  );\n  updates(\n    UpdatePipelineServiceRequestSchema,\n    \"Pipeline service\",\n    pipeline.changeSet.service.updates as HasRequest[],\n  );\n  creates(\n    CreatePipelineResolverRequestSchema,\n    \"Resolver\",\n    pipeline.changeSet.resolver.creates as HasRequest[],\n  );\n  updates(\n    UpdatePipelineResolverRequestSchema,\n    \"Resolver\",\n    pipeline.changeSet.resolver.updates as HasRequest[],\n  );\n\n  creates(\n    CreateExecutorExecutorRequestSchema,\n    \"Executor\",\n    executor.changeSet.creates as HasRequest[],\n  );\n  updates(\n    UpdateExecutorExecutorRequestSchema,\n    \"Executor\",\n    executor.changeSet.updates as HasRequest[],\n  );\n\n  creates(\n    CreateWorkflowRequestSchema,\n    \"Workflow\",\n    workflow.changeSet.creates.map((item) => ({\n      name: item.name,\n      request: buildWorkflowValidationShape(item.workspaceId, item.workflow),\n    })),\n  );\n  updates(\n    UpdateWorkflowRequestSchema,\n    \"Workflow\",\n    workflow.changeSet.updates.map((item) => ({\n      name: item.name,\n      request: buildWorkflowValidationShape(item.workspaceId, item.workflow),\n    })),\n  );\n\n  // Validate job function names using the first workspace that defines them.\n  const workflowJobNameWorkspaceId =\n    workflow.changeSet.creates[0]?.workspaceId ?? workflow.changeSet.updates[0]?.workspaceId ?? \"\";\n  if (workflowJobNameWorkspaceId) {\n    const allJobNames = new Set<string>();\n    for (const item of [...workflow.changeSet.creates, ...workflow.changeSet.updates]) {\n      for (const jobName of item.usedJobNames) {\n        allJobNames.add(jobName);\n      }\n    }\n    for (const jobName of workflow.unchangedWorkflowJobNames) {\n      allJobNames.add(jobName);\n    }\n    creates(\n      CreateWorkflowJobFunctionRequestSchema,\n      \"Workflow job function\",\n      [...allJobNames].map((jobName) => ({\n        name: jobName,\n        request: {\n          workspaceId: workflowJobNameWorkspaceId,\n          jobFunctionName: jobName,\n          scriptRef: jobName,\n        },\n      })),\n    );\n  }\n\n  creates(\n    CreateWorkflowJobFunctionExecutionPolicyRequestSchema,\n    \"Workflow execution policy\",\n    // Replaces re-create the resource after deleting it (execution_policy_key is\n    // immutable), so their Create-shaped request must clear validation too.\n    [\n      ...workflowExecutionPolicy.changeSet.creates,\n      ...workflowExecutionPolicy.changeSet.replaces,\n    ].map((item) => ({\n      name: item.name,\n      request: {\n        workspaceId: item.workspaceId,\n        executionPolicyName: item.policy.name,\n        executionPolicyKey: toPlatformExecutionPolicyKey(item.policy),\n        ...(item.policy.concurrencyPolicy && {\n          concurrencyPolicy: {\n            maxConcurrentExecutions: item.policy.concurrencyPolicy.maxConcurrentExecutions,\n          },\n        }),\n      },\n    })),\n  );\n  updates(\n    UpdateWorkflowJobFunctionExecutionPolicyRequestSchema,\n    \"Workflow execution policy\",\n    workflowExecutionPolicy.changeSet.updates.map((item) => ({\n      name: item.name,\n      request: {\n        workspaceId: item.workspaceId,\n        executionPolicyName: item.policy.name,\n        ...(item.policy.concurrencyPolicy && {\n          concurrencyPolicy: {\n            maxConcurrentExecutions: item.policy.concurrencyPolicy.maxConcurrentExecutions,\n          },\n        }),\n      },\n    })),\n  );\n\n  creates(\n    CreateSecretManagerVaultRequestSchema,\n    \"Secret Manager vault\",\n    secretManager.vaultChangeSet.creates.map((item) => ({\n      name: item.name,\n      request: vaultCreateRequest(item),\n    })),\n  );\n  creates(\n    CreateSecretManagerSecretRequestSchema,\n    \"Secret Manager secret\",\n    secretManager.secretChangeSet.creates.map((item) => ({\n      name: item.name,\n      request: secretCreateRequest(item),\n    })),\n  );\n  updates(\n    UpdateSecretManagerSecretRequestSchema,\n    \"Secret Manager secret\",\n    secretManager.secretChangeSet.updates.map((item) => ({\n      name: item.name,\n      request: secretUpdateRequest(item),\n    })),\n  );\n\n  // cors is excluded: static-website URL placeholders are resolved at apply time.\n  creates(\n    CreateApplicationRequestSchema,\n    \"Application\",\n    app.creates.map((item) => ({\n      name: item.name,\n      request: { ...item.request, cors: undefined },\n    })),\n  );\n  updates(\n    UpdateApplicationRequestSchema,\n    \"Application\",\n    [...app.updates, ...app.unchanged].map((item) => ({\n      name: item.name,\n      request: { ...item.request, cors: undefined },\n    })),\n  );\n\n  creates(\n    CreateAuthConnectionRequestSchema,\n    \"Auth connection\",\n    auth.changeSet.connection.creates as HasRequest[],\n  );\n  inPlaceReplaces(\n    UpdateAuthConnectionRequestSchema,\n    \"Auth connection\",\n    auth.changeSet.connection.replaces as HasUpdateRequest[],\n  );\n\n  if (violations.length === 0) {\n    return;\n  }\n\n  const resourceNames = new Set(violations.map((v) => `${v.kind}:${v.name}`));\n  logger.error(\n    `Pre-flight validation found ${violations.length} violation(s) across ${resourceNames.size} resource(s):`,\n  );\n  for (const v of violations) {\n    logger.log(\n      `  ${styles.resourceType(v.kind)} ${styles.resourceName(v.name)} ` +\n        `(${v.action}) — ${styles.bold(v.fieldPath)}: ${v.message}`,\n    );\n  }\n\n  throw CLIError({\n    code: \"DEPLOY_VALIDATION_FAILED\",\n    message: `${violations.length} validation error(s) found in ${resourceNames.size} resource(s)`,\n  });\n}\n","import type { z } from \"zod\";\n\nexport function formatIssues(issues: z.ZodError[\"issues\"]): string {\n  return issues.map((issue) => issue.message).join(\"; \") || \"Invalid options\";\n}\n\nexport function parseOptions<Schema extends z.ZodType>(\n  schema: Schema,\n  options: z.input<Schema>,\n): z.output<Schema> {\n  const result = schema.safeParse(options);\n  if (!result.success) {\n    throw new Error(formatIssues(result.error.issues));\n  }\n  return result.data;\n}\n","import { z } from \"zod\";\n\nexport const profileNameSchema = z.string().min(1, \"Profile must not be empty\");\n","import { z } from \"zod\";\nimport { formatIssues } from \"#/cli/shared/parse-options\";\n\nconst WORKSPACE_NAME_MIN_LENGTH = 3;\nconst WORKSPACE_NAME_MAX_LENGTH = 63;\nconst WORKSPACE_NAME_ALLOWED_CHARS_DESCRIPTION = \"lowercase letters, numbers, and hyphens\";\nconst WORKSPACE_NAME_NO_LEADING_TRAILING_HYPHEN_DESCRIPTION = \"cannot start or end with a hyphen\";\n\n/**\n * Validates a workspace name against the platform's naming rules: 3-63\n * lowercase alphanumeric or hyphen characters, not starting or ending with a\n * hyphen.\n */\nexport const workspaceNameSchema = z\n  .string()\n  .min(WORKSPACE_NAME_MIN_LENGTH, `Name must be at least ${WORKSPACE_NAME_MIN_LENGTH} characters`)\n  .max(WORKSPACE_NAME_MAX_LENGTH, `Name must be at most ${WORKSPACE_NAME_MAX_LENGTH} characters`)\n  .regex(/^[a-z0-9-]+$/, `Name can only contain ${WORKSPACE_NAME_ALLOWED_CHARS_DESCRIPTION}`)\n  .refine(\n    (name) => !name.startsWith(\"-\") && !name.endsWith(\"-\"),\n    `Name ${WORKSPACE_NAME_NO_LEADING_TRAILING_HYPHEN_DESCRIPTION}`,\n  );\n\n/**\n * Validate a workspace name for use in an interactive prompt.\n * @param name - Candidate workspace name\n * @returns True when valid, otherwise a validation message\n */\nexport function validateWorkspaceName(name: string): true | string {\n  const result = workspaceNameSchema.safeParse(name);\n  return result.success ? true : formatIssues(result.error.issues);\n}\n","import { z } from \"zod\";\nimport { CLIError } from \"#/cli/shared/errors\";\n\nconst agePattern = /^(\\d+)(s|m|h|d)$/;\n\nconst ageUnitToMs = {\n  s: 1000,\n  m: 60 * 1000,\n  h: 60 * 60 * 1000,\n  d: 24 * 60 * 60 * 1000,\n} as const;\n\nexport const ageArg = z.string().regex(agePattern, {\n  message: \"Invalid duration format. Expected a number with a unit: '30m', '24h', '7d'\",\n});\n\n/**\n * Parse a validated age string into milliseconds.\n * @param age - Age string such as `30m`, `24h`, or `7d`\n * @returns Age in milliseconds\n */\nexport function parseAge(age: string): number {\n  const match = age.match(agePattern);\n  if (!match?.[1] || !match[2]) {\n    throw CLIError({\n      code: \"PRUNE_AGE_INVALID\",\n      message: `invalid age format: ${age}`,\n      command: \"workspace prune\",\n    });\n  }\n  const unit = match[2] as keyof typeof ageUnitToMs;\n  return parseInt(match[1], 10) * ageUnitToMs[unit];\n}\n","import { createApplyLimiter } from \"#/cli/shared/apply-concurrency\";\nimport { toError } from \"#/cli/shared/errors\";\nimport { writeMetadataLabelsDirect, type MetadataLabelClient } from \"../deploy/label\";\n\n/** Label key recording when a workspace becomes eligible for pruning. */\nexport const expiresAtLabelKey = \"sdk-expires-at\";\n\n// Label values are `^$|^[a-z][a-z0-9_-]{0,62}$`, so the epoch seconds carry a\n// lowercase prefix. Seconds rather than milliseconds keep the value short and\n// match the resolution `createTime` is reported at.\nconst expiresAtValuePattern = /^s-(\\d{1,15})$/;\n\n/**\n * Build the TRN naming the workspace itself.\n *\n * The `:kind:name` tail every other SDK TRN carries identifies a resource\n * inside a workspace; omitting it addresses the workspace.\n * @param workspaceId - Workspace ID\n * @returns Fully-qualified TRN string\n */\nexport function workspaceTrn(workspaceId: string): string {\n  return `trn:v1:workspace:${workspaceId}`;\n}\n\n/**\n * Encode an expiry instant as a metadata label value.\n * @param expiresAt - Instant the workspace becomes prunable\n * @returns Label value\n */\nexport function encodeExpiresAt(expiresAt: Date): string {\n  return `s-${Math.floor(expiresAt.getTime() / 1000)}`;\n}\n\n/**\n * Decode a recorded expiry label value.\n *\n * Anything this module could not have written is rejected rather than read as\n * an expiry, so a hand-written or truncated value cannot make a workspace\n * deletable.\n * @param value - Label value read back from the platform\n * @returns The recorded instant, or undefined when the value is not one\n */\nexport function decodeExpiresAt(value: string | undefined): Date | undefined {\n  const match = value?.match(expiresAtValuePattern);\n  if (!match?.[1]) return undefined;\n  const seconds = Number(match[1]);\n  if (!Number.isSafeInteger(seconds)) return undefined;\n  const expiresAt = new Date(seconds * 1000);\n  return Number.isNaN(expiresAt.getTime()) ? undefined : expiresAt;\n}\n\n/** What a workspace's own labels say about when it may be pruned. */\nexport type WorkspaceExpiry =\n  | { state: \"expired\"; expiresAt: Date }\n  | { state: \"pending\"; expiresAt: Date }\n  | { state: \"unset\" }\n  | { state: \"invalid\"; value: string };\n\n/**\n * Read a workspace's recorded expiry and compare it against a reference time.\n * @param labels - Labels stored on the workspace\n * @param now - Reference time\n * @returns The expiry state the labels describe\n */\nexport function readWorkspaceExpiry(\n  labels: Record<string, string> | undefined,\n  now: Date,\n): WorkspaceExpiry {\n  const value = labels?.[expiresAtLabelKey];\n  if (value === undefined || value === \"\") return { state: \"unset\" };\n  const expiresAt = decodeExpiresAt(value);\n  if (!expiresAt) return { state: \"invalid\", value };\n  return expiresAt.getTime() <= now.getTime()\n    ? { state: \"expired\", expiresAt }\n    : { state: \"pending\", expiresAt };\n}\n\n/**\n * Fetch one workspace's expiry state.\n *\n * A read that fails is reported as such rather than as an absent label: the\n * caller must not read a permission or transport error as \"no expiry recorded\"\n * and delete on the strength of it.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param now - Reference time\n * @returns The expiry state, or the error that prevented reading it\n */\nexport async function fetchWorkspaceExpiry(\n  client: MetadataLabelClient,\n  workspaceId: string,\n  now: Date,\n): Promise<{ expiry: WorkspaceExpiry } | { error: Error }> {\n  try {\n    const response = await client.getMetadata({ trn: workspaceTrn(workspaceId) });\n    return { expiry: readWorkspaceExpiry(response.metadata?.labels, now) };\n  } catch (error) {\n    return { error: toError(error) };\n  }\n}\n\n/**\n * Record when a workspace becomes prunable.\n *\n * Goes through the read-merge-write helper so the workspace's other labels\n * survive: `SetMetadata` replaces the whole label map.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param expiresAt - Instant the workspace becomes prunable\n */\nexport async function writeWorkspaceExpiry(\n  client: MetadataLabelClient,\n  workspaceId: string,\n  expiresAt: Date,\n): Promise<void> {\n  await writeMetadataLabelsDirect(client, {\n    trn: workspaceTrn(workspaceId),\n    labels: { [expiresAtLabelKey]: encodeExpiresAt(expiresAt) },\n  });\n}\n\n/**\n * Drop a workspace's recorded expiry, leaving its other labels in place.\n *\n * The key is removed rather than set to an empty value so nothing later reads\n * a blank expiry as a recorded one.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n */\nexport async function clearWorkspaceExpiry(\n  client: MetadataLabelClient,\n  workspaceId: string,\n): Promise<void> {\n  await writeMetadataLabelsDirect(client, {\n    trn: workspaceTrn(workspaceId),\n    remove: [expiresAtLabelKey],\n  });\n}\n\n/** How a command reports a workspace's recorded expiry. */\nexport type ReportedExpiry = string | null | \"invalid\" | \"unavailable\";\n\n/**\n * Describe an expiry state for command output.\n *\n * A state that could not be read reports as unavailable rather than as no\n * expiry, so output never implies a workspace is safe from `prune --expired`\n * when that is unknown.\n * @param result - What reading the expiry produced\n * @returns The value to report\n */\nexport function reportedExpiry(\n  result: { expiry: WorkspaceExpiry } | { error: Error },\n): ReportedExpiry {\n  if (\"error\" in result) return \"unavailable\";\n  switch (result.expiry.state) {\n    case \"unset\":\n      return null;\n    case \"invalid\":\n      return \"invalid\";\n    default:\n      return result.expiry.expiresAt.toISOString();\n  }\n}\n\n/**\n * Read the recorded expiry of each workspace, bounded by the apply limiter.\n * @param client - Operator client instance\n * @param workspaceIds - Workspace IDs to read\n * @param now - Reference time\n * @returns Reported expiry per workspace, in the order given\n */\nexport async function fetchReportedExpiries(\n  client: MetadataLabelClient,\n  workspaceIds: readonly string[],\n  now: Date,\n): Promise<ReportedExpiry[]> {\n  const limit = createApplyLimiter();\n  return Promise.all(\n    workspaceIds.map(async (workspaceId) => {\n      const result = await limit(() => fetchWorkspaceExpiry(client, workspaceId, now));\n      return reportedExpiry(result);\n    }),\n  );\n}\n","import { timestampDate } from \"@bufbuild/protobuf/wkt\";\nimport { formatDistanceToNowStrict } from \"date-fns\";\nimport { renderTable } from \"./ascii-table\";\nimport type { AsciiTableConfig } from \"./ascii-table\";\nimport type { Timestamp } from \"@bufbuild/protobuf/wkt\";\n\n/**\n * Format a protobuf Timestamp to ISO string.\n * @param timestamp - Protobuf timestamp\n * @returns Date object or null if invalid\n */\nexport function formatTimestamp(timestamp: Timestamp | undefined): Date | null {\n  if (!timestamp) {\n    return null;\n  }\n  const date = timestampDate(timestamp);\n  if (Number.isNaN(date.getTime())) {\n    return null;\n  }\n  return date;\n}\n\n/**\n * Formats a table with consistent single-line border style.\n * Use this instead of importing a table-rendering package directly.\n * @param data - Table data\n * @param config - Table configuration\n * @returns Formatted table string\n */\nexport function formatTable(data: unknown[][], config?: AsciiTableConfig): string {\n  return renderTable(data, config);\n}\n\n/**\n * Formats a key-value table with single-line border style.\n * @param data - Key-value pairs\n * @returns Formatted key-value table string\n */\nexport function formatKeyValueTable(data: [string, string][]): string {\n  return formatTable(data, { singleLine: true });\n}\n\n/**\n * Formats a table with headers, using single-line border style.\n * Draws horizontal lines only at top, after header, and bottom.\n * @param headers - Table header labels\n * @param rows - Table rows\n * @returns Formatted table string with headers\n */\nexport function formatTableWithHeaders(headers: string[], rows: string[][]): string {\n  return formatTable([headers, ...rows], {\n    drawHorizontalLine: (lineIndex, rowCount) => {\n      return lineIndex === 0 || lineIndex === 1 || lineIndex === rowCount;\n    },\n  });\n}\n\n/**\n * Format a 2D array of values into a table string.\n * @param value - Value to format\n * @returns Human-readable string representation\n */\nexport function formatValue(value: unknown): string {\n  if (value === null || value === undefined) {\n    return \"\";\n  }\n  if (Array.isArray(value)) {\n    return value.map(String).join(\"\\n\");\n  }\n  if (typeof value === \"object\") {\n    return JSON.stringify(value, null, 2);\n  }\n  return String(value);\n}\n\n/**\n * Format a Date or ISO timestamp string as a human-readable relative time.\n * @param value - Date object, ISO date string, or null\n * @returns Relative time (e.g., \"5 minutes ago\") or \"N/A\" for null/invalid\n */\nexport function humanizeRelativeTime(value: Date | string | null): string {\n  if (value === null) {\n    return \"N/A\";\n  }\n  const date = value instanceof Date ? value : new Date(value);\n  if (Number.isNaN(date.getTime())) {\n    return typeof value === \"string\" ? value : \"N/A\";\n  }\n  return formatDistanceToNowStrict(date, { addSuffix: true });\n}\n","import { Code, ConnectError } from \"@connectrpc/connect\";\nimport pLimit from \"p-limit\";\nimport { formatTimestamp } from \"#/cli/shared/format\";\nimport { logger, type FieldTransformer } from \"#/cli/shared/logger\";\nimport type { OperatorClient } from \"#/cli/shared/client\";\nimport type { Workspace } from \"@tailor-platform/tailor-proto/workspace_resource_pb\";\n\nexport interface WorkspaceInfo {\n  id: string;\n  name: string;\n  folderName?: string;\n  organizationId?: string;\n  folderId?: string;\n  region: string;\n  createdAt: Date | null;\n  updatedAt: Date | null;\n}\n\nexport interface WorkspaceDetails extends WorkspaceInfo {\n  deleteProtection: boolean;\n  organizationId: string;\n  folderId: string;\n}\n\nexport const workspaceInfo = (workspace: Workspace, folderName?: string): WorkspaceInfo => {\n  const info = {\n    id: workspace.id,\n    name: workspace.name,\n    region: workspace.region,\n    ...(workspace.organizationId ? { organizationId: workspace.organizationId } : {}),\n    ...(workspace.folderId ? { folderId: workspace.folderId } : {}),\n    createdAt: formatTimestamp(workspace.createTime),\n    updatedAt: formatTimestamp(workspace.updateTime),\n  };\n  return folderName ? { ...info, folderName } : info;\n};\n\nconst workspaceDetails = (workspace: Workspace, folderName?: string): WorkspaceDetails => {\n  return {\n    ...workspaceInfo(workspace, folderName),\n    deleteProtection: workspace.deleteProtection,\n    organizationId: workspace.organizationId,\n    folderId: workspace.folderId,\n  };\n};\n\nexport async function resolveWorkspaceFolderName(\n  client: OperatorClient,\n  workspace: Workspace,\n): Promise<string | undefined> {\n  if (!workspace.organizationId || !workspace.folderId) return undefined;\n\n  try {\n    const response = await client.getOrganizationFolder({\n      organizationId: workspace.organizationId,\n      folderId: workspace.folderId,\n    });\n\n    return response.folder?.name || undefined;\n  } catch (error) {\n    if (\n      error instanceof ConnectError &&\n      (error.code === Code.NotFound || error.code === Code.PermissionDenied)\n    ) {\n      return undefined;\n    }\n    logger.warn(`Failed to resolve workspace folder name: ${error}`);\n    return undefined;\n  }\n}\n\nfunction createWorkspaceFolderNameResolver(client: OperatorClient) {\n  const cache = new Map<string, Promise<string | undefined>>();\n\n  return (workspace: Workspace): Promise<string | undefined> => {\n    if (!workspace.organizationId || !workspace.folderId) return Promise.resolve(undefined);\n\n    const cacheKey = `${workspace.organizationId}/${workspace.folderId}`;\n    const cached = cache.get(cacheKey);\n    if (cached) return cached;\n\n    const promise = resolveWorkspaceFolderName(client, workspace);\n    cache.set(cacheKey, promise);\n    return promise;\n  };\n}\n\nexport async function workspaceInfoWithFolderName(\n  client: OperatorClient,\n  workspace: Workspace,\n): Promise<WorkspaceInfo> {\n  const folderName = await resolveWorkspaceFolderName(client, workspace);\n  return workspaceInfo(workspace, folderName);\n}\n\nexport async function workspaceDetailsWithFolderName(\n  client: OperatorClient,\n  workspace: Workspace,\n): Promise<WorkspaceDetails> {\n  const folderName = await resolveWorkspaceFolderName(client, workspace);\n  return workspaceDetails(workspace, folderName);\n}\n\nexport async function workspaceInfosWithFolderNames(\n  client: OperatorClient,\n  workspaces: Workspace[],\n): Promise<WorkspaceInfo[]> {\n  const resolveFolderName = createWorkspaceFolderNameResolver(client);\n  const limit = pLimit(5);\n  return Promise.all(\n    workspaces.map((workspace) =>\n      limit(async () => workspaceInfo(workspace, await resolveFolderName(workspace))),\n    ),\n  );\n}\n\nexport function workspaceDisplayName(workspace: Pick<WorkspaceInfo, \"name\" | \"folderName\">) {\n  return workspace.folderName ? `${workspace.folderName}/${workspace.name}` : workspace.name;\n}\n\nexport function createWorkspaceNameTransformer(\n  nameKey: string,\n  folderNameKey: string,\n): NonNullable<FieldTransformer> {\n  return (value: unknown, item: object): string => {\n    const workspace = item as Record<string, unknown>;\n    const name = workspace[nameKey];\n    const folderName = workspace[folderNameKey];\n    if (typeof name === \"string\" && typeof folderName === \"string\") {\n      return workspaceDisplayName({ name, folderName });\n    }\n    return String(value ?? \"\");\n  };\n}\n\nexport const workspaceNameTransformer = createWorkspaceNameTransformer(\"name\", \"folderName\");\n","import { timestampDate } from \"@bufbuild/protobuf/wkt\";\nimport { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { recoveryContextArgs } from \"#/cli/shared/args\";\nimport {\n  getOAuth2ClientId,\n  getPlatformBaseUrl,\n  initOperatorClient,\n  isDefaultPlatform,\n  normalizeBaseUrl,\n  type OperatorClient,\n  type PlatformClientConfig,\n} from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport {\n  loadAccessToken,\n  loadPlatformClientConfig,\n  platformConfigFromProfile,\n  readPlatformConfig,\n  resolveConfigUser,\n  writePlatformConfig,\n} from \"#/cli/shared/context\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { profileNameSchema } from \"#/cli/shared/profile-name\";\nimport { assertWritable } from \"#/cli/shared/readonly-guard\";\nimport { workspaceNameSchema } from \"#/cli/shared/workspace-name\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { ageArg, parseAge } from \"./age\";\nimport { writeWorkspaceExpiry } from \"./expiry\";\nimport {\n  workspaceDisplayName,\n  workspaceInfoWithFolderName,\n  workspaceNameTransformer,\n  type WorkspaceInfo,\n} from \"./transform\";\nimport type { ProfileInfo } from \"../profile\";\nimport type { Timestamp } from \"@bufbuild/protobuf/wkt\";\n\n/**\n * Schema for workspace creation options\n * - name: 3-63 chars, lowercase alphanumeric and hyphens, cannot start/end with hyphen\n * - organizationId, folderId: optional UUIDs\n */\n// strip unknown keys\nconst createWorkspaceOptionsSchema = z.object({\n  name: workspaceNameSchema,\n  region: z.string(),\n  deleteProtection: z.boolean().optional(),\n  organizationId: z.uuid().optional(),\n  folderId: z.uuid().optional(),\n  ttl: ageArg.optional(),\n  profile: profileNameSchema.optional(),\n});\n\nexport type CreateWorkspaceOptions = z.input<typeof createWorkspaceOptionsSchema>;\nexport type ValidatedCreateWorkspaceOptions = z.output<typeof createWorkspaceOptionsSchema>;\n\n/** A created workspace, plus how recording its prune expiry went when one was requested. */\nexport type CreatedWorkspaceInfo = WorkspaceInfo & { ttl?: TtlWriteResult };\n\nconst validateRegion = async (region: string, client: OperatorClient) => {\n  const availableRegions = await client.listAvailableWorkspaceRegions({});\n  if (!availableRegions.regions.includes(region)) {\n    throw CLIError({\n      code: \"WORKSPACE_REGION_INVALID\",\n      message: `Region must be one of: ${availableRegions.regions.join(\", \")}.`,\n      command: \"workspace create\",\n    });\n  }\n};\n\nfunction profilePlatformSettings(platformConfig?: PlatformClientConfig) {\n  const hasOAuth2ClientId =\n    platformConfig?.oauth2ClientId || process.env.TAILOR_PLATFORM_OAUTH2_CLIENT_ID;\n  // getConsoleBaseUrl() also infers a URL from platform_url and applies the\n  // TAILOR_CONSOLE_NEXT rewrite; only an explicitly configured console URL is\n  // persisted here so a new profile never bakes in a runtime-only redirect.\n  const explicitConsoleUrl = platformConfig?.consoleUrl ?? process.env.TAILOR_PLATFORM_CONSOLE_URL;\n\n  return {\n    ...(isDefaultPlatform(platformConfig)\n      ? {}\n      : { platform_url: getPlatformBaseUrl(platformConfig) }),\n    ...(hasOAuth2ClientId ? { oauth2_client_id: getOAuth2ClientId(platformConfig) } : {}),\n    ...(explicitConsoleUrl ? { console_url: normalizeBaseUrl(explicitConsoleUrl) } : {}),\n  };\n}\n\n/**\n * Create a new workspace with the given options.\n * @param options - Workspace creation options\n * @returns Created workspace info\n */\nexport async function createWorkspace(\n  options: CreateWorkspaceOptions,\n): Promise<CreatedWorkspaceInfo> {\n  const validated = validateCreateWorkspaceOptions(options);\n  const accessToken = await loadAccessToken({ profile: validated.profile });\n  const platformConfig = await loadPlatformClientConfig({ profile: validated.profile });\n  const client = await initOperatorClient(accessToken, platformConfig);\n  await validateRegion(validated.region, client);\n  return createValidatedWorkspaceWithClient(client, validated);\n}\n\n/**\n * Create a workspace after its local options and region have been validated.\n * @param client - Authenticated Operator client\n * @param options - Validated workspace creation options\n * @returns Created workspace info\n */\nexport async function createValidatedWorkspaceWithClient(\n  client: OperatorClient,\n  options: ValidatedCreateWorkspaceOptions,\n): Promise<CreatedWorkspaceInfo> {\n  // Create workspace\n  const resp = await client.createWorkspace({\n    workspaceName: options.name,\n    workspaceRegion: options.region,\n    deleteProtection: options.deleteProtection ?? false,\n    organizationId: options.organizationId,\n    folderId: options.folderId,\n  });\n\n  const workspace = assertDefined(resp.workspace, \"createWorkspace response missing workspace\");\n  const ttl =\n    options.ttl === undefined\n      ? undefined\n      : await recordTtl(client, workspace.id, options.ttl, workspace.createTime);\n\n  const info = await workspaceInfoWithFolderName(client, workspace);\n  return ttl ? { ...info, ttl } : info;\n}\n\n/** Outcome of recording a created workspace's prune expiry. */\nexport type TtlWriteResult =\n  | { state: \"written\"; expiresAt: Date }\n  | { state: \"unconfirmed\"; expiresAt: Date; requested: string; message: string };\n\n/**\n * Record when a freshly created workspace becomes prunable.\n *\n * The expiry is anchored to the platform's own `createTime` so the creating\n * machine's clock cannot shift it, and stored as an absolute instant so a\n * later change to `createTime` cannot reinterpret it. When the platform\n * reports no `createTime`, the local clock stands in.\n *\n * The workspace already exists by the time this runs, so a failure is\n * returned rather than thrown: the caller still has a workspace to report and\n * a profile to create, and its recovery step is `workspace ttl set`, not\n * creating the workspace again.\n * @param client - Authenticated Operator client\n * @param workspaceId - Created workspace ID\n * @param ttl - Duration after creation, such as `24h`\n * @param createTime - Creation time reported by the platform\n * @returns Whether the expiry is known to have been recorded\n */\nasync function recordTtl(\n  client: OperatorClient,\n  workspaceId: string,\n  ttl: string,\n  createTime: Timestamp | undefined,\n): Promise<TtlWriteResult> {\n  const createdAt = createTime ? timestampDate(createTime) : new Date();\n  const expiresAt = new Date(createdAt.getTime() + parseAge(ttl));\n  try {\n    await writeWorkspaceExpiry(client, workspaceId, expiresAt);\n    return { state: \"written\", expiresAt };\n  } catch (error) {\n    // The write may still have landed on the platform, so this reports an\n    // unconfirmed expiry rather than asserting the workspace records none.\n    return {\n      state: \"unconfirmed\",\n      expiresAt,\n      requested: ttl,\n      message: error instanceof Error ? error.message : String(error),\n    };\n  }\n}\n\n/**\n * Validate workspace creation options without making API calls.\n * @param options - Workspace creation options\n * @returns Validated workspace creation options\n */\nexport function validateCreateWorkspaceOptions(\n  options: CreateWorkspaceOptions,\n): ValidatedCreateWorkspaceOptions {\n  return parseOptions(createWorkspaceOptionsSchema, options);\n}\n\nexport { validateWorkspaceName } from \"#/cli/shared/workspace-name\";\n\nexport const createCommand = defineAppCommand({\n  name: \"create\",\n  description: \"Create a new Tailor Platform workspace.\",\n  args: z.strictObject({\n    // createWorkspace() re-applies this schema for programmatic callers; here it\n    // fails --name during option parsing, before any Platform request.\n    name: arg(workspaceNameSchema, {\n      alias: \"n\",\n      description: \"Workspace name\",\n    }),\n    region: arg(z.string(), {\n      alias: \"r\",\n      description: \"Workspace region (us-west, asia-northeast)\",\n    }),\n    \"delete-protection\": arg(z.boolean().default(false), {\n      alias: \"d\",\n      description: \"Enable delete protection\",\n    }),\n    \"organization-id\": arg(z.string().optional(), {\n      alias: \"o\",\n      description: \"Organization ID to workspace associate with\",\n      env: \"TAILOR_PLATFORM_ORGANIZATION_ID\",\n    }),\n    \"folder-id\": arg(z.string().optional(), {\n      alias: \"f\",\n      description: \"Folder ID to workspace associate with\",\n      env: \"TAILOR_PLATFORM_FOLDER_ID\",\n    }),\n    ttl: arg(ageArg.optional(), {\n      description:\n        \"Record on the workspace itself when it becomes prunable, such as 30m, 24h, or 7d. `workspace prune --expired` deletes it once that has passed\",\n    }),\n    \"profile-name\": arg(z.string().optional(), {\n      alias: \"p\",\n      description: \"Profile name to create\",\n    }),\n    profile: arg(profileNameSchema.optional(), {\n      description: \"Workspace profile used for authentication and Platform selection\",\n      env: \"TAILOR_PLATFORM_PROFILE\",\n    }),\n    \"profile-user\": arg(z.string().optional(), {\n      description:\n        \"User email address or machine user client ID for the profile (defaults to current user)\",\n    }),\n    permission: arg(z.enum([\"write\", \"read\"]).default(\"write\"), {\n      description:\n        \"Profile permission (requires --profile-name). 'read' blocks all write commands while the profile is active.\",\n    }),\n  }),\n  run: async (args) => {\n    await assertWritable({ profile: args.profile });\n    const profileName = args[\"profile-name\"];\n    let profileSetup:\n      | {\n          name: string;\n          user: string;\n          platformSettings: ReturnType<typeof profilePlatformSettings>;\n        }\n      | undefined;\n    if (profileName) {\n      const config = await readPlatformConfig();\n      if (config.profiles[profileName]) {\n        throw CLIError({\n          code: \"PROFILE_EXISTS\",\n          message: `Profile \"${profileName}\" already exists.`,\n        });\n      }\n\n      const activeProfileName = args.profile;\n      const activeProfileEntry = activeProfileName ? config.profiles[activeProfileName] : undefined;\n      const platformConfig = activeProfileEntry\n        ? platformConfigFromProfile(activeProfileEntry)\n        : undefined;\n      const profileUser = args[\"profile-user\"] || activeProfileEntry?.user || config.current_user;\n      if (!profileUser) {\n        throw CLIError({\n          code: \"USER_NOT_SET\",\n          message: \"Current user not found.\",\n          suggestion: \"Log in or specify --profile-user to create a profile.\",\n          command: \"workspace create\",\n        });\n      }\n\n      const resolvedProfileUser = resolveConfigUser(config, profileUser, platformConfig);\n      if (!resolvedProfileUser) {\n        throw CLIError({\n          code: \"USER_NOT_FOUND\",\n          message: `User \"${profileUser}\" not found.`,\n          suggestion: \"Verify the user name and log in.\",\n          next: {\n            command: \"tailor\",\n            args: [\"login\", ...recoveryContextArgs({ profile: activeProfileName })],\n          },\n        });\n      }\n      profileSetup = {\n        name: profileName,\n        user: resolvedProfileUser,\n        platformSettings: profilePlatformSettings(platformConfig),\n      };\n    }\n\n    // Execute workspace create logic\n    const workspace = await createWorkspace({\n      name: args.name,\n      region: args.region,\n      deleteProtection: args[\"delete-protection\"],\n      organizationId: args[\"organization-id\"],\n      folderId: args[\"folder-id\"],\n      ttl: args.ttl,\n      profile: args.profile,\n    });\n\n    let profileInfo: ProfileInfo | undefined;\n    if (profileSetup) {\n      const config = await readPlatformConfig();\n      const platformSettings = profileSetup.platformSettings;\n      config.profiles[profileSetup.name] = {\n        user: profileSetup.user,\n        workspace_id: workspace.id,\n        ...(args.permission === \"read\" ? { readonly: true } : {}),\n        ...platformSettings,\n      };\n      writePlatformConfig(config);\n      profileInfo = {\n        name: profileSetup.name,\n        user: profileSetup.user,\n        workspaceId: workspace.id,\n        permission: args.permission,\n        ...(platformSettings.platform_url ? { platformUrl: platformSettings.platform_url } : {}),\n        ...(platformSettings.oauth2_client_id\n          ? { oauth2ClientId: platformSettings.oauth2_client_id }\n          : {}),\n        ...(platformSettings.console_url ? { consoleUrl: platformSettings.console_url } : {}),\n      };\n\n      if (!args.json) {\n        logger.success(`Profile \"${profileSetup.name}\" created successfully.`);\n      }\n    }\n\n    const { ttl, ...workspaceOutput } = workspace;\n    if (!args.json) {\n      logger.success(`Workspace \"${workspaceDisplayName(workspace)}\" created successfully.`);\n      if (ttl?.state === \"written\") {\n        logger.info(`Workspace becomes prunable at ${ttl.expiresAt.toISOString()}.`);\n      }\n    }\n\n    if (args.json && profileInfo) {\n      logger.out({ ...workspaceOutput, profile: profileInfo });\n    } else {\n      logger.out(workspaceOutput, {\n        display: { name: workspaceNameTransformer, folderName: null },\n      });\n      if (profileInfo) {\n        logger.out(\"Profile:\");\n        logger.out(profileInfo);\n      }\n    }\n\n    if (ttl?.state === \"unconfirmed\") {\n      throw CLIError({\n        code: \"WORKSPACE_TTL_WRITE_FAILED\",\n        message: `Workspace \"${workspaceDisplayName(workspace)}\" was created, but --ttl could not be confirmed: ${ttl.message}`,\n        details:\n          \"The workspace exists. Whether it records the expiry is unknown — the write may have landed. Set the expiry again to be sure.\",\n        context: {\n          workspaceId: workspace.id,\n          requestedExpiresAt: ttl.expiresAt.toISOString(),\n          ...(profileInfo ? { profileCreated: profileInfo.name } : {}),\n        },\n        next: {\n          command: \"tailor\",\n          args: [\n            \"workspace\",\n            \"ttl\",\n            \"set\",\n            \"--ttl\",\n            ttl.requested,\n            ...recoveryContextArgs({ workspaceId: workspace.id, profile: args.profile }),\n          ],\n        },\n      });\n    }\n  },\n});\n","import { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { type Order, paginationArgs, toPageDirection } from \"#/cli/shared/args\";\nimport { fetchPaged, initOperatorClient } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadAccessToken, loadPlatformClientConfig } from \"#/cli/shared/context\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { profileNameSchema } from \"#/cli/shared/profile-name\";\nimport { fetchReportedExpiries, type ReportedExpiry } from \"./expiry\";\nimport {\n  workspaceInfosWithFolderNames,\n  workspaceNameTransformer,\n  type WorkspaceInfo,\n} from \"./transform\";\n\nexport interface ListWorkspacesOptions {\n  order?: Order;\n  limit?: number;\n  profile?: string;\n}\n\n/** A listed workspace, plus the prune expiry it records. */\nexport type WorkspaceInfoWithExpiry = WorkspaceInfo & { expiresAt: ReportedExpiry };\n\n/**\n * List workspaces with an optional order and limit.\n * @param options - Workspace listing options\n * @returns List of workspaces\n */\nexport async function listWorkspaces(options?: ListWorkspacesOptions): Promise<WorkspaceInfo[]> {\n  const profile = profileNameSchema.optional().parse(options?.profile);\n  const accessToken = await loadAccessToken({ profile });\n  const platformConfig = await loadPlatformClientConfig({ profile });\n  const client = await initOperatorClient(accessToken, platformConfig);\n  return listWorkspacesWithClient(client, options);\n}\n\n/**\n * List workspaces along with the prune expiry each one records.\n *\n * The expiries are read per workspace, so this stays out of the plain listing\n * path that deploy uses to pick a workspace.\n * @param options - Workspace listing options\n * @returns List of workspaces, each carrying its recorded expiry\n */\nexport async function listWorkspacesWithExpiry(\n  options?: ListWorkspacesOptions,\n): Promise<WorkspaceInfoWithExpiry[]> {\n  const profile = profileNameSchema.optional().parse(options?.profile);\n  const accessToken = await loadAccessToken({ profile });\n  const platformConfig = await loadPlatformClientConfig({ profile });\n  const client = await initOperatorClient(accessToken, platformConfig);\n  const workspaces = await listWorkspacesWithClient(client, options);\n  const expiries = await fetchReportedExpiries(\n    client,\n    workspaces.map(({ id }) => id),\n    new Date(),\n  );\n  return workspaces.map((workspace, index) => {\n    const expiresAt = expiries[index];\n    return { ...workspace, expiresAt: expiresAt === undefined ? \"unavailable\" : expiresAt };\n  });\n}\n\n/**\n * List workspaces using an existing Operator client.\n * @param client - Authenticated Operator client\n * @param options - Workspace listing options\n * @returns List of workspaces\n */\nexport async function listWorkspacesWithClient(\n  client: Parameters<typeof workspaceInfosWithFolderNames>[0],\n  options?: ListWorkspacesOptions,\n): Promise<WorkspaceInfo[]> {\n  const pageDirection = toPageDirection(options?.order);\n  const workspaces = await fetchPaged(\n    async (pageToken, pageSize) => {\n      const { workspaces, nextPageToken } = await client.listWorkspaces({\n        pageToken,\n        pageSize,\n        pageDirection,\n      });\n      return [workspaces, nextPageToken];\n    },\n    { limit: options?.limit },\n  );\n\n  return workspaceInfosWithFolderNames(client, workspaces);\n}\n\nexport const listCommand = defineAppCommand({\n  name: \"list\",\n  description: \"List all Tailor Platform workspaces.\",\n  args: z.strictObject({\n    ...paginationArgs(),\n    profile: arg(profileNameSchema.optional(), {\n      description: \"Workspace profile used for authentication and Platform selection\",\n      env: \"TAILOR_PLATFORM_PROFILE\",\n    }),\n  }),\n  run: async (args) => {\n    const workspaces = await listWorkspacesWithExpiry({\n      order: args.order,\n      limit: args.limit,\n      profile: args.profile,\n    });\n    logger.out(workspaces, {\n      display: {\n        name: workspaceNameTransformer,\n        folderName: null,\n        organizationId: null,\n        folderId: null,\n        updatedAt: null,\n      },\n    });\n  },\n});\n","import { randomUUID } from \"node:crypto\";\nimport { readFile, mkdir, rename, rm, writeFile } from \"node:fs/promises\";\nimport { basename, dirname, join, resolve } from \"pathe\";\nimport { z } from \"zod\";\nimport { getDistDir } from \"#/cli/shared/dist-dir\";\n\n// strip unknown keys\nconst workspaceContextSchema = z.object({\n  version: z.literal(1),\n  platformUrl: z.url(),\n  applicationId: z.string().min(1).optional(),\n  workspaceId: z.uuid(),\n});\n\nexport type WorkspaceContext = z.output<typeof workspaceContextSchema>;\n\nfunction defaultConfigPath(): string {\n  return resolve(process.cwd(), \"tailor.config.ts\");\n}\n\nfunction contextPath(configPath: string): string {\n  return join(dirname(configPath), getDistDir(), `${basename(configPath)}.context.json`);\n}\n\n/**\n * Load the project workspace context when it belongs to the current platform.\n * Missing, malformed, and cross-platform state is ignored.\n * @param platformUrl - Current Platform API base URL\n * @param configPath - Configuration file whose workspace selection is loaded\n * @param applicationId - Application identity that must match the saved context\n * @returns Valid context for the current platform, or undefined\n */\nexport async function loadWorkspaceContext(\n  platformUrl: string,\n  configPath = defaultConfigPath(),\n  applicationId?: string,\n): Promise<WorkspaceContext | undefined> {\n  let contents: string;\n  try {\n    contents = await readFile(contextPath(configPath), \"utf8\");\n  } catch (error) {\n    if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") return undefined;\n    throw error;\n  }\n\n  let value: unknown;\n  try {\n    value = JSON.parse(contents);\n  } catch {\n    return undefined;\n  }\n\n  const result = workspaceContextSchema.safeParse(value);\n  if (\n    !result.success ||\n    result.data.platformUrl !== platformUrl ||\n    (applicationId !== undefined && result.data.applicationId !== applicationId)\n  ) {\n    return undefined;\n  }\n  return result.data;\n}\n\n/**\n * Persist the selected workspace as project-local SDK state.\n * @param context - Workspace context to persist\n * @param configPath - Configuration file whose workspace selection is persisted\n * @param applicationId - Application identity stored with the workspace selection\n */\nexport async function saveWorkspaceContext(\n  context: WorkspaceContext,\n  configPath = defaultConfigPath(),\n  applicationId?: string,\n): Promise<void> {\n  const validated = workspaceContextSchema.parse({\n    ...context,\n    ...(applicationId === undefined ? {} : { applicationId }),\n  });\n  const stateDirectory = join(dirname(configPath), getDistDir());\n  const targetPath = contextPath(configPath);\n  const serialized = `${JSON.stringify(validated, null, 2)}\\n`;\n  try {\n    if ((await readFile(targetPath, \"utf8\")) === serialized) return;\n  } catch {\n    // Missing or unreadable state should still fall through to the atomic replacement attempt.\n  }\n  const temporaryPath = `${targetPath}.${process.pid}.${randomUUID()}.tmp`;\n  await mkdir(stateDirectory, { recursive: true });\n  try {\n    await writeFile(temporaryPath, serialized, { mode: 0o600 });\n    await rename(temporaryPath, targetPath);\n  } catch (error) {\n    await rm(temporaryPath, { force: true }).catch(() => undefined);\n    throw error;\n  }\n}\n","import { Code, ConnectError } from \"@connectrpc/connect\";\nimport { basename } from \"pathe\";\nimport { recoveryContextArgs } from \"#/cli/shared/args\";\nimport { getPlatformBaseUrl, initOperatorClient, type OperatorClient } from \"#/cli/shared/client\";\nimport {\n  loadAccessToken,\n  loadPlatformClientConfig,\n  tryLoadWorkspaceId,\n} from \"#/cli/shared/context\";\nimport {\n  CLIError,\n  type CLIErrorNextAction,\n  formatCopyableCommand,\n  internalError,\n} from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { canPrompt, prompt } from \"#/cli/shared/prompt\";\nimport {\n  createValidatedWorkspaceWithClient,\n  type ValidatedCreateWorkspaceOptions,\n  validateCreateWorkspaceOptions,\n  validateWorkspaceName,\n} from \"../workspace/create\";\nimport { listWorkspacesWithClient } from \"../workspace/list\";\nimport { workspaceDisplayName, workspaceInfo, type WorkspaceInfo } from \"../workspace/transform\";\nimport {\n  loadWorkspaceContext,\n  saveWorkspaceContext,\n  type WorkspaceContext,\n} from \"./workspace-context\";\n\nexport interface ResolveDeployWorkspaceOptions {\n  workspaceId?: string;\n  profile?: string;\n  createWorkspace?: boolean;\n  workspaceName?: string;\n  workspaceRegion?: string;\n  organizationId?: string;\n  folderId?: string;\n  dryRun?: boolean;\n  contextTargets?: readonly WorkspaceContextTarget[];\n  deployArgs?: readonly string[];\n  workspaceCommandArgs?: readonly string[];\n  workspaceCommandJson?: boolean;\n}\n\ninterface WorkspaceContextTarget {\n  configPath: string;\n  applicationId: string;\n}\n\nexport interface ResolvedDeployWorkspace {\n  client: OperatorClient;\n  workspaceId: string;\n}\n\nfunction suggestedWorkspaceName(): string {\n  const name = basename(process.cwd())\n    .toLowerCase()\n    .replaceAll(/[^a-z0-9-]+/g, \"-\")\n    .replaceAll(/^-+|-+$/g, \"\")\n    .slice(0, 63)\n    .replace(/-+$/, \"\");\n  return validateWorkspaceName(name) === true ? name : \"my-workspace\";\n}\n\nfunction executableAction(args: readonly string[]): CLIErrorNextAction {\n  return { command: \"tailor\", args };\n}\n\nfunction deployArgs(options: ResolveDeployWorkspaceOptions): readonly string[] {\n  return options.deployArgs ?? [\"deploy\"];\n}\n\nfunction workspaceCommandArgs(options: ResolveDeployWorkspaceOptions): readonly string[] {\n  return options.workspaceCommandArgs ?? [];\n}\n\nfunction createDeployArgs(\n  options: ResolveDeployWorkspaceOptions,\n  name: string,\n  region: string,\n): readonly string[] {\n  return [\n    ...deployArgs(options),\n    \"--create-workspace\",\n    \"--workspace-name\",\n    name,\n    \"--workspace-region\",\n    region,\n    ...(options.organizationId ? [\"--organization-id\", options.organizationId] : []),\n    ...(options.folderId ? [\"--folder-id\", options.folderId] : []),\n  ];\n}\n\nfunction selectDeployArgs(options: ResolveDeployWorkspaceOptions): readonly string[] {\n  return [...deployArgs(options), \"--workspace-id\", \"<workspace-id>\"];\n}\n\nfunction workspaceLabel(workspace: WorkspaceInfo): string {\n  const organization = workspace.organizationId ?? \"personal\";\n  return `${workspaceDisplayName(workspace)} (${workspace.region}, org: ${organization}, id: ${workspace.id})`;\n}\n\nfunction workspaceMatchesRequestedIdentity(\n  workspace: WorkspaceInfo,\n  options: ResolveDeployWorkspaceOptions,\n): boolean {\n  return (\n    options.workspaceName === workspace.name &&\n    options.workspaceRegion === workspace.region &&\n    options.organizationId === workspace.organizationId &&\n    options.folderId === workspace.folderId\n  );\n}\n\nfunction workspaceIdentity(workspace: WorkspaceInfo) {\n  const { id, name, region, organizationId, folderId } = workspace;\n  return { id, name, region, organizationId, folderId };\n}\n\nfunction projectContextTargets(\n  contextTargets?: readonly WorkspaceContextTarget[],\n): WorkspaceContextTarget[] | undefined {\n  if (!contextTargets) return undefined;\n  return [...new Map(contextTargets.map((target) => [target.configPath, target])).values()];\n}\n\nasync function loadProjectContexts(\n  platformUrl: string,\n  contextTargets?: readonly WorkspaceContextTarget[],\n): Promise<WorkspaceContext[]> {\n  const targets = projectContextTargets(contextTargets);\n  if (!targets || targets.length === 0) {\n    const context = await loadWorkspaceContext(platformUrl);\n    return context ? [context] : [];\n  }\n  const contexts = await Promise.all(\n    targets.map(({ configPath, applicationId }) =>\n      loadWorkspaceContext(platformUrl, configPath, applicationId),\n    ),\n  );\n  return contexts.filter((context): context is WorkspaceContext => context !== undefined);\n}\n\nasync function persistWorkspaceContext(\n  context: WorkspaceContext,\n  contextTargets?: readonly WorkspaceContextTarget[],\n): Promise<void> {\n  const targets = projectContextTargets(contextTargets);\n  if (!targets || targets.length === 0) {\n    await saveWorkspaceContext(context);\n    return;\n  }\n  const results = await Promise.allSettled(\n    targets.map(({ configPath, applicationId }) =>\n      saveWorkspaceContext(context, configPath, applicationId),\n    ),\n  );\n  const failures = results.filter((result) => result.status === \"rejected\");\n  if (failures.length > 0) {\n    throw CLIError({\n      code: \"WORKSPACE_CONTEXT_SAVE_FAILED\",\n      message: failures\n        .map(({ reason }) => (reason instanceof Error ? reason.message : String(reason)))\n        .join(\"; \"),\n    });\n  }\n}\n\nasync function rememberWorkspaceContext(\n  context: WorkspaceContext,\n  options: ResolveDeployWorkspaceOptions,\n  failurePolicy: \"error-on-partial\" | \"warn\" = \"error-on-partial\",\n): Promise<void> {\n  if (options.dryRun) return;\n  try {\n    await persistWorkspaceContext(context, options.contextTargets);\n  } catch (error) {\n    const contextPathCount = projectContextTargets(options.contextTargets)?.length;\n    if ((contextPathCount ?? 0) > 1 && failurePolicy === \"error-on-partial\") {\n      throw CLIError({\n        code: \"WORKSPACE_CONTEXT_SAVE_FAILED\",\n        message: \"The workspace selection could not be saved for every configuration file.\",\n        details: error instanceof Error ? error.message : String(error),\n        suggestion: \"Fix project state permissions, then rerun deploy with the workspace ID.\",\n        next: executableAction([\n          ...deployArgs(options),\n          ...recoveryContextArgs({ workspaceId: context.workspaceId }),\n        ]),\n        context: {\n          workspaceId: context.workspaceId,\n          configPaths: options.contextTargets?.map(({ configPath }) => configPath),\n        },\n      });\n    }\n    logger.warn(\n      `Could not save the project workspace selection (${error instanceof Error ? error.message : String(error)}). Continue with --workspace-id ${context.workspaceId} on later runs.`,\n    );\n  }\n}\n\nasync function useWorkspace(\n  client: OperatorClient,\n  platformUrl: string,\n  workspace: WorkspaceInfo,\n  options: ResolveDeployWorkspaceOptions,\n  failurePolicy: \"error-on-partial\" | \"warn\" = \"error-on-partial\",\n): Promise<ResolvedDeployWorkspace> {\n  await rememberWorkspaceContext(\n    {\n      version: 1,\n      platformUrl,\n      workspaceId: workspace.id,\n    },\n    options,\n    failurePolicy,\n  );\n  logger.info(`Using workspace: ${workspaceLabel(workspace)}`);\n  return { client, workspaceId: workspace.id };\n}\n\nfunction useRememberedWorkspace(\n  client: OperatorClient,\n  workspace: WorkspaceInfo,\n): ResolvedDeployWorkspace {\n  logger.warn(`Using saved workspace selection: ${workspaceLabel(workspace)}`);\n  return { client, workspaceId: workspace.id };\n}\n\nconst createNewWorkspaceSelection = \"create-new-workspace\";\n\nasync function chooseWorkspace(\n  client: OperatorClient,\n  platformUrl: string,\n  workspaces: readonly WorkspaceInfo[],\n  options: ResolveDeployWorkspaceOptions,\n): Promise<ResolvedDeployWorkspace> {\n  const workspaceId = await prompt.select({\n    message: \"Select a workspace\",\n    choices: [\n      ...workspaces.map((workspace) => ({\n        name: workspaceLabel(workspace),\n        value: workspace.id,\n      })),\n      { name: \"Create new workspace\", value: createNewWorkspaceSelection },\n    ],\n  });\n  if (workspaceId === createNewWorkspaceSelection) {\n    return createWorkspaceForDeploy(client, platformUrl, options);\n  }\n  const workspace = workspaces.find(({ id }) => id === workspaceId);\n  if (!workspace) throw internalError(\"Selected workspace was not found\");\n  return useWorkspace(client, platformUrl, workspace, options);\n}\n\nfunction invalidCreateOptionsError(\n  options: ResolveDeployWorkspaceOptions,\n  name: string,\n  region: string,\n  details: string,\n): Error {\n  return CLIError({\n    code: \"WORKSPACE_CREATE_OPTIONS_INVALID\",\n    message: \"Workspace creation options are invalid.\",\n    details,\n    suggestion: \"Correct the workspace creation options and rerun deploy.\",\n    next: executableAction(createDeployArgs(options, name, region)),\n  });\n}\n\nasync function createWorkspace(\n  client: OperatorClient,\n  platformUrl: string,\n  options: ResolveDeployWorkspaceOptions,\n  availableRegions: readonly string[],\n  validatedOptions?: ValidatedCreateWorkspaceOptions,\n): Promise<ResolvedDeployWorkspace> {\n  let name = options.workspaceName;\n  let region = options.workspaceRegion;\n  const interactive = canPrompt();\n\n  if (interactive) {\n    name ??= await prompt.text({\n      message: \"Workspace name\",\n      default: suggestedWorkspaceName(),\n      validate: validateWorkspaceName,\n    });\n    region ??= await prompt.select({\n      message: \"Workspace region\",\n      choices: availableRegions.map((value) => ({ name: value, value })),\n    });\n  } else {\n    const missingOptions = [\n      ...(name === undefined ? [\"--workspace-name\"] : []),\n      ...(region === undefined ? [\"--workspace-region\"] : []),\n    ];\n    if (missingOptions.length > 0) {\n      throw CLIError({\n        code: \"WORKSPACE_CREATE_OPTIONS_REQUIRED\",\n        message: \"Workspace creation requires a name and region in non-interactive mode.\",\n        suggestion: \"Provide every workspace creation option and rerun deploy.\",\n        next: executableAction(createDeployArgs(options, name ?? \"<name>\", region ?? \"<region>\")),\n        context: { missingOptions },\n      });\n    }\n  }\n\n  if (!name || !region) throw internalError(\"Workspace creation options were not resolved\");\n\n  let validated = validatedOptions;\n  if (!validated) {\n    try {\n      validated = validateCreateWorkspaceOptions({\n        name,\n        region,\n        organizationId: options.organizationId,\n        folderId: options.folderId,\n      });\n    } catch (error) {\n      throw invalidCreateOptionsError(\n        options,\n        name,\n        region,\n        error instanceof Error ? error.message : String(error),\n      );\n    }\n    if (!availableRegions.includes(region)) {\n      throw invalidCreateOptionsError(\n        options,\n        name,\n        region,\n        `Region must be one of: ${availableRegions.join(\", \")}.`,\n      );\n    }\n  }\n\n  if (interactive) {\n    const scope = [\n      options.organizationId ? `organization: ${options.organizationId}` : undefined,\n      options.folderId ? `folder: ${options.folderId}` : undefined,\n    ].filter((value): value is string => value !== undefined);\n    const confirmed = await prompt.confirm({\n      message: `Create workspace \"${name}\" in ${region}${scope.length > 0 ? ` (${scope.join(\", \")})` : \"\"}?`,\n      default: true,\n    });\n    if (!confirmed) {\n      throw CLIError({\n        code: \"WORKSPACE_CREATION_CANCELLED\",\n        message: \"Workspace creation was cancelled.\",\n      });\n    }\n  }\n\n  let workspace: WorkspaceInfo;\n  try {\n    workspace = await createValidatedWorkspaceWithClient(client, validated);\n  } catch (error) {\n    if (\n      error instanceof ConnectError &&\n      ![\n        Code.Canceled,\n        Code.Unknown,\n        Code.DeadlineExceeded,\n        Code.Aborted,\n        Code.Internal,\n        Code.Unavailable,\n        Code.DataLoss,\n      ].includes(error.code)\n    ) {\n      throw error;\n    }\n    throw CLIError({\n      code: \"WORKSPACE_CREATION_FAILED\",\n      message: \"Workspace creation did not complete successfully.\",\n      details: error instanceof Error ? error.message : String(error),\n      suggestion:\n        \"The outcome may be uncertain. List workspaces before retrying creation to avoid duplicates.\",\n      next: executableAction([\"workspace\", \"list\", ...workspaceCommandArgs(options), \"--json\"]),\n    });\n  }\n\n  await rememberWorkspaceContext(\n    {\n      version: 1,\n      platformUrl,\n      workspaceId: workspace.id,\n    },\n    options,\n  );\n  logger.success(`Created workspace: ${workspaceLabel(workspace)}`);\n  logger.info(\n    `Reuse this workspace with: ${formatCopyableCommand([\n      \"tailor\",\n      \"deploy\",\n      ...recoveryContextArgs({ workspaceId: workspace.id, profile: options.profile }),\n    ])}`,\n  );\n  logger.info(`Or set TAILOR_PLATFORM_WORKSPACE_ID=${workspace.id}.`);\n  return { client, workspaceId: workspace.id };\n}\n\nasync function createWorkspaceForDeploy(\n  client: OperatorClient,\n  platformUrl: string,\n  options: ResolveDeployWorkspaceOptions,\n  requestedRegions?: readonly string[],\n  validatedOptions?: ValidatedCreateWorkspaceOptions,\n): Promise<ResolvedDeployWorkspace> {\n  const regions = requestedRegions ?? (await client.listAvailableWorkspaceRegions({})).regions;\n  if (options.dryRun) {\n    throw CLIError({\n      code: \"WORKSPACE_CREATION_DISABLED_IN_DRY_RUN\",\n      message: \"Dry-run cannot create the workspace required to build a deployment plan.\",\n      suggestion:\n        \"Create a workspace explicitly, then rerun the same dry-run with its workspace ID.\",\n      context: { availableRegions: regions },\n    });\n  }\n  return createWorkspace(client, platformUrl, options, regions, validatedOptions);\n}\n\n/**\n * Resolve or provision the workspace used by deploy.\n * Explicit configuration wins over project context and account discovery.\n * @param options - Deploy workspace selection and creation options\n * @returns Authenticated client and resolved workspace ID\n */\nexport async function resolveDeployWorkspace(\n  options: ResolveDeployWorkspaceOptions = {},\n): Promise<ResolvedDeployWorkspace> {\n  const createOptionNames = [\n    options.workspaceName !== undefined ? \"--workspace-name\" : undefined,\n    options.workspaceRegion !== undefined ? \"--workspace-region\" : undefined,\n  ].filter((name): name is string => name !== undefined);\n  if (!options.createWorkspace && createOptionNames.length > 0) {\n    throw CLIError({\n      code: \"WORKSPACE_CREATE_FLAG_REQUIRED\",\n      message: \"Workspace creation options require --create-workspace.\",\n      suggestion: \"Add --create-workspace or remove the workspace creation options.\",\n      next: executableAction(\n        createDeployArgs(\n          options,\n          options.workspaceName ?? \"<name>\",\n          options.workspaceRegion ?? \"<region>\",\n        ),\n      ),\n      context: { options: createOptionNames },\n    });\n  }\n  if (options.createWorkspace && options.workspaceName !== undefined) {\n    const nameValidation = validateWorkspaceName(options.workspaceName);\n    if (nameValidation !== true) {\n      throw invalidCreateOptionsError(\n        options,\n        options.workspaceName,\n        options.workspaceRegion ?? \"<region>\",\n        nameValidation,\n      );\n    }\n  }\n  if (options.createWorkspace && options.workspaceRegion === \"\") {\n    throw invalidCreateOptionsError(\n      options,\n      options.workspaceName ?? \"<name>\",\n      options.workspaceRegion,\n      \"Region must not be empty.\",\n    );\n  }\n\n  const explicitWorkspaceId = await tryLoadWorkspaceId({\n    workspaceId: options.workspaceId,\n    profile: options.profile,\n  });\n  const accessToken = await loadAccessToken({ profile: options.profile });\n  const platformConfig = await loadPlatformClientConfig({\n    profile: options.profile,\n    allowMissingProfile: explicitWorkspaceId !== undefined,\n  });\n  const platformUrl = getPlatformBaseUrl(platformConfig);\n  const client = await initOperatorClient(accessToken, platformConfig);\n\n  if (explicitWorkspaceId) {\n    let response;\n    try {\n      response = await client.getWorkspace({ workspaceId: explicitWorkspaceId });\n    } catch (error) {\n      if (error instanceof ConnectError && error.code === Code.NotFound) {\n        throw CLIError({\n          code: \"WORKSPACE_NOT_FOUND\",\n          message: `Workspace \"${explicitWorkspaceId}\" was not found.`,\n        });\n      }\n      throw error;\n    }\n    if (!response.workspace) {\n      throw CLIError({\n        code: \"WORKSPACE_NOT_FOUND\",\n        message: `Workspace \"${explicitWorkspaceId}\" was not found.`,\n      });\n    }\n    return useWorkspace(client, platformUrl, workspaceInfo(response.workspace), options, \"warn\");\n  }\n\n  let requestedCreateOptions;\n  if (\n    options.createWorkspace &&\n    options.workspaceName !== undefined &&\n    options.workspaceRegion !== undefined\n  ) {\n    try {\n      requestedCreateOptions = validateCreateWorkspaceOptions({\n        name: options.workspaceName,\n        region: options.workspaceRegion,\n        organizationId: options.organizationId,\n        folderId: options.folderId,\n      });\n    } catch (error) {\n      throw invalidCreateOptionsError(\n        options,\n        options.workspaceName,\n        options.workspaceRegion,\n        error instanceof Error ? error.message : String(error),\n      );\n    }\n  }\n\n  const [contexts, workspaces] = await Promise.all([\n    loadProjectContexts(platformUrl, options.contextTargets),\n    listWorkspacesWithClient(client),\n  ]);\n  const interactive = canPrompt();\n\n  const contextWorkspaceIds = new Set(contexts.map(({ workspaceId }) => workspaceId));\n  const linkedWorkspace =\n    contextWorkspaceIds.size === 1\n      ? workspaces.find(({ id }) => contextWorkspaceIds.has(id))\n      : undefined;\n  if (\n    linkedWorkspace &&\n    (!options.createWorkspace || workspaceMatchesRequestedIdentity(linkedWorkspace, options))\n  ) {\n    const contextTargetCount = projectContextTargets(options.contextTargets)?.length ?? 1;\n    return contexts.length === contextTargetCount\n      ? useRememberedWorkspace(client, linkedWorkspace)\n      : useWorkspace(client, platformUrl, linkedWorkspace, options);\n  }\n\n  const onlyWorkspace = workspaces.length === 1 ? workspaces[0] : undefined;\n  const canReuseOnlyWorkspace =\n    onlyWorkspace !== undefined &&\n    requestedCreateOptions !== undefined &&\n    workspaceMatchesRequestedIdentity(onlyWorkspace, options);\n  let requestedRegions: { regions: readonly string[] } | undefined;\n  if (requestedCreateOptions && !canReuseOnlyWorkspace) {\n    requestedRegions = await client.listAvailableWorkspaceRegions({});\n    if (!requestedRegions.regions.includes(requestedCreateOptions.region)) {\n      throw invalidCreateOptionsError(\n        options,\n        requestedCreateOptions.name,\n        requestedCreateOptions.region,\n        `Region must be one of: ${requestedRegions.regions.join(\", \")}.`,\n      );\n    }\n  }\n\n  if (\n    workspaces.length === 0 &&\n    (interactive || options.createWorkspace || contexts.length === 0)\n  ) {\n    const regions =\n      requestedRegions?.regions ?? (await client.listAvailableWorkspaceRegions({})).regions;\n    if (options.dryRun || interactive || options.createWorkspace) {\n      return createWorkspaceForDeploy(\n        client,\n        platformUrl,\n        options,\n        regions,\n        requestedCreateOptions,\n      );\n    }\n\n    throw CLIError({\n      code: \"WORKSPACE_NOT_FOUND\",\n      message: \"No workspaces are available for this account.\",\n      suggestion:\n        \"Create one during deploy by providing the workspace name and one of the available regions.\",\n      next: executableAction(createDeployArgs(options, \"<name>\", \"<region>\")),\n      context: { availableRegions: regions },\n    });\n  }\n\n  if (contextWorkspaceIds.size > 1) {\n    const canReplaceStaleContexts =\n      options.createWorkspace === true &&\n      options.workspaceName !== undefined &&\n      options.workspaceRegion !== undefined &&\n      workspaces.length === 0;\n    if (!interactive && !canReplaceStaleContexts) {\n      throw CLIError({\n        code: \"WORKSPACE_CONTEXT_CONFLICT\",\n        message: \"The deployed configuration files are linked to different workspaces.\",\n        suggestion: \"Choose one workspace explicitly for the combined deployment.\",\n        next: executableAction(selectDeployArgs(options)),\n        context: { savedWorkspaceIds: [...contextWorkspaceIds] },\n      });\n    }\n    if (workspaces.length > 0 && !options.createWorkspace) {\n      return chooseWorkspace(client, platformUrl, workspaces, options);\n    }\n  }\n\n  if (!linkedWorkspace && contexts.length > 0) {\n    const explicitlyEnsuringSingleTarget =\n      options.createWorkspace === true &&\n      options.workspaceName !== undefined &&\n      options.workspaceRegion !== undefined &&\n      workspaces.length <= 1;\n    if (!interactive && !explicitlyEnsuringSingleTarget) {\n      throw CLIError({\n        code: \"WORKSPACE_CONTEXT_STALE\",\n        message: \"The saved project workspace is no longer available.\",\n        suggestion: \"Choose an available workspace explicitly before deploying.\",\n        next: executableAction(selectDeployArgs(options)),\n        context: {\n          savedWorkspaceIds: [...contextWorkspaceIds],\n          workspaces: workspaces.map(workspaceIdentity),\n        },\n      });\n    }\n    if (workspaces.length > 0 && interactive && !options.createWorkspace) {\n      return chooseWorkspace(client, platformUrl, workspaces, options);\n    }\n  }\n\n  if (workspaces.length === 1) {\n    const [workspace] = workspaces;\n    if (!workspace) throw internalError(\"Workspace discovery returned an invalid result\");\n\n    if (options.createWorkspace && !workspaceMatchesRequestedIdentity(workspace, options)) {\n      throw CLIError({\n        code: \"WORKSPACE_CREATE_CONFLICT\",\n        message: \"The existing workspace does not match the requested workspace.\",\n        suggestion:\n          \"Use the existing workspace, or run the explicit workspace create command to create another one.\",\n        next: executableAction([\n          \"workspace\",\n          \"create\",\n          ...workspaceCommandArgs(options),\n          ...(options.workspaceCommandJson ? [\"--json\"] : []),\n          \"--name\",\n          options.workspaceName ?? \"<name>\",\n          \"--region\",\n          options.workspaceRegion ?? \"<region>\",\n          ...(options.organizationId ? [\"--organization-id\", options.organizationId] : []),\n          ...(options.folderId ? [\"--folder-id\", options.folderId] : []),\n        ]),\n        context: {\n          existingWorkspace: workspaceIdentity(workspace),\n        },\n      });\n    }\n\n    if (interactive && !options.createWorkspace) {\n      return chooseWorkspace(client, platformUrl, workspaces, options);\n    }\n\n    return useWorkspace(client, platformUrl, workspace, options);\n  }\n\n  if (workspaces.length > 1) {\n    if (!interactive) {\n      throw CLIError({\n        code: \"WORKSPACE_SELECTION_REQUIRED\",\n        message: \"Multiple workspaces are available.\",\n        suggestion: \"Choose one explicitly for non-interactive deployment.\",\n        next: executableAction(selectDeployArgs(options)),\n        context: {\n          workspaces: workspaces.map(workspaceIdentity),\n        },\n      });\n    }\n\n    return chooseWorkspace(client, platformUrl, workspaces, options);\n  }\n\n  throw internalError(\"Workspace discovery returned an invalid result\");\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"pathe\";\nimport { type Application } from \"#/cli/services/application\";\nimport { assertUniqueTailorDBTypeNamesWithExternal } from \"#/cli/services/tailordb/type-name-validation\";\nimport { recoveryContextArgs } from \"#/cli/shared/args\";\nimport { getOrNull, type OperatorClient } from \"#/cli/shared/client\";\nimport { getDistDir } from \"#/cli/shared/dist-dir\";\nimport { CLIError, internalError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { readPackageJson } from \"#/cli/shared/package-json\";\nimport { parseBoolean } from \"#/cli/shared/parse-boolean\";\nimport { beginUserModuleRun } from \"#/cli/shared/user-modules\";\nimport { withSpan } from \"#/cli/telemetry/index\";\nimport { beginWaitPointScope } from \"#/utils/wait-point-registry\";\nimport { planAIGateway } from \"./aigateway\";\nimport { planApplication } from \"./application\";\nimport {\n  applyDeploymentPlans,\n  deploymentPlanResults,\n  type PlannedDeployment,\n} from \"./apply-phases\";\nimport { planAuth } from \"./auth\";\nimport { mergeBundledScripts } from \"./bundled-scripts\";\nimport {\n  confirmImportantResourceDeletion,\n  confirmMigrationCheckpointRepairs,\n  confirmMissingDependentApps,\n  confirmOwnerConflict,\n  confirmUnmanagedResources,\n  type ImportantResourceDeletion,\n  type MissingDependentApp,\n} from \"./confirm\";\nimport { fetchMissingDependentApps } from \"./dependency-records\";\nimport {\n  buildDeploymentTargets,\n  loadDeployConfigs,\n  parseDeployConfigPaths,\n  type BuiltDeploymentTarget,\n} from \"./deployment-target\";\nimport {\n  assertRecordableDependencies,\n  collectDependentApps,\n  collectEventSubscriptions,\n  collectWorkflowJobPublishEvents,\n  ownedSubscriptions,\n  subscribedIdps,\n  subscribedResolvers,\n  subscribedResourceKeys,\n  subscribedTailorDBTables,\n  subscribedWorkflows,\n  type EventSubscription,\n} from \"./event-subscriptions\";\nimport { planExecutor } from \"./executor\";\nimport {\n  collectFunctionEntries,\n  filterBundledWorkflowJobs,\n  planFunctionRegistry,\n  WORKFLOW_PREFIX,\n} from \"./function-registry\";\nimport { planIdP } from \"./idp\";\nimport { buildMetaRequest, hasMatchingSdkVersion, resourceTrn, sdkNameLabelKey } from \"./label\";\nimport {\n  assertUniqueGlobalResourceNames,\n  collectDeploymentResourceOwners,\n  collectImportantResourceDeletions,\n  collectOwnerConflicts,\n  collectUnmanagedResources,\n  computeRenamedAppDeletions,\n  dropCrossDeploymentManagedDeletes,\n} from \"./managed-resources\";\nimport { createMetadataLookupClient } from \"./metadata-lookup\";\nimport { printDeploymentPlans } from \"./plan-report\";\nimport { planPipeline } from \"./resolver\";\nimport { planSecretManager } from \"./secret-manager\";\nimport { planStaticWebsite } from \"./staticwebsite\";\nimport { planTailorDB } from \"./tailordb\";\nimport { validatePlan } from \"./validate-plan\";\nimport {\n  collectVisibleIdpNames,\n  collectVisibleResolverNamespaces,\n  collectVisibleTailorDBTypeNamespaces,\n} from \"./visible-resources\";\nimport { planWorkflow } from \"./workflow\";\nimport { planWorkflowJobFunctionExecutionPolicy } from \"./workflow-execution-policy\";\nimport { resolveDeployWorkspace } from \"./workspace\";\nimport type {\n  PlanContext,\n  TailorDBMigrationTestBaseline,\n  TailorDBMigrationTestSnapshots,\n} from \"./types\";\n\nexport interface DeployOptions {\n  workspaceId?: string;\n  profile?: string;\n  configPath?: string;\n  dryRun?: boolean;\n  yes?: boolean;\n  noSchemaCheck?: boolean;\n  noValidate?: boolean;\n  noCache?: boolean;\n  cleanCache?: boolean;\n  createWorkspace?: boolean;\n  workspaceName?: string;\n  workspaceRegion?: string;\n  organizationId?: string;\n  folderId?: string;\n  // NOTE(remiposo): Provide an option to run build-only for testing purposes.\n  // This could potentially be exposed as a CLI option.\n  buildOnly?: boolean;\n}\n\ninterface DeployCLIContext {\n  envFile?: string;\n  envFileIfExists?: string;\n  verbose?: boolean;\n  json?: boolean;\n}\n\ninterface DeployInternalContext {\n  migrationTestBaselines?: ReadonlyMap<string, TailorDBMigrationTestBaseline>;\n  migrationTestSnapshots?: TailorDBMigrationTestSnapshots;\n  suppressResultOutput?: boolean;\n}\n\nfunction collectExpectedLocalStaticWebsiteNames(\n  targets: ReadonlyArray<BuiltDeploymentTarget>,\n): ReadonlySet<string> {\n  const websiteNames = new Set<string>();\n  for (const target of targets) {\n    for (const website of target.application.staticWebsiteServices) {\n      websiteNames.add(website.name);\n    }\n  }\n  return websiteNames;\n}\n\n/**\n * Detect whether any resource owned by this application was last applied by a\n * different SDK version, in which case every resource is re-applied.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param application - Application being deployed\n * @param functionEntries - Function registry entries of the application\n * @returns True when an owned resource carries a different sdk-version label\n */\nexport async function shouldForceApplyAll(\n  client: OperatorClient,\n  workspaceId: string,\n  application: Readonly<Application>,\n  functionEntries: ReadonlyArray<{ name: string }>,\n) {\n  const desiredLabels = (\n    await buildMetaRequest({\n      trn: resourceTrn(workspaceId, \"application\", application.name),\n      appName: application.name,\n      appId: application.id,\n    })\n  ).labels;\n  const candidateTrns = new Set<string>();\n\n  if (application.subgraphs.length > 0) {\n    candidateTrns.add(resourceTrn(workspaceId, \"application\", application.name));\n  }\n  application.staticWebsiteServices.forEach((website) => {\n    candidateTrns.add(resourceTrn(workspaceId, \"staticwebsite\", website.name));\n  });\n  application.aiGatewayServices.forEach((gateway) => {\n    candidateTrns.add(resourceTrn(workspaceId, \"aigateway\", gateway.name));\n  });\n  application.resolverServices.forEach((pipeline) => {\n    candidateTrns.add(resourceTrn(workspaceId, \"pipeline\", pipeline.namespace));\n  });\n  application.idpServices.forEach((idp) => {\n    candidateTrns.add(resourceTrn(workspaceId, \"idp\", idp.name));\n  });\n  if (application.authService) {\n    candidateTrns.add(resourceTrn(workspaceId, \"auth\", application.authService.config.name));\n  }\n  Object.values(application.executorService?.executors ?? {}).forEach((executor) => {\n    candidateTrns.add(resourceTrn(workspaceId, \"executor\", executor.name));\n  });\n  Object.values(application.workflowService?.workflows ?? {}).forEach((workflow) => {\n    candidateTrns.add(resourceTrn(workspaceId, \"workflow\", workflow.name));\n  });\n  application.tailorDBServices.forEach((service) => {\n    candidateTrns.add(resourceTrn(workspaceId, \"tailordb\", service.namespace));\n  });\n  application.secrets.forEach((vault) => {\n    candidateTrns.add(resourceTrn(workspaceId, \"vault\", vault.vaultName));\n  });\n  functionEntries.forEach((entry) => {\n    candidateTrns.add(resourceTrn(workspaceId, \"function_registry\", entry.name));\n  });\n\n  const results = await Promise.allSettled(\n    [...candidateTrns].map((trn) =>\n      getOrNull(async () => {\n        const { metadata } = await client.getMetadata({ trn });\n        return metadata;\n      }),\n    ),\n  );\n\n  const hasMismatch = results.some(\n    (result) =>\n      result.status === \"fulfilled\" &&\n      result.value?.labels[sdkNameLabelKey] === application.name &&\n      !hasMatchingSdkVersion(result.value.labels, desiredLabels),\n  );\n  if (hasMismatch) {\n    return true;\n  }\n  const failure = results.find((result) => result.status === \"rejected\");\n  if (failure) {\n    throw failure.reason;\n  }\n  return false;\n}\n\ntype DeployRunPlanInputs = Pick<\n  PlanContext,\n  \"expectedLocalStaticWebsiteNames\" | \"externalAuthIdpConfigNames\" | \"runAppIds\"\n> & {\n  /** Every event subscription in the run, resolved to its declaring config. */\n  eventSubscriptions: ReadonlyArray<EventSubscription>;\n};\n\ntype PlanDeploymentTargetParams = {\n  target: BuiltDeploymentTarget;\n  targets: ReadonlyArray<BuiltDeploymentTarget>;\n  runInputs: DeployRunPlanInputs;\n  client: OperatorClient;\n  workspaceId: string;\n  noSchemaCheck: boolean | undefined;\n  migrationTestBaselines?: ReadonlyMap<string, TailorDBMigrationTestBaseline>;\n  migrationTestSnapshots?: TailorDBMigrationTestSnapshots;\n};\n\ntype ConfirmDeploymentPlansParams = {\n  deployments: PlannedDeployment[];\n  yes: boolean;\n  dryRun?: boolean;\n  /** Applications recorded as dependencies but absent from this deploy. */\n  missingDependentApps?: MissingDependentApp[];\n};\n\ntype PlanDeploymentTargetsParams = {\n  targets: ReadonlyArray<BuiltDeploymentTarget>;\n  runInputs: DeployRunPlanInputs;\n  client: OperatorClient;\n  workspaceId: string;\n  noSchemaCheck: boolean | undefined;\n  migrationTestBaselines?: ReadonlyMap<string, TailorDBMigrationTestBaseline>;\n  migrationTestSnapshots?: TailorDBMigrationTestSnapshots;\n  planTarget?: (params: PlanDeploymentTargetParams) => Promise<PlannedDeployment>;\n};\n\nfunction recoveryEnvironmentArgs(\n  options: DeployOptions | undefined,\n  cliContext?: DeployCLIContext,\n): readonly string[] {\n  return [\n    ...(cliContext?.envFile ? [\"--env-file\", path.resolve(process.cwd(), cliContext.envFile)] : []),\n    ...(cliContext?.envFileIfExists\n      ? [\"--env-file-if-exists\", path.resolve(process.cwd(), cliContext.envFileIfExists)]\n      : []),\n    ...recoveryContextArgs({ profile: options?.profile }),\n  ];\n}\n\nfunction recoveryOutputArgs(cliContext?: DeployCLIContext): readonly string[] {\n  return [\n    ...(cliContext?.verbose ? [\"--verbose\"] : []),\n    ...(cliContext?.json || logger.jsonMode ? [\"--json\"] : []),\n  ];\n}\n\nfunction retryDeployArgs(\n  options: DeployOptions | undefined,\n  configPaths: readonly string[],\n  cliContext?: DeployCLIContext,\n): readonly string[] {\n  return [\n    \"deploy\",\n    \"--config\",\n    configPaths.join(\",\"),\n    ...recoveryEnvironmentArgs(options, cliContext),\n    ...(options?.dryRun ? [\"--dry-run\"] : []),\n    ...(options?.yes ? [\"--yes\"] : []),\n    ...(options?.noSchemaCheck ? [\"--no-schema-check\"] : []),\n    ...(options?.noValidate ? [\"--no-validate\"] : []),\n    ...(options?.noCache ? [\"--no-cache\"] : []),\n    ...(options?.cleanCache ? [\"--clean-cache\"] : []),\n    ...recoveryOutputArgs(cliContext),\n  ];\n}\n\nfunction workspaceRecoveryArgs(\n  options: DeployOptions | undefined,\n  cliContext?: DeployCLIContext,\n): readonly string[] {\n  return [\n    ...recoveryEnvironmentArgs(options, cliContext),\n    ...(cliContext?.verbose ? [\"--verbose\"] : []),\n  ];\n}\n\nfunction collectPlannedExternalTailorDBServices(\n  target: BuiltDeploymentTarget,\n  targets: ReadonlyArray<BuiltDeploymentTarget>,\n): Application[\"tailorDBServices\"] {\n  const externalNamespaces = new Set(target.application.externalTailorDBNamespaces);\n  if (externalNamespaces.size === 0) {\n    return [];\n  }\n\n  return targets.flatMap((candidate) =>\n    candidate.application.tailorDBServices.filter((service) =>\n      externalNamespaces.has(service.namespace),\n    ),\n  );\n}\n\nexport function collectExternalAuthIdpConfigNames(\n  targets: ReadonlyArray<BuiltDeploymentTarget>,\n): ReadonlyMap<string, string | undefined> {\n  const idpConfigNames = new Map<string, string | undefined>();\n  for (const target of targets) {\n    const authService = target.application.authService;\n    if (!authService) {\n      continue;\n    }\n    const { name } = authService.config;\n    const idpConfigName = authService.config.idProvider?.name;\n    if (idpConfigNames.has(name) && idpConfigNames.get(name) !== idpConfigName) {\n      throw CLIError({\n        code: \"AUTH_NAMESPACE_CONFLICT\",\n        message:\n          `Auth namespace \"${name}\" is defined by multiple config files with different IdP configs. ` +\n          `Auth namespace names must be unique across all configs in a single deploy.`,\n      });\n    }\n    idpConfigNames.set(name, idpConfigName);\n  }\n  return idpConfigNames;\n}\n\nfunction collectDeployRunPlanInputs(\n  targets: ReadonlyArray<BuiltDeploymentTarget>,\n  writes: boolean,\n): DeployRunPlanInputs {\n  const eventSubscriptions = collectEventSubscriptions(targets);\n  assertRecordableDependencies(eventSubscriptions, writes);\n  return {\n    eventSubscriptions,\n    runAppIds: new Set(\n      targets.map((target) => target.application.id).filter((id) => id !== undefined),\n    ),\n    expectedLocalStaticWebsiteNames: collectExpectedLocalStaticWebsiteNames(targets),\n    externalAuthIdpConfigNames: collectExternalAuthIdpConfigNames(targets),\n  };\n}\n\nasync function planDeploymentTarget(\n  params: PlanDeploymentTargetParams,\n): Promise<PlannedDeployment> {\n  const {\n    target,\n    targets,\n    runInputs,\n    client,\n    workspaceId,\n    noSchemaCheck,\n    migrationTestBaselines,\n    migrationTestSnapshots,\n  } = params;\n  const { config, application, workflowBuildResult, httpAdapterBuildResult, bundledScripts } =\n    target;\n  const owned = ownedSubscriptions(runInputs.eventSubscriptions, target);\n\n  const migrationTestServices = application.tailorDBServices.map((service) => {\n    const snapshot = migrationTestSnapshots?.get(service.namespace);\n    return snapshot ? { ...service, types: snapshot.tables, typeSourceInfo: {} } : service;\n  });\n  await withSpan(\"plan.validateTailorDBTypeNames\", () =>\n    assertUniqueTailorDBTypeNamesWithExternal({\n      client,\n      workspaceId,\n      tailorDBServices: migrationTestServices,\n      externalTailorDBNamespaces: application.externalTailorDBNamespaces,\n      plannedExternalTailorDBServices: collectPlannedExternalTailorDBServices(target, targets),\n    }),\n  );\n\n  const workflowService = application.workflowService;\n  const bundledWorkflowJobs = filterBundledWorkflowJobs(\n    workflowService?.jobs ?? [],\n    workflowBuildResult?.usedJobNames ?? [],\n  );\n  const functionEntries = collectFunctionEntries(application, bundledWorkflowJobs, bundledScripts);\n  const forceApplyAll = await withSpan(\"plan.detectSdkVersionChange\", () =>\n    shouldForceApplyAll(client, workspaceId, application, functionEntries),\n  );\n\n  return withSpan(\"plan\", async () => {\n    const applications = targets.map((target) => target.application);\n    const tailorDBTypeNamespaces = collectVisibleTailorDBTypeNamespaces(application, applications);\n    const resolverNamespaces = collectVisibleResolverNamespaces(application, applications);\n    const idpNames = collectVisibleIdpNames(application, applications);\n    const ctx: PlanContext = {\n      client,\n      workspaceId,\n      application,\n      forRemoval: false,\n      config,\n      noSchemaCheck,\n      migrationTestBaselines,\n      migrationTestSnapshots,\n      forceApplyAll,\n      ...runInputs,\n      idpUserTriggerTargets: subscribedIdps(owned),\n      executorUsedTailorDBTables: subscribedTailorDBTables(owned),\n      executorUsedResolvers: subscribedResolvers(owned),\n      dependentApps: collectDependentApps(owned),\n      tailorDBTypeNamespaces,\n      resolverNamespaces,\n      idpNames,\n    };\n    const functionRegistry = await withSpan(\"plan.functionRegistry\", () =>\n      planFunctionRegistry(client, workspaceId, application.name, application.id, functionEntries),\n    );\n    const unchangedWorkflowJobs = new Set(\n      functionRegistry.changeSet.unchanged\n        .filter((entry) => entry.name.startsWith(WORKFLOW_PREFIX))\n        .map((entry) => entry.name.slice(WORKFLOW_PREFIX.length)),\n    );\n    const [\n      tailorDB,\n      staticWebsite,\n      aiGateway,\n      idp,\n      auth,\n      pipeline,\n      app,\n      executor,\n      workflow,\n      workflowExecutionPolicy,\n      secretManager,\n    ] = await Promise.all([\n      withSpan(\"plan.tailorDB\", () => planTailorDB(ctx)),\n      withSpan(\"plan.staticWebsite\", () => planStaticWebsite(ctx)),\n      withSpan(\"plan.aiGateway\", () => planAIGateway(ctx)),\n      withSpan(\"plan.idp\", () => planIdP(ctx)),\n      withSpan(\"plan.auth\", () => planAuth(ctx)),\n      withSpan(\"plan.pipeline\", () => planPipeline(ctx)),\n      withSpan(\"plan.application\", () => planApplication(ctx, httpAdapterBuildResult)),\n      withSpan(\"plan.executor\", () => planExecutor(ctx)),\n      withSpan(\"plan.workflow\", () =>\n        planWorkflow(\n          client,\n          workspaceId,\n          application.name,\n          application.id,\n          workflowService?.workflows ?? {},\n          workflowBuildResult?.mainJobDeps ?? {},\n          unchangedWorkflowJobs,\n          {\n            ...subscribedWorkflows(owned),\n            jobPublishEvents: collectWorkflowJobPublishEvents(target),\n            dependentApps: ctx.dependentApps,\n            runAppIds: ctx.runAppIds,\n          },\n        ),\n      ),\n      withSpan(\"plan.workflowExecutionPolicy\", () =>\n        planWorkflowJobFunctionExecutionPolicy(\n          client,\n          workspaceId,\n          application.name,\n          application.id,\n          config.workflow?.executionPolicies ?? {},\n        ),\n      ),\n      withSpan(\"plan.secretManager\", () => planSecretManager(ctx)),\n    ]);\n\n    return {\n      application,\n      functionRegistry,\n      tailorDB,\n      staticWebsite,\n      aiGateway,\n      idp,\n      auth,\n      pipeline,\n      app,\n      executor,\n      workflow,\n      workflowExecutionPolicy,\n      secretManager,\n    };\n  });\n}\n\nexport async function planDeploymentTargets(\n  params: PlanDeploymentTargetsParams,\n): Promise<PlannedDeployment[]> {\n  const { targets, planTarget = planDeploymentTarget, ...planParams } = params;\n  return Promise.all(\n    targets.map((target) =>\n      planTarget({\n        ...planParams,\n        target,\n        targets,\n      }),\n    ),\n  );\n}\n\nexport async function confirmDeploymentPlans(params: ConfirmDeploymentPlansParams): Promise<void> {\n  const { deployments, yes, dryRun = false, missingDependentApps = [] } = params;\n  if (!dryRun) {\n    await confirmMigrationCheckpointRepairs(\n      deployments.flatMap((deployment) => deployment.tailorDB.context.checkpointRepairs),\n      yes,\n    );\n  }\n  await confirmMissingDependentApps(missingDependentApps, yes);\n  const targetAppNames = new Set(deployments.map((deployment) => deployment.application.name));\n  const resourceOwners = collectDeploymentResourceOwners(deployments);\n  const scheduledRenamedAppDeletes = new Set<string>();\n  const importantDeletions: ImportantResourceDeletion[] = [];\n\n  for (const deployment of deployments) {\n    const results = deploymentPlanResults(deployment);\n    const conflicts = collectOwnerConflicts(results);\n    await confirmOwnerConflict(\n      conflicts,\n      deployment.application.name,\n      yes,\n      deployment.application.id,\n    );\n\n    const unmanaged = collectUnmanagedResources(results);\n    await confirmUnmanagedResources(unmanaged, deployment.application.name, yes);\n\n    importantDeletions.push(...collectImportantResourceDeletions(results));\n\n    const emptyApps = computeRenamedAppDeletions({\n      conflicts,\n      resourceOwners,\n      protectedAppNames: targetAppNames,\n    });\n    for (const emptyApp of emptyApps) {\n      if (scheduledRenamedAppDeletes.has(emptyApp)) {\n        continue;\n      }\n      scheduledRenamedAppDeletes.add(emptyApp);\n      deployment.app.deletes.push({\n        name: emptyApp,\n        request: {\n          workspaceId: deployment.tailorDB.context.workspaceId,\n          applicationName: emptyApp,\n        },\n      });\n    }\n  }\n\n  await confirmImportantResourceDeletion(importantDeletions, yes);\n}\n\nasync function validateDeploymentPlans(\n  deployments: ReadonlyArray<PlannedDeployment>,\n): Promise<void> {\n  for (const deployment of deployments) {\n    await validatePlan(deploymentPlanResults(deployment));\n  }\n}\n\n/**\n * Strip the services a migration test deploy must not manage, so plan modules\n * see an application that already reflects the deploy's scope. Baseline deploys\n * omit executors and Auth user profiles (data loading must not trigger current\n * event handlers or reference the final schema); every migration test deploy\n * omits workspace-bound static website custom domains.\n * @param application - Application built from the user's config\n * @param internalContext - Internal deployment behavior used by composed CLI workflows\n * @returns The application as the migration test deploy manages it\n */\nexport function adjustApplicationForMigrationTest(\n  application: Application,\n  internalContext: DeployInternalContext | undefined,\n): Application {\n  if (!internalContext?.migrationTestSnapshots) {\n    return application;\n  }\n  const forBaseline = internalContext.migrationTestBaselines !== undefined;\n  const authService =\n    forBaseline && application.authService\n      ? { ...application.authService, userProfile: undefined }\n      : application.authService;\n  const adjusted: Application = {\n    ...application,\n    executorService: forBaseline ? undefined : application.executorService,\n    authService,\n    staticWebsiteServices: application.staticWebsiteServices.map((website) => ({\n      ...website,\n      customDomains: undefined,\n    })),\n    get applications() {\n      return [adjusted];\n    },\n  };\n  return adjusted;\n}\n\n/**\n * Deploy the configured application to the Tailor platform.\n * @param options - Deploy execution options\n * @param cliContext - Global CLI arguments to preserve in recovery actions\n * @param internalContext - Internal deployment behavior used by composed CLI workflows\n * @returns Promise that resolves to `{ bundledScripts }` when `buildOnly` is true, otherwise void\n */\nasync function deployInternal(\n  options?: DeployOptions,\n  cliContext?: DeployCLIContext,\n  internalContext?: DeployInternalContext,\n) {\n  return withSpan(\"deploy\", async (rootSpan) => {\n    rootSpan.setAttribute(\"deploy.dry_run\", options?.dryRun ?? false);\n\n    // Before the first config load, so this run re-evaluates user modules\n    // instead of reusing another run's cached ones, and is judged on the keys\n    // it declares rather than on ones an earlier failed run left behind.\n    beginUserModuleRun();\n    beginWaitPointScope();\n\n    const configPaths = parseDeployConfigPaths(options?.configPath);\n    const dryRun = options?.dryRun ?? false;\n    const buildOnly =\n      options?.buildOnly ?? parseBoolean(process.env.TAILOR_DEPLOY_BUILD_ONLY) === true;\n    const preflightConfigs = buildOnly\n      ? []\n      : await withSpan(\"config.preflight\", () =>\n          loadDeployConfigs({ configPaths, dryRun, buildOnly }),\n        );\n    const resolvedConfigPaths = preflightConfigs.map(({ config }) => config.path);\n    const workspaceContextTargets = preflightConfigs.map(({ config }) => ({\n      configPath: config.path,\n      applicationId: config.id ?? `name:${config.name}`,\n    }));\n    const workspace = buildOnly\n      ? undefined\n      : await resolveDeployWorkspace({\n          workspaceId: options?.workspaceId,\n          profile: options?.profile,\n          createWorkspace: options?.createWorkspace,\n          workspaceName: options?.workspaceName,\n          workspaceRegion: options?.workspaceRegion,\n          organizationId: options?.organizationId,\n          folderId: options?.folderId,\n          dryRun,\n          contextTargets: workspaceContextTargets,\n          deployArgs: retryDeployArgs(options, resolvedConfigPaths, cliContext),\n          workspaceCommandArgs: workspaceRecoveryArgs(options, cliContext),\n          workspaceCommandJson: cliContext?.json || logger.jsonMode,\n        });\n    const targets = await withSpan(\"build\", async () => {\n      const noCache = options?.noCache ?? false;\n      const packageJson = await readPackageJson();\n      const cacheDir = path.resolve(getDistDir(), \"cache\");\n      if (options?.cleanCache) {\n        fs.rmSync(cacheDir, { recursive: true, force: true });\n        logger.info(\"Bundle cache cleaned\");\n      }\n\n      const targets = await buildDeploymentTargets({\n        configPaths,\n        loadedConfigs: buildOnly ? undefined : preflightConfigs,\n        dryRun,\n        buildOnly,\n        noCache,\n        packageVersion: packageJson.version ?? \"unknown\",\n        cacheDir,\n      });\n\n      return targets;\n    });\n    if (buildOnly) {\n      return { bundledScripts: mergeBundledScripts(targets) };\n    }\n\n    assertUniqueGlobalResourceNames(targets);\n\n    // Note: the normal apply path intentionally skips writing bundle files to\n    // .tailor/. Bundles are kept in memory and uploaded directly to the\n    // function registry. To test a function locally, use `function run`\n    // with a .ts source file instead of a pre-bundled .js file.\n\n    if (!workspace) throw internalError(\"Workspace was not resolved\");\n    const { client, workspaceId } = workspace;\n\n    rootSpan.setAttribute(\"app.name\", targets.map((target) => target.application.name).join(\",\"));\n    rootSpan.setAttribute(\"workspace.id\", workspaceId);\n\n    const planTargets = targets.map((target) => ({\n      ...target,\n      application: adjustApplicationForMigrationTest(target.application, internalContext),\n    }));\n    const metadataClient = await withSpan(\"plan.metadataLookup\", () =>\n      createMetadataLookupClient({\n        client,\n        workspaceId,\n        applications: planTargets.map(({ application }) => application),\n      }),\n    );\n    const runInputs = collectDeployRunPlanInputs(planTargets, !options?.dryRun);\n    const deployments = await planDeploymentTargets({\n      targets: planTargets,\n      runInputs,\n      client: metadataClient,\n      workspaceId,\n      noSchemaCheck: options?.noSchemaCheck,\n      migrationTestBaselines: internalContext?.migrationTestBaselines,\n      migrationTestSnapshots: internalContext?.migrationTestSnapshots,\n    });\n\n    const yes = options?.yes ?? false;\n\n    dropCrossDeploymentManagedDeletes(deployments);\n\n    // Phase 1b: Confirm\n    const missingDependentApps = (\n      await Promise.all(\n        planTargets.map((target) =>\n          fetchMissingDependentApps({\n            client: metadataClient,\n            workspaceId,\n            application: target.application,\n            runAppIds: runInputs.runAppIds ?? new Set<string>(),\n            subscribedKeys: subscribedResourceKeys(runInputs.eventSubscriptions, target),\n            jobsByWorkflow: target.workflowBuildResult?.mainJobDeps ?? {},\n          }),\n        ),\n      )\n    ).flat();\n\n    await withSpan(\"confirm\", async () => {\n      await confirmDeploymentPlans({ deployments, yes, dryRun, missingDependentApps });\n    });\n\n    const planSummary = printDeploymentPlans(deployments, { dryRun: options?.dryRun });\n\n    if (options?.noValidate) {\n      logger.warn(\"Client-side validation skipped (--no-validate).\");\n    } else {\n      await validateDeploymentPlans(deployments);\n    }\n\n    if (dryRun) {\n      logger.info(\"Dry run enabled. No changes applied.\");\n      return undefined;\n    }\n\n    await applyDeploymentPlans(client, workspaceId, deployments);\n\n    if (!internalContext?.suppressResultOutput) {\n      if (logger.jsonMode) {\n        logger.out({ summary: planSummary, status: \"applied\" });\n      } else {\n        logger.success(\"Successfully applied changes.\");\n      }\n    }\n\n    return undefined;\n  });\n}\n\n/**\n * Deploy using the programmatic CLI API.\n * @param options - Deploy execution options\n * @returns Deploy result\n */\nexport function deploy(options?: DeployOptions) {\n  return deployInternal(options);\n}\n\n/**\n * Deploy TailorDB baseline snapshots for an isolated migration test.\n * @param options - Deploy execution options\n * @param baselines - Baseline snapshots keyed by TailorDB namespace\n * @param baselineSnapshots - All schema snapshots that must match the source before data loading\n * @returns Deploy result\n */\nexport function deployMigrationTestBaseline(\n  options: DeployOptions,\n  baselines: ReadonlyMap<string, TailorDBMigrationTestBaseline>,\n  baselineSnapshots: TailorDBMigrationTestSnapshots,\n) {\n  return deployInternal(options, undefined, {\n    migrationTestBaselines: baselines,\n    migrationTestSnapshots: baselineSnapshots,\n    suppressResultOutput: true,\n  });\n}\n\n/**\n * Deploy pending migrations without emitting deploy's standalone result payload.\n * @param options - Deploy execution options\n * @param snapshots - Final committed snapshots keyed by TailorDB namespace\n * @returns Deploy result\n */\nexport function deployMigrationTestTarget(\n  options: DeployOptions,\n  snapshots: TailorDBMigrationTestSnapshots,\n) {\n  return deployInternal(options, undefined, {\n    migrationTestSnapshots: snapshots,\n    suppressResultOutput: true,\n  });\n}\n\n/**\n * Deploy from the command adapter while preserving global CLI arguments in recovery actions.\n * @param options - Deploy execution options\n * @param cliContext - Global CLI arguments already applied by the command runner\n * @returns Deploy result\n */\nexport function deployFromCLI(options: DeployOptions | undefined, cliContext: DeployCLIContext) {\n  return deployInternal(options, cliContext);\n}\n","import {\n  ExecutorJobStatus,\n  ExecutorTargetType,\n  ExecutorTriggerType,\n} from \"@tailor-platform/tailor-proto/executor_resource_pb\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { styles } from \"#/cli/shared/logger\";\n\n// ============================================================================\n// Executor Job Status\n// ============================================================================\n\nexport type ExecutorJobStatusClass = \"success\" | \"failure\" | \"transient\";\n\n/**\n * Colorize executor job status string.\n * @param status - Executor job status string\n * @returns Colorized status string\n */\nexport function colorizeExecutorJobStatus(status: string): string {\n  switch (status) {\n    case \"PENDING\":\n      return styles.dim(status);\n    case \"RUNNING\":\n      return styles.info(status);\n    case \"SUCCESS\":\n      return styles.success(status);\n    case \"FAILED\":\n      return styles.error(status);\n    case \"CANCELED\":\n      return styles.warning(status);\n    default:\n      return status;\n  }\n}\n\n/**\n * Check if executor job status is terminal.\n * @param status - Executor job status enum value\n * @returns True if status is terminal\n */\nfunction isExecutorJobTerminalStatus(status: ExecutorJobStatus): boolean {\n  return isExecutorJobSuccessStatus(status) || isExecutorJobFailureStatus(status);\n}\n\n/**\n * Check if executor job status is successful.\n * @param status - Executor job status enum value\n * @returns True if status is success\n */\nfunction isExecutorJobSuccessStatus(status: ExecutorJobStatus): boolean {\n  return status === ExecutorJobStatus.SUCCESS;\n}\n\n/**\n * Check if executor job status is a terminal failure.\n * @param status - Executor job status enum value\n * @returns True if status is failure\n */\nfunction isExecutorJobFailureStatus(status: ExecutorJobStatus): boolean {\n  return status === ExecutorJobStatus.FAILED || status === ExecutorJobStatus.CANCELED;\n}\n\n/**\n * Check if executor job status can still progress.\n * @param status - Executor job status enum value\n * @returns True if status is transient\n */\nfunction isExecutorJobTransientStatus(status: ExecutorJobStatus): boolean {\n  return (\n    status === ExecutorJobStatus.UNSPECIFIED ||\n    status === ExecutorJobStatus.PENDING ||\n    status === ExecutorJobStatus.RUNNING\n  );\n}\n\n/**\n * Classify executor job status for waiter decisions.\n * @param status - Executor job status enum value\n * @returns Classified executor job status\n */\nexport function classifyExecutorJobStatus(status: ExecutorJobStatus): ExecutorJobStatusClass {\n  if (isExecutorJobSuccessStatus(status)) {\n    return \"success\";\n  }\n  if (isExecutorJobTerminalStatus(status)) {\n    return \"failure\";\n  }\n  if (isExecutorJobTransientStatus(status)) {\n    return \"transient\";\n  }\n  // Safety net: unknown future statuses are treated as transient\n  return \"transient\";\n}\n\n/**\n * Parse executor job status string to enum.\n * @param status - Status string to parse\n * @returns ExecutorJobStatus enum value\n */\nexport function parseExecutorJobStatus(status: string): ExecutorJobStatus {\n  const upperStatus = status.toUpperCase();\n  switch (upperStatus) {\n    case \"PENDING\":\n      return ExecutorJobStatus.PENDING;\n    case \"RUNNING\":\n      return ExecutorJobStatus.RUNNING;\n    case \"SUCCESS\":\n      return ExecutorJobStatus.SUCCESS;\n    case \"FAILED\":\n      return ExecutorJobStatus.FAILED;\n    case \"CANCELED\":\n      return ExecutorJobStatus.CANCELED;\n    default:\n      throw CLIError({\n        code: \"EXECUTOR_STATUS_INVALID\",\n        message: `Invalid status: ${status}. Valid values: PENDING, RUNNING, SUCCESS, FAILED, CANCELED`,\n      });\n  }\n}\n\n// ============================================================================\n// Executor Target Type\n// ============================================================================\n\n/**\n * Convert executor target type enum to string.\n * @param targetType - Executor target type enum value\n * @returns Target type string representation\n */\nexport function executorTargetTypeToString(targetType: ExecutorTargetType): string {\n  switch (targetType) {\n    case ExecutorTargetType.WEBHOOK:\n      return \"WEBHOOK\";\n    case ExecutorTargetType.TAILOR_GRAPHQL:\n      return \"GRAPHQL\";\n    case ExecutorTargetType.FUNCTION:\n      return \"FUNCTION\";\n    case ExecutorTargetType.JOB_FUNCTION:\n      return \"JOB_FUNCTION\";\n    case ExecutorTargetType.WORKFLOW:\n      return \"WORKFLOW\";\n    default:\n      return \"UNSPECIFIED\";\n  }\n}\n\n/**\n * Convert executor trigger type enum to string.\n * @param triggerType - Executor trigger type enum value\n * @returns Trigger type string representation\n */\nexport function executorTriggerTypeToString(triggerType: ExecutorTriggerType): string {\n  switch (triggerType) {\n    case ExecutorTriggerType.SCHEDULE:\n      return \"SCHEDULE\";\n    case ExecutorTriggerType.EVENT:\n      return \"EVENT\";\n    case ExecutorTriggerType.INCOMING_WEBHOOK:\n      return \"INCOMING_WEBHOOK\";\n    default:\n      return \"UNSPECIFIED\";\n  }\n}\n","import { timestampDate } from \"@bufbuild/protobuf/wkt\";\nimport { ExecutorJobStatus } from \"@tailor-platform/tailor-proto/executor_resource_pb\";\nimport { executorTargetTypeToString, executorTriggerTypeToString } from \"./status\";\nimport type {\n  ExecutorExecutor,\n  ExecutorJob,\n  ExecutorJobAttempt,\n  ExecutorTriggerEventConfig,\n} from \"@tailor-platform/tailor-proto/executor_resource_pb\";\n\nexport interface ExecutorJobListInfo {\n  id: string;\n  executorName: string;\n  status: string;\n  createdAt: string;\n}\n\nexport interface ExecutorJobInfo {\n  id: string;\n  executorName: string;\n  status: string;\n  scheduledAt: string;\n  createdAt: string;\n  updatedAt: string;\n}\n\nexport interface ExecutorJobAttemptInfo {\n  id: string;\n  jobId: string;\n  status: string;\n  error: string;\n  startedAt: string;\n  finishedAt: string;\n  operationReference: string;\n}\n\nfunction executorJobStatusToString(status: ExecutorJobStatus): string {\n  switch (status) {\n    case ExecutorJobStatus.PENDING:\n      return \"PENDING\";\n    case ExecutorJobStatus.RUNNING:\n      return \"RUNNING\";\n    case ExecutorJobStatus.SUCCESS:\n      return \"SUCCESS\";\n    case ExecutorJobStatus.FAILED:\n      return \"FAILED\";\n    case ExecutorJobStatus.CANCELED:\n      return \"CANCELED\";\n    default:\n      return \"UNSPECIFIED\";\n  }\n}\n\n/**\n * Transform ExecutorJob to ExecutorJobListInfo for list display.\n * @param job - ExecutorJob from proto\n * @returns Executor job list info\n */\nexport function toExecutorJobListInfo(job: ExecutorJob): ExecutorJobListInfo {\n  return {\n    id: job.id,\n    executorName: job.executorName,\n    status: executorJobStatusToString(job.status),\n    createdAt: job.createdAt ? timestampDate(job.createdAt).toISOString() : \"N/A\",\n  };\n}\n\n/**\n * Transform ExecutorJob to ExecutorJobInfo for detail display.\n * @param job - ExecutorJob from proto\n * @returns Executor job info\n */\nexport function toExecutorJobInfo(job: ExecutorJob): ExecutorJobInfo {\n  return {\n    id: job.id,\n    executorName: job.executorName,\n    status: executorJobStatusToString(job.status),\n    scheduledAt: job.scheduledAt ? timestampDate(job.scheduledAt).toISOString() : \"N/A\",\n    createdAt: job.createdAt ? timestampDate(job.createdAt).toISOString() : \"N/A\",\n    updatedAt: job.updatedAt ? timestampDate(job.updatedAt).toISOString() : \"N/A\",\n  };\n}\n\n/**\n * Transform ExecutorJobAttempt to ExecutorJobAttemptInfo.\n * @param attempt - ExecutorJobAttempt from proto\n * @returns Executor job attempt info\n */\nexport function toExecutorJobAttemptInfo(attempt: ExecutorJobAttempt): ExecutorJobAttemptInfo {\n  return {\n    id: attempt.id,\n    jobId: attempt.jobId,\n    status: executorJobStatusToString(attempt.status),\n    error: attempt.error || \"\",\n    startedAt: attempt.startedAt ? timestampDate(attempt.startedAt).toISOString() : \"N/A\",\n    finishedAt: attempt.finishedAt ? timestampDate(attempt.finishedAt).toISOString() : \"N/A\",\n    operationReference: attempt.operationReference || \"\",\n  };\n}\n\n// ============================================================================\n// Executor (ExecutorExecutor) Transform Functions\n// ============================================================================\n\nexport interface ExecutorListInfo {\n  name: string;\n  triggerType: string;\n  targetType: string;\n  disabled: boolean;\n}\n\nexport interface ExecutorInfo {\n  name: string;\n  description: string;\n  triggerType: string;\n  targetType: string;\n  disabled: boolean;\n  triggerConfig: Record<string, unknown>;\n  targetConfig: Record<string, unknown>;\n}\n\nfunction formatSubjectEvent(subject: string, eventTypes: readonly string[]): string {\n  const actions = eventTypes\n    .map((eventType) => eventType.split(\".\").at(-1) ?? eventType)\n    .join(\", \");\n  return actions ? `event: ${subject} ${actions}` : `event: ${subject}`;\n}\n\nfunction formatTypedEventTrigger(config: ExecutorTriggerEventConfig): string | null {\n  const typedConfig = config.typedConfig;\n  if (typedConfig.case === undefined) {\n    return null;\n  }\n\n  switch (typedConfig.case) {\n    case \"tailordb\":\n      return formatSubjectEvent(typedConfig.value.typeName, typedConfig.value.eventTypes);\n    case \"pipeline\":\n      return formatSubjectEvent(typedConfig.value.resolverName, typedConfig.value.eventTypes);\n    case \"idp\":\n      return formatSubjectEvent(\"idp user\", typedConfig.value.eventTypes);\n    case \"auth\":\n      return formatSubjectEvent(\"auth access_token\", typedConfig.value.eventTypes);\n    default:\n      return null;\n  }\n}\n\n/**\n * Format trigger type for human-readable display.\n * Examples:\n *   - event with typeName \"User\" and action \"created\" → \"event: User created\"\n *   - event with resolverName \"myResolver\" → \"event: myResolver executed\"\n *   - schedule with frequency \"0 12 * * *\" and timezone \"UTC\" → \"schedule: 0 12 * * * (UTC)\"\n *   - incomingWebhook → \"webhook\"\n * @param executor - Executor from proto\n * @returns Formatted trigger type string\n */\nfunction formatTriggerType(executor: ExecutorExecutor): string {\n  const config = executor.triggerConfig?.config;\n  if (!config || config.case === undefined) {\n    return executorTriggerTypeToString(executor.triggerType);\n  }\n\n  switch (config.case) {\n    case \"schedule\":\n      return `schedule: ${config.value.frequency} (${config.value.timezone})`;\n    case \"event\": {\n      const typedTrigger = formatTypedEventTrigger(config.value);\n      if (typedTrigger) {\n        return typedTrigger;\n      }\n      const legacyConfig = readLegacyEventTriggerConfig(config.value);\n      if (!legacyConfig.eventType) {\n        return executorTriggerTypeToString(executor.triggerType);\n      }\n      return formatEventTrigger(legacyConfig.eventType, legacyConfig.condition);\n    }\n    case \"incomingWebhook\":\n      return \"webhook\";\n    default:\n      return executorTriggerTypeToString(executor.triggerType);\n  }\n}\n\nfunction readLegacyEventTriggerConfig(config: ExecutorTriggerEventConfig): {\n  eventType: string;\n  condition?: string;\n} {\n  // oxlint-disable-next-line typescript/no-deprecated -- Existing resources can still contain the legacy event fields.\n  return { eventType: config.eventType, condition: config.condition?.expr };\n}\n\n/**\n * Format event trigger for display by parsing condition to extract type/resolver name.\n * @param eventType - Event type string (e.g., \"tailordb.type_record.created\")\n * @param condition - Condition expression that may contain args.typeName or args.resolverName\n * @returns Formatted string (e.g., \"event: User created\")\n */\nfunction formatEventTrigger(eventType: string, condition?: string): string {\n  const parts = eventType.split(\".\");\n  if (parts.length < 3) {\n    return `event: ${eventType}`;\n  }\n\n  const [service, resource, action] = parts;\n\n  // Try to extract name from condition\n  if (condition) {\n    // Match args.typeName === \"User\" or args.typeName === 'User'\n    const typeNameMatch = condition.match(/args\\.typeName\\s*===?\\s*[\"']([^\"']+)[\"']/);\n    if (typeNameMatch) {\n      return `event: ${typeNameMatch[1]} ${action}`;\n    }\n\n    // Match args.resolverName === \"myResolver\" or args.resolverName === 'myResolver'\n    const resolverNameMatch = condition.match(/args\\.resolverName\\s*===?\\s*[\"']([^\"']+)[\"']/);\n    if (resolverNameMatch) {\n      return `event: ${resolverNameMatch[1]} ${action}`;\n    }\n  }\n\n  // Fallback: use service, resource and action\n  return `event: ${service} ${resource} ${action}`;\n}\n\n/**\n * Format trigger config for display.\n * @param executor - Executor from proto\n * @returns Formatted trigger config\n */\nfunction formatTriggerConfig(executor: ExecutorExecutor): Record<string, unknown> {\n  const config = executor.triggerConfig?.config;\n  if (!config || config.case === undefined) {\n    return {};\n  }\n\n  switch (config.case) {\n    case \"schedule\":\n      return {\n        timezone: config.value.timezone,\n        frequency: config.value.frequency,\n      };\n    case \"event\":\n      return formatEventTriggerConfig(config.value);\n    case \"incomingWebhook\":\n      return {\n        secret: config.value.secret ? \"***\" : \"\",\n      };\n    default:\n      return {};\n  }\n}\n\nfunction formatEventTriggerConfig(config: ExecutorTriggerEventConfig): Record<string, unknown> {\n  const typedConfig = config.typedConfig;\n  if (typedConfig.case === undefined) {\n    const legacyConfig = readLegacyEventTriggerConfig(config);\n    return {\n      eventType: legacyConfig.eventType,\n      condition: legacyConfig.condition || \"\",\n    };\n  }\n\n  // Workflows are workspace-scoped, so this is the only case with no namespace.\n  // Returning early keeps `namespaceName` in the key position every other case\n  // has always emitted it in.\n  if (typedConfig.case === \"workflow\") {\n    return {\n      kind: typedConfig.case,\n      eventTypes: typedConfig.value.eventTypes,\n      condition: typedConfig.value.condition?.expr || \"\",\n      ...(typedConfig.value.workflowName && { workflowName: typedConfig.value.workflowName }),\n    };\n  }\n\n  const base = {\n    kind: typedConfig.case,\n    eventTypes: typedConfig.value.eventTypes,\n    namespaceName: typedConfig.value.namespaceName,\n    condition: typedConfig.value.condition?.expr || \"\",\n  };\n\n  switch (typedConfig.case) {\n    case \"tailordb\":\n      return { ...base, typeName: typedConfig.value.typeName };\n    case \"pipeline\":\n      return { ...base, resolverName: typedConfig.value.resolverName };\n    default:\n      return base;\n  }\n}\n\n/**\n * Format target config for display.\n * @param executor - Executor from proto\n * @returns Formatted target config\n */\nfunction formatTargetConfig(executor: ExecutorExecutor): Record<string, unknown> {\n  const config = executor.targetConfig?.config;\n  if (!config || config.case === undefined) {\n    return {};\n  }\n\n  switch (config.case) {\n    case \"webhook\":\n      return {\n        url: config.value.url?.expr || \"\",\n        headers: config.value.headers.length,\n      };\n    case \"tailorGraphql\":\n      return {\n        appName: config.value.appName,\n        query: config.value.query,\n      };\n    case \"function\":\n      return {\n        name: config.value.name,\n      };\n    case \"workflow\":\n      return {\n        workflowName: config.value.workflowName,\n      };\n    default:\n      return {};\n  }\n}\n\n/**\n * Transform ExecutorExecutor to ExecutorListInfo for list display.\n * @param executor - Executor from proto\n * @returns Executor list info\n */\nexport function toExecutorListInfo(executor: ExecutorExecutor): ExecutorListInfo {\n  return {\n    name: executor.name,\n    triggerType: formatTriggerType(executor),\n    targetType: executorTargetTypeToString(executor.targetType),\n    disabled: executor.disabled,\n  };\n}\n\n/**\n * Transform ExecutorExecutor to ExecutorInfo for detail display.\n * @param executor - Executor from proto\n * @returns Executor info\n */\nexport function toExecutorInfo(executor: ExecutorExecutor): ExecutorInfo {\n  return {\n    name: executor.name,\n    description: executor.description,\n    triggerType: formatTriggerType(executor),\n    targetType: executorTargetTypeToString(executor.targetType),\n    disabled: executor.disabled,\n    triggerConfig: formatTriggerConfig(executor),\n    targetConfig: formatTargetConfig(executor),\n  };\n}\n","import { Code, ConnectError } from \"@connectrpc/connect\";\nimport { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { workspaceArgs } from \"#/cli/shared/args\";\nimport { type initOperatorClient } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { type ExecutorInfo, toExecutorInfo } from \"./transform\";\n\ntype ExecutorLike = {\n  name: string;\n};\n\nconst nameArgs = {\n  name: arg(z.string(), {\n    positional: true,\n    description: \"Executor name\",\n  }),\n};\n\nexport type GetExecutorTypedOptions<E extends ExecutorLike = ExecutorLike> = {\n  executor: E;\n  workspaceId?: string;\n  profile?: string;\n};\n\n/**\n * Resolve an executor by name.\n * @param client - Operator client\n * @param workspaceId - Workspace ID\n * @param name - Executor name\n * @returns Resolved executor\n */\nasync function resolveExecutor(\n  client: Awaited<ReturnType<typeof initOperatorClient>>,\n  workspaceId: string,\n  name: string,\n) {\n  const { executor } = await client.getExecutorExecutor({\n    workspaceId,\n    name,\n  });\n  if (!executor) {\n    throw CLIError({ code: \"EXECUTOR_NOT_FOUND\", message: `Executor '${name}' not found.` });\n  }\n  return executor;\n}\n\n/**\n * Get an executor by name and return CLI-friendly info.\n * @param options - Executor lookup options\n * @returns Executor information\n */\nexport async function getExecutor<E extends ExecutorLike>(\n  options: GetExecutorTypedOptions<E>,\n): Promise<ExecutorInfo> {\n  const name = options.executor.name;\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options.profile,\n    workspaceId: options.workspaceId,\n  });\n\n  try {\n    const executor = await resolveExecutor(client, workspaceId, name);\n    return toExecutorInfo(executor);\n  } catch (error) {\n    if (error instanceof ConnectError && error.code === Code.NotFound) {\n      throw CLIError({\n        code: \"EXECUTOR_NOT_FOUND\",\n        message: `Executor '${name}' not found.`,\n        cause: error,\n      });\n    }\n    throw error;\n  }\n}\n\nexport const getCommand = defineAppCommand({\n  name: \"get\",\n  description: \"Get executor details\",\n  args: z.strictObject({\n    ...workspaceArgs,\n    ...nameArgs,\n  }),\n  run: async (args) => {\n    const executor = await getExecutor({\n      executor: { name: args.name },\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n    });\n\n    logger.out(executor, {\n      display: {\n        triggerConfig: null,\n        targetConfig: null,\n      },\n    });\n  },\n});\n","import { timestampDate } from \"@bufbuild/protobuf/wkt\";\nimport {\n  FunctionExecution_Status,\n  FunctionLogSeverity,\n} from \"@tailor-platform/tailor-proto/function_resource_pb\";\nimport { styles } from \"./logger\";\nimport type { FunctionLogEntry } from \"@tailor-platform/tailor-proto/function_resource_pb\";\n\n/**\n * A structured log line recorded while a function execution ran.\n */\nexport interface FunctionLogEntryInfo {\n  /** Log message */\n  message: string;\n  /** Severity name such as `INFO`, `WARNING`, or `ERROR` */\n  severity: string;\n  /** When the line was logged, or null when unknown */\n  timestamp: Date | null;\n}\n\n/**\n * Convert function execution status enum to string.\n * @param status - Function execution status enum value\n * @returns Status string representation\n */\nexport function functionExecutionStatusToString(status: FunctionExecution_Status): string {\n  switch (status) {\n    case FunctionExecution_Status.RUNNING:\n      return \"RUNNING\";\n    case FunctionExecution_Status.SUCCESS:\n      return \"SUCCESS\";\n    case FunctionExecution_Status.FAILED:\n      return \"FAILED\";\n    case FunctionExecution_Status.SUSPEND:\n      return \"SUSPEND\";\n    case FunctionExecution_Status.CANCELING:\n      return \"CANCELING\";\n    case FunctionExecution_Status.CANCELED:\n      return \"CANCELED\";\n    default:\n      return \"UNSPECIFIED\";\n  }\n}\n\n/**\n * Colorize function execution status string.\n * @param status - Function execution status string\n * @returns Colorized status string\n */\nexport function colorizeFunctionExecutionStatus(status: string): string {\n  switch (status) {\n    case \"RUNNING\":\n      return styles.info(status);\n    case \"SUCCESS\":\n      return styles.success(status);\n    case \"FAILED\":\n      return styles.error(status);\n    default:\n      return status;\n  }\n}\n\n/**\n * Check if function execution status is terminal.\n * @param status - Function execution status enum value\n * @returns True if status is terminal\n */\nexport function isFunctionExecutionTerminalStatus(status: FunctionExecution_Status): boolean {\n  return (\n    status === FunctionExecution_Status.SUCCESS ||\n    status === FunctionExecution_Status.FAILED ||\n    status === FunctionExecution_Status.CANCELED\n  );\n}\n\n/**\n * Convert function log severity enum to string.\n * @param severity - Function log severity enum value\n * @returns Severity string representation\n */\nexport function functionLogSeverityToString(severity: FunctionLogSeverity): string {\n  switch (severity) {\n    case FunctionLogSeverity.LOG:\n      return \"LOG\";\n    case FunctionLogSeverity.DEBUG:\n      return \"DEBUG\";\n    case FunctionLogSeverity.INFO:\n      return \"INFO\";\n    case FunctionLogSeverity.WARNING:\n      return \"WARNING\";\n    case FunctionLogSeverity.ERROR:\n      return \"ERROR\";\n    default:\n      return \"UNSPECIFIED\";\n  }\n}\n\n/**\n * Transform a FunctionLogEntry proto into CLI-friendly log entry info.\n * @param entry - Function log entry from proto\n * @returns Log entry info with string severity and Date timestamp\n */\nexport function toFunctionLogEntryInfo(entry: FunctionLogEntry): FunctionLogEntryInfo {\n  return {\n    message: entry.message,\n    severity: functionLogSeverityToString(entry.severity),\n    timestamp: entry.timestamp ? timestampDate(entry.timestamp) : null,\n  };\n}\n\nfunction colorizeLogSeverity(severity: string): string {\n  const label = `[${severity}]`;\n  switch (severity) {\n    case \"ERROR\":\n      return styles.error(label);\n    case \"WARNING\":\n      return styles.warning(label);\n    case \"DEBUG\":\n      return styles.dim(label);\n    default:\n      return label;\n  }\n}\n\n/**\n * Format a log entry as a single human-readable line.\n * @param entry - Log entry info\n * @returns `<timestamp> [<severity>] <message>`\n */\nexport function formatFunctionLogEntry(entry: FunctionLogEntryInfo): string {\n  const timestamp = entry.timestamp ? entry.timestamp.toISOString() : \"N/A\";\n  return `${styles.dim(timestamp)} ${colorizeLogSeverity(entry.severity)} ${entry.message}`;\n}\n\n/**\n * Build the lines of a logs section. Structured entries take precedence;\n * the flat `logs` string is used only when no entries are available.\n * @param logEntries - Structured log entries, if any\n * @param logs - Flat newline-delimited logs, if any\n * @returns Lines to print, empty when there is nothing to show\n */\nexport function formatFunctionLogLines(\n  logEntries: FunctionLogEntryInfo[] | undefined,\n  logs: string | undefined,\n): string[] {\n  if (logEntries && logEntries.length > 0) {\n    return logEntries.map(formatFunctionLogEntry);\n  }\n  return logs ? logs.split(\"\\n\") : [];\n}\n","import { Code, ConnectError } from \"@connectrpc/connect\";\n\n/**\n * Format a caught error into a string for diagnostics.\n * @param error - Error to format\n * @returns Error message string\n */\nexport function formatWaitError(error: unknown): string {\n  return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * Check whether a polling error is retryable (transient platform errors).\n * @param error - Error to check\n * @returns True if the error should be retried\n */\nexport function isRetryableWaitError(error: unknown): boolean {\n  if (!(error instanceof ConnectError)) {\n    return false;\n  }\n  return (\n    error.code === Code.Aborted ||\n    error.code === Code.ResourceExhausted ||\n    error.code === Code.Unavailable\n  );\n}\n","import { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { durationArg } from \"#/cli/shared/args\";\nimport type { WorkflowWaitUntil } from \"./status\";\n\ntype ArgsShape = Record<string, z.ZodType>;\n\nconst workflowWaitUntilArg = z.enum([\n  \"success\",\n  \"suspended\",\n  \"terminal\",\n]) satisfies z.ZodType<WorkflowWaitUntil>;\n\nexport const nameArgs = {\n  name: arg(z.string(), {\n    positional: true,\n    description: \"Workflow name\",\n  }),\n} satisfies ArgsShape;\n\nexport const workflowWaitControlArgs = {\n  interval: arg(durationArg.default(\"3s\"), {\n    alias: \"i\",\n    description: \"Polling interval when waiting (e.g., '3s', '500ms', '1m')\",\n  }),\n  timeout: arg(durationArg.default(\"10m\"), {\n    alias: \"t\",\n    description: \"Maximum time to wait (e.g., '30s', '10m')\",\n  }),\n  until: arg(workflowWaitUntilArg.default(\"terminal\"), {\n    alias: \"u\",\n    description: \"Wait target (success, suspended, terminal)\",\n  }),\n  logs: arg(z.boolean().default(false), {\n    alias: \"l\",\n    description: \"Display job execution logs after completion\",\n  }),\n} satisfies ArgsShape;\n\nexport const waitArgs = {\n  wait: arg(z.boolean().default(false), {\n    alias: \"W\",\n    description: \"Wait for execution to complete\",\n  }),\n  ...workflowWaitControlArgs,\n} satisfies ArgsShape;\n","import {\n  WorkflowExecution_Status,\n  WorkflowJobExecution_Status,\n} from \"@tailor-platform/tailor-proto/workflow_resource_pb\";\nimport type { WorkflowExecution } from \"@tailor-platform/tailor-proto/workflow_resource_pb\";\n\nexport type WorkflowWaitUntil = \"success\" | \"suspended\" | \"terminal\";\n\nexport type WorkflowExecutionStatusClass = \"success\" | \"suspended\" | \"failure\" | \"transient\";\n\nexport interface WorkflowExecutionStatusClassification {\n  statusClass: WorkflowExecutionStatusClass;\n  status: WorkflowExecution_Status;\n}\n\n/**\n * Check if workflow execution status is successful.\n * @param status - Workflow execution status enum value\n * @returns True if status is success\n */\nfunction isWorkflowExecutionSuccessStatus(status: WorkflowExecution_Status): boolean {\n  return status === WorkflowExecution_Status.SUCCESS;\n}\n\n/**\n * Check if workflow job execution status is suspended or waiting.\n * @param status - Workflow job execution status enum value\n * @returns True if status represents a wait point\n */\nfunction isWorkflowJobExecutionSuspendedStatus(status: WorkflowJobExecution_Status): boolean {\n  return (\n    status === WorkflowJobExecution_Status.SUSPEND || status === WorkflowJobExecution_Status.WAITING\n  );\n}\n\n/**\n * Check if workflow execution status is suspended or waiting.\n * @param status - Workflow execution status enum value\n * @returns True if status represents a suspended execution\n */\nexport function isWorkflowExecutionSuspendedStatus(status: WorkflowExecution_Status): boolean {\n  return (\n    status === WorkflowExecution_Status.PENDING_RESUME ||\n    status === WorkflowExecution_Status.WAITING\n  );\n}\n\n/**\n * Check if workflow execution status is a terminal failure.\n * @param status - Workflow execution status enum value\n * @returns True if status represents failure\n */\nexport function isWorkflowExecutionFailureStatus(status: WorkflowExecution_Status): boolean {\n  return status === WorkflowExecution_Status.FAILED;\n}\n\n/**\n * Check if workflow execution status can still progress without user action.\n * @param status - Workflow execution status enum value\n * @returns True if status is transient\n */\nfunction isWorkflowExecutionTransientStatus(status: WorkflowExecution_Status): boolean {\n  return (\n    status === WorkflowExecution_Status.UNSPECIFIED ||\n    status === WorkflowExecution_Status.PENDING ||\n    status === WorkflowExecution_Status.RUNNING ||\n    status === WorkflowExecution_Status.PENDING_RETRY\n  );\n}\n\n/**\n * Check if workflow execution status is terminal.\n * @param status - Workflow execution status enum value\n * @returns True if status is terminal\n */\nfunction isWorkflowExecutionTerminalStatus(status: WorkflowExecution_Status): boolean {\n  return (\n    isWorkflowExecutionSuccessStatus(status) ||\n    isWorkflowExecutionFailureStatus(status) ||\n    isWorkflowExecutionSuspendedStatus(status)\n  );\n}\n\n/**\n * Classify workflow execution status for waiter decisions.\n * @param execution - Workflow execution to classify\n * @returns Classified workflow execution status\n */\nexport function classifyWorkflowExecutionStatus(\n  execution: WorkflowExecution,\n): WorkflowExecutionStatusClassification {\n  if (isWorkflowExecutionTerminalStatus(execution.status)) {\n    if (isWorkflowExecutionSuccessStatus(execution.status)) {\n      return { statusClass: \"success\", status: execution.status };\n    }\n    if (isWorkflowExecutionFailureStatus(execution.status)) {\n      return { statusClass: \"failure\", status: execution.status };\n    }\n    return { statusClass: \"suspended\", status: execution.status };\n  }\n  if (execution.jobExecutions.some((job) => isWorkflowJobExecutionSuspendedStatus(job.status))) {\n    return { statusClass: \"suspended\", status: execution.status };\n  }\n  if (isWorkflowExecutionTransientStatus(execution.status)) {\n    return { statusClass: \"transient\", status: execution.status };\n  }\n  // Safety net: unknown future statuses are treated as transient\n  return { statusClass: \"transient\", status: execution.status };\n}\n\n/**\n * Check if a classified workflow execution has reached the requested waiter target.\n * @param classification - Workflow execution status classification\n * @param until - Requested wait target\n * @returns True if the wait target is reached\n */\nexport function hasReachedWorkflowWaitTarget(\n  classification: WorkflowExecutionStatusClassification,\n  until: WorkflowWaitUntil,\n): boolean {\n  switch (until) {\n    case \"success\":\n      return classification.statusClass === \"success\";\n    case \"suspended\":\n      return classification.statusClass === \"suspended\";\n    case \"terminal\":\n      return (\n        classification.statusClass === \"success\" ||\n        classification.statusClass === \"failure\" ||\n        classification.statusClass === \"suspended\"\n      );\n  }\n}\n","import { timestampDate } from \"@bufbuild/protobuf/wkt\";\nimport {\n  WorkflowExecution_Status,\n  WorkflowJobExecution_Status,\n} from \"@tailor-platform/tailor-proto/workflow_resource_pb\";\nimport type {\n  Workflow,\n  WorkflowExecution,\n  WorkflowJobExecution,\n} from \"@tailor-platform/tailor-proto/workflow_resource_pb\";\n\nexport interface WorkflowListInfo {\n  name: string;\n  mainJob: string;\n  jobFunctions: number;\n  updatedAt: Date | null;\n}\n\nexport interface WorkflowInfo {\n  name: string;\n  id: string;\n  mainJob: string;\n  jobFunctions: Record<string, string>;\n  createdAt: Date | null;\n  updatedAt: Date | null;\n}\n\nexport interface WorkflowJobExecutionInfo {\n  id: string;\n  stackedJobName: string;\n  status: string;\n  executionId: string;\n  startedAt: Date | null;\n  finishedAt: Date | null;\n}\n\nexport interface WorkflowExecutionInfo {\n  id: string;\n  workflowName: string;\n  status: string;\n  jobExecutions: number;\n  startedAt: Date | null;\n  finishedAt: Date | null;\n}\n\n/**\n * Convert a workflow execution status enum to a string.\n * @param status - Workflow execution status\n * @returns String representation of the status\n */\nfunction workflowExecutionStatusToString(status: WorkflowExecution_Status): string {\n  switch (status) {\n    case WorkflowExecution_Status.PENDING:\n      return \"PENDING\";\n    case WorkflowExecution_Status.PENDING_RESUME:\n      return \"PENDING_RESUME\";\n    case WorkflowExecution_Status.RUNNING:\n      return \"RUNNING\";\n    case WorkflowExecution_Status.SUCCESS:\n      return \"SUCCESS\";\n    case WorkflowExecution_Status.FAILED:\n      return \"FAILED\";\n    case WorkflowExecution_Status.PENDING_RETRY:\n      return \"PENDING_RETRY\";\n    case WorkflowExecution_Status.WAITING:\n      return \"WAITING\";\n    default:\n      return \"UNSPECIFIED\";\n  }\n}\n\n/**\n * Convert a workflow job execution status enum to a string.\n * @param status - Workflow job execution status\n * @returns String representation of the status\n */\nfunction workflowJobExecutionStatusToString(status: WorkflowJobExecution_Status): string {\n  switch (status) {\n    case WorkflowJobExecution_Status.RUNNING:\n      return \"RUNNING\";\n    case WorkflowJobExecution_Status.SUSPEND:\n      return \"SUSPEND\";\n    case WorkflowJobExecution_Status.SUCCESS:\n      return \"SUCCESS\";\n    case WorkflowJobExecution_Status.FAILED:\n      return \"FAILED\";\n    case WorkflowJobExecution_Status.WAITING:\n      return \"WAITING\";\n    default:\n      return \"UNSPECIFIED\";\n  }\n}\n\n/**\n * Convert a Workflow proto to CLI-friendly list info.\n * @param workflow - Workflow resource\n * @returns Flattened workflow list info\n */\nexport function toWorkflowListInfo(workflow: Workflow): WorkflowListInfo {\n  return {\n    name: workflow.name,\n    mainJob: workflow.mainJobFunctionName,\n    jobFunctions: Object.keys(workflow.jobFunctions).length,\n    updatedAt: workflow.updatedAt ? timestampDate(workflow.updatedAt) : null,\n  };\n}\n\n/**\n * Convert a Workflow proto to detailed workflow info for CLI output.\n * @param workflow - Workflow resource\n * @returns Detailed workflow info\n */\nexport function toWorkflowInfo(workflow: Workflow): WorkflowInfo {\n  const jobFunctions: Record<string, string> = {};\n  for (const [name, version] of Object.entries(workflow.jobFunctions)) {\n    jobFunctions[name] = version.toString();\n  }\n\n  return {\n    name: workflow.name,\n    id: workflow.id,\n    mainJob: workflow.mainJobFunctionName,\n    jobFunctions: jobFunctions,\n    createdAt: workflow.createdAt ? timestampDate(workflow.createdAt) : null,\n    updatedAt: workflow.updatedAt ? timestampDate(workflow.updatedAt) : null,\n  };\n}\n\n/**\n * Convert a WorkflowJobExecution proto to CLI-friendly job execution info.\n * @param jobExecution - Workflow job execution resource\n * @returns Flattened job execution info\n */\nexport function toWorkflowJobExecutionInfo(\n  jobExecution: WorkflowJobExecution,\n): WorkflowJobExecutionInfo {\n  return {\n    id: jobExecution.id,\n    stackedJobName: jobExecution.stackedJobName,\n    status: workflowJobExecutionStatusToString(jobExecution.status),\n    executionId: jobExecution.executionId,\n    startedAt: jobExecution.startedAt ? timestampDate(jobExecution.startedAt) : null,\n    finishedAt: jobExecution.finishedAt ? timestampDate(jobExecution.finishedAt) : null,\n  };\n}\n\n/**\n * Convert a WorkflowExecution proto to CLI-friendly execution info.\n * @param execution - Workflow execution resource\n * @returns Flattened execution info\n */\nexport function toWorkflowExecutionInfo(execution: WorkflowExecution): WorkflowExecutionInfo {\n  return {\n    id: execution.id,\n    workflowName: execution.workflowName,\n    status: workflowExecutionStatusToString(execution.status),\n    jobExecutions: execution.jobExecutions.length,\n    startedAt: execution.startedAt ? timestampDate(execution.startedAt) : null,\n    finishedAt: execution.finishedAt ? timestampDate(execution.finishedAt) : null,\n  };\n}\n","import { setTimeout } from \"node:timers/promises\";\nimport {\n  WorkflowExecution_Status,\n  WorkflowJobExecution_Status,\n} from \"@tailor-platform/tailor-proto/workflow_resource_pb\";\nimport { type initOperatorClient } from \"#/cli/shared/client\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger, styles } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { spinner } from \"#/cli/shared/spinner\";\nimport { formatWaitError, isRetryableWaitError } from \"#/cli/shared/wait-error\";\nimport {\n  classifyWorkflowExecutionStatus,\n  hasReachedWorkflowWaitTarget,\n  isWorkflowExecutionFailureStatus,\n  isWorkflowExecutionSuspendedStatus,\n  type WorkflowExecutionStatusClass,\n  type WorkflowWaitUntil,\n} from \"./status\";\nimport { type WorkflowExecutionInfo, toWorkflowExecutionInfo } from \"./transform\";\nimport type { WorkflowExecution } from \"@tailor-platform/tailor-proto/workflow_resource_pb\";\n\nconst DEFAULT_WORKFLOW_WAIT_INTERVAL_MS = 3000;\n\nexport interface WorkflowWaitOptions {\n  client: Awaited<ReturnType<typeof initOperatorClient>>;\n  workspaceId: string;\n  executionId: string;\n  interval?: number;\n  timeout?: number;\n  until?: WorkflowWaitUntil;\n  showProgress?: boolean;\n  trackJobs?: boolean;\n}\n\nexport interface WaitWorkflowExecutionOptions {\n  executionId: string;\n  workspaceId?: string;\n  profile?: string;\n  interval?: number;\n  timeout?: number;\n  until?: WorkflowWaitUntil;\n  showProgress?: boolean;\n  trackJobs?: boolean;\n}\n\nexport interface WorkflowWaitResult extends WorkflowExecutionInfo {\n  statusClass: WorkflowExecutionStatusClass | \"unknown\";\n  elapsedMs: number;\n  attempts: number;\n  timedOut: boolean;\n  lastError: string | null;\n}\n\nfunction formatTime(date: Date): string {\n  return date.toLocaleTimeString(\"en-US\", { hour12: false });\n}\n\nfunction colorizeStatus(status: WorkflowExecution_Status): string {\n  const statusText = WorkflowExecution_Status[status];\n  switch (status) {\n    case WorkflowExecution_Status.PENDING:\n    case WorkflowExecution_Status.UNSPECIFIED:\n      return styles.dim(statusText);\n    case WorkflowExecution_Status.PENDING_RESUME:\n    case WorkflowExecution_Status.PENDING_RETRY:\n    case WorkflowExecution_Status.WAITING:\n      return styles.warning(statusText);\n    case WorkflowExecution_Status.RUNNING:\n      return styles.info(statusText);\n    case WorkflowExecution_Status.SUCCESS:\n      return styles.success(statusText);\n    case WorkflowExecution_Status.FAILED:\n      return styles.error(statusText);\n    default:\n      return statusText;\n  }\n}\n\nfunction getActiveJobs(execution: WorkflowExecution): string {\n  return execution.jobExecutions\n    .filter(\n      (job) =>\n        job.status === WorkflowJobExecution_Status.RUNNING ||\n        job.status === WorkflowJobExecution_Status.SUSPEND ||\n        job.status === WorkflowJobExecution_Status.WAITING,\n    )\n    .map((job) => job.stackedJobName)\n    .join(\", \");\n}\n\ninterface CreateWorkflowWaitResultOptions {\n  executionId: string;\n  execution: WorkflowExecution | undefined;\n  startedAt: number;\n  attempts: number;\n  timedOut: boolean;\n  lastError: string | null;\n}\n\nfunction createWorkflowWaitResult(options: CreateWorkflowWaitResultOptions): WorkflowWaitResult {\n  const elapsedMs = Date.now() - options.startedAt;\n  if (options.execution) {\n    const classification = classifyWorkflowExecutionStatus(options.execution);\n    return {\n      ...toWorkflowExecutionInfo(options.execution),\n      statusClass: classification.statusClass,\n      elapsedMs,\n      attempts: options.attempts,\n      timedOut: options.timedOut,\n      lastError: options.lastError,\n    };\n  }\n  return {\n    id: options.executionId,\n    workflowName: \"\",\n    status: \"UNKNOWN\",\n    statusClass: \"unknown\",\n    jobExecutions: 0,\n    startedAt: null,\n    finishedAt: null,\n    elapsedMs,\n    attempts: options.attempts,\n    timedOut: options.timedOut,\n    lastError: options.lastError,\n  };\n}\n\n/**\n * Wait for a workflow execution to reach the requested state.\n * @param options - Workflow waiter options\n * @returns Final or timed-out workflow wait result\n */\nexport async function waitForWorkflowExecution(\n  options: WorkflowWaitOptions,\n): Promise<WorkflowWaitResult> {\n  const interval = options.interval ?? DEFAULT_WORKFLOW_WAIT_INTERVAL_MS;\n  const until = options.until ?? \"terminal\";\n  const startedAt = Date.now();\n  const sp = options.showProgress\n    ? spinner({ indent: 2 }).start(\"Waiting for workflow to complete...\")\n    : null;\n\n  let attempts = 0;\n  let lastExecution: WorkflowExecution | undefined;\n  let lastError: string | null = null;\n  let lastStatus: WorkflowExecution_Status | undefined;\n  let lastActiveJobs: string | undefined;\n\n  try {\n    // oxlint-disable-next-line typescript/no-unnecessary-condition\n    while (true) {\n      const elapsedMs = Date.now() - startedAt;\n      const remainingMs = options.timeout === undefined ? undefined : options.timeout - elapsedMs;\n      if (remainingMs !== undefined && remainingMs <= 0) {\n        sp?.fail(\"Workflow wait timed out.\");\n        return createWorkflowWaitResult({\n          executionId: options.executionId,\n          execution: lastExecution,\n          startedAt,\n          attempts,\n          timedOut: true,\n          lastError,\n        });\n      }\n\n      try {\n        attempts += 1;\n        const { execution } = await options.client.getWorkflowExecution({\n          workspaceId: options.workspaceId,\n          executionId: options.executionId,\n        });\n\n        if (!execution) {\n          sp?.fail(`Execution '${options.executionId}' not found.`);\n          throw CLIError({\n            code: \"WORKFLOW_EXECUTION_NOT_FOUND\",\n            message: `Execution '${options.executionId}' not found.`,\n          });\n        }\n\n        lastExecution = execution;\n        lastError = null;\n\n        const classification = classifyWorkflowExecutionStatus(execution);\n        const coloredStatus = colorizeStatus(execution.status);\n\n        if (execution.status !== lastStatus) {\n          if (options.showProgress) {\n            sp?.stop();\n            logger.info(`Status: ${coloredStatus}`, {\n              mode: \"stream\",\n              indent: 2,\n            });\n            sp?.start(\"Waiting for workflow to complete...\");\n          }\n          lastStatus = execution.status;\n        }\n\n        if (options.trackJobs) {\n          const activeJobs = getActiveJobs(execution);\n          if (activeJobs && activeJobs !== lastActiveJobs) {\n            if (options.showProgress) {\n              sp?.stop();\n              logger.info(`Job | ${activeJobs}: ${coloredStatus}`, {\n                mode: \"stream\",\n                indent: 2,\n              });\n              sp?.start(\"Waiting for workflow to complete...\");\n            }\n            lastActiveJobs = activeJobs;\n          }\n        }\n\n        if (sp) {\n          sp.text = `Waiting for workflow to complete... (${formatTime(new Date())})`;\n        }\n\n        if (\n          hasReachedWorkflowWaitTarget(classification, until) ||\n          classification.statusClass === \"failure\" ||\n          (until === \"suspended\" && classification.statusClass === \"success\")\n        ) {\n          if (execution.status === WorkflowExecution_Status.SUCCESS) {\n            sp?.succeed(`Completed: ${coloredStatus}`);\n          } else if (isWorkflowExecutionFailureStatus(execution.status)) {\n            sp?.fail(`Completed: ${coloredStatus}`);\n          } else if (isWorkflowExecutionSuspendedStatus(execution.status)) {\n            sp?.warn(`Completed: ${coloredStatus}`);\n          } else {\n            sp?.succeed(`Completed: ${coloredStatus}`);\n          }\n          return createWorkflowWaitResult({\n            executionId: options.executionId,\n            execution,\n            startedAt,\n            attempts,\n            timedOut: false,\n            lastError,\n          });\n        }\n      } catch (error) {\n        if (!isRetryableWaitError(error)) {\n          throw error;\n        }\n        lastError = formatWaitError(error);\n        if (options.showProgress) {\n          if (sp) {\n            sp.text = `Retrying workflow status poll... (${formatTime(new Date())})`;\n          }\n        }\n      }\n\n      const nextElapsedMs = Date.now() - startedAt;\n      const nextRemainingMs =\n        options.timeout === undefined ? undefined : options.timeout - nextElapsedMs;\n      if (nextRemainingMs !== undefined && nextRemainingMs <= 0) {\n        sp?.fail(\"Workflow wait timed out.\");\n        return createWorkflowWaitResult({\n          executionId: options.executionId,\n          execution: lastExecution,\n          startedAt,\n          attempts,\n          timedOut: true,\n          lastError,\n        });\n      }\n\n      await setTimeout(\n        nextRemainingMs === undefined ? interval : Math.min(interval, nextRemainingMs),\n      );\n    }\n  } finally {\n    sp?.stop();\n  }\n}\n\n/**\n * Wait for an existing workflow execution by ID.\n * @param options - Workflow execution wait options\n * @returns Workflow wait result\n */\nexport async function waitForWorkflowExecutionById(\n  options: WaitWorkflowExecutionOptions,\n): Promise<WorkflowWaitResult> {\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options.profile,\n    workspaceId: options.workspaceId,\n  });\n\n  return await waitForWorkflowExecution({\n    client,\n    workspaceId,\n    executionId: options.executionId,\n    interval: options.interval,\n    timeout: options.timeout,\n    until: options.until,\n    showProgress: options.showProgress,\n    trackJobs: options.trackJobs,\n  });\n}\n\n/**\n * Build the failure for a workflow wait result.\n * @param result - Workflow wait result\n * @param until - Requested wait target\n * @returns Coded failure, or undefined when the wait succeeded\n */\nexport function getWorkflowWaitFailure(\n  result: WorkflowWaitResult,\n  until: WorkflowWaitUntil,\n): CLIError | undefined {\n  const context = { executionId: result.id, status: result.status };\n  if (result.timedOut) {\n    return CLIError({\n      code: \"WORKFLOW_WAIT_TIMEOUT\",\n      message: `Timed out waiting for workflow execution '${result.id}' to reach ${until}. Last status: ${result.status}.`,\n      context,\n    });\n  }\n  if (result.status === \"FAILED\") {\n    return CLIError({\n      code: \"WORKFLOW_EXECUTION_FAILED\",\n      message: `Workflow execution '${result.id}' failed.`,\n      context,\n    });\n  }\n  if (until === \"success\" && result.statusClass !== \"success\") {\n    return CLIError({\n      code: \"WORKFLOW_EXECUTION_NOT_SUCCESSFUL\",\n      message: `Workflow execution '${result.id}' reached ${result.status} before success.`,\n      context,\n    });\n  }\n  if (until === \"suspended\" && result.statusClass !== \"suspended\") {\n    return CLIError({\n      code: \"WORKFLOW_EXECUTION_NOT_SUSPENDED\",\n      message: `Workflow execution '${result.id}' reached ${result.status} before suspension.`,\n      context,\n    });\n  }\n  return undefined;\n}\n","import { create } from \"@bufbuild/protobuf\";\nimport { Code, ConnectError } from \"@connectrpc/connect\";\nimport { arg } from \"@politty/zod\";\nimport {\n  Condition_Operator,\n  ConditionSchema,\n  FilterSchema,\n} from \"@tailor-platform/tailor-proto/resource_pb\";\nimport { WorkflowExecution_Status } from \"@tailor-platform/tailor-proto/workflow_resource_pb\";\nimport { z } from \"zod\";\nimport {\n  type Order,\n  pagedLogArgs,\n  parseDuration,\n  toPageDirection,\n  workspaceArgs,\n} from \"#/cli/shared/args\";\nimport { fetchPaged } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { formatKeyValueTable } from \"#/cli/shared/format\";\nimport {\n  formatFunctionLogLines,\n  type FunctionLogEntryInfo,\n  toFunctionLogEntryInfo,\n} from \"#/cli/shared/function-execution\";\nimport { styles, logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { waitArgs } from \"./args\";\nimport { type WorkflowWaitUntil } from \"./status\";\nimport {\n  type WorkflowExecutionInfo,\n  type WorkflowJobExecutionInfo,\n  toWorkflowExecutionInfo,\n  toWorkflowJobExecutionInfo,\n} from \"./transform\";\nimport {\n  getWorkflowWaitFailure,\n  waitForWorkflowExecution,\n  waitForWorkflowExecutionById,\n  type WorkflowWaitResult,\n} from \"./waiter\";\nimport type { FunctionExecution } from \"@tailor-platform/tailor-proto/function_resource_pb\";\n\ntype WorkflowLike = {\n  name: string;\n};\n\nexport type ListWorkflowExecutionsTypedOptions<W extends WorkflowLike = WorkflowLike> = {\n  workflow?: W;\n  status?: string;\n  workspaceId?: string;\n  profile?: string;\n  order?: Order;\n  limit?: number;\n};\n\nexport interface GetWorkflowExecutionOptions {\n  executionId: string;\n  workspaceId?: string;\n  profile?: string;\n  interval?: number;\n  timeout?: number;\n  until?: WorkflowWaitUntil;\n  logs?: boolean;\n}\n\nexport interface WorkflowExecutionDetailInfo extends WorkflowExecutionInfo {\n  jobDetails?: (WorkflowJobExecutionInfo & {\n    logs?: string;\n    logEntries?: FunctionLogEntryInfo[];\n    result?: string;\n  })[];\n}\n\nexport interface WorkflowExecutionWaitInfo extends WorkflowExecutionDetailInfo {\n  statusClass: WorkflowWaitResult[\"statusClass\"];\n  elapsedMs: number;\n  attempts: number;\n  timedOut: boolean;\n  lastError: string | null;\n}\n\nexport interface GetWorkflowExecutionResult {\n  execution: WorkflowExecutionDetailInfo;\n  wait: () => Promise<WorkflowExecutionWaitInfo>;\n}\n\nfunction parseStatus(status: string): WorkflowExecution_Status {\n  const upperStatus = status.toUpperCase();\n  switch (upperStatus) {\n    case \"PENDING\":\n      return WorkflowExecution_Status.PENDING;\n    case \"PENDING_RESUME\":\n      return WorkflowExecution_Status.PENDING_RESUME;\n    case \"RUNNING\":\n      return WorkflowExecution_Status.RUNNING;\n    case \"SUCCESS\":\n      return WorkflowExecution_Status.SUCCESS;\n    case \"FAILED\":\n      return WorkflowExecution_Status.FAILED;\n    case \"PENDING_RETRY\":\n      return WorkflowExecution_Status.PENDING_RETRY;\n    case \"WAITING\":\n      return WorkflowExecution_Status.WAITING;\n    case \"UNSPECIFIED\":\n      return WorkflowExecution_Status.UNSPECIFIED;\n    default:\n      throw CLIError({\n        code: \"WORKFLOW_STATUS_INVALID\",\n        message: `Invalid status: ${status}. Valid values: UNSPECIFIED, PENDING, PENDING_RESUME, RUNNING, SUCCESS, FAILED, PENDING_RETRY, WAITING`,\n        command: \"workflow executions\",\n      });\n  }\n}\n\n/**\n * List workflow executions with optional filters.\n *\n * Returns at most `options.limit` items. When `limit` is omitted or 0 the\n * function pages through every execution. The CLI caps this at 50 by\n * default via `pagedLogArgs`; programmatic callers that want the same\n * cap should pass `limit: 50` explicitly.\n * @param options - Workflow execution listing options\n * @returns List of workflow executions\n */\nexport async function listWorkflowExecutions<W extends WorkflowLike>(\n  options?: ListWorkflowExecutionsTypedOptions<W>,\n): Promise<WorkflowExecutionInfo[]> {\n  const workflowName = options?.workflow?.name;\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options?.profile,\n    workspaceId: options?.workspaceId,\n  });\n\n  const filters: ReturnType<typeof create<typeof FilterSchema>>[] = [];\n\n  if (options?.status) {\n    const statusValue = parseStatus(options.status);\n    filters.push(\n      create(FilterSchema, {\n        condition: create(ConditionSchema, {\n          field: \"status\",\n          operator: Condition_Operator.EQ,\n          value: { kind: { case: \"numberValue\", value: statusValue } },\n        }),\n      }),\n    );\n  }\n\n  const filter =\n    filters.length > 0\n      ? create(FilterSchema, {\n          and: filters,\n        })\n      : undefined;\n\n  const pageDirection = toPageDirection(options?.order ?? \"desc\");\n  const executions = await fetchPaged(\n    async (pageToken, pageSize) => {\n      const { executions, nextPageToken } = await client.listWorkflowExecutions({\n        workspaceId,\n        workflowName: workflowName ?? \"\",\n        pageToken,\n        pageSize,\n        pageDirection,\n        filter,\n      });\n      return [executions, nextPageToken];\n    },\n    { limit: options?.limit },\n  );\n\n  return executions.map(toWorkflowExecutionInfo);\n}\n\n/**\n * Get a single workflow execution with optional logs.\n * @param options - Workflow execution lookup options\n * @returns Workflow execution with optional logs\n */\nexport async function getWorkflowExecution(\n  options: GetWorkflowExecutionOptions,\n): Promise<GetWorkflowExecutionResult> {\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options.profile,\n    workspaceId: options.workspaceId,\n  });\n\n  async function fetchFunctionExecution(\n    functionExecutionId: string,\n  ): Promise<FunctionExecution | undefined> {\n    try {\n      const { execution } = await client.getFunctionExecution({\n        workspaceId,\n        executionId: functionExecutionId,\n      });\n      return execution;\n    } catch (error) {\n      if (!(error instanceof ConnectError && error.code === Code.NotFound)) {\n        logger.warn(\n          `Could not fetch logs for function execution '${functionExecutionId}': ${error instanceof Error ? error.message : String(error)}`,\n        );\n      }\n      return undefined;\n    }\n  }\n\n  async function fetchExecutionWithLogs(\n    executionId: string,\n    includeLogs: boolean,\n  ): Promise<WorkflowExecutionDetailInfo> {\n    const { execution } = await client.getWorkflowExecution({\n      workspaceId,\n      executionId,\n    });\n\n    if (!execution) {\n      throw CLIError({\n        code: \"WORKFLOW_EXECUTION_NOT_FOUND\",\n        message: `Execution '${executionId}' not found.`,\n      });\n    }\n\n    const result: WorkflowExecutionDetailInfo = toWorkflowExecutionInfo(execution);\n\n    if (includeLogs && execution.jobExecutions.length > 0) {\n      result.jobDetails = await Promise.all(\n        execution.jobExecutions.map(async (job) => {\n          const jobInfo = toWorkflowJobExecutionInfo(job);\n          if (job.executionId) {\n            const functionExecution = await fetchFunctionExecution(job.executionId);\n            if (functionExecution) {\n              return {\n                ...jobInfo,\n                logs: functionExecution.logs || undefined,\n                logEntries:\n                  functionExecution.logEntries.length > 0\n                    ? functionExecution.logEntries.map(toFunctionLogEntryInfo)\n                    : undefined,\n                result: functionExecution.result || undefined,\n              };\n            }\n          }\n          return jobInfo;\n        }),\n      );\n    }\n\n    return result;\n  }\n\n  async function waitForCompletion(): Promise<WorkflowExecutionWaitInfo> {\n    const interval = options.interval ?? 3000;\n    const waitResult = await waitForWorkflowExecution({\n      client,\n      workspaceId,\n      executionId: options.executionId,\n      interval,\n      timeout: options.timeout,\n      until: options.until ?? \"terminal\",\n    });\n    const execution = await fetchExecutionWithLogs(options.executionId, options.logs ?? false);\n    return {\n      ...execution,\n      statusClass: waitResult.statusClass,\n      elapsedMs: waitResult.elapsedMs,\n      attempts: waitResult.attempts,\n      timedOut: waitResult.timedOut,\n      lastError: waitResult.lastError,\n    };\n  }\n\n  const execution = await fetchExecutionWithLogs(options.executionId, options.logs ?? false);\n\n  return {\n    execution,\n    wait: waitForCompletion,\n  };\n}\n\n/**\n * Print a workflow execution and its logs in a human-readable format.\n * @param execution - Workflow execution detail info\n */\nexport function printExecutionWithLogs(execution: WorkflowExecutionDetailInfo): void {\n  // Helper to format Date as ISO string or \"N/A\"\n  const formatDate = (date: Date | null): string => (date ? date.toISOString() : \"N/A\");\n\n  // Print execution summary\n  const summaryData: [string, string][] = [\n    [\"id\", execution.id],\n    [\"workflowName\", execution.workflowName],\n    [\"status\", execution.status],\n    [\"jobExecutions\", execution.jobExecutions.toString()],\n    [\"startedAt\", formatDate(execution.startedAt)],\n    [\"finishedAt\", formatDate(execution.finishedAt)],\n  ];\n  logger.out(formatKeyValueTable(summaryData));\n\n  // Print job details with logs\n  if (execution.jobDetails && execution.jobDetails.length > 0) {\n    logger.log(styles.bold(\"\\nJob Executions:\"));\n    for (const job of execution.jobDetails) {\n      logger.log(styles.info(`\\n--- ${job.stackedJobName} ---`));\n      logger.log(`  Status: ${job.status}`);\n      logger.log(`  Started: ${formatDate(job.startedAt)}`);\n      logger.log(`  Finished: ${formatDate(job.finishedAt)}`);\n\n      const logLines = formatFunctionLogLines(job.logEntries, job.logs);\n      if (logLines.length > 0) {\n        logger.log(styles.warning(\"\\n  Logs:\"));\n        for (const line of logLines) {\n          logger.log(`    ${line}`);\n        }\n      }\n\n      if (job.result) {\n        logger.log(styles.success(\"\\n  Result:\"));\n        try {\n          const parsed = JSON.parse(job.result);\n          logger.log(`    ${JSON.stringify(parsed, null, 2).split(\"\\n\").join(\"\\n    \")}`);\n        } catch {\n          logger.log(`    ${job.result}`);\n        }\n      }\n    }\n  }\n}\n\nexport const executionsCommand = defineAppCommand({\n  name: \"executions\",\n  description: \"List or get workflow executions.\",\n  args: z.strictObject({\n    ...workspaceArgs,\n    ...pagedLogArgs,\n    \"execution-id\": arg(z.string().optional(), {\n      positional: true,\n      description: \"Execution ID (if provided, shows details)\",\n    }),\n    \"workflow-name\": arg(\n      z\n        .string()\n        .regex(\n          /^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/,\n          \"Must be 3-63 lowercase alphanumeric characters or hyphens, starting and ending with alphanumeric\",\n        )\n        .optional(),\n      {\n        alias: \"n\",\n        description: \"Filter by workflow name (list mode only)\",\n      },\n    ),\n    status: arg(z.string().optional(), {\n      alias: \"s\",\n      description: \"Filter by status (list mode only)\",\n    }),\n    ...waitArgs,\n    logs: arg(z.boolean().default(false), {\n      description: \"Display job execution logs (detail mode only)\",\n    }),\n  }),\n  run: async (args) => {\n    const jsonOutput = logger.jsonMode || args.json;\n    if (args.executionId) {\n      const interval = parseDuration(args.interval);\n\n      if (!jsonOutput) {\n        logger.info(`Execution ID: ${args.executionId}`, { mode: \"stream\" });\n      }\n\n      if (args.wait) {\n        const result = await waitForWorkflowExecutionById({\n          executionId: args.executionId,\n          workspaceId: args[\"workspace-id\"],\n          profile: args.profile,\n          interval,\n          timeout: parseDuration(args.timeout),\n          until: args.until,\n          showProgress: !jsonOutput,\n          trackJobs: true,\n        });\n\n        if (args.logs && !jsonOutput) {\n          const { execution } = await getWorkflowExecution({\n            executionId: args.executionId,\n            workspaceId: args[\"workspace-id\"],\n            profile: args.profile,\n            logs: true,\n          });\n          printExecutionWithLogs(execution);\n        } else if (args.logs) {\n          const { execution } = await getWorkflowExecution({\n            executionId: args.executionId,\n            workspaceId: args[\"workspace-id\"],\n            profile: args.profile,\n            logs: true,\n          });\n          const output: WorkflowWaitResult & Pick<WorkflowExecutionDetailInfo, \"jobDetails\"> = {\n            ...result,\n            jobDetails: execution.jobDetails,\n          };\n          logger.out(output);\n        } else {\n          logger.out(result);\n        }\n\n        const failure = getWorkflowWaitFailure(result, args.until);\n        if (failure) {\n          throw failure;\n        }\n        return;\n      }\n\n      const { execution } = await getWorkflowExecution({\n        executionId: args.executionId,\n        workspaceId: args[\"workspace-id\"],\n        profile: args.profile,\n        interval,\n        logs: args.logs,\n      });\n\n      if (args.logs && !jsonOutput) {\n        printExecutionWithLogs(execution);\n      } else {\n        logger.out(execution);\n      }\n    } else {\n      const executions = await listWorkflowExecutions({\n        workspaceId: args[\"workspace-id\"],\n        profile: args.profile,\n        workflow: args[\"workflow-name\"] === undefined ? undefined : { name: args[\"workflow-name\"] },\n        status: args.status,\n        order: args.order,\n        limit: args.limit,\n      });\n      logger.out(executions);\n    }\n  },\n});\n","import { Code, ConnectError } from \"@connectrpc/connect\";\nimport { z } from \"zod\";\nimport { workspaceArgs } from \"#/cli/shared/args\";\nimport { type initOperatorClient } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { nameArgs } from \"./args\";\nimport { type WorkflowInfo, toWorkflowInfo } from \"./transform\";\n\ntype WorkflowLike = {\n  name: string;\n};\n\nexport type GetWorkflowTypedOptions<W extends WorkflowLike = WorkflowLike> = {\n  workflow: W;\n  workspaceId?: string;\n  profile?: string;\n};\n\n/**\n * Resolve a workflow definition by name.\n * @param client - Operator client\n * @param workspaceId - Workspace ID\n * @param name - Workflow name\n * @returns Resolved workflow\n */\nexport async function resolveWorkflow(\n  client: Awaited<ReturnType<typeof initOperatorClient>>,\n  workspaceId: string,\n  name: string,\n) {\n  const { workflow } = await client.getWorkflowByName({\n    workspaceId,\n    workflowName: name,\n  });\n  if (!workflow) {\n    throw CLIError({ code: \"WORKFLOW_NOT_FOUND\", message: `Workflow '${name}' not found.` });\n  }\n  return workflow;\n}\n\n/**\n * Get a workflow by name and return CLI-friendly info.\n * @param options - Workflow lookup options\n * @returns Workflow information\n */\nexport async function getWorkflow<W extends WorkflowLike>(\n  options: GetWorkflowTypedOptions<W>,\n): Promise<WorkflowInfo> {\n  const name = options.workflow.name;\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options.profile,\n    workspaceId: options.workspaceId,\n  });\n\n  try {\n    const workflow = await resolveWorkflow(client, workspaceId, name);\n    return toWorkflowInfo(workflow);\n  } catch (error) {\n    if (error instanceof ConnectError && error.code === Code.NotFound) {\n      throw CLIError({\n        code: \"WORKFLOW_NOT_FOUND\",\n        message: `Workflow '${name}' not found.`,\n        cause: error,\n      });\n    }\n    throw error;\n  }\n}\n\nexport const getCommand = defineAppCommand({\n  name: \"get\",\n  description: \"Get workflow details.\",\n  args: z.strictObject({\n    ...workspaceArgs,\n    ...nameArgs,\n  }),\n  run: async (args) => {\n    const workflow = await getWorkflow({\n      workflow: { name: args.name },\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n    });\n\n    logger.out(workflow);\n  },\n});\n","import { create } from \"@bufbuild/protobuf\";\nimport { Code, ConnectError } from \"@connectrpc/connect\";\nimport { arg } from \"@politty/zod\";\nimport { AuthInvokerSchema } from \"@tailor-platform/tailor-proto/auth_resource_pb\";\nimport { z } from \"zod\";\nimport {\n  deploymentArgs,\n  parseDuration,\n  resolveMachineUserInputSource,\n  type MachineUserInputSource,\n} from \"#/cli/shared/args\";\nimport { type initOperatorClient } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadConfig } from \"#/cli/shared/config-loader\";\nimport { loadMachineUserName } from \"#/cli/shared/context\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { nameArgs, waitArgs } from \"./args\";\nimport { getWorkflowExecution, printExecutionWithLogs } from \"./executions\";\nimport { resolveWorkflow } from \"./get\";\nimport { type WorkflowWaitUntil } from \"./status\";\nimport {\n  getWorkflowWaitFailure,\n  waitForWorkflowExecution,\n  type WorkflowWaitResult,\n} from \"./waiter\";\n// Import from the public entry (not `@/types/auth`) so the `./cli` d.ts references\n// `@tailor-platform/sdk` externally instead of inlining the registry — a single\n// generated `declare module \"@tailor-platform/sdk\"` then narrows both entries.\nimport type { MachineUserName } from \"@tailor-platform/sdk\";\nimport type { Jsonifiable } from \"type-fest\";\n\ntype WorkflowLike = {\n  name: string;\n  mainJob: {\n    body: unknown;\n  };\n};\n\ntype WorkflowInvoker<M extends string = string> = {\n  namespace: string;\n  machineUserName: M;\n};\n\ntype WorkflowInput<W extends WorkflowLike> = W extends WorkflowLike\n  ? W[\"mainJob\"][\"body\"] extends (...args: infer Args) => unknown\n    ? Args[0]\n    : never\n  : never;\n\ntype StartWorkflowArgOptionForSingleWorkflow<W extends WorkflowLike> = WorkflowLike extends W\n  ? { arg?: Jsonifiable }\n  : undefined extends WorkflowInput<W>\n    ? { arg?: WorkflowInput<W> }\n    : { arg: WorkflowInput<W> };\n\ntype StartWorkflowArgOption<W extends WorkflowLike> = W extends WorkflowLike\n  ? StartWorkflowArgOptionForSingleWorkflow<W>\n  : never;\n\ntype StartWorkflowByNameOptions = {\n  name: string;\n  machineUser?: string;\n  arg?: Jsonifiable;\n  workspaceId?: string;\n  profile?: string;\n  configPath?: string;\n  interval?: number;\n  machineUserSource?: MachineUserInputSource;\n};\n\ntype StartWorkflowTypedBaseOptions<W extends WorkflowLike> = {\n  workflow: W;\n  invoker: MachineUserName;\n  workspaceId?: string;\n  profile?: string;\n  configPath?: string;\n  interval?: number;\n};\n\nexport type StartWorkflowTypedOptions<W extends WorkflowLike = WorkflowLike> =\n  W extends WorkflowLike ? StartWorkflowTypedBaseOptions<W> & StartWorkflowArgOption<W> : never;\n\nexport { waitForWorkflowExecution as waitForExecution };\n\nexport interface WaitOptions {\n  showProgress?: boolean;\n  timeout?: number;\n  until?: WorkflowWaitUntil;\n}\n\nexport interface StartWorkflowResultWithWait {\n  executionId: string;\n  wait: (options?: WaitOptions) => Promise<WorkflowWaitResult>;\n}\n\ninterface StartWorkflowCoreOptions {\n  client: Awaited<ReturnType<typeof initOperatorClient>>;\n  workspaceId: string;\n  workflowName: string;\n  invoker: WorkflowInvoker<string>;\n  arg?: unknown;\n  interval?: number;\n}\n\nasync function startWorkflowCore(\n  options: StartWorkflowCoreOptions,\n): Promise<StartWorkflowResultWithWait> {\n  const { client, workspaceId, workflowName } = options;\n\n  try {\n    const workflow = await resolveWorkflow(client, workspaceId, workflowName);\n    const invoker = create(AuthInvokerSchema, options.invoker);\n    const arg =\n      options.arg === undefined\n        ? undefined\n        : typeof options.arg === \"string\"\n          ? options.arg\n          : JSON.stringify(options.arg);\n\n    const { executionId } = await client.startWorkflow({\n      workspaceId,\n      workflowId: workflow.id,\n      authInvoker: invoker,\n      arg,\n    });\n\n    return {\n      executionId,\n      wait: (waitOptions?: WaitOptions) =>\n        waitForWorkflowExecution({\n          client,\n          workspaceId,\n          executionId,\n          interval: options.interval ?? 3000,\n          timeout: waitOptions?.timeout,\n          until: waitOptions?.until,\n          showProgress: waitOptions?.showProgress,\n          trackJobs: true,\n        }),\n    };\n  } catch (error) {\n    if (error instanceof ConnectError && error.code === Code.NotFound) {\n      throw CLIError({\n        code: \"WORKFLOW_NOT_FOUND\",\n        message: `Workflow '${workflowName}' not found.`,\n        cause: error,\n      });\n    }\n    throw error;\n  }\n}\n\nasync function resolveApplicationAuthNamespace(options: {\n  client: Awaited<ReturnType<typeof initOperatorClient>>;\n  workspaceId: string;\n  configPath?: string;\n}): Promise<string> {\n  const { config } = await loadConfig(options.configPath);\n  const { application } = await options.client.getApplication({\n    workspaceId: options.workspaceId,\n    applicationName: config.name,\n  });\n  const authNamespace = application?.authNamespace || config.auth?.name;\n  if (!authNamespace) {\n    throw CLIError({\n      code: \"AUTH_CONFIG_REQUIRED\",\n      message: `Application ${config.name} does not have an auth configuration.`,\n    });\n  }\n  return authNamespace;\n}\n\n/**\n * Start a workflow looked up by name, resolving the machine user from the\n * flag, environment, or profile default. Backs the `workflow start` command;\n * programmatic callers use {@link startWorkflow} with a workflow definition.\n * @param options - Start options keyed by workflow name\n * @returns Start result with wait helper\n */\nexport async function startWorkflowByName(\n  options: StartWorkflowByNameOptions,\n): Promise<StartWorkflowResultWithWait> {\n  const machineUser = await loadMachineUserName({\n    machineUser: options.machineUser,\n    machineUserSource: options.machineUserSource,\n    profile: options.profile,\n  });\n  if (!machineUser) {\n    throw CLIError({\n      code: \"MACHINE_USER_REQUIRED\",\n      message: \"Machine user is required.\",\n      suggestion:\n        \"Specify --machine-user, set TAILOR_PLATFORM_MACHINE_USER_NAME, or set a profile default with 'tailor profile update <profile> --machine-user <name>'.\",\n    });\n  }\n\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options.profile,\n    workspaceId: options.workspaceId,\n  });\n\n  const authNamespace = await resolveApplicationAuthNamespace({\n    client,\n    workspaceId,\n    configPath: options.configPath,\n  });\n\n  return await startWorkflowCore({\n    client,\n    workspaceId,\n    workflowName: options.name,\n    invoker: {\n      namespace: authNamespace,\n      machineUserName: machineUser,\n    },\n    arg: options.arg,\n    interval: options.interval,\n  });\n}\n\n/**\n * Start a workflow and return a handle to wait for completion.\n * @param options - Start options\n * @returns Start result with wait helper\n */\nexport async function startWorkflow<W extends WorkflowLike>(\n  options: StartWorkflowTypedOptions<W>,\n): Promise<StartWorkflowResultWithWait> {\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options.profile,\n    workspaceId: options.workspaceId,\n  });\n  const authNamespace = await resolveApplicationAuthNamespace({\n    client,\n    workspaceId,\n    configPath: options.configPath,\n  });\n\n  return await startWorkflowCore({\n    client,\n    workspaceId,\n    workflowName: options.workflow.name,\n    invoker: {\n      namespace: authNamespace,\n      machineUserName: options.invoker,\n    },\n    arg: options.arg,\n    interval: options.interval,\n  });\n}\n\nexport const startCommand = defineAppCommand({\n  name: \"start\",\n  description: \"Start a workflow execution.\",\n  args: z.strictObject({\n    ...deploymentArgs,\n    ...nameArgs,\n    \"machine-user\": arg(z.string().optional(), {\n      alias: \"m\",\n      description: \"Machine user name. Falls back to the active profile's default machine user.\",\n      env: \"TAILOR_PLATFORM_MACHINE_USER_NAME\",\n    }),\n    arg: arg(z.string().optional(), {\n      alias: \"a\",\n      description: \"Workflow argument (JSON string)\",\n    }),\n    ...waitArgs,\n  }),\n  run: async (args) => {\n    const { executionId, wait } = await startWorkflowByName({\n      name: args.name,\n      machineUser: args[\"machine-user\"],\n      machineUserSource: resolveMachineUserInputSource(args[\"machine-user\"]),\n      arg: args.arg,\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      configPath: args.config,\n      interval: parseDuration(args.interval),\n    });\n    const jsonOutput = logger.jsonMode;\n\n    logger.info(`Execution ID: ${executionId}`, { mode: \"stream\" });\n\n    if (args.wait) {\n      const result = await wait({\n        showProgress: !jsonOutput,\n        timeout: parseDuration(args.timeout),\n        until: args.until,\n      });\n      if (args.logs && !jsonOutput) {\n        const { execution } = await getWorkflowExecution({\n          executionId,\n          workspaceId: args[\"workspace-id\"],\n          profile: args.profile,\n          logs: true,\n        });\n        printExecutionWithLogs(execution);\n      } else if (args.logs) {\n        const { execution } = await getWorkflowExecution({\n          executionId,\n          workspaceId: args[\"workspace-id\"],\n          profile: args.profile,\n          logs: true,\n        });\n        logger.out({ ...result, jobDetails: execution.jobDetails });\n      } else {\n        logger.out(result);\n      }\n      const failure = getWorkflowWaitFailure(result, args.until);\n      if (failure) {\n        throw failure;\n      }\n    } else {\n      logger.out({ executionId });\n    }\n  },\n});\n","import { setTimeout } from \"timers/promises\";\nimport { create } from \"@bufbuild/protobuf\";\nimport { Code, ConnectError } from \"@connectrpc/connect\";\nimport { arg } from \"@politty/zod\";\nimport {\n  ExecutorJobStatus,\n  ExecutorTargetType,\n} from \"@tailor-platform/tailor-proto/executor_resource_pb\";\nimport { FunctionExecution_Status } from \"@tailor-platform/tailor-proto/function_resource_pb\";\nimport {\n  Condition_Operator,\n  ConditionSchema,\n  FilterSchema,\n  PageDirection,\n} from \"@tailor-platform/tailor-proto/resource_pb\";\nimport { z } from \"zod\";\nimport {\n  durationArg,\n  nonNegativeIntArg,\n  type Order,\n  pagedLogArgs,\n  parseDuration,\n  toPageDirection,\n  workspaceArgs,\n} from \"#/cli/shared/args\";\nimport { fetchAll, fetchPaged } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { formatKeyValueTable } from \"#/cli/shared/format\";\nimport {\n  colorizeFunctionExecutionStatus,\n  functionExecutionStatusToString,\n  isFunctionExecutionTerminalStatus,\n} from \"#/cli/shared/function-execution\";\nimport { logger, styles } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { spinner } from \"#/cli/shared/spinner\";\nimport { formatWaitError, isRetryableWaitError } from \"#/cli/shared/wait-error\";\nimport { getWorkflowExecution } from \"../workflow/executions\";\nimport { waitForExecution } from \"../workflow/start\";\nimport {\n  classifyExecutorJobStatus,\n  colorizeExecutorJobStatus,\n  executorTargetTypeToString,\n  parseExecutorJobStatus,\n} from \"./status\";\nimport {\n  type ExecutorJobListInfo,\n  type ExecutorJobInfo,\n  type ExecutorJobAttemptInfo,\n  toExecutorJobListInfo,\n  toExecutorJobInfo,\n  toExecutorJobAttemptInfo,\n} from \"./transform\";\n\ntype ExecutorLike = {\n  name: string;\n};\n\nexport type ListExecutorJobsTypedOptions<E extends ExecutorLike = ExecutorLike> = {\n  executor: E;\n  status?: string;\n  order?: Order;\n  limit?: number;\n  workspaceId?: string;\n  profile?: string;\n};\n\nexport type GetExecutorJobTypedOptions<E extends ExecutorLike = ExecutorLike> = {\n  executor: E;\n  jobId: string;\n  attempts?: boolean;\n  workspaceId?: string;\n  profile?: string;\n};\n\nexport type WatchExecutorJobTypedOptions<E extends ExecutorLike = ExecutorLike> = {\n  executor: E;\n  jobId: string;\n  workspaceId?: string;\n  profile?: string;\n  interval?: number;\n  timeout?: number;\n  logs?: boolean;\n  showProgress?: boolean;\n};\n\nexport interface ExecutorJobDetailInfo extends ExecutorJobInfo {\n  attempts?: ExecutorJobAttemptInfo[];\n}\n\ninterface WorkflowJobLog {\n  jobName: string;\n  logs?: string;\n  result?: string;\n}\n\nexport interface WatchExecutorJobResult {\n  job: ExecutorJobDetailInfo;\n  targetType: string;\n  elapsedMs: number;\n  attempts: number;\n  timedOut: boolean;\n  lastError: string | null;\n  workflowExecutionId?: string;\n  workflowStatus?: string;\n  workflowJobLogs?: WorkflowJobLog[];\n  functionExecutionId?: string;\n  functionStatus?: string;\n  functionLogs?: string;\n}\n\nfunction formatTime(date: Date): string {\n  return date.toLocaleTimeString(\"en-US\", { hour12: false });\n}\n\nfunction createUnknownExecutorJob(executorName: string, jobId: string): ExecutorJobDetailInfo {\n  return {\n    id: jobId,\n    executorName,\n    status: \"UNKNOWN\",\n    scheduledAt: \"N/A\",\n    createdAt: \"N/A\",\n    updatedAt: \"N/A\",\n  };\n}\n\n/**\n * List executor jobs for a given executor.\n *\n * Returns at most `options.limit` items. When `limit` is omitted or 0 the\n * function pages through every job. The CLI caps this at 50 by default\n * via `pagedLogArgs`; programmatic callers that want the same cap should\n * pass `limit: 50` explicitly.\n * @param options - Options for listing executor jobs\n * @returns List of executor job information\n */\nexport async function listExecutorJobs<E extends ExecutorLike>(\n  options: ListExecutorJobsTypedOptions<E>,\n): Promise<ExecutorJobListInfo[]> {\n  const executorName = options.executor.name;\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options.profile,\n    workspaceId: options.workspaceId,\n  });\n\n  const filters: ReturnType<typeof create<typeof FilterSchema>>[] = [];\n\n  if (options.status) {\n    const statusValue = parseExecutorJobStatus(options.status);\n    filters.push(\n      create(FilterSchema, {\n        condition: create(ConditionSchema, {\n          field: \"status\",\n          operator: Condition_Operator.EQ,\n          value: { kind: { case: \"numberValue\", value: statusValue } },\n        }),\n      }),\n    );\n  }\n\n  const filter = filters.length > 0 ? create(FilterSchema, { and: filters }) : undefined;\n\n  const pageDirection = toPageDirection(options.order ?? \"desc\");\n\n  try {\n    const jobs = await fetchPaged(\n      async (pageToken, pageSize) => {\n        const { jobs, nextPageToken } = await client.listExecutorJobs({\n          workspaceId,\n          executorName,\n          pageToken,\n          pageSize,\n          pageDirection,\n          filter,\n        });\n        return [jobs, nextPageToken];\n      },\n      { limit: options.limit },\n    );\n\n    return jobs.map(toExecutorJobListInfo);\n  } catch (error) {\n    if (error instanceof ConnectError && error.code === Code.NotFound) {\n      throw CLIError({\n        code: \"EXECUTOR_NOT_FOUND\",\n        message: `Executor '${executorName}' not found.`,\n        cause: error,\n      });\n    }\n    throw error;\n  }\n}\n\n/**\n * Get details of a specific executor job.\n * @param options - Options for getting executor job details\n * @returns Executor job detail information\n */\nexport async function getExecutorJob<E extends ExecutorLike>(\n  options: GetExecutorJobTypedOptions<E>,\n): Promise<ExecutorJobDetailInfo> {\n  const executorName = options.executor.name;\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options.profile,\n    workspaceId: options.workspaceId,\n  });\n\n  try {\n    const { job } = await client.getExecutorJob({\n      workspaceId,\n      executorName,\n      jobId: options.jobId,\n    });\n\n    if (!job) {\n      throw CLIError({\n        code: \"EXECUTOR_JOB_NOT_FOUND\",\n        message: `Job '${options.jobId}' not found.`,\n      });\n    }\n\n    const jobInfo = toExecutorJobInfo(job);\n\n    if (options.attempts) {\n      const attempts = await fetchAll(async (pageToken, maxPageSize) => {\n        const { attempts, nextPageToken } = await client.listExecutorJobAttempts({\n          workspaceId,\n          jobId: options.jobId,\n          pageToken,\n          pageSize: maxPageSize,\n          pageDirection: PageDirection.DESC,\n        });\n        return [attempts, nextPageToken];\n      });\n\n      return {\n        ...jobInfo,\n        attempts: attempts.map(toExecutorJobAttemptInfo),\n      };\n    }\n\n    return jobInfo;\n  } catch (error) {\n    if (error instanceof ConnectError && error.code === Code.NotFound) {\n      throw CLIError({\n        code: \"EXECUTOR_JOB_NOT_FOUND\",\n        message: `Job '${options.jobId}' not found for executor '${executorName}'.`,\n        cause: error,\n      });\n    }\n    throw error;\n  }\n}\n\n/**\n * Watch an executor job until completion, including downstream executions.\n * @param options - Options for watching executor job\n * @returns Result including job details and downstream execution info\n */\nexport async function watchExecutorJob<E extends ExecutorLike>(\n  options: WatchExecutorJobTypedOptions<E>,\n): Promise<WatchExecutorJobResult> {\n  const executorName = options.executor.name;\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options.profile,\n    workspaceId: options.workspaceId,\n  });\n\n  const interval = options.interval ?? 3000;\n  const timeout = options.timeout;\n  const showProgress = options.showProgress ?? !logger.jsonMode;\n  const startedAt = Date.now();\n  const sp = showProgress ? spinner().start(\"Waiting for executor job to complete...\") : null;\n\n  let attempts = 0;\n  let lastError: string | null = null;\n\n  type WatchExecutorJobResultBase = Omit<\n    WatchExecutorJobResult,\n    \"elapsedMs\" | \"attempts\" | \"timedOut\" | \"lastError\"\n  >;\n\n  const remainingTimeout = (): number | undefined => {\n    if (timeout === undefined) {\n      return undefined;\n    }\n    return timeout - (Date.now() - startedAt);\n  };\n\n  const withWaitMetadata = (\n    result: WatchExecutorJobResultBase,\n    timedOut: boolean,\n  ): WatchExecutorJobResult => ({\n    ...result,\n    elapsedMs: Date.now() - startedAt,\n    attempts,\n    timedOut,\n    lastError,\n  });\n\n  const timeoutResult = (\n    targetType: string,\n    job: Awaited<ReturnType<typeof client.getExecutorJob>>[\"job\"],\n  ): WatchExecutorJobResult =>\n    withWaitMetadata(\n      {\n        job: job ? toExecutorJobInfo(job) : createUnknownExecutorJob(executorName, options.jobId),\n        targetType,\n      },\n      true,\n    );\n\n  try {\n    // Get executor details to determine target type\n    const { executor } = await client.getExecutorExecutor({\n      workspaceId,\n      name: executorName,\n    });\n\n    if (!executor) {\n      throw CLIError({\n        code: \"EXECUTOR_NOT_FOUND\",\n        message: `Executor '${executorName}' not found.`,\n      });\n    }\n\n    const targetType = executor.targetType;\n    const targetTypeStr = executorTargetTypeToString(targetType);\n\n    // Phase 1: Wait for executor job to complete\n    let job: Awaited<ReturnType<typeof client.getExecutorJob>>[\"job\"];\n    // loop exits when the executor job reaches a terminal status\n    // oxlint-disable-next-line typescript/no-unnecessary-condition\n    while (true) {\n      const remainingMs = remainingTimeout();\n      if (remainingMs !== undefined && remainingMs <= 0) {\n        sp?.fail(\"Executor job wait timed out.\");\n        return timeoutResult(targetTypeStr, job);\n      }\n\n      try {\n        attempts += 1;\n        const response = await client.getExecutorJob({\n          workspaceId,\n          executorName,\n          jobId: options.jobId,\n        });\n\n        job = response.job;\n        if (!job) {\n          throw CLIError({\n            code: \"EXECUTOR_JOB_NOT_FOUND\",\n            message: `Job '${options.jobId}' not found.`,\n          });\n        }\n        lastError = null;\n\n        if (classifyExecutorJobStatus(job.status) !== \"transient\") {\n          break;\n        }\n      } catch (error) {\n        if (!isRetryableWaitError(error)) {\n          throw error;\n        }\n        lastError = formatWaitError(error);\n        if (sp) {\n          sp.text = `Retrying executor job poll... (${formatTime(new Date())})`;\n        }\n      }\n\n      const nextRemainingMs = remainingTimeout();\n      if (nextRemainingMs !== undefined && nextRemainingMs <= 0) {\n        sp?.fail(\"Executor job wait timed out.\");\n        return timeoutResult(targetTypeStr, job);\n      }\n\n      if (sp) {\n        sp.text = `Waiting for executor job... (${formatTime(new Date())})`;\n      }\n      await setTimeout(\n        nextRemainingMs === undefined ? interval : Math.min(interval, nextRemainingMs),\n      );\n    }\n\n    const jobInfo = toExecutorJobInfo(job);\n    const coloredStatus = colorizeExecutorJobStatus(jobInfo.status);\n\n    if (job.status === ExecutorJobStatus.SUCCESS) {\n      sp?.succeed(`Executor job completed: ${coloredStatus}`);\n    } else {\n      sp?.fail(`Executor job completed: ${coloredStatus}`);\n    }\n\n    // Get attempts to find operationReference\n    const attemptRecords = await fetchAll(async (pageToken, maxPageSize) => {\n      const { attempts: jobAttempts, nextPageToken } = await client.listExecutorJobAttempts({\n        workspaceId,\n        jobId: options.jobId,\n        pageToken,\n        pageSize: maxPageSize,\n        pageDirection: PageDirection.DESC,\n      });\n      return [jobAttempts, nextPageToken];\n    });\n\n    const attemptInfos = attemptRecords.map(toExecutorJobAttemptInfo);\n    const jobDetail: ExecutorJobDetailInfo = {\n      ...jobInfo,\n      attempts: attemptInfos,\n    };\n\n    const latestAttempt = attemptInfos[0];\n    const operationReference = latestAttempt?.operationReference;\n\n    // Phase 2: Based on target type, wait for the downstream execution\n    if (operationReference) {\n      switch (targetType) {\n        case ExecutorTargetType.WORKFLOW: {\n          // Wait for workflow execution with progress display\n          sp?.stop();\n\n          try {\n            const workflowTimeout = remainingTimeout();\n            if (workflowTimeout !== undefined && workflowTimeout <= 0) {\n              return withWaitMetadata(\n                {\n                  job: jobDetail,\n                  targetType: targetTypeStr,\n                  workflowExecutionId: operationReference,\n                },\n                true,\n              );\n            }\n\n            // Use waitForExecution with progress display (same as workflow start)\n            const executionResult = await waitForExecution({\n              client,\n              workspaceId,\n              executionId: operationReference,\n              interval,\n              timeout: workflowTimeout,\n              showProgress,\n              trackJobs: true,\n            });\n            attempts += executionResult.attempts;\n            lastError = executionResult.lastError;\n\n            // Fetch logs if requested\n            let workflowJobLogs: WorkflowJobLog[] | undefined;\n            if (options.logs) {\n              try {\n                const { execution: execWithLogs } = await getWorkflowExecution({\n                  executionId: operationReference,\n                  workspaceId: options.workspaceId,\n                  profile: options.profile,\n                  logs: true,\n                });\n                if (execWithLogs.jobDetails) {\n                  workflowJobLogs = execWithLogs.jobDetails\n                    .filter((job) => job.logs || job.result)\n                    .map((job) => ({\n                      jobName: job.stackedJobName || job.id,\n                      logs: job.logs,\n                      result: job.result,\n                    }));\n                }\n              } catch (error) {\n                logger.warn(\n                  `Could not fetch workflow execution logs: ${error instanceof Error ? error.message : error}`,\n                );\n              }\n            }\n\n            return withWaitMetadata(\n              {\n                job: jobDetail,\n                targetType: targetTypeStr,\n                workflowExecutionId: operationReference,\n                workflowStatus: executionResult.status,\n                workflowJobLogs,\n              },\n              executionResult.timedOut,\n            );\n          } catch (error) {\n            logger.warn(\n              `Could not track workflow execution: ${error instanceof Error ? error.message : error}`,\n            );\n            return withWaitMetadata(\n              {\n                job: jobDetail,\n                targetType: targetTypeStr,\n                workflowExecutionId: operationReference,\n              },\n              false,\n            );\n          }\n        }\n\n        case ExecutorTargetType.FUNCTION:\n        case ExecutorTargetType.JOB_FUNCTION:\n          {\n            // Wait for function execution\n            sp?.start(`Waiting for function execution ${operationReference}...`);\n\n            try {\n              let functionStatus: string | undefined;\n              // oxlint-disable-next-line typescript/no-unnecessary-condition\n              while (true) {\n                const functionTimeout = remainingTimeout();\n                if (functionTimeout !== undefined && functionTimeout <= 0) {\n                  sp?.fail(\"Function execution wait timed out.\");\n                  return withWaitMetadata(\n                    {\n                      job: jobDetail,\n                      targetType: targetTypeStr,\n                      functionExecutionId: operationReference,\n                      functionStatus,\n                    },\n                    true,\n                  );\n                }\n\n                try {\n                  attempts += 1;\n                  const { execution } = await client.getFunctionExecution({\n                    workspaceId,\n                    executionId: operationReference,\n                  });\n\n                  if (!execution) {\n                    throw CLIError({\n                      code: \"FUNCTION_EXECUTION_NOT_FOUND\",\n                      message: `Function execution '${operationReference}' not found.`,\n                    });\n                  }\n\n                  lastError = null;\n                  functionStatus = functionExecutionStatusToString(execution.status);\n\n                  if (isFunctionExecutionTerminalStatus(execution.status)) {\n                    const coloredFnStatus = colorizeFunctionExecutionStatus(functionStatus);\n                    if (execution.status === FunctionExecution_Status.SUCCESS) {\n                      sp?.succeed(`Function execution completed: ${coloredFnStatus}`);\n                    } else {\n                      sp?.fail(`Function execution completed: ${coloredFnStatus}`);\n                    }\n                    return withWaitMetadata(\n                      {\n                        job: jobDetail,\n                        targetType: targetTypeStr,\n                        functionExecutionId: operationReference,\n                        functionStatus,\n                        functionLogs: options.logs ? execution.logs || undefined : undefined,\n                      },\n                      false,\n                    );\n                  }\n                } catch (error) {\n                  if (!isRetryableWaitError(error)) {\n                    throw error;\n                  }\n                  lastError = formatWaitError(error);\n                  if (sp) {\n                    sp.text = `Retrying function execution poll... (${formatTime(new Date())})`;\n                  }\n                }\n\n                const nextFunctionTimeout = remainingTimeout();\n                if (nextFunctionTimeout !== undefined && nextFunctionTimeout <= 0) {\n                  sp?.fail(\"Function execution wait timed out.\");\n                  return withWaitMetadata(\n                    {\n                      job: jobDetail,\n                      targetType: targetTypeStr,\n                      functionExecutionId: operationReference,\n                      functionStatus,\n                    },\n                    true,\n                  );\n                }\n\n                if (sp) {\n                  sp.text = `Waiting for function execution... (${formatTime(new Date())})`;\n                }\n                await setTimeout(\n                  nextFunctionTimeout === undefined\n                    ? interval\n                    : Math.min(interval, nextFunctionTimeout),\n                );\n              }\n            } catch (error) {\n              sp?.warn(\n                `Could not track function execution: ${error instanceof Error ? error.message : error}`,\n              );\n              return withWaitMetadata(\n                {\n                  job: jobDetail,\n                  targetType: targetTypeStr,\n                  functionExecutionId: operationReference,\n                },\n                false,\n              );\n            }\n          }\n          break;\n        default:\n          // WEBHOOK, TAILOR_GRAPHQL, or unknown - no downstream execution to track\n          break;\n      }\n    }\n\n    return withWaitMetadata({ job: jobDetail, targetType: targetTypeStr }, false);\n  } finally {\n    sp?.stop();\n  }\n}\n\n/**\n * Build the failure for an executor job wait result.\n * @param result - Executor job wait result\n * @returns Coded failure, or undefined when the wait succeeded\n */\nexport function getExecutorWaitFailure(result: WatchExecutorJobResult): CLIError | undefined {\n  const context = {\n    jobId: result.job.id,\n    status: result.job.status,\n    workflowExecutionId: result.workflowExecutionId,\n    functionExecutionId: result.functionExecutionId,\n  };\n  if (result.timedOut) {\n    return CLIError({\n      code: \"EXECUTOR_WAIT_TIMEOUT\",\n      message: `Timed out waiting for executor job '${result.job.id}'. Last status: ${result.job.status}.`,\n      context,\n    });\n  }\n  if (result.job.status === \"FAILED\" || result.job.status === \"CANCELED\") {\n    return CLIError({\n      code: \"EXECUTOR_JOB_FAILED\",\n      message: `Executor job '${result.job.id}' completed with status ${result.job.status}.`,\n      context,\n    });\n  }\n  if (result.workflowStatus === \"FAILED\") {\n    return CLIError({\n      code: \"WORKFLOW_EXECUTION_FAILED\",\n      message: `Workflow execution '${result.workflowExecutionId}' failed.`,\n      context,\n    });\n  }\n  if (result.functionStatus === \"FAILED\") {\n    return CLIError({\n      code: \"FUNCTION_EXECUTION_FAILED\",\n      message: `Function execution '${result.functionExecutionId}' failed.`,\n      context,\n    });\n  }\n  if (result.functionStatus === \"CANCELED\") {\n    return CLIError({\n      code: \"FUNCTION_EXECUTION_CANCELED\",\n      message: `Function execution '${result.functionExecutionId}' was canceled.`,\n      context,\n    });\n  }\n  return undefined;\n}\n\n/**\n * Build a user-facing failure message for an executor job wait result.\n * @param result - Executor job wait result\n * @returns Failure message, or undefined when the wait succeeded\n */\nexport function getExecutorWaitFailureMessage(result: WatchExecutorJobResult): string | undefined {\n  return getExecutorWaitFailure(result)?.message;\n}\n\nfunction printJobWithAttempts(job: ExecutorJobDetailInfo): void {\n  // Print job summary\n  const summaryData: [string, string][] = [\n    [\"id\", job.id],\n    [\"executorName\", job.executorName],\n    [\"status\", job.status],\n    [\"scheduledAt\", job.scheduledAt],\n    [\"createdAt\", job.createdAt],\n    [\"updatedAt\", job.updatedAt],\n  ];\n  logger.log(formatKeyValueTable(summaryData));\n\n  // Print attempts\n  if (job.attempts && job.attempts.length > 0) {\n    logger.log(styles.bold(\"\\nAttempts:\"));\n    for (const attempt of job.attempts) {\n      logger.log(styles.info(`\\n--- Attempt ${attempt.id} ---`));\n      logger.log(`  Status: ${attempt.status}`);\n      logger.log(`  Started: ${attempt.startedAt}`);\n      logger.log(`  Finished: ${attempt.finishedAt}`);\n\n      if (attempt.error) {\n        logger.log(styles.error(\"\\n  Error:\"));\n        const errorLines = attempt.error.split(\"\\n\");\n        for (const line of errorLines) {\n          logger.log(`    ${line}`);\n        }\n      }\n    }\n  }\n}\n\nexport const jobsCommand = defineAppCommand({\n  name: \"jobs\",\n  description: \"List or get executor jobs.\",\n  examples: [\n    {\n      cmd: \"my-executor\",\n      desc: \"List jobs for an executor (default: 50 jobs)\",\n    },\n    { cmd: \"my-executor --limit 10\", desc: \"Limit the number of jobs\" },\n    { cmd: \"my-executor -s RUNNING\", desc: \"Filter by status\" },\n    { cmd: \"my-executor <job-id>\", desc: \"Get job details\" },\n    {\n      cmd: \"my-executor <job-id> --attempts\",\n      desc: \"Get job details with attempts\",\n    },\n    { cmd: \"my-executor <job-id> -W\", desc: \"Wait for job to complete\" },\n    {\n      cmd: \"my-executor <job-id> -W -l\",\n      desc: \"Wait for job with logs\",\n    },\n  ],\n  args: z.strictObject({\n    ...workspaceArgs,\n    \"executor-name\": arg(z.string(), {\n      positional: true,\n      description: \"Executor name\",\n    }),\n    \"job-id\": arg(z.string().optional(), {\n      positional: true,\n      description: \"Job ID (if provided, shows job details)\",\n    }),\n    status: arg(z.string().optional(), {\n      alias: \"s\",\n      description:\n        \"Filter by status (PENDING, RUNNING, SUCCESS, FAILED, CANCELED) (list mode only)\",\n    }),\n    attempts: arg(z.boolean().default(false), {\n      description: \"Show job attempts (only with job ID) (detail mode only)\",\n    }),\n    wait: arg(z.boolean().default(false), {\n      alias: \"W\",\n      description:\n        \"Wait for job completion and downstream execution (workflow/function) if applicable (detail mode only)\",\n    }),\n    interval: arg(durationArg.default(\"3s\"), {\n      alias: \"i\",\n      description: \"Polling interval when using --wait (e.g., '3s', '500ms', '1m')\",\n    }),\n    timeout: arg(durationArg.default(\"5m\"), {\n      alias: \"t\",\n      description: \"Maximum time to wait when using --wait (e.g., '30s', '5m')\",\n    }),\n    ...pagedLogArgs,\n    limit: arg(nonNegativeIntArg.default(50), {\n      description: \"Maximum number of jobs to list (0: unlimited, default: 50) (list mode only)\",\n    }),\n    logs: arg(z.boolean().default(false), {\n      alias: \"l\",\n      description: \"Display function execution logs after completion (requires --wait)\",\n    }),\n  }),\n  run: async (args) => {\n    const jsonOutput = logger.jsonMode || args.json;\n    if (args.jobId) {\n      if (args.wait) {\n        const result = await watchExecutorJob({\n          executor: { name: args.executorName },\n          jobId: args.jobId,\n          workspaceId: args[\"workspace-id\"],\n          profile: args.profile,\n          interval: parseDuration(args.interval),\n          timeout: parseDuration(args.timeout),\n          logs: args.logs,\n          showProgress: !jsonOutput,\n        });\n\n        // Print result\n        if (!jsonOutput) {\n          logger.log(styles.bold(`Target Type: ${result.targetType}\\n`));\n          printJobWithAttempts(result.job);\n          if (result.workflowExecutionId) {\n            logger.log(styles.bold(\"\\nWorkflow Execution:\"));\n            logger.log(`  ID: ${result.workflowExecutionId}`);\n            if (result.workflowStatus) {\n              logger.log(`  Status: ${result.workflowStatus}`);\n            }\n            if (result.workflowJobLogs && result.workflowJobLogs.length > 0) {\n              for (const jobLog of result.workflowJobLogs) {\n                logger.log(styles.bold(`\\n  Job: ${jobLog.jobName}`));\n                if (jobLog.logs) {\n                  logger.log(styles.dim(\"    Logs:\"));\n                  for (const line of jobLog.logs.split(\"\\n\")) {\n                    logger.log(`      ${line}`);\n                  }\n                }\n                if (jobLog.result) {\n                  logger.log(styles.dim(\"    Result:\"));\n                  try {\n                    const parsed = JSON.parse(jobLog.result);\n                    const formatted = JSON.stringify(parsed, null, 2);\n                    for (const line of formatted.split(\"\\n\")) {\n                      logger.log(`      ${line}`);\n                    }\n                  } catch {\n                    logger.log(`      ${jobLog.result}`);\n                  }\n                }\n              }\n            }\n          }\n          if (result.functionExecutionId) {\n            logger.log(styles.bold(\"\\nFunction Execution:\"));\n            logger.log(`  ID: ${result.functionExecutionId}`);\n            if (result.functionStatus) {\n              logger.log(`  Status: ${result.functionStatus}`);\n            }\n            if (result.functionLogs) {\n              logger.log(styles.dim(\"  Logs:\"));\n              for (const line of result.functionLogs.split(\"\\n\")) {\n                logger.log(`    ${line}`);\n              }\n            }\n          }\n        } else {\n          logger.out(result);\n        }\n        const failure = getExecutorWaitFailure(result);\n        if (failure) {\n          throw failure;\n        }\n        return;\n      }\n\n      const job = await getExecutorJob({\n        executor: { name: args.executorName },\n        jobId: args.jobId,\n        attempts: args.attempts,\n        workspaceId: args[\"workspace-id\"],\n        profile: args.profile,\n      });\n      if (args.attempts && !jsonOutput) {\n        printJobWithAttempts(job);\n      } else {\n        logger.out(job);\n      }\n    } else {\n      if (args.wait) {\n        logger.warn(\"--wait flag is ignored in list mode. Specify a job ID to wait.\");\n      }\n      const jobs = await listExecutorJobs({\n        executor: { name: args.executorName },\n        status: args.status,\n        order: args.order,\n        limit: args.limit,\n        workspaceId: args[\"workspace-id\"],\n        profile: args.profile,\n      });\n      logger.out(jobs);\n    }\n  },\n});\n","import { z } from \"zod\";\nimport {\n  type Order,\n  paginationArgs,\n  recoveryContextArgs,\n  toPageDirection,\n  workspaceArgs,\n} from \"#/cli/shared/args\";\nimport { fetchPaged } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { formatCopyableCommand } from \"#/cli/shared/errors\";\nimport { logger, styles } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { type ExecutorListInfo, toExecutorListInfo } from \"./transform\";\n\nexport interface ListExecutorsOptions {\n  workspaceId?: string;\n  profile?: string;\n  order?: Order;\n  limit?: number;\n}\n\n/**\n * List executors in the workspace and return CLI-friendly info.\n * @param options - Executor listing options\n * @returns List of executors\n */\nexport async function listExecutors(options?: ListExecutorsOptions): Promise<ExecutorListInfo[]> {\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options?.profile,\n    workspaceId: options?.workspaceId,\n  });\n\n  const pageDirection = toPageDirection(options?.order);\n  const executors = await fetchPaged(\n    async (pageToken, pageSize) => {\n      const { executors, nextPageToken } = await client.listExecutorExecutors({\n        workspaceId,\n        pageToken,\n        pageSize,\n        pageDirection,\n      });\n      return [executors, nextPageToken];\n    },\n    { limit: options?.limit },\n  );\n\n  return executors.map((e) => toExecutorListInfo(e));\n}\n\nexport const listCommand = defineAppCommand({\n  name: \"list\",\n  description: \"List all executors\",\n  args: z.strictObject({\n    ...workspaceArgs,\n    ...paginationArgs(),\n  }),\n  run: async (args) => {\n    const jsonOutput = logger.jsonMode;\n    const executors = await listExecutors({\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      order: args.order,\n      limit: args.limit,\n    });\n\n    if (executors.length === 0) {\n      logger.info(\"No executors found.\");\n      if (jsonOutput) {\n        logger.out([]);\n      }\n      return;\n    }\n\n    logger.out(executors, {\n      display: {\n        disabled: (v) => (v ? styles.warning(\"true\") : styles.dim(\"false\")),\n      },\n    });\n\n    // Show hint if there are webhook executors (non-JSON mode only)\n    if (!jsonOutput) {\n      const hasWebhook = executors.some((e) => e.triggerType === \"webhook\");\n      if (hasWebhook) {\n        const listWebhooks = formatCopyableCommand([\n          \"tailor\",\n          \"executor\",\n          \"webhook\",\n          \"list\",\n          ...recoveryContextArgs({ profile: args.profile, workspaceId: args[\"workspace-id\"] }),\n        ]);\n        logger.info(`To see webhook URLs, run: ${listWebhooks}`);\n      }\n    }\n  },\n});\n","import { Code, ConnectError } from \"@connectrpc/connect\";\nimport { arg } from \"@politty/zod\";\nimport { ExecutorTriggerType } from \"@tailor-platform/tailor-proto/executor_resource_pb\";\nimport { z } from \"zod\";\nimport { durationArg, parseDuration, workspaceArgs } from \"#/cli/shared/args\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger, styles } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { assertWritable } from \"#/cli/shared/readonly-guard\";\nimport { getExecutorWaitFailure, watchExecutorJob } from \"./jobs\";\nimport { executorTriggerTypeToString } from \"./status\";\nimport type { IncomingWebhookTrigger, ScheduleTriggerInput } from \"#/types/executor.generated\";\nimport type { JsonObject } from \"@bufbuild/protobuf\";\n\n/**\n * Schema for JSON string validation (object only)\n * Transforms the string to a parsed object\n */\nconst jsonDataArg = z\n  .string()\n  .transform((val) => {\n    try {\n      return JSON.parse(val) as unknown;\n    } catch {\n      throw CLIError({\n        code: \"EXECUTOR_DATA_INVALID\",\n        message: `Invalid JSON data: ${val}. Please provide a valid JSON string.`,\n        command: \"executor trigger\",\n      });\n    }\n  })\n  .refine((v): v is JsonObject => typeof v === \"object\" && v !== null && !Array.isArray(v), {\n    message: \"JSON data must be an object, not an array or primitive value\",\n  });\n\n/**\n * Schema for header string validation (format: \"Key: Value\")\n * Transforms the string to an object with key and value properties\n */\nconst headerArg = z\n  .string()\n  .superRefine((val, ctx) => {\n    if (!val.includes(\":\")) {\n      ctx.addIssue({\n        code: \"custom\",\n        message: `Invalid header format: '${val}'. Expected format: 'Key: Value'`,\n      });\n    }\n  })\n  .transform((val) => {\n    const colonIndex = val.indexOf(\":\");\n    return {\n      key: val.slice(0, colonIndex).trim(),\n      value: val.slice(colonIndex + 1).trim(),\n    };\n  })\n  .refine((h) => h.key.length > 0, {\n    message: \"Header name cannot be empty\",\n  });\n\ntype ManualTrigger = IncomingWebhookTrigger | ScheduleTriggerInput;\n\ntype ManualTriggerExecutor<T extends ManualTrigger = ManualTrigger> = T extends ManualTrigger\n  ? {\n      name: string;\n      trigger: T;\n    }\n  : never;\n\ntype TriggerExecutorBaseOptions<E extends ManualTriggerExecutor> = {\n  executor: E;\n  workspaceId?: string;\n  profile?: string;\n};\n\ninterface TriggerExecutorByNameOptions {\n  executorName: string;\n  payload?: JsonObject;\n  workspaceId?: string;\n  profile?: string;\n}\n\nexport type TriggerExecutorTypedOptions<E extends ManualTriggerExecutor = ManualTriggerExecutor> =\n  E extends ManualTriggerExecutor<IncomingWebhookTrigger>\n    ? TriggerExecutorBaseOptions<E> & { payload?: JsonObject }\n    : TriggerExecutorBaseOptions<E> & { payload?: never };\n\nexport interface TriggerExecutorResult {\n  jobId?: string;\n}\n\nasync function triggerExecutorByName(\n  options: TriggerExecutorByNameOptions,\n): Promise<TriggerExecutorResult> {\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options.profile,\n    workspaceId: options.workspaceId,\n  });\n\n  try {\n    const response = await client.triggerExecutor({\n      workspaceId,\n      executorName: options.executorName,\n      payload: options.payload,\n    });\n\n    return { jobId: response.jobId };\n  } catch (error) {\n    if (error instanceof ConnectError && error.code === Code.NotFound) {\n      throw CLIError({\n        code: \"EXECUTOR_NOT_FOUND\",\n        message: `Executor '${options.executorName}' not found.`,\n        cause: error,\n      });\n    }\n    if (error instanceof ConnectError && error.code === Code.InvalidArgument) {\n      throw CLIError({\n        code: \"EXECUTOR_ARGUMENT_INVALID\",\n        message: `Invalid argument: ${error.message}`,\n        cause: error,\n      });\n    }\n    throw error;\n  }\n}\n\n/**\n * Trigger an executor and return the job ID.\n * @param options - Options for triggering executor\n * @returns Result containing the job ID if available\n */\nexport async function triggerExecutor<E extends ManualTriggerExecutor>(\n  options: TriggerExecutorTypedOptions<E>,\n): Promise<TriggerExecutorResult> {\n  if (options.executor.trigger.kind !== \"incomingWebhook\" && options.payload !== undefined) {\n    throw CLIError({\n      code: \"EXECUTOR_TRIGGER_UNSUPPORTED\",\n      message:\n        `Executor '${options.executor.name}' has '${options.executor.trigger.kind}' trigger type. ` +\n        `The payload is only available for 'incomingWebhook' trigger type.`,\n    });\n  }\n\n  return await triggerExecutorByName({\n    executorName: options.executor.name,\n    payload: options.payload,\n    workspaceId: options.workspaceId,\n    profile: options.profile,\n  });\n}\n\nexport const triggerCommand = defineAppCommand({\n  name: \"trigger\",\n  description: \"Trigger an executor manually.\",\n  notes: `Only executors with \\`INCOMING_WEBHOOK\\` or \\`SCHEDULE\\` trigger types can be triggered manually.\nExecutors with \\`EVENT\\` trigger types (such as \\`recordCreated\\`, \\`recordUpdated\\`, \\`recordDeleted\\`) cannot be triggered manually.\n\nThe \\`--data\\` and \\`--header\\` options are only available for \\`INCOMING_WEBHOOK\\` trigger type.\n\n**Downstream Execution Tracking**\n\nWhen using \\`--wait\\`, the CLI tracks not only the executor job but also any downstream executions:\n\n- **Workflow targets**: Waits for the workflow execution to complete (SUCCESS, FAILED, or PENDING_RESUME). Shows real-time status changes and currently running job names during execution (same output as \\`workflow start --wait\\`).\n- **Function targets**: Waits for the function execution to complete\n- **Webhook/GraphQL targets**: Only waits for the executor job itself\n\nThe \\`--logs\\` option displays logs from the downstream execution when available.`,\n  examples: [\n    { cmd: \"my-executor\", desc: \"Trigger an executor\" },\n    {\n      cmd: 'my-executor -d \\'{\"message\": \"hello\"}\\'',\n      desc: \"Trigger with data\",\n    },\n    {\n      cmd: 'my-executor -d \\'{\"message\": \"hello\"}\\' -H \"X-Custom: value\" -H \"X-Another: value2\"',\n      desc: \"Trigger with data and headers\",\n    },\n    { cmd: \"my-executor -W\", desc: \"Trigger and wait for completion\" },\n    { cmd: \"my-executor -W -l\", desc: \"Trigger, wait, and show logs\" },\n  ],\n  args: z.strictObject({\n    ...workspaceArgs,\n    \"executor-name\": arg(z.string(), {\n      positional: true,\n      description: \"Executor name\",\n    }),\n    data: arg(jsonDataArg.optional(), {\n      alias: \"d\",\n      description: \"Request body (JSON string)\",\n    }),\n    header: arg(headerArg.array().optional(), {\n      alias: \"H\",\n      overrideBuiltinAlias: true,\n      description: \"Request header (format: 'Key: Value', can be specified multiple times)\",\n    }),\n    wait: arg(z.boolean().default(false), {\n      alias: \"W\",\n      description:\n        \"Wait for job completion and downstream execution (workflow/function) if applicable\",\n    }),\n    interval: arg(durationArg.default(\"3s\"), {\n      alias: \"i\",\n      description: \"Polling interval when using --wait (e.g., '3s', '500ms', '1m')\",\n    }),\n    timeout: arg(durationArg.default(\"5m\"), {\n      alias: \"t\",\n      description: \"Maximum time to wait when using --wait (e.g., '30s', '5m')\",\n    }),\n    logs: arg(z.boolean().default(false), {\n      alias: \"l\",\n      description: \"Display function execution logs after completion (requires --wait)\",\n    }),\n  }),\n  run: async (args) => {\n    const jsonOutput = logger.jsonMode || args.json;\n    await assertWritable({ profile: args.profile });\n    // Validate trigger type before processing\n    const { client, workspaceId } = await loadOperatorWorkspaceContext({\n      profile: args.profile,\n      workspaceId: args[\"workspace-id\"],\n    });\n\n    const { executor } = await client.getExecutorExecutor({\n      workspaceId,\n      name: args.executorName,\n    });\n\n    if (!executor) {\n      throw CLIError({\n        code: \"EXECUTOR_NOT_FOUND\",\n        message: `Executor '${args.executorName}' not found.`,\n      });\n    }\n\n    // EVENT trigger type cannot be triggered manually\n    if (executor.triggerType === ExecutorTriggerType.EVENT) {\n      throw CLIError({\n        code: \"EXECUTOR_TRIGGER_UNSUPPORTED\",\n        message:\n          `Executor '${args.executorName}' has '${executorTriggerTypeToString(executor.triggerType)}' trigger type and cannot be triggered manually. ` +\n          `Only executors with 'INCOMING_WEBHOOK' or 'SCHEDULE' triggers can be triggered manually.`,\n      });\n    }\n\n    // SCHEDULE trigger type does not accept --data or --header options\n    if (executor.triggerType === ExecutorTriggerType.SCHEDULE && (args.data || args.header)) {\n      throw CLIError({\n        code: \"EXECUTOR_TRIGGER_OPTIONS_INVALID\",\n        message:\n          `Executor '${args.executorName}' has 'SCHEDULE' trigger type. ` +\n          `The --data and --header options are only available for 'INCOMING_WEBHOOK' trigger type.`,\n        command: \"executor trigger\",\n      });\n    }\n\n    let payload: JsonObject | undefined;\n\n    // Build payload if data or headers are provided\n    const body: JsonObject | undefined = args.data;\n    const headers: Record<string, string> = {};\n    if (args.header) {\n      for (const h of args.header) {\n        headers[h.key] = h.value;\n      }\n    }\n\n    if (body !== undefined || Object.keys(headers).length > 0) {\n      payload = {\n        body: body ?? {},\n        headers,\n      };\n    }\n\n    const result = await triggerExecutorByName({\n      executorName: args.executorName,\n      payload,\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n    });\n\n    if (!result.jobId) {\n      logger.success(`Executor '${args.executorName}' triggered successfully.`);\n      if (args.wait) {\n        logger.warn(\"Cannot watch: job ID not available. The API may need to be updated.\");\n      }\n      return;\n    }\n\n    logger.success(\n      `Executor '${args.executorName}' triggered successfully. Job ID: ${result.jobId}`,\n    );\n\n    if (args.wait) {\n      const watchResult = await watchExecutorJob({\n        executor: { name: args.executorName },\n        jobId: result.jobId,\n        workspaceId: args[\"workspace-id\"],\n        profile: args.profile,\n        interval: parseDuration(args.interval),\n        timeout: parseDuration(args.timeout),\n        logs: args.logs,\n        showProgress: !jsonOutput,\n      });\n\n      // Print result\n      if (!jsonOutput) {\n        logger.log(styles.bold(`\\nTarget Type: ${watchResult.targetType}`));\n        logger.log(`Job Status: ${watchResult.job.status}`);\n\n        if (watchResult.workflowExecutionId) {\n          logger.log(styles.bold(\"\\nWorkflow Execution:\"));\n          logger.log(`  ID: ${watchResult.workflowExecutionId}`);\n          if (watchResult.workflowStatus) {\n            logger.log(`  Status: ${watchResult.workflowStatus}`);\n          }\n          if (watchResult.workflowJobLogs && watchResult.workflowJobLogs.length > 0) {\n            for (const jobLog of watchResult.workflowJobLogs) {\n              logger.log(styles.bold(`\\n  Job: ${jobLog.jobName}`));\n              if (jobLog.logs) {\n                logger.log(styles.dim(\"    Logs:\"));\n                for (const line of jobLog.logs.split(\"\\n\")) {\n                  logger.log(`      ${line}`);\n                }\n              }\n              if (jobLog.result) {\n                logger.log(styles.dim(\"    Result:\"));\n                try {\n                  const parsed = JSON.parse(jobLog.result);\n                  const formatted = JSON.stringify(parsed, null, 2);\n                  for (const line of formatted.split(\"\\n\")) {\n                    logger.log(`      ${line}`);\n                  }\n                } catch {\n                  logger.log(`      ${jobLog.result}`);\n                }\n              }\n            }\n          }\n        }\n        if (watchResult.functionExecutionId) {\n          logger.log(styles.bold(\"\\nFunction Execution:\"));\n          logger.log(`  ID: ${watchResult.functionExecutionId}`);\n          if (watchResult.functionStatus) {\n            logger.log(`  Status: ${watchResult.functionStatus}`);\n          }\n          if (watchResult.functionLogs) {\n            logger.log(styles.dim(\"  Logs:\"));\n            for (const line of watchResult.functionLogs.split(\"\\n\")) {\n              logger.log(`    ${line}`);\n            }\n          }\n        }\n      } else {\n        logger.out(watchResult);\n      }\n      const failure = getExecutorWaitFailure(watchResult);\n      if (failure) {\n        throw failure;\n      }\n    }\n  },\n});\n","import { defineCommand } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport {\n  type Order,\n  paginationArgs,\n  recoveryContextArgs,\n  toPageDirection,\n  workspaceArgs,\n} from \"#/cli/shared/args\";\nimport { fetchPaged } from \"#/cli/shared/client\";\nimport { defineAppCommand, runDefaultSubCommand } from \"#/cli/shared/command\";\nimport { formatCopyableCommand } from \"#/cli/shared/errors\";\nimport { logger, styles } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\n\nexport interface WebhookExecutorInfo {\n  name: string;\n  webhookUrl: string;\n  disabled: boolean;\n}\n\nexport interface ListWebhookExecutorsOptions {\n  workspaceId?: string;\n  profile?: string;\n  order?: Order;\n  limit?: number;\n}\n\n/**\n * List executors with incoming webhook triggers and return CLI-friendly info.\n * @param options - Listing options\n * @returns List of webhook executors with URLs\n */\nexport async function listWebhookExecutors(\n  options?: ListWebhookExecutorsOptions,\n): Promise<WebhookExecutorInfo[]> {\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options?.profile,\n    workspaceId: options?.workspaceId,\n  });\n\n  const pageDirection = toPageDirection(options?.order);\n  const webhooks = await fetchPaged(\n    async (pageToken, pageSize) => {\n      const { webhooks, nextPageToken } = await client.listExecutorIncomingWebhooks({\n        workspaceId,\n        pageToken,\n        pageSize,\n        pageDirection,\n      });\n      return [webhooks, nextPageToken];\n    },\n    { limit: options?.limit },\n  );\n\n  return webhooks.map((w) => ({\n    name: w.executorName,\n    webhookUrl: w.url,\n    disabled: w.disabled,\n  }));\n}\n\nconst listWebhookCommand = defineAppCommand({\n  name: \"list\",\n  description: \"List executors with incoming webhook triggers\",\n  args: z.strictObject({\n    ...workspaceArgs,\n    ...paginationArgs(),\n  }),\n  run: async (args) => {\n    const jsonOutput = logger.jsonMode;\n    const executors = await listWebhookExecutors({\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      order: args.order,\n      limit: args.limit,\n    });\n\n    if (executors.length === 0) {\n      logger.info(\"No webhook executors found.\");\n      if (jsonOutput) {\n        logger.out([]);\n      }\n      return;\n    }\n\n    logger.out(executors, {\n      display: {\n        disabled: (v) => (v ? styles.warning(\"true\") : styles.dim(\"false\")),\n      },\n    });\n\n    if (!jsonOutput) {\n      const trigger = formatCopyableCommand([\n        \"tailor\",\n        \"executor\",\n        \"trigger\",\n        \"<name>\",\n        \"-d\",\n        '{\"key\":\"value\"}',\n        ...recoveryContextArgs({ profile: args.profile, workspaceId: args[\"workspace-id\"] }),\n      ]);\n      logger.info(`To test a webhook, run: ${trigger}`);\n    }\n  },\n});\n\nexport const webhookCommand = defineCommand({\n  name: \"webhook\",\n  description: \"Manage executor webhooks\",\n  subCommands: {\n    list: listWebhookCommand,\n  },\n  async run() {\n    await runDefaultSubCommand(listWebhookCommand);\n  },\n});\n","import { formatTimestamp } from \"#/cli/shared/format\";\nimport type { FunctionRegistry } from \"@tailor-platform/tailor-proto/function_registry_pb\";\n\nexport interface FunctionRegistryInfo {\n  name: string;\n  description: string;\n  sizeBytes: string;\n  contentHash: string;\n  createdAt: Date | null;\n  updatedAt: Date | null;\n}\n\nexport const functionRegistryInfo = (fn: FunctionRegistry): FunctionRegistryInfo => {\n  return {\n    name: fn.name,\n    description: fn.description,\n    sizeBytes: fn.sizeBytes.toString(),\n    contentHash: fn.contentHash,\n    createdAt: formatTimestamp(fn.createdAt),\n    updatedAt: formatTimestamp(fn.updatedAt),\n  };\n};\n","import { Code, ConnectError } from \"@connectrpc/connect\";\nimport { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { workspaceArgs } from \"#/cli/shared/args\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { humanizeRelativeTime } from \"#/cli/shared/format\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { functionRegistryInfo, type FunctionRegistryInfo } from \"./transform\";\n\n// strip unknown keys\nconst getFunctionRegistryOptionsSchema = z.object({\n  workspaceId: z.uuid({ message: \"workspace-id must be a valid UUID\" }).optional(),\n  profile: z.string().optional(),\n  name: z.string().min(1, { message: \"name is required\" }),\n});\n\nexport type GetFunctionRegistryOptions = z.input<typeof getFunctionRegistryOptionsSchema>;\n\nasync function loadOptions(options: GetFunctionRegistryOptions) {\n  const validated = parseOptions(getFunctionRegistryOptionsSchema, options);\n\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: validated.profile,\n    workspaceId: validated.workspaceId,\n  });\n\n  return {\n    client,\n    workspaceId,\n    name: validated.name,\n  };\n}\n\n/**\n * Get a function registry by name.\n * @param options - Function registry get options\n * @returns Function registry info\n */\nexport async function getFunctionRegistry(\n  options: GetFunctionRegistryOptions,\n): Promise<FunctionRegistryInfo> {\n  const { client, workspaceId, name } = await loadOptions(options);\n\n  const notFoundErrorMessage = `Function registry \"${name}\" not found.`;\n  try {\n    const response = await client.getFunctionRegistry({\n      workspaceId,\n      name,\n    });\n\n    if (!response.function) {\n      throw CLIError({ code: \"FUNCTION_NOT_FOUND\", message: notFoundErrorMessage });\n    }\n\n    return functionRegistryInfo(response.function);\n  } catch (error) {\n    if (error instanceof ConnectError && error.code === Code.NotFound) {\n      throw CLIError({ code: \"FUNCTION_NOT_FOUND\", message: notFoundErrorMessage, cause: error });\n    }\n    throw error;\n  }\n}\n\nexport const getCommand = defineAppCommand({\n  name: \"get\",\n  description: \"Get a function registry by name\",\n  args: z.strictObject({\n    ...workspaceArgs,\n    name: arg(z.string(), {\n      description: \"Function name\",\n      alias: \"n\",\n    }),\n  }),\n  run: async (args) => {\n    const fn = await getFunctionRegistry({\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      name: args.name,\n    });\n\n    const formatted = args.json\n      ? fn\n      : {\n          ...fn,\n          createdAt: humanizeRelativeTime(fn.createdAt),\n          updatedAt: humanizeRelativeTime(fn.updatedAt),\n        };\n\n    logger.out(formatted);\n  },\n});\n","import { Code, ConnectError } from \"@connectrpc/connect\";\nimport { z } from \"zod\";\nimport { paginationArgs, toPageDirection, workspaceArgs } from \"#/cli/shared/args\";\nimport { fetchPaged } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { humanizeRelativeTime } from \"#/cli/shared/format\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { functionRegistryInfo, type FunctionRegistryInfo } from \"./transform\";\n\n// strip unknown keys\nconst listFunctionRegistriesOptionsSchema = z.object({\n  workspaceId: z.uuid({ message: \"workspace-id must be a valid UUID\" }).optional(),\n  profile: z.string().optional(),\n  order: z.enum([\"asc\", \"desc\"]).optional(),\n  limit: z.coerce.number().int().nonnegative().optional(),\n});\n\nexport type ListFunctionRegistriesOptions = z.input<typeof listFunctionRegistriesOptionsSchema>;\n\nasync function loadOptions(options: ListFunctionRegistriesOptions) {\n  const validated = parseOptions(listFunctionRegistriesOptionsSchema, options);\n\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: validated.profile,\n    workspaceId: validated.workspaceId,\n  });\n\n  return {\n    client,\n    workspaceId,\n    order: validated.order,\n    limit: validated.limit,\n  };\n}\n\n/**\n * List function registries in a workspace with optional pagination.\n * @param options - Function registry listing options\n * @returns List of function registries\n */\nexport async function listFunctionRegistries(\n  options: ListFunctionRegistriesOptions,\n): Promise<FunctionRegistryInfo[]> {\n  const { client, workspaceId, order, limit } = await loadOptions(options);\n  const pageDirection = toPageDirection(order);\n\n  const registries = await fetchPaged(\n    async (pageToken, pageSize) => {\n      try {\n        const { functions, nextPageToken } = await client.listFunctionRegistries({\n          workspaceId,\n          pageToken,\n          pageSize,\n          sortBy: \"updated_at\",\n          pageDirection,\n        });\n        return [functions, nextPageToken];\n      } catch (error) {\n        if (error instanceof ConnectError && error.code === Code.NotFound) {\n          return [[], \"\"];\n        }\n        throw error;\n      }\n    },\n    { limit },\n  );\n\n  return registries.map(functionRegistryInfo);\n}\n\nexport const listCommand = defineAppCommand({\n  name: \"list\",\n  description: \"List function registries in a workspace\",\n  args: z.strictObject({\n    ...workspaceArgs,\n    ...paginationArgs(),\n  }),\n  run: async (args) => {\n    const jsonOutput = logger.jsonMode;\n    const registries = await listFunctionRegistries({\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      order: args.order,\n      limit: args.limit,\n    });\n\n    const formatted = jsonOutput\n      ? registries\n      : registries.map(({ createdAt, updatedAt, ...rest }) => ({\n          ...rest,\n          createdAt: humanizeRelativeTime(createdAt),\n          updatedAt: humanizeRelativeTime(updatedAt),\n        }));\n\n    logger.out(formatted);\n  },\n});\n","/**\n * Script execution service\n *\n * Provides a reusable utility for executing scripts and polling for completion.\n */\n\nimport { FunctionExecution_Status } from \"@tailor-platform/tailor-proto/function_resource_pb\";\nimport type { OperatorClient } from \"#/cli/shared/client\";\nimport type { MessageInitShape } from \"@bufbuild/protobuf\";\nimport type { AuthInvokerSchema } from \"@tailor-platform/tailor-proto/auth_resource_pb\";\nimport type { Jsonifiable } from \"type-fest\";\n\n/** Authentication context for script execution, provided as a plain object. */\nexport type ScriptInvoker = MessageInitShape<typeof AuthInvokerSchema>;\n\n/**\n * Default polling interval for script execution status in milliseconds (1 second)\n */\nexport const DEFAULT_POLL_INTERVAL = 1000;\n\n/**\n * Options for script execution\n */\nexport interface ScriptExecutionOptions<T extends Jsonifiable = Jsonifiable> {\n  /** Operator client instance */\n  client: OperatorClient;\n  /** Workspace ID */\n  workspaceId: string;\n  /** Script name (for identification) */\n  name: string;\n  /** Bundled script code to execute */\n  code: string;\n  /** Optional JSON-serializable argument to pass to the script */\n  arg?: T;\n  /** Auth invoker for script execution */\n  invoker: ScriptInvoker;\n  /** Polling interval in milliseconds (default: 1000ms) */\n  pollInterval?: number;\n}\n\n/**\n * Result of script execution\n */\nexport interface ScriptExecutionResult {\n  /** Whether the script executed successfully */\n  success: boolean;\n  /** Logs output from the script execution */\n  logs: string;\n  /** Result value from the script execution */\n  result: string;\n  /** Error message if execution failed */\n  error?: string;\n}\n\n/**\n * Result from waiting for execution completion\n */\nexport interface ExecutionWaitResult {\n  /** Execution status */\n  status: FunctionExecution_Status;\n  /** Logs output from the execution */\n  logs: string;\n  /** Result value from the execution */\n  result: string;\n}\n\n/**\n * Wait for a function execution to complete\n *\n * Polls the getFunctionExecution API until the execution reaches a terminal state\n * (SUCCESS, FAILED, or CANCELED).\n * @param {OperatorClient} client - Operator client instance\n * @param {string} workspaceId - Workspace ID\n * @param {string} executionId - Execution ID to wait for\n * @param {number} [pollInterval] - Polling interval in milliseconds (default: 1000ms)\n * @returns {Promise<ExecutionWaitResult>} Execution result\n * @throws {Error} If execution is not found\n */\nexport async function waitForExecution(\n  client: OperatorClient,\n  workspaceId: string,\n  executionId: string,\n  pollInterval: number = DEFAULT_POLL_INTERVAL,\n): Promise<ExecutionWaitResult> {\n  // loop exits when the function execution reaches a terminal status\n  // oxlint-disable-next-line typescript/no-unnecessary-condition\n  while (true) {\n    const { execution } = await client.getFunctionExecution({\n      workspaceId,\n      executionId,\n    });\n\n    if (!execution) {\n      throw new Error(`Execution '${executionId}' not found.`);\n    }\n\n    // Check for terminal states\n    if (\n      execution.status === FunctionExecution_Status.SUCCESS ||\n      execution.status === FunctionExecution_Status.FAILED ||\n      execution.status === FunctionExecution_Status.CANCELED\n    ) {\n      return {\n        status: execution.status,\n        logs: execution.logs,\n        result: execution.result,\n      };\n    }\n\n    // Wait before polling again\n    await new Promise((resolve) => setTimeout(resolve, pollInterval));\n  }\n}\n\n/**\n * Execute a script and wait for completion\n *\n * This function:\n * 1. Starts the script execution\n * 2. Polls getFunctionExecution until completion\n * 3. Returns structured result with success/failure status\n * @param {ScriptExecutionOptions} options - Execution options\n * @returns {Promise<ScriptExecutionResult>} Execution result\n */\nexport async function executeScript<T extends Jsonifiable = Jsonifiable>(\n  options: ScriptExecutionOptions<T>,\n): Promise<ScriptExecutionResult> {\n  const { client, workspaceId, name, code, arg, invoker, pollInterval } = options;\n\n  // Execute the script\n  const response = await client.execScript({\n    workspaceId,\n    name,\n    code,\n    arg: JSON.stringify(arg === undefined ? {} : arg),\n    invoker,\n  });\n  const executionId = response.executionId;\n\n  // Wait for completion\n  const result = await waitForExecution(client, workspaceId, executionId, pollInterval);\n\n  if (result.status === FunctionExecution_Status.SUCCESS) {\n    return {\n      success: true,\n      logs: result.logs,\n      result: result.result,\n    };\n  } else {\n    return {\n      success: false,\n      logs: result.logs,\n      result: result.result || response.result,\n      error:\n        result.result ||\n        response.result ||\n        (result.status === FunctionExecution_Status.CANCELED\n          ? \"Script execution was canceled\"\n          : \"Script execution failed with unknown error\"),\n    };\n  }\n}\n","import type { LoadedConfig } from \"./config-loader\";\n\n/**\n * Extracts every namespace key declared under `config.db`, including those\n * declared with `{ external: true }`.\n * @param config - Loaded application configuration.\n * @returns Namespace names in insertion order.\n */\nexport function extractAllNamespaces(config: LoadedConfig): string[] {\n  const namespaces = new Set<string>();\n\n  if (config.db) {\n    for (const namespaceName of Object.keys(config.db)) {\n      namespaces.add(namespaceName);\n    }\n  }\n\n  return Array.from(namespaces);\n}\n\n/**\n * Extracts namespace keys under `config.db` that this app owns\n * (i.e. not declared with `{ external: true }`). Use this for destructive\n * operations like `tailordb truncate --all` to avoid touching namespaces\n * owned by other apps.\n * @param config - Loaded application configuration.\n * @returns Owned namespace names in insertion order.\n */\nexport function extractOwnedNamespaces(config: LoadedConfig): string[] {\n  const namespaces = new Set<string>();\n\n  if (config.db) {\n    for (const [namespaceName, nsConfig] of Object.entries(config.db)) {\n      if (\"external\" in nsConfig) continue;\n      namespaces.add(namespaceName);\n    }\n  }\n\n  return Array.from(namespaces);\n}\n","import { defineApplication, type Application } from \"#/cli/services/application\";\nimport { PluginManager } from \"#/plugin/manager\";\nimport { loadConfig, type LoadedConfig } from \"./config-loader\";\nimport { generateUserTypes } from \"./type-generator\";\nimport type { Plugin, TailorDBNamespaceData } from \"#/plugin/types\";\n\n/**\n * Namespace selection for {@link loadTailorDBNamespaces}: explicit namespace\n * names, or a selector deriving them from the loaded config and its plugins.\n * Returning `undefined` (or omitting the option) loads all owned namespaces.\n */\nexport type TailorDBNamespaceSelector =\n  | string[]\n  | ((config: LoadedConfig, plugins: Plugin[]) => string[] | undefined);\n\n/**\n * Options for {@link loadTailorDBNamespaces}.\n */\nexport interface LoadTailorDBNamespacesOptions {\n  /** Path to tailor.config.ts. Defaults to searching from the current directory. */\n  configPath?: string;\n  /** Namespaces to load. Omit to load all owned namespaces. */\n  namespaces?: TailorDBNamespaceSelector;\n}\n\n/**\n * Result of {@link loadTailorDBNamespaces}.\n */\nexport interface LoadedTailorDBNamespaces {\n  /** The loaded Tailor config. */\n  config: LoadedConfig;\n  /** Plugins collected from the config module's plugin-array exports (typically `definePlugins()`). */\n  plugins: Plugin[];\n  /** Loaded TailorDB namespace data, in config order. */\n  namespaces: TailorDBNamespaceData[];\n}\n\n/**\n * Result of {@link loadApplicationNamespaces}: the loaded namespaces plus the\n * config plugins and application they were loaded through.\n */\nexport interface LoadedApplicationNamespaces extends LoadedTailorDBNamespaces {\n  /** Application defined from the loaded config. */\n  application: Application;\n}\n\n/**\n * Load local TailorDB namespaces along with the config plugins and the\n * defined application. Internal superset of {@link loadTailorDBNamespaces}.\n * @param options - Namespace loading options.\n * @returns The loaded config, plugins, application, and TailorDB namespace data.\n */\nexport async function loadApplicationNamespaces(\n  options: LoadTailorDBNamespacesOptions = {},\n): Promise<LoadedApplicationNamespaces> {\n  const { config, plugins } = await loadConfig(options.configPath);\n\n  await generateUserTypes({ config, configPath: config.path });\n\n  const pluginManager = plugins.length > 0 ? new PluginManager(plugins) : undefined;\n  const application = defineApplication({\n    config,\n    pluginManager,\n  });\n  const namespaceNames =\n    typeof options.namespaces === \"function\"\n      ? options.namespaces(config, plugins)\n      : options.namespaces;\n  const namespaceFilter = namespaceNames ? new Set(namespaceNames) : undefined;\n  const services = namespaceFilter\n    ? application.tailorDBServices.filter((db) => namespaceFilter.has(db.namespace))\n    : application.tailorDBServices;\n\n  if (namespaceFilter && services.length !== namespaceFilter.size) {\n    const found = new Set(services.map((db) => db.namespace));\n    const missing = [...namespaceFilter].filter((ns) => !found.has(ns)).join(\", \");\n    const available = application.tailorDBServices.map((db) => db.namespace).join(\", \");\n    throw new Error(\n      `TailorDB namespace \"${missing}\" not found in local config.db.` +\n        (available ? ` Available owned namespaces: ${available}` : \"\"),\n    );\n  }\n\n  const namespaces: TailorDBNamespaceData[] = [];\n\n  for (const db of services) {\n    await db.loadTypes();\n    await db.processNamespacePlugins();\n    namespaces.push({\n      namespace: db.namespace,\n      tables: { ...db.types },\n      sourceInfo: new Map(Object.entries(db.typeSourceInfo)),\n      pluginAttachments: db.pluginAttachments,\n    });\n  }\n\n  return { config, plugins, application, namespaces };\n}\n\n/**\n * Load local TailorDB namespaces exactly as SDK generation/deploy sees them:\n * the config is loaded, user types are generated, and each selected\n * namespace's types are loaded with namespace plugins applied.\n * @param options - Namespace loading options.\n * @returns The loaded config and TailorDB namespace data.\n */\nexport async function loadTailorDBNamespaces(\n  options: LoadTailorDBNamespacesOptions = {},\n): Promise<LoadedTailorDBNamespaces> {\n  const { config, plugins, namespaces } = await loadApplicationNamespaces(options);\n  return { config, plugins, namespaces };\n}\n","import type { Plugin, PluginConfigRegistry } from \"./types\";\n\n/**\n * Find a plugin by `id` in a `Plugin[]` array and return its config, typed\n * via {@link PluginConfigRegistry} -- no explicit type argument, no import\n * of the plugin's own option type required. A runtime `id` match has no\n * compiler-level link to a generic type parameter on its own, so this keys\n * off the registry instead: an `id` not registered there fails to compile\n * at the call site.\n * @param plugins - The configured plugins to search\n * @param id - A registered plugin id (registered via declaration merging on {@link PluginConfigRegistry})\n * @returns The matching plugin's config, or `undefined` if not configured\n */\nexport function resolvePluginConfig<Id extends keyof PluginConfigRegistry>(\n  plugins: readonly Plugin[],\n  id: Id,\n): PluginConfigRegistry[Id] | undefined {\n  const plugin = plugins.find((candidate) => candidate.id === id);\n  return plugin?.pluginConfig as PluginConfigRegistry[Id] | undefined;\n}\n","import type { Application } from \"#/cli/services/application\";\nimport type { GeneratorAuthInput } from \"#/plugin/types\";\n\n/**\n * Build the auth input passed to generator plugins from an application's\n * auth service.\n * @param application - Application instance to read the auth service from\n * @returns Auth input for generator plugins, or undefined when the config has no auth\n */\nexport function getAuthInput(application: Application): GeneratorAuthInput | undefined {\n  const authService = application.authService;\n  if (!authService) return undefined;\n\n  const authConfig = authService.config;\n  const userProfile = authService.userProfile;\n  return {\n    name: authConfig.name,\n    userProfile: userProfile\n      ? {\n          tableName: userProfile.type.name,\n          namespace: userProfile.namespace,\n          usernameField: userProfile.usernameField,\n        }\n      : undefined,\n    machineUsers: authConfig.machineUsers,\n    oauth2Clients: authConfig.oauth2Clients,\n    idProvider: authConfig.idProvider,\n  };\n}\n","import { Code, ConnectError } from \"@connectrpc/connect\";\nimport { getErrorDiagnostics } from \"./error-diagnostics\";\nimport { isCLIError, typeOnlyImportHint, type CLIErrorNextAction } from \"./errors\";\nimport { redactSecrets } from \"./logger\";\nimport type { Jsonifiable } from \"type-fest\";\n\n/**\n * `JSON.stringify` replacer that redacts registered secrets from every string value it\n * walks, and from any value that `JSON.stringify` would otherwise emit as a bare\n * (unquoted) token — a number, boolean, or `null` — however deeply nested, since\n * `error.context` is an arbitrary `Record<string, unknown>` a secret could in principle\n * reach through a nested value. Passed as `JSON.stringify`'s second argument rather than\n * pre-walking the envelope by hand, so `JSON.stringify`'s own handling of circular\n * references (throws, caught by the existing fallback below) and `toJSON`-bearing values\n * (e.g. `Date`, already converted to its string form before this replacer sees it) both\n * keep working unmodified.\n *\n * A bare-token value is redacted through its `JSON.stringify`d form (e.g. `1234567890`,\n * `\"true\"`, `\"null\"`), matching a registered secret that happens to equal that same text\n * (e.g. a numeric PIN, or — degenerate but possible, since it only needs to clear the\n * 4-character minimum — a secret literally equal to `\"true\"`/`\"false\"`/`\"null\"`).\n * Returning the redacted string in place of the original value keeps `JSON.stringify`\n * quoting it correctly, so the envelope stays valid JSON even where the outer,\n * structure-unaware `redactSecrets()` pass `logger.log()` applies later would otherwise\n * turn a bare matching token into an unquoted `<redacted>`.\n * @param _key - Property key being visited (unused)\n * @param value - Property value being visited\n * @returns `value`, redacted if it is a string, number, boolean, or `null`\n */\nfunction redactStringValues(_key: string, value: unknown): unknown {\n  if (typeof value === \"string\") return redactSecrets(value);\n  if (typeof value === \"number\" || typeof value === \"boolean\" || value === null) {\n    const text = JSON.stringify(value);\n    const redacted = redactSecrets(text);\n    return redacted === text ? value : redacted;\n  }\n  return value;\n}\n\nexport interface ErrorToJsonOptions {\n  /** Include the original stack trace in the error envelope. */\n  includeStack?: boolean;\n}\n\n/**\n * Convert a CLI failure into the stable JSON error envelope.\n * @param error - Failure to serialize\n * @param options - JSON serialization options\n * @returns JSON-compatible error envelope\n */\nexport function errorToJson(\n  error: unknown,\n  options?: ErrorToJsonOptions,\n): { error: Readonly<Record<string, Jsonifiable | undefined>> } {\n  const envelope = baseErrorToJson(error, options);\n  if (!(error instanceof Error)) return envelope;\n  // `location` drives source annotations for tooling, not the error envelope.\n  const { causes, context, location: _location, ...diagnostics } = getErrorDiagnostics(error);\n  return {\n    error: {\n      ...envelope.error,\n      ...diagnostics,\n      ...(context || causes\n        ? {\n            context: {\n              ...context,\n              ...Object.fromEntries(\n                Object.entries(causes ?? {}).map(([phase, cause]) => [\n                  phase,\n                  errorToJson(cause, options).error,\n                ]),\n              ),\n            },\n          }\n        : {}),\n    },\n  };\n}\n\nfunction baseErrorToJson(\n  error: unknown,\n  options?: ErrorToJsonOptions,\n): { error: Readonly<Record<string, Jsonifiable | undefined>> } {\n  if (isCLIError(error)) {\n    return {\n      error: {\n        code: error.code || \"CLI_ERROR\",\n        message: error.message,\n        ...(error.details ? { details: error.details } : {}),\n        ...(error.suggestion ? { suggestion: error.suggestion } : {}),\n        ...(error.command\n          ? {\n              help: executableHelpAction(error.command),\n            }\n          : {}),\n        ...(error.next ? { next: error.next } : {}),\n        ...(error.context ? { context: error.context } : {}),\n        ...(options?.includeStack && error.stack ? { stack: error.stack } : {}),\n      },\n    };\n  }\n  if (error instanceof ConnectError) {\n    const codeName = Code[error.code];\n    const stableCode =\n      typeof codeName === \"string\"\n        ? codeName.replaceAll(/([a-z0-9])([A-Z])/g, \"$1_$2\").toUpperCase()\n        : `CODE_${error.code}`;\n    return {\n      error: {\n        code: `RPC_${stableCode}`,\n        message: error.message,\n        ...(options?.includeStack && error.stack ? { stack: error.stack } : {}),\n      },\n    };\n  }\n  if (error instanceof Error) {\n    const suggestion = typeOnlyImportHint(error);\n    return {\n      error: {\n        code: error.name === \"CIPromptError\" ? \"INTERACTIVE_PROMPT_REQUIRED\" : \"UNEXPECTED_ERROR\",\n        message: error.message,\n        ...(suggestion ? { suggestion } : {}),\n        ...(options?.includeStack && error.stack ? { stack: error.stack } : {}),\n      },\n    };\n  }\n  return { error: { code: \"UNKNOWN_ERROR\", message: String(error) } };\n}\n\n/**\n * Serialize a CLI failure into the stable JSON error envelope.\n *\n * Redacts registered secrets from every string, number, boolean, and `null` *value* in the\n * envelope, however deeply nested, before this function's own `JSON.stringify` call, rather\n * than relying only on the redaction `logger.log()` does on the final string: an upstream\n * error message (or `error.context`, an arbitrary record) can already embed a secret in\n * JSON-escaped form (e.g. echoed back inside a JSON API error body), and stringifying the\n * envelope would escape that a second time, no longer matching a registered secret's\n * single-level-escaped form. Redacting non-string bare tokens here also matters because the\n * later, structure-unaware `redactSecrets()` pass over the fully rendered JSON text cannot\n * tell a bare token apart from a JSON string, so a secret whose value coincides with an\n * unrelated number/boolean/`null` elsewhere in the envelope would otherwise become an\n * unquoted `<redacted>` and break the output as JSON.\n *\n * Does not cover a secret used as an object *key* (e.g. `context: { [secret]: true }`) —\n * `JSON.stringify`'s replacer can only transform values, never rename keys. No current\n * caller does this (`context` keys are always fixed, SDK-chosen strings), and the CLI's own\n * `logger.log(serializeError(...))` call site is still protected regardless, since that\n * redaction pass re-scans the fully rendered JSON text and does not distinguish key\n * position from value position.\n * @param error - Failure to serialize\n * @param options - JSON serialization options\n * @returns Serialized JSON error envelope\n */\nexport function serializeError(error: unknown, options?: ErrorToJsonOptions): string {\n  const envelope = errorToJson(error, options);\n  try {\n    return JSON.stringify(envelope, redactStringValues);\n  } catch {\n    const fallbackError = { ...envelope.error };\n    delete fallbackError.context;\n    delete fallbackError.stack;\n    return JSON.stringify({ error: fallbackError }, redactStringValues);\n  }\n}\n\nfunction executableHelpAction(command: string): CLIErrorNextAction {\n  return {\n    command: \"tailor\",\n    args: [...command.split(/\\s+/).filter(Boolean), \"--help\"],\n  };\n}\n","import * as fs from \"node:fs\";\nimport { stripVTControlCharacters } from \"node:util\";\nimport * as path from \"pathe\";\nimport {\n  defineApplication,\n  generatePluginFilesIfNeeded,\n  type Application,\n} from \"#/cli/services/application\";\nimport { createExecutorService } from \"#/cli/services/executor/service\";\nimport { assertUniqueLocalTailorDBTypeNames } from \"#/cli/services/tailordb/type-name-validation\";\nimport { getAuthInput } from \"#/cli/shared/auth-input\";\nimport { loadConfig, type LoadedConfig } from \"#/cli/shared/config-loader\";\nimport { getDistDir } from \"#/cli/shared/dist-dir\";\nimport { errorToJson } from \"#/cli/shared/error-json\";\nimport { CLIError, isCLIError } from \"#/cli/shared/errors\";\nimport { logger, styles } from \"#/cli/shared/logger\";\nimport { generateUserTypes } from \"#/cli/shared/type-generator\";\nimport { withSpan } from \"#/cli/telemetry/index\";\nimport { PluginManager } from \"#/plugin/manager\";\nimport { assertDefined } from \"#/utils/assert\";\nimport type { TypeSourceInfo, TailorDBType } from \"#/parser/service/tailordb/types\";\nimport type {\n  GeneratorResult,\n  TailorDBNamespaceData,\n  ResolverNamespaceData,\n  Plugin,\n  PluginAttachment,\n} from \"#/plugin/types\";\nimport type { Executor } from \"#/types/executor.generated\";\nimport type { Resolver } from \"#/types/resolver.generated\";\nimport type { GenerateOptions } from \"./options\";\n\ntype TypeInfo = {\n  types: Record<string, TailorDBType>;\n  sourceInfo: TypeSourceInfo;\n  pluginAttachments: ReadonlyMap<string, readonly PluginAttachment[]>;\n};\n\n/**\n * Generation manager type.\n */\nexport type GenerationManager = {\n  readonly application: Application;\n  readonly baseDir: string;\n  readonly services: {\n    tailordb: Record<string, TypeInfo>;\n    resolver: Record<string, Record<string, Resolver>>;\n    executor: Record<string, Executor>;\n  };\n  generate: () => Promise<void>;\n};\n\n/**\n * Creates a generation manager.\n * @param params - Parameters for creating the generation manager\n * @param params.application - Application instance to generate code for\n * @param params.config - Loaded configuration\n * @param params.pluginManager - Plugin manager for processing plugins\n * @returns GenerationManager instance\n */\nexport function createGenerationManager(params: {\n  application: Application;\n  config: LoadedConfig;\n  pluginManager?: PluginManager;\n}): GenerationManager {\n  const { application, config, pluginManager } = params;\n  const baseDir = path.join(getDistDir(), \"generated\");\n  fs.mkdirSync(baseDir, { recursive: true });\n\n  const services: {\n    tailordb: Record<string, TypeInfo>;\n    resolver: Record<string, Record<string, Resolver>>;\n    executor: Record<string, Executor>;\n  } = { tailordb: {}, resolver: {}, executor: {} };\n\n  // Get plugins that have generation hooks\n  const generationPlugins = pluginManager?.getPluginsWithGenerationHooks() ?? [];\n\n  // =========================================================================\n  // Plugin phase-complete hook runner\n  // =========================================================================\n\n  /**\n   * Build TailorDB namespace data array from loaded services.\n   * @returns Array of TailorDB namespace data\n   */\n  function buildTailorDBData(): TailorDBNamespaceData[] {\n    return Object.entries(services.tailordb).map(([namespace, info]) => ({\n      namespace,\n      tables: info.types,\n      sourceInfo: new Map(Object.entries(info.sourceInfo)),\n      pluginAttachments: info.pluginAttachments,\n    }));\n  }\n\n  /**\n   * Build resolver namespace data array from loaded services.\n   * @returns Array of resolver namespace data\n   */\n  function buildResolverData(): ResolverNamespaceData[] {\n    return Object.entries(services.resolver).map(([namespace, resolvers]) => ({\n      namespace,\n      resolvers,\n    }));\n  }\n\n  /**\n   * Run a plugin's phase-complete hook and write any generated files.\n   * @param plugin - Plugin to run the hook on\n   * @param hookName - Name of the hook to call\n   * @returns Promise that resolves when hook completes\n   */\n  async function runPluginPhaseHook(\n    plugin: Plugin,\n    hookName: \"onTailorDBReady\" | \"onResolverReady\" | \"onExecutorReady\",\n  ): Promise<void> {\n    const hook = plugin[hookName];\n    if (!hook) return;\n\n    const pluginBaseDir = path.join(baseDir, plugin.id);\n    const auth = getAuthInput(application);\n    const tailordb = buildTailorDBData();\n\n    let result: GeneratorResult;\n\n    switch (hookName) {\n      case \"onTailorDBReady\":\n        result = await assertDefined(\n          plugin.onTailorDBReady,\n          \"plugin.onTailorDBReady hook missing\",\n        )({\n          tailordb,\n          auth,\n          baseDir: pluginBaseDir,\n          configPath: config.path,\n          pluginConfig: plugin.pluginConfig,\n        });\n        break;\n      case \"onResolverReady\":\n        result = await assertDefined(\n          plugin.onResolverReady,\n          \"plugin.onResolverReady hook missing\",\n        )({\n          tailordb,\n          resolvers: buildResolverData(),\n          auth,\n          baseDir: pluginBaseDir,\n          configPath: config.path,\n          pluginConfig: plugin.pluginConfig,\n        });\n        break;\n      case \"onExecutorReady\":\n        result = await assertDefined(\n          plugin.onExecutorReady,\n          \"plugin.onExecutorReady hook missing\",\n        )({\n          tailordb,\n          resolvers: buildResolverData(),\n          executors: { ...services.executor },\n          auth,\n          baseDir: pluginBaseDir,\n          configPath: config.path,\n          pluginConfig: plugin.pluginConfig,\n        });\n        break;\n    }\n\n    await writeGeneratedFiles(plugin.id, result);\n  }\n\n  /**\n   * Run a specific generation-time hook for all plugins that implement it.\n   * Each hook runs at its natural pipeline phase, ensuring outputs from earlier\n   * phases are available when later phases load resolvers/executors.\n   * @param hookName - Name of the hook to call\n   */\n  async function runPluginHook(\n    hookName: \"onTailorDBReady\" | \"onResolverReady\" | \"onExecutorReady\",\n  ): Promise<void> {\n    const plugins = generationPlugins.filter((p) => p[hookName] != null);\n    if (plugins.length === 0) return;\n    const results = await Promise.allSettled(\n      plugins.map(async (plugin) => {\n        try {\n          await runPluginPhaseHook(plugin, hookName);\n        } catch (error) {\n          logger.error(`Error processing plugin ${styles.bold(plugin.id)} (${hookName})`);\n          logger.error(String(error));\n          throw error;\n        }\n      }),\n    );\n    const failures = results.flatMap((result, index) =>\n      result.status === \"rejected\"\n        ? [\n            {\n              plugin: assertDefined(plugins[index], \"Plugin result has no matching plugin\").id,\n              reason: result.reason as unknown,\n            },\n          ]\n        : [],\n    );\n    if (failures.length > 0) {\n      throw CLIError({\n        code: \"PLUGIN_GENERATION_FAILED\",\n        message: `Plugin generation failed during ${hookName}.`,\n        details: failures\n          .map(\n            ({ plugin, reason }) =>\n              `${plugin}: ${isCLIError(reason) ? stripVTControlCharacters(reason.format()) : String(reason)}`,\n          )\n          .join(\"\\n\"),\n        context: {\n          hook: hookName,\n          failures: failures.map(({ plugin, reason }) => ({\n            plugin,\n            error: errorToJson(reason, { includeStack: logger.verbose }).error,\n          })),\n        },\n      });\n    }\n  }\n\n  // =========================================================================\n  // Shared file writing\n  // =========================================================================\n\n  /**\n   * Write generated files to disk.\n   * @param sourceId - Plugin ID for logging\n   * @param result - Generation result containing files to write\n   */\n  async function writeGeneratedFiles(sourceId: string, result: GeneratorResult): Promise<void> {\n    await Promise.all(\n      result.files.map(async (file) => {\n        fs.mkdirSync(path.dirname(file.path), { recursive: true });\n        return new Promise<void>((resolve, reject) => {\n          if (file.skipIfExists && fs.existsSync(file.path)) {\n            const relativePath = path.relative(process.cwd(), file.path);\n            logger.debug(`${sourceId} | skip existing: ${relativePath}`);\n            return resolve();\n          }\n\n          fs.writeFile(file.path, file.content, (err) => {\n            if (err) {\n              const relativePath = path.relative(process.cwd(), file.path);\n              logger.error(`Error writing file ${styles.bold(relativePath)}`);\n              logger.error(String(err));\n              reject(err);\n            } else {\n              const relativePath = path.relative(process.cwd(), file.path);\n              logger.debug(`${sourceId} | generate: ${styles.success(relativePath)}`);\n              // Set executable permission if requested\n              if (file.executable) {\n                fs.chmod(file.path, 0o755, (chmodErr) => {\n                  if (chmodErr) {\n                    const relativePath = path.relative(process.cwd(), file.path);\n                    logger.error(\n                      `Error setting executable permission on ${styles.bold(relativePath)}`,\n                    );\n                    logger.error(String(chmodErr));\n                    reject(chmodErr);\n                  } else {\n                    resolve();\n                  }\n                });\n              } else {\n                resolve();\n              }\n            }\n          });\n        });\n      }),\n    );\n    if (result.files.length > 0) {\n      logger.log(`${sourceId} | generation complete`);\n    }\n  }\n\n  return {\n    application,\n    baseDir,\n    services,\n\n    async generate(): Promise<void> {\n      logger.newline();\n      logger.log(`Generation for application: ${styles.highlight(application.config.name)}`);\n\n      const app = application;\n\n      // Load TailorDB tables (includes plugin-generated tables)\n      await withSpan(\"generate.loadTailorDBTypes\", async (span) => {\n        span.setAttribute(\"generate.namespace_count\", app.tailorDBServices.length);\n        for (const db of app.tailorDBServices) {\n          const namespace = db.namespace;\n          await withSpan(`generate.loadTypes.${namespace}`, async () => {\n            try {\n              await db.loadTypes();\n\n              // Process namespace plugins after loading tables\n              // These plugins generate tables without requiring a source table\n              await db.processNamespacePlugins();\n\n              services.tailordb[namespace] = {\n                types: db.types,\n                sourceInfo: db.typeSourceInfo,\n                pluginAttachments: db.pluginAttachments,\n              };\n            } catch (error) {\n              logger.error(`Error loading tables for TailorDB service ${styles.bold(namespace)}`);\n              logger.error(String(error));\n              throw error;\n            }\n          });\n        }\n        try {\n          assertUniqueLocalTailorDBTypeNames({\n            tailorDBServices: app.tailorDBServices,\n          });\n        } catch (error) {\n          logger.error(\"Error validating TailorDB table names\");\n          logger.error(String(error));\n          throw error;\n        }\n      });\n\n      // Generate plugin type and executor files\n      // This must happen after TailorDB tables are loaded since plugins process during table loading\n      const { pluginExecutorFiles, executorService } = await withSpan(\n        \"generate.pluginFiles\",\n        async () => {\n          const pluginExecutorFiles = generatePluginFilesIfNeeded(\n            pluginManager,\n            app.tailorDBServices,\n            config.path,\n          );\n          const executorService =\n            app.executorService ??\n            (pluginExecutorFiles.length > 0\n              ? createExecutorService({ config: { files: [] }, baseDir: path.dirname(config.path) })\n              : undefined);\n          return { pluginExecutorFiles, executorService };\n        },\n      );\n\n      // Resolve Auth namespaces (depends on TailorDB)\n      if (app.authService) {\n        const authService = app.authService;\n        await withSpan(\"generate.resolveAuthNamespaces\", async () =>\n          authService.resolveNamespaces(),\n        );\n      }\n\n      // Add blank line after TailorDB tables loaded\n      if (app.tailorDBServices.length > 0 || pluginExecutorFiles.length > 0) {\n        logger.newline();\n      }\n\n      // Run plugin hooks for onTailorDBReady\n      const hasOnTailorDBReady = generationPlugins.some((p) => p.onTailorDBReady != null);\n      if (hasOnTailorDBReady) {\n        await withSpan(\"generate.onTailorDBReady\", async () => {\n          await runPluginHook(\"onTailorDBReady\");\n        });\n        logger.newline();\n      }\n\n      // Load Resolvers (can now import generated files)\n      await withSpan(\"generate.loadResolvers\", async () => {\n        for (const resolverService of app.resolverServices) {\n          const namespace = resolverService.namespace;\n          await withSpan(`generate.loadResolvers.${namespace}`, async () => {\n            try {\n              await resolverService.loadResolvers();\n              const namespaceResolvers: Record<string, Resolver> = {};\n              services.resolver[namespace] = namespaceResolvers;\n              Object.entries(resolverService.resolvers).forEach(([_, resolver]) => {\n                namespaceResolvers[resolver.name] = resolver;\n              });\n            } catch (error) {\n              logger.error(\n                `Error loading resolvers for Resolver service ${styles.bold(namespace)}`,\n              );\n              logger.error(String(error));\n              throw error;\n            }\n          });\n        }\n      });\n\n      // Run plugin hooks for onResolverReady\n      const hasOnResolverReady = generationPlugins.some((p) => p.onResolverReady != null);\n      if (hasOnResolverReady) {\n        await withSpan(\"generate.onResolversReady\", async () => {\n          await runPluginHook(\"onResolverReady\");\n        });\n        logger.newline();\n      }\n\n      // Load Executors (can now import generated files)\n      await withSpan(\"generate.loadExecutors\", async () => {\n        if (executorService) {\n          await executorService.loadExecutors();\n          // Load plugin-generated executors from generated TypeScript files\n          if (pluginExecutorFiles.length > 0) {\n            await executorService.loadPluginExecutorFiles([...pluginExecutorFiles]);\n          }\n        }\n        // Get all executors (file-based and plugin-generated)\n        const allExecutors = executorService?.executors ?? {};\n        Object.entries(allExecutors).forEach(([key, executor]) => {\n          services.executor[key] = executor;\n        });\n      });\n\n      // Run plugin hooks for onExecutorReady\n      const hasOnExecutorReady = generationPlugins.some((p) => p.onExecutorReady != null);\n      if (hasOnExecutorReady) {\n        await withSpan(\"generate.onExecutorsReady\", async () => {\n          await runPluginHook(\"onExecutorReady\");\n        });\n        logger.newline();\n      }\n    },\n  };\n}\n\n/**\n * Run code generation using the Tailor configuration.\n * @param options - Generation options\n * @returns Promise that resolves when generation completes\n */\nexport async function generate(options?: GenerateOptions) {\n  return withSpan(\"generate\", async (rootSpan) => {\n    // Load and validate options\n    const { config, plugins } = await withSpan(\"generate.loadConfig\", async () => {\n      return loadConfig(options?.configPath);\n    });\n\n    // Generate user types from loaded config\n    await withSpan(\"generate.generateUserTypes\", async () =>\n      generateUserTypes({ config, configPath: config.path }),\n    );\n\n    // Initialize plugin manager if plugins are provided\n    let pluginManager: PluginManager | undefined;\n    if (plugins.length > 0) {\n      pluginManager = new PluginManager(plugins);\n    }\n\n    // Create a lightweight application (tables not yet loaded)\n    const application = defineApplication({ config, pluginManager });\n\n    rootSpan.setAttribute(\"app.name\", application.config.name);\n\n    const manager = createGenerationManager({ application, config, pluginManager });\n    await manager.generate();\n  });\n}\n","import { toJson } from \"@bufbuild/protobuf\";\nimport { timestampDate, ValueSchema } from \"@bufbuild/protobuf/wkt\";\nimport { z } from \"zod\";\nimport { deploymentArgs, type Order, paginationArgs, toPageDirection } from \"#/cli/shared/args\";\nimport { fetchPaged } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadConfig } from \"#/cli/shared/config-loader\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport type { MachineUser } from \"@tailor-platform/tailor-proto/auth_resource_pb\";\n\nexport interface ListMachineUsersOptions {\n  workspaceId?: string;\n  profile?: string;\n  configPath?: string;\n  order?: Order;\n  limit?: number;\n}\n\nexport interface MachineUserInfo {\n  name: string;\n  clientId: string;\n  clientSecret: string;\n  createdAt: Date | null;\n  updatedAt: Date | null;\n  attributes: Record<string, unknown>;\n}\n\n/**\n * Map a MachineUser protobuf message to CLI-friendly info.\n * @param user - Machine user resource\n * @returns Flattened machine user info\n */\nfunction machineUserInfo(user: MachineUser): MachineUserInfo {\n  logger.registerSecret(user.clientSecret);\n  return {\n    name: user.name,\n    clientId: user.clientId,\n    clientSecret: user.clientSecret,\n    createdAt: user.createdAt ? timestampDate(user.createdAt) : null,\n    updatedAt: user.updatedAt ? timestampDate(user.updatedAt) : null,\n    attributes: Object.fromEntries(\n      Object.entries(user.attributeMap).map(([key, value]) => [key, toJson(ValueSchema, value)]),\n    ),\n  };\n}\n\n/**\n * List machine users for the current application.\n * @param options - Machine user listing options\n * @returns List of machine users\n */\nexport async function listMachineUsers(\n  options?: ListMachineUsersOptions,\n): Promise<MachineUserInfo[]> {\n  // Load and validate options\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options?.profile,\n    workspaceId: options?.workspaceId,\n  });\n\n  // Get application\n  const { config } = await loadConfig(options?.configPath);\n  const { application } = await client.getApplication({\n    workspaceId,\n    applicationName: config.name,\n  });\n  if (!application?.authNamespace) {\n    throw CLIError({\n      code: \"AUTH_CONFIG_REQUIRED\",\n      message: `Application ${config.name} does not have an auth configuration.`,\n    });\n  }\n\n  const pageDirection = toPageDirection(options?.order);\n  const machineUsers = await fetchPaged(\n    async (pageToken, pageSize) => {\n      const { machineUsers, nextPageToken } = await client.listAuthMachineUsers({\n        workspaceId,\n        pageToken,\n        pageSize,\n        authNamespace: application.authNamespace,\n        pageDirection,\n      });\n      return [machineUsers, nextPageToken];\n    },\n    { limit: options?.limit },\n  );\n\n  return machineUsers.map(machineUserInfo);\n}\n\nexport const listCommand = defineAppCommand({\n  name: \"list\",\n  description: \"List all machine users in the application.\",\n  args: z.strictObject({\n    ...deploymentArgs,\n    ...paginationArgs(),\n  }),\n  run: async (args) => {\n    // Execute machineuser list logic\n    const machineUsers = await listMachineUsers({\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      configPath: args.config,\n      order: args.order,\n      limit: args.limit,\n    });\n\n    // Show machine users info\n    logger.out(machineUsers, { display: { createdAt: null, updatedAt: null } });\n  },\n});\n","import { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport {\n  deploymentArgs,\n  resolveMachineUserInputSource,\n  type MachineUserInputSource,\n} from \"#/cli/shared/args\";\nimport { fetchMachineUserToken } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadConfig } from \"#/cli/shared/config-loader\";\nimport { loadMachineUserName } from \"#/cli/shared/context\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\n\nexport interface GetMachineUserTokenOptions {\n  name?: string;\n  workspaceId?: string;\n  profile?: string;\n  configPath?: string;\n}\n\ntype GetMachineUserTokenInternalOptions = GetMachineUserTokenOptions & {\n  nameSource?: MachineUserInputSource;\n};\n\nexport interface MachineUserTokenInfo {\n  accessToken: string;\n  tokenType: string;\n  expiresAt: string;\n}\n\nasync function getMachineUserTokenInternal(\n  options: GetMachineUserTokenInternalOptions,\n): Promise<MachineUserTokenInfo> {\n  // Load and validate options\n  const name = await loadMachineUserName({\n    machineUser: options.name,\n    machineUserSource: options.nameSource,\n    profile: options.profile,\n  });\n  if (!name) {\n    throw CLIError({\n      code: \"MACHINE_USER_REQUIRED\",\n      message: \"Machine user is required.\",\n      suggestion:\n        \"Provide the NAME positional argument, set TAILOR_PLATFORM_MACHINE_USER_NAME, or set a profile default with 'tailor profile update <profile> --machine-user <name>'.\",\n      command: \"machineuser token\",\n    });\n  }\n\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options.profile,\n    workspaceId: options.workspaceId,\n  });\n\n  // Get application\n  const { config } = await loadConfig(options.configPath);\n  const { application } = await client.getApplication({\n    workspaceId,\n    applicationName: config.name,\n  });\n  if (!application?.authNamespace) {\n    throw CLIError({\n      code: \"AUTH_CONFIG_REQUIRED\",\n      message: `Application ${config.name} does not have an auth configuration.`,\n    });\n  }\n\n  // Get machine user\n  const { machineUser } = await client.getAuthMachineUser({\n    workspaceId,\n    authNamespace: application.authNamespace,\n    name,\n  });\n  if (!machineUser) {\n    throw CLIError({ code: \"MACHINE_USER_NOT_FOUND\", message: `Machine user ${name} not found.` });\n  }\n\n  // Fetch machine user token\n  const resp = await fetchMachineUserToken(\n    application.url,\n    machineUser.clientId,\n    machineUser.clientSecret,\n  );\n  const expiresAt = new Date();\n  expiresAt.setSeconds(expiresAt.getSeconds() + resp.expires_in);\n\n  return {\n    accessToken: resp.access_token,\n    tokenType: resp.token_type,\n    expiresAt: expiresAt.toISOString(),\n  };\n}\n\n/**\n * Get a machine user access token for the current application.\n * @param options - Token retrieval options\n * @returns Machine user token info\n */\nexport async function getMachineUserToken(\n  options: GetMachineUserTokenOptions,\n): Promise<MachineUserTokenInfo> {\n  return await getMachineUserTokenInternal(options);\n}\n\nexport const tokenCommand = defineAppCommand({\n  name: \"token\",\n  description: \"Get an access token for a machine user.\",\n  args: z.strictObject({\n    ...deploymentArgs,\n    name: arg(z.string().optional(), {\n      positional: true,\n      description:\n        \"Machine user name. Falls back to TAILOR_PLATFORM_MACHINE_USER_NAME, then the active profile's default machine user.\",\n    }),\n  }),\n  run: async (args) => {\n    // Execute machineuser token logic\n    const token = await getMachineUserTokenInternal({\n      name: args.name,\n      nameSource: resolveMachineUserInputSource(args.name, process.argv.slice(2), {\n        valueIsExplicit: args.name !== undefined,\n      }),\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      configPath: args.config,\n    });\n\n    // Show machine user token info\n    // TODO: remove this transformation\n    const tokenInfo = {\n      access_token: token.accessToken,\n      token_type: token.tokenType,\n      expires_at: token.expiresAt,\n    };\n    logger.out(tokenInfo);\n  },\n});\n","import { timestampDate } from \"@bufbuild/protobuf/wkt\";\nimport {\n  type AuthOAuth2Client,\n  AuthOAuth2Client_GrantType,\n} from \"@tailor-platform/tailor-proto/auth_resource_pb\";\nimport { logger } from \"#/cli/shared/logger\";\n\nconst grantTypeToString = (grantType: AuthOAuth2Client_GrantType): string => {\n  switch (grantType) {\n    case AuthOAuth2Client_GrantType.AUTHORIZATION_CODE:\n      return \"authorization_code\";\n    case AuthOAuth2Client_GrantType.REFRESH_TOKEN:\n      return \"refresh_token\";\n    default:\n      return \"unknown\";\n  }\n};\n\nexport interface OAuth2ClientInfo {\n  name: string;\n  description: string;\n  clientId: string;\n  grantTypes: string[];\n  redirectUris: string[];\n  createdAt: Date | null;\n}\n\nexport interface OAuth2ClientCredentials {\n  name: string;\n  description: string;\n  clientId: string;\n  clientSecret: string;\n  grantTypes: string[];\n  redirectUris: string[];\n  createdAt: Date | null;\n}\n\n/**\n * Transform an AuthOAuth2Client into CLI-friendly OAuth2 client info.\n * @param client - OAuth2 client resource\n * @returns Flattened OAuth2 client info\n */\nexport function toOAuth2ClientInfo(client: AuthOAuth2Client): OAuth2ClientInfo {\n  return {\n    name: client.name,\n    description: client.description,\n    clientId: client.clientId,\n    grantTypes: client.grantTypes.map(grantTypeToString),\n    redirectUris: client.redirectUris,\n    createdAt: client.createdAt ? timestampDate(client.createdAt) : null,\n  };\n}\n\n/**\n * Transform an AuthOAuth2Client into OAuth2 client credentials info.\n * @param client - OAuth2 client resource\n * @returns OAuth2 client credentials\n */\nexport function toOAuth2ClientCredentials(client: AuthOAuth2Client): OAuth2ClientCredentials {\n  logger.registerSecret(client.clientSecret);\n  return {\n    name: client.name,\n    description: client.description,\n    clientId: client.clientId,\n    clientSecret: client.clientSecret,\n    grantTypes: client.grantTypes.map(grantTypeToString),\n    redirectUris: client.redirectUris,\n    createdAt: client.createdAt ? timestampDate(client.createdAt) : null,\n  };\n}\n","import { Code, ConnectError } from \"@connectrpc/connect\";\nimport { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { deploymentArgs } from \"#/cli/shared/args\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadConfig } from \"#/cli/shared/config-loader\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { type OAuth2ClientCredentials, toOAuth2ClientCredentials } from \"./transform\";\n\nexport interface GetOAuth2ClientOptions {\n  name: string;\n  workspaceId?: string;\n  profile?: string;\n  configPath?: string;\n}\n\n/**\n * Get OAuth2 client credentials for the current application.\n * @param options - OAuth2 client lookup options\n * @returns OAuth2 client credentials\n */\nexport async function getOAuth2Client(\n  options: GetOAuth2ClientOptions,\n): Promise<OAuth2ClientCredentials> {\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options.profile,\n    workspaceId: options.workspaceId,\n  });\n\n  const { config } = await loadConfig(options.configPath);\n  const { application } = await client.getApplication({\n    workspaceId,\n    applicationName: config.name,\n  });\n  if (!application?.authNamespace) {\n    throw CLIError({\n      code: \"AUTH_CONFIG_REQUIRED\",\n      message: `Application ${config.name} does not have an auth configuration.`,\n    });\n  }\n\n  try {\n    const { oauth2Client } = await client.getAuthOAuth2Client({\n      workspaceId,\n      namespaceName: application.authNamespace,\n      name: options.name,\n    });\n\n    return toOAuth2ClientCredentials(\n      assertDefined(oauth2Client, \"oauth2Client missing in response\"),\n    );\n  } catch (error) {\n    if (error instanceof ConnectError && error.code === Code.NotFound) {\n      throw CLIError({\n        code: \"OAUTH2_CLIENT_NOT_FOUND\",\n        message: `OAuth2 client '${options.name}' not found.`,\n        cause: error,\n      });\n    }\n    throw error;\n  }\n}\n\nexport const getCommand = defineAppCommand({\n  name: \"get\",\n  description: \"Get OAuth2 client credentials (including client secret).\",\n  args: z.strictObject({\n    ...deploymentArgs,\n    name: arg(z.string(), {\n      positional: true,\n      description: \"OAuth2 client name\",\n    }),\n  }),\n  run: async (args) => {\n    const credentials = await getOAuth2Client({\n      name: args.name,\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      configPath: args.config,\n    });\n\n    logger.out(credentials);\n  },\n});\n","import { z } from \"zod\";\nimport { deploymentArgs, type Order, paginationArgs, toPageDirection } from \"#/cli/shared/args\";\nimport { fetchPaged } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadConfig } from \"#/cli/shared/config-loader\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { type OAuth2ClientInfo, toOAuth2ClientInfo } from \"./transform\";\n\nexport interface ListOAuth2ClientsOptions {\n  workspaceId?: string;\n  profile?: string;\n  configPath?: string;\n  order?: Order;\n  limit?: number;\n}\n\n/**\n * List OAuth2 clients for the current application.\n * @param options - OAuth2 client listing options\n * @returns List of OAuth2 clients\n */\nexport async function listOAuth2Clients(\n  options?: ListOAuth2ClientsOptions,\n): Promise<OAuth2ClientInfo[]> {\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options?.profile,\n    workspaceId: options?.workspaceId,\n  });\n\n  const { config } = await loadConfig(options?.configPath);\n  const { application } = await client.getApplication({\n    workspaceId,\n    applicationName: config.name,\n  });\n  if (!application?.authNamespace) {\n    throw CLIError({\n      code: \"AUTH_CONFIG_REQUIRED\",\n      message: `Application ${config.name} does not have an auth configuration.`,\n    });\n  }\n\n  const pageDirection = toPageDirection(options?.order);\n  const oauth2Clients = await fetchPaged(\n    async (pageToken, pageSize) => {\n      const { oauth2Clients, nextPageToken } = await client.listAuthOAuth2Clients({\n        workspaceId,\n        pageToken,\n        pageSize,\n        namespaceName: application.authNamespace,\n        pageDirection,\n      });\n      return [oauth2Clients, nextPageToken];\n    },\n    { limit: options?.limit },\n  );\n\n  return oauth2Clients.map(toOAuth2ClientInfo);\n}\n\nexport const listCommand = defineAppCommand({\n  name: \"list\",\n  description: \"List all OAuth2 clients in the application.\",\n  args: z.strictObject({\n    ...deploymentArgs,\n    ...paginationArgs(),\n  }),\n  run: async (args) => {\n    const oauth2Clients = await listOAuth2Clients({\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      configPath: args.config,\n      order: args.order,\n      limit: args.limit,\n    });\n\n    logger.out(oauth2Clients);\n  },\n});\n","import { formatTimestamp } from \"#/cli/shared/format\";\nimport type { ListUserOrganizationsResponse_UserOrganization } from \"@tailor-platform/tailor-proto/workspace_pb\";\nimport type { Organization, Folder } from \"@tailor-platform/tailor-proto/workspace_resource_pb\";\n\nexport interface UserOrganizationInfo {\n  organizationId: string;\n  organizationName: string;\n  rootFolderId: string;\n  rootFolderName: string;\n  displayName: string;\n}\n\nexport interface OrganizationInfo {\n  id: string;\n  name: string;\n  createdAt: Date | null;\n  updatedAt: Date | null;\n}\n\nexport interface FolderListInfo {\n  id: string;\n  name: string;\n  organizationId: string;\n  parentFolderId: string;\n  hasChildren: boolean;\n  createdAt: Date | null;\n}\n\nexport interface FolderInfo extends FolderListInfo {\n  updatedAt: Date | null;\n}\n\nexport const userOrganizationInfo = (\n  org: ListUserOrganizationsResponse_UserOrganization,\n): UserOrganizationInfo => ({\n  organizationId: org.organizationId,\n  organizationName: org.organizationName,\n  rootFolderId: org.rootFolderId,\n  rootFolderName: org.rootFolderName,\n  displayName: org.displayName,\n});\n\nexport const organizationInfo = (org: Organization): OrganizationInfo => ({\n  id: org.id,\n  name: org.name,\n  createdAt: formatTimestamp(org.createTime),\n  updatedAt: formatTimestamp(org.updateTime),\n});\n\nexport const folderListInfo = (folder: Folder): FolderListInfo => ({\n  id: folder.id,\n  name: folder.name,\n  organizationId: folder.organizationId,\n  parentFolderId: folder.parentFolderId,\n  hasChildren: folder.hasChildren,\n  createdAt: formatTimestamp(folder.createTime),\n});\n\nexport const folderInfo = (folder: Folder): FolderInfo => ({\n  ...folderListInfo(folder),\n  updatedAt: formatTimestamp(folder.updateTime),\n});\n","import { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { organizationArgs } from \"#/cli/shared/args\";\nimport { initOperatorClient } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadAccessToken } from \"#/cli/shared/context\";\nimport { internalError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { assertWritable } from \"#/cli/shared/readonly-guard\";\nimport { folderInfo, type FolderInfo } from \"../transform\";\n\n// strip unknown keys\nconst createFolderOptionsSchema = z.object({\n  organizationId: z.uuid({ message: \"organization-id must be a valid UUID\" }),\n  parentFolderId: z.string().optional(),\n  name: z.string().min(1, \"Name must not be empty\"),\n});\n\nexport type CreateFolderOptions = z.input<typeof createFolderOptionsSchema>;\n\n/**\n * Create a new folder in an organization.\n * @param options - Folder creation options\n * @returns Created folder details\n */\nexport async function createFolder(options: CreateFolderOptions): Promise<FolderInfo> {\n  const validated = parseOptions(createFolderOptionsSchema, options);\n\n  const accessToken = await loadAccessToken();\n  const client = await initOperatorClient(accessToken);\n\n  const response = await client.createOrganizationFolder({\n    organizationId: validated.organizationId,\n    parentFolderId: validated.parentFolderId ?? \"\",\n    folderName: validated.name,\n  });\n\n  if (!response.folder) {\n    throw internalError(\"Failed to create folder.\");\n  }\n\n  return folderInfo(response.folder);\n}\n\nexport const createCommand = defineAppCommand({\n  name: \"create\",\n  description: \"Create a new folder in an organization.\",\n  args: z.strictObject({\n    ...organizationArgs,\n    \"parent-folder-id\": arg(z.string().optional(), {\n      description: \"Parent folder ID\",\n    }),\n    name: arg(z.string(), {\n      alias: \"n\",\n      description: \"Folder name\",\n    }),\n  }),\n  run: async (args) => {\n    await assertWritable();\n    const folder = await createFolder({\n      organizationId: args[\"organization-id\"],\n      parentFolderId: args[\"parent-folder-id\"],\n      name: args.name,\n    });\n\n    if (!args.json) {\n      logger.success(`Folder \"${folder.name}\" created successfully.`);\n    }\n\n    logger.out(folder);\n  },\n});\n","import { Code, ConnectError } from \"@connectrpc/connect\";\nimport { z } from \"zod\";\nimport { confirmationArgs, folderArgs, organizationArgs } from \"#/cli/shared/args\";\nimport { initOperatorClient } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadAccessToken } from \"#/cli/shared/context\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { prompt } from \"#/cli/shared/prompt\";\nimport { assertWritable } from \"#/cli/shared/readonly-guard\";\n\n// strip unknown keys\nconst deleteFolderOptionsSchema = z.object({\n  organizationId: z.uuid({ message: \"organization-id must be a valid UUID\" }),\n  folderId: z.uuid({ message: \"folder-id must be a valid UUID\" }),\n});\n\nexport type DeleteFolderOptions = z.input<typeof deleteFolderOptionsSchema>;\n\n/**\n * Delete a folder from an organization.\n * @param options - Folder deletion options\n * @returns Promise that resolves when deletion completes\n */\nexport async function deleteFolder(options: DeleteFolderOptions): Promise<void> {\n  const validated = parseOptions(deleteFolderOptionsSchema, options);\n\n  const accessToken = await loadAccessToken();\n  const client = await initOperatorClient(accessToken);\n\n  await client.deleteOrganizationFolder({\n    organizationId: validated.organizationId,\n    folderId: validated.folderId,\n  });\n}\n\nexport const deleteCommand = defineAppCommand({\n  name: \"delete\",\n  description: \"Delete a folder from an organization.\",\n  args: z.strictObject({\n    ...organizationArgs,\n    ...folderArgs,\n    ...confirmationArgs,\n  }),\n  run: async (args) => {\n    await assertWritable();\n    const accessToken = await loadAccessToken();\n    const client = await initOperatorClient(accessToken);\n\n    // Check if folder exists and get its name\n    let response: Awaited<ReturnType<typeof client.getOrganizationFolder>>;\n    try {\n      response = await client.getOrganizationFolder({\n        organizationId: args[\"organization-id\"],\n        folderId: args[\"folder-id\"],\n      });\n    } catch (error) {\n      if (error instanceof ConnectError && error.code === Code.NotFound) {\n        throw CLIError({\n          code: \"FOLDER_NOT_FOUND\",\n          message: `Folder \"${args[\"folder-id\"]}\" not found.`,\n          cause: error,\n        });\n      }\n      throw error;\n    }\n    if (!response.folder) {\n      throw CLIError({\n        code: \"FOLDER_NOT_FOUND\",\n        message: `Folder \"${args[\"folder-id\"]}\" not found.`,\n      });\n    }\n    const folderName = response.folder.name;\n\n    // Confirm deletion if not forced\n    if (!args.yes) {\n      const confirmed = await prompt.confirm({\n        message: `Are you sure you want to delete folder \"${folderName}\"?`,\n      });\n      if (!confirmed) {\n        logger.info(\"Folder deletion cancelled.\");\n        return;\n      }\n    }\n\n    await client.deleteOrganizationFolder({\n      organizationId: args[\"organization-id\"],\n      folderId: args[\"folder-id\"],\n    });\n\n    logger.success(`Folder \"${folderName}\" deleted successfully.`);\n  },\n});\n","import { z } from \"zod\";\nimport { folderArgs, organizationArgs } from \"#/cli/shared/args\";\nimport { initOperatorClient } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadAccessToken } from \"#/cli/shared/context\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { humanizeRelativeTime } from \"#/cli/shared/format\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { folderInfo, type FolderInfo } from \"../transform\";\n\n// strip unknown keys\nconst getFolderOptionsSchema = z.object({\n  organizationId: z.uuid({ message: \"organization-id must be a valid UUID\" }),\n  folderId: z.uuid({ message: \"folder-id must be a valid UUID\" }),\n});\n\nexport type GetFolderOptions = z.input<typeof getFolderOptionsSchema>;\n\n/**\n * Get detailed information about a folder.\n * @param options - Folder get options\n * @returns Folder details\n */\nexport async function getFolder(options: GetFolderOptions): Promise<FolderInfo> {\n  const validated = parseOptions(getFolderOptionsSchema, options);\n\n  const accessToken = await loadAccessToken();\n  const client = await initOperatorClient(accessToken);\n\n  const response = await client.getOrganizationFolder({\n    organizationId: validated.organizationId,\n    folderId: validated.folderId,\n  });\n\n  if (!response.folder) {\n    throw CLIError({\n      code: \"FOLDER_NOT_FOUND\",\n      message: `Folder \"${validated.folderId}\" not found.`,\n    });\n  }\n\n  return folderInfo(response.folder);\n}\n\nexport const getCommand = defineAppCommand({\n  name: \"get\",\n  description: \"Show detailed information about a folder.\",\n  args: z.strictObject({\n    ...organizationArgs,\n    ...folderArgs,\n  }),\n  run: async (args) => {\n    const folder = await getFolder({\n      organizationId: args[\"organization-id\"],\n      folderId: args[\"folder-id\"],\n    });\n\n    const formattedFolder = args.json\n      ? folder\n      : {\n          ...folder,\n          createdAt: humanizeRelativeTime(folder.createdAt),\n          updatedAt: humanizeRelativeTime(folder.updatedAt),\n        };\n\n    logger.out(formattedFolder);\n  },\n});\n","import { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { orderArg, organizationArgs, paginationArgs, toPageDirection } from \"#/cli/shared/args\";\nimport { fetchPaged, initOperatorClient } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadAccessToken } from \"#/cli/shared/context\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { folderListInfo, type FolderListInfo } from \"../transform\";\n\n// strip unknown keys\nconst listFoldersOptionsSchema = z.object({\n  organizationId: z.uuid({ message: \"organization-id must be a valid UUID\" }),\n  parentFolderId: z.string().optional(),\n  order: orderArg.optional(),\n  limit: z.number().int().nonnegative().optional(),\n});\n\nexport type ListFoldersOptions = z.input<typeof listFoldersOptionsSchema>;\n\n/**\n * List folders in an organization.\n * @param options - Folder listing options\n * @returns List of folders\n */\nexport async function listFolders(options: ListFoldersOptions): Promise<FolderListInfo[]> {\n  const validated = parseOptions(listFoldersOptionsSchema, options);\n\n  const { organizationId, parentFolderId, order, limit } = validated;\n\n  const accessToken = await loadAccessToken();\n  const client = await initOperatorClient(accessToken);\n\n  const pageDirection = toPageDirection(order);\n  const folders = await fetchPaged(\n    async (pageToken, pageSize) => {\n      const response = await client.listOrganizationFolders({\n        organizationId,\n        ...(parentFolderId ? { parentFolderId } : {}),\n        pageToken,\n        pageSize,\n        pageDirection,\n      });\n      return [response.folders, response.nextPageToken];\n    },\n    { limit },\n  );\n\n  return folders.map(folderListInfo);\n}\n\nexport const listCommand = defineAppCommand({\n  name: \"list\",\n  description: \"List folders in an organization.\",\n  args: z.strictObject({\n    ...organizationArgs,\n    \"parent-folder-id\": arg(z.string().optional(), {\n      description: \"Parent folder ID to list children of\",\n    }),\n    ...paginationArgs(),\n  }),\n  run: async (args) => {\n    const folders = await listFolders({\n      organizationId: args[\"organization-id\"],\n      parentFolderId: args[\"parent-folder-id\"],\n      order: args.order,\n      limit: args.limit,\n    });\n    logger.out(folders, { display: { updatedAt: null } });\n  },\n});\n","import { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { folderArgs, organizationArgs } from \"#/cli/shared/args\";\nimport { initOperatorClient } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadAccessToken } from \"#/cli/shared/context\";\nimport { internalError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { assertWritable } from \"#/cli/shared/readonly-guard\";\nimport { folderInfo, type FolderInfo } from \"../transform\";\n\n// strip unknown keys\nconst updateFolderOptionsSchema = z.object({\n  organizationId: z.uuid({ message: \"organization-id must be a valid UUID\" }),\n  folderId: z.uuid({ message: \"folder-id must be a valid UUID\" }),\n  name: z.string().min(1, \"Name must not be empty\"),\n});\n\nexport type UpdateFolderOptions = z.input<typeof updateFolderOptionsSchema>;\n\n/**\n * Update a folder's name.\n * @param options - Folder update options\n * @returns Updated folder details\n */\nexport async function updateFolder(options: UpdateFolderOptions): Promise<FolderInfo> {\n  const validated = parseOptions(updateFolderOptionsSchema, options);\n\n  const accessToken = await loadAccessToken();\n  const client = await initOperatorClient(accessToken);\n\n  const response = await client.updateOrganizationFolder({\n    organizationId: validated.organizationId,\n    folderId: validated.folderId,\n    folderName: validated.name,\n  });\n\n  if (!response.folder) {\n    throw internalError(`Failed to update folder \"${validated.folderId}\".`);\n  }\n\n  return folderInfo(response.folder);\n}\n\nexport const updateCommand = defineAppCommand({\n  name: \"update\",\n  description: \"Update a folder's name.\",\n  args: z.strictObject({\n    ...organizationArgs,\n    ...folderArgs,\n    name: arg(z.string(), {\n      alias: \"n\",\n      description: \"New folder name\",\n    }),\n  }),\n  run: async (args) => {\n    await assertWritable();\n    const folder = await updateFolder({\n      organizationId: args[\"organization-id\"],\n      folderId: args[\"folder-id\"],\n      name: args.name,\n    });\n\n    if (!args.json) {\n      logger.success(`Folder \"${folder.name}\" updated successfully.`);\n    }\n\n    logger.out(folder);\n  },\n});\n","import { z } from \"zod\";\nimport { organizationArgs } from \"#/cli/shared/args\";\nimport { initOperatorClient } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadAccessToken } from \"#/cli/shared/context\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { humanizeRelativeTime } from \"#/cli/shared/format\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { organizationInfo, type OrganizationInfo } from \"./transform\";\n\n// strip unknown keys\nconst getOrganizationOptionsSchema = z.object({\n  organizationId: z.uuid({ message: \"organization-id must be a valid UUID\" }),\n});\n\nexport type GetOrganizationOptions = z.input<typeof getOrganizationOptionsSchema>;\n\n/**\n * Get detailed information about an organization.\n * @param options - Organization get options\n * @returns Organization details\n */\nexport async function getOrganization(options: GetOrganizationOptions): Promise<OrganizationInfo> {\n  const validated = parseOptions(getOrganizationOptionsSchema, options);\n\n  const accessToken = await loadAccessToken();\n  const client = await initOperatorClient(accessToken);\n\n  const response = await client.getOrganization({\n    organizationId: validated.organizationId,\n  });\n\n  if (!response.organization) {\n    throw CLIError({\n      code: \"ORGANIZATION_NOT_FOUND\",\n      message: `Organization \"${validated.organizationId}\" not found.`,\n    });\n  }\n\n  return organizationInfo(response.organization);\n}\n\nexport const getCommand = defineAppCommand({\n  name: \"get\",\n  description: \"Show detailed information about an organization.\",\n  args: z.strictObject({\n    ...organizationArgs,\n  }),\n  run: async (args) => {\n    const organization = await getOrganization({\n      organizationId: args[\"organization-id\"],\n    });\n\n    const formattedOrganization = args.json\n      ? organization\n      : {\n          ...organization,\n          createdAt: humanizeRelativeTime(organization.createdAt),\n          updatedAt: humanizeRelativeTime(organization.updatedAt),\n        };\n\n    logger.out(formattedOrganization);\n  },\n});\n","import { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { positiveIntArg } from \"#/cli/shared/args\";\nimport { initOperatorClient } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadAccessToken } from \"#/cli/shared/context\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { userOrganizationInfo, type UserOrganizationInfo } from \"./transform\";\n\nexport interface ListOrganizationsOptions {\n  limit?: number;\n}\n\n/**\n * List organizations the current user belongs to.\n * @param options - Organization listing options\n * @returns List of user organizations\n */\nexport async function listOrganizations(\n  options?: ListOrganizationsOptions,\n): Promise<UserOrganizationInfo[]> {\n  const limit = options?.limit;\n  const accessToken = await loadAccessToken();\n  const client = await initOperatorClient(accessToken);\n\n  const { userOrganizations } = await client.listUserOrganizations({});\n  const results = userOrganizations.map(userOrganizationInfo);\n\n  if (limit !== undefined) {\n    return results.slice(0, limit);\n  }\n  return results;\n}\n\nexport const listCommand = defineAppCommand({\n  name: \"list\",\n  description: \"List organizations you belong to.\",\n  args: z.strictObject({\n    limit: arg(positiveIntArg.optional(), {\n      alias: \"l\",\n      description: \"Maximum number of organizations to list\",\n    }),\n  }),\n  run: async (args) => {\n    const organizations = await listOrganizations({ limit: args.limit });\n    logger.out(organizations);\n  },\n});\n","import { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { positiveIntArg } from \"#/cli/shared/args\";\nimport { fetchAll, initOperatorClient, type OperatorClient } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadAccessToken } from \"#/cli/shared/context\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { listOrganizations } from \"./list\";\nimport type { UserOrganizationInfo } from \"./transform\";\n\ninterface TreeNode {\n  name: string;\n  children: TreeNode[];\n}\n\nexport interface OrganizationTreeOptions {\n  organizationId?: string;\n  depth?: number;\n}\n\ninterface OrganizationTreeJson {\n  organizationId: string;\n  organizationName: string;\n  folders: FolderTreeJson[];\n}\n\ninterface FolderTreeJson {\n  id: string;\n  name: string;\n  children: FolderTreeJson[];\n}\n\nasync function fetchChildFolders(\n  client: OperatorClient,\n  organizationId: string,\n  parentFolderId: string,\n  currentDepth: number,\n  maxDepth: number | undefined,\n): Promise<TreeNode[]> {\n  if (maxDepth !== undefined && currentDepth >= maxDepth) {\n    return [];\n  }\n\n  const folders = await fetchAll(async (pageToken, maxPageSize) => {\n    const response = await client.listOrganizationFolders({\n      organizationId,\n      parentFolderId,\n      pageToken,\n      pageSize: maxPageSize,\n    });\n    return [response.folders, response.nextPageToken];\n  });\n\n  const nodes: TreeNode[] = [];\n  for (const folder of folders) {\n    const children = folder.hasChildren\n      ? await fetchChildFolders(client, organizationId, folder.id, currentDepth + 1, maxDepth)\n      : [];\n    nodes.push({ name: folder.name, children });\n  }\n  return nodes;\n}\n\nasync function buildFolderTreeJson(\n  client: OperatorClient,\n  organizationId: string,\n  parentFolderId: string,\n  currentDepth: number,\n  maxDepth: number | undefined,\n): Promise<FolderTreeJson[]> {\n  if (maxDepth !== undefined && currentDepth >= maxDepth) {\n    return [];\n  }\n\n  const folders = await fetchAll(async (pageToken, maxPageSize) => {\n    const response = await client.listOrganizationFolders({\n      organizationId,\n      parentFolderId,\n      pageToken,\n      pageSize: maxPageSize,\n    });\n    return [response.folders, response.nextPageToken];\n  });\n\n  const result: FolderTreeJson[] = [];\n  for (const folder of folders) {\n    const children = folder.hasChildren\n      ? await buildFolderTreeJson(client, organizationId, folder.id, currentDepth + 1, maxDepth)\n      : [];\n    result.push({ id: folder.id, name: folder.name, children });\n  }\n  return result;\n}\n\nfunction renderTree(nodes: TreeNode[], prefix: string): string {\n  let output = \"\";\n  for (const [i, node] of nodes.entries()) {\n    const isLast = i === nodes.length - 1;\n    const connector = isLast ? \"\\u2514\\u2500\\u2500 \" : \"\\u251c\\u2500\\u2500 \";\n    const childPrefix = isLast ? \"    \" : \"\\u2502   \";\n    output += `${prefix}${connector}${node.name}\\n`;\n    if (node.children.length > 0) {\n      output += renderTree(node.children, prefix + childPrefix);\n    }\n  }\n  return output;\n}\n\nasync function buildOrgTree(\n  client: OperatorClient,\n  org: UserOrganizationInfo,\n  depth: number | undefined,\n): Promise<string> {\n  const children = await fetchChildFolders(client, org.organizationId, org.rootFolderId, 0, depth);\n  let output = `${org.organizationName}\\n`;\n  output += renderTree(children, \"\");\n  return output;\n}\n\n/**\n * Display a tree view of organizations and their folder hierarchy.\n * @param options - Tree display options\n * @returns Organization tree as structured data\n */\nexport async function organizationTree(\n  options?: OrganizationTreeOptions,\n): Promise<OrganizationTreeJson[]> {\n  const accessToken = await loadAccessToken();\n  const client = await initOperatorClient(accessToken);\n\n  let orgs: UserOrganizationInfo[];\n  if (options?.organizationId) {\n    orgs = (await listOrganizations()).filter((o) => o.organizationId === options.organizationId);\n    if (orgs.length === 0) {\n      throw CLIError({\n        code: \"ORGANIZATION_NOT_FOUND\",\n        message: `Organization \"${options.organizationId}\" not found.`,\n      });\n    }\n  } else {\n    orgs = await listOrganizations();\n  }\n\n  const depth = options?.depth;\n\n  const jsonResult: OrganizationTreeJson[] = [];\n  for (const org of orgs) {\n    const folders = await buildFolderTreeJson(\n      client,\n      org.organizationId,\n      org.rootFolderId,\n      0,\n      depth,\n    );\n    jsonResult.push({\n      organizationId: org.organizationId,\n      organizationName: org.organizationName,\n      folders,\n    });\n  }\n\n  return jsonResult;\n}\n\nexport const treeCommand = defineAppCommand({\n  name: \"tree\",\n  description: \"Display organization folder hierarchy as a tree.\",\n  args: z.strictObject({\n    \"organization-id\": arg(z.string().optional(), {\n      alias: \"o\",\n      description: \"Organization ID (show all if omitted)\",\n      env: \"TAILOR_PLATFORM_ORGANIZATION_ID\",\n    }),\n    depth: arg(positiveIntArg.optional(), {\n      alias: \"d\",\n      description: \"Maximum folder depth to display\",\n    }),\n  }),\n  run: async (args) => {\n    const accessToken = await loadAccessToken();\n    const client = await initOperatorClient(accessToken);\n\n    let orgs: UserOrganizationInfo[];\n    if (args[\"organization-id\"]) {\n      orgs = (await listOrganizations()).filter(\n        (o) => o.organizationId === args[\"organization-id\"],\n      );\n      if (orgs.length === 0) {\n        throw CLIError({\n          code: \"ORGANIZATION_NOT_FOUND\",\n          message: `Organization \"${args[\"organization-id\"]}\" not found.`,\n        });\n      }\n    } else {\n      orgs = await listOrganizations();\n    }\n\n    if (args.json) {\n      const jsonResult: OrganizationTreeJson[] = [];\n      for (const org of orgs) {\n        const folders = await buildFolderTreeJson(\n          client,\n          org.organizationId,\n          org.rootFolderId,\n          0,\n          args.depth,\n        );\n        jsonResult.push({\n          organizationId: org.organizationId,\n          organizationName: org.organizationName,\n          folders,\n        });\n      }\n      logger.out(jsonResult);\n      return;\n    }\n\n    const trees: string[] = [];\n    for (const org of orgs) {\n      trees.push(await buildOrgTree(client, org, args.depth));\n    }\n\n    logger.log(trees.join(\"\\n\"));\n  },\n});\n","import { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { organizationArgs } from \"#/cli/shared/args\";\nimport { initOperatorClient } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadAccessToken } from \"#/cli/shared/context\";\nimport { internalError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { assertWritable } from \"#/cli/shared/readonly-guard\";\nimport { organizationInfo, type OrganizationInfo } from \"./transform\";\n\n// strip unknown keys\nconst updateOrganizationOptionsSchema = z.object({\n  organizationId: z.uuid({ message: \"organization-id must be a valid UUID\" }),\n  name: z.string().min(1, \"Name must not be empty\"),\n});\n\nexport type UpdateOrganizationOptions = z.input<typeof updateOrganizationOptionsSchema>;\n\n/**\n * Update an organization's name.\n * @param options - Organization update options\n * @returns Updated organization details\n */\nexport async function updateOrganization(\n  options: UpdateOrganizationOptions,\n): Promise<OrganizationInfo> {\n  const validated = parseOptions(updateOrganizationOptionsSchema, options);\n\n  const accessToken = await loadAccessToken();\n  const client = await initOperatorClient(accessToken);\n\n  const response = await client.updateOrganization({\n    organizationId: validated.organizationId,\n    organizationName: validated.name,\n  });\n\n  if (!response.organization) {\n    throw internalError(`Failed to update organization \"${validated.organizationId}\".`);\n  }\n\n  return organizationInfo(response.organization);\n}\n\nexport const updateCommand = defineAppCommand({\n  name: \"update\",\n  description: \"Update an organization's name.\",\n  args: z.strictObject({\n    ...organizationArgs,\n    name: arg(z.string(), {\n      alias: \"n\",\n      description: \"New organization name\",\n    }),\n  }),\n  run: async (args) => {\n    await assertWritable();\n    const organization = await updateOrganization({\n      organizationId: args[\"organization-id\"],\n      name: args.name,\n    });\n\n    if (!args.json) {\n      logger.success(`Organization \"${organization.name}\" updated successfully.`);\n    }\n\n    logger.out(organization);\n  },\n});\n","import { z } from \"zod\";\nimport { applyAIGateway, planAIGateway } from \"#/cli/commands/deploy/aigateway\";\nimport { findAppIdLock, resolveLockedAppIds } from \"#/cli/commands/deploy/app-id-lock\";\nimport { applyApplication, planApplication } from \"#/cli/commands/deploy/application\";\nimport { applyAuth, planAuth } from \"#/cli/commands/deploy/auth\";\nimport { warnMissingAppId } from \"#/cli/commands/deploy/config-id-injector\";\nimport { applyExecutor, planExecutor } from \"#/cli/commands/deploy/executor\";\nimport {\n  applyFunctionRegistry,\n  planFunctionRegistry,\n} from \"#/cli/commands/deploy/function-registry\";\nimport { applyIdP, planIdP } from \"#/cli/commands/deploy/idp\";\nimport { applyPipeline, planPipeline } from \"#/cli/commands/deploy/resolver\";\nimport { applySecretManager, planSecretManager } from \"#/cli/commands/deploy/secret-manager\";\nimport { applyStaticWebsite, planStaticWebsite } from \"#/cli/commands/deploy/staticwebsite\";\nimport { applyTailorDB, planTailorDB } from \"#/cli/commands/deploy/tailordb/index\";\nimport { applyWorkflow, planWorkflow } from \"#/cli/commands/deploy/workflow\";\nimport {\n  applyWorkflowJobFunctionExecutionPolicy,\n  planWorkflowJobFunctionExecutionPolicy,\n} from \"#/cli/commands/deploy/workflow-execution-policy\";\nimport { type Application, defineApplication } from \"#/cli/services/application\";\nimport { confirmationArgs, deploymentArgs } from \"#/cli/shared/args\";\nimport { type OperatorClient } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadConfig, type LoadedConfig } from \"#/cli/shared/config-loader\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { prompt } from \"#/cli/shared/prompt\";\nimport { assertWritable } from \"#/cli/shared/readonly-guard\";\nimport ml from \"#/utils/multiline\";\nimport type { PlannedDeployment } from \"#/cli/commands/deploy/apply-phases\";\nimport type { PlanContext } from \"#/cli/commands/deploy/types\";\n\nexport interface RemoveOptions {\n  workspaceId?: string;\n  profile?: string;\n  configPath?: string;\n}\n\n// remove never writes: a config whose id is not recorded yet is removed by\n// name, with the same warning deploy prints.\nasync function resolveRemoveConfigId(config: LoadedConfig): Promise<LoadedConfig> {\n  const lock = findAppIdLock(config.path);\n  if (lock === null) {\n    warnMissingAppId(config.id);\n    return config;\n  }\n  const plan = await resolveLockedAppIds({\n    lock,\n    mode: \"read\",\n    entries: [{ configPath: config.path, configId: config.id }],\n  });\n  return { ...config, id: plan.entries[0]?.id };\n}\n\nasync function loadOptions(options?: RemoveOptions) {\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options?.profile,\n    workspaceId: options?.workspaceId,\n  });\n  const { config: loadedConfig } = await loadConfig(options?.configPath);\n  const config = await resolveRemoveConfigId(loadedConfig);\n  const application = defineApplication({ config });\n  return {\n    client,\n    workspaceId,\n    application,\n    config,\n  };\n}\n\nasync function execRemove(\n  client: OperatorClient,\n  workspaceId: string,\n  application: Application,\n  config: LoadedConfig,\n  confirm?: () => Promise<void>,\n) {\n  // Plan all resources with forRemoval=true\n  const ctx: PlanContext = {\n    client,\n    workspaceId,\n    application,\n    forRemoval: true,\n    config,\n  };\n  // Keyed like `PlannedDeployment` (deploy/apply-phases.ts): adding a resource\n  // type there without also adding it here fails to compile.\n  const plans = {\n    tailorDB: await planTailorDB(ctx),\n    staticWebsite: await planStaticWebsite(ctx),\n    aiGateway: await planAIGateway(ctx),\n    idp: await planIdP(ctx),\n    auth: await planAuth(ctx),\n    pipeline: await planPipeline(ctx),\n    app: await planApplication(ctx),\n    executor: await planExecutor(ctx),\n    workflow: await planWorkflow(client, workspaceId, application.name, application.id, {}, {}),\n    workflowExecutionPolicy: await planWorkflowJobFunctionExecutionPolicy(\n      client,\n      workspaceId,\n      application.name,\n      application.id,\n      {},\n    ),\n    functionRegistry: await planFunctionRegistry(\n      client,\n      workspaceId,\n      application.name,\n      application.id,\n      [],\n    ),\n    secretManager: await planSecretManager(ctx),\n  } satisfies Omit<PlannedDeployment, \"application\">;\n\n  // Resources carrying this application's sdk-name whose sdk-app-id the config\n  // does not match, because it holds a different id or none. They are skipped,\n  // so removal is not complete.\n  const leftBehind = Object.values(plans).some(\n    (plan) => \"resourceOwners\" in plan && plan.resourceOwners.has(application.name),\n  );\n\n  // Print planned deletions (same order as apply dry-run)\n  const removeLines = [\n    ...plans.functionRegistry.changeSet.lines(),\n    ...plans.staticWebsite.changeSet.lines(),\n    ...plans.aiGateway.changeSet.lines(),\n    ...plans.app.lines(),\n    ...plans.tailorDB.changeSet.service.lines(),\n    ...plans.tailorDB.changeSet.type.lines(),\n    ...plans.tailorDB.changeSet.gqlPermission.lines(),\n    ...plans.pipeline.changeSet.service.lines(),\n    ...plans.pipeline.changeSet.resolver.lines(),\n    ...plans.executor.changeSet.lines(),\n    ...plans.workflow.changeSet.lines(),\n    ...plans.workflowExecutionPolicy.changeSet.lines(),\n    ...plans.idp.changeSet.service.lines(),\n    ...plans.idp.changeSet.client.lines(),\n    ...plans.auth.changeSet.service.lines(),\n    ...plans.auth.changeSet.idpConfig.lines(),\n    ...plans.auth.changeSet.userProfileConfig.lines(),\n    ...plans.auth.changeSet.tenantConfig.lines(),\n    ...plans.auth.changeSet.machineUser.lines(),\n    ...plans.auth.changeSet.oauth2Client.lines(),\n    ...plans.auth.changeSet.authHook.lines(),\n    ...plans.auth.changeSet.scim.lines(),\n    ...plans.auth.changeSet.scimResource.lines(),\n    ...plans.auth.changeSet.connection.lines(),\n    ...plans.secretManager.vaultChangeSet.lines(),\n    ...plans.secretManager.secretChangeSet.lines(),\n  ];\n  if (removeLines.length > 0) logger.log(removeLines.join(\"\\n\"));\n\n  if (\n    plans.tailorDB.changeSet.service.deletes.length === 0 &&\n    plans.staticWebsite.changeSet.deletes.length === 0 &&\n    plans.aiGateway.changeSet.deletes.length === 0 &&\n    plans.idp.changeSet.service.deletes.length === 0 &&\n    plans.auth.changeSet.service.deletes.length === 0 &&\n    plans.pipeline.changeSet.service.deletes.length === 0 &&\n    plans.app.deletes.length === 0 &&\n    plans.executor.changeSet.deletes.length === 0 &&\n    plans.workflow.changeSet.deletes.length === 0 &&\n    plans.workflowExecutionPolicy.changeSet.deletes.length === 0 &&\n    plans.functionRegistry.changeSet.deletes.length === 0 &&\n    plans.secretManager.vaultChangeSet.deletes.length === 0 &&\n    plans.secretManager.secretChangeSet.deletes.length === 0\n  ) {\n    return { leftBehind };\n  }\n\n  // Confirm deletion\n  if (confirm) {\n    await confirm();\n  }\n\n  // Apply deletions in reverse order of dependencies\n  await applyWorkflow(client, plans.workflow, \"delete\");\n  await applyWorkflowJobFunctionExecutionPolicy(client, plans.workflowExecutionPolicy, \"delete\");\n  await applyExecutor(client, plans.executor, \"delete\");\n  await applyStaticWebsite(client, plans.staticWebsite, \"delete\");\n  await applyAIGateway(client, plans.aiGateway, \"delete\");\n  await applyApplication(client, plans.app, \"delete\");\n  await applyPipeline(client, plans.pipeline, \"delete-resources\");\n  await applyPipeline(client, plans.pipeline, \"delete-services\");\n  await applyAuth(client, plans.auth, \"delete-resources\");\n  await applyAuth(client, plans.auth, \"delete-services\");\n  await applyIdP(client, plans.idp, \"delete-resources\");\n  await applyIdP(client, plans.idp, \"delete-services\");\n  await applyTailorDB(client, plans.tailorDB, \"delete-resources\");\n  await applyTailorDB(client, plans.tailorDB, \"delete-services\");\n  await applyFunctionRegistry(client, workspaceId, plans.functionRegistry, \"delete\");\n  await applySecretManager(client, plans.secretManager, \"delete\");\n\n  return { leftBehind };\n}\n\n/**\n * Remove all resources managed by the current application.\n * @param options - Remove options\n * @returns Promise that resolves when removal completes\n */\nexport async function remove(options?: RemoveOptions): Promise<void> {\n  const { client, workspaceId, application, config } = await loadOptions(options);\n  await execRemove(client, workspaceId, application, config);\n}\n\nexport const removeCommand = defineAppCommand({\n  name: \"remove\",\n  description: \"Remove all resources managed by the application from the workspace.\",\n  args: z.strictObject({\n    ...deploymentArgs,\n    ...confirmationArgs,\n  }),\n  run: async (args) => {\n    await assertWritable({ profile: args.profile });\n    const { client, workspaceId, application, config } = await loadOptions({\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      configPath: args.config,\n    });\n\n    logger.info(`Planning removal of resources managed by \"${application.name}\"...`);\n    logger.newline();\n\n    const { leftBehind } = await execRemove(client, workspaceId, application, config, async () => {\n      if (!args.yes) {\n        const confirmed = await prompt.confirm({\n          message: \"Are you sure you want to remove all resources?\",\n          default: false,\n        });\n        if (!confirmed) {\n          throw CLIError({\n            code: \"REMOVE_CANCELLED\",\n            message: ml`\n        Remove cancelled. No resources were deleted.\n        To override, run again and confirm, or use --yes flag.\n      `,\n          });\n        }\n      } else {\n        logger.success(\"Removing all resources (--yes flag specified)...\");\n      }\n    });\n\n    if (leftBehind) {\n      logger.warn(ml`\n        Resources tagged with \"${application.name}\" were left in place: they carry an application id this config does not match.\n        Record that id for this config (in .github/tailor.lock, or the config's 'id'), or run deploy to take them over first, then remove again.\n      `);\n      return;\n    }\n    logger.success(`Successfully removed all resources managed by \"${application.name}\".`);\n  },\n});\n","import { timestampDate } from \"@bufbuild/protobuf/wkt\";\nimport { Code, ConnectError } from \"@connectrpc/connect\";\nimport { z } from \"zod\";\nimport { deploymentArgs } from \"#/cli/shared/args\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadConfig } from \"#/cli/shared/config-loader\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { createWorkspaceNameTransformer, resolveWorkspaceFolderName } from \"./workspace/transform\";\nimport type { OperatorClient } from \"#/cli/shared/client\";\nimport type { Application } from \"@tailor-platform/tailor-proto/application_resource_pb\";\n\nexport interface ShowOptions {\n  workspaceId?: string;\n  profile?: string;\n  configPath?: string;\n}\n\ninterface WorkspaceInfo {\n  workspaceId: string;\n  workspaceName: string;\n  workspaceFolderName?: string;\n  workspaceRegion?: string;\n}\n\nexport interface ApplicationInfo {\n  name: string;\n  domain: string;\n  url: string;\n  auth: string;\n  cors: string[];\n  allowedIpAddresses: string[];\n  disableIntrospection: boolean;\n  createdAt: Date | null;\n  updatedAt: Date | null;\n}\n\nexport interface AIGatewayInfo {\n  name: string;\n  url: string;\n}\n\nexport interface ShowInfo extends ApplicationInfo, WorkspaceInfo {\n  aiGateways: AIGatewayInfo[];\n}\n\nfunction applicationInfo(app: Application): ApplicationInfo {\n  return {\n    name: app.name,\n    domain: app.domain,\n    url: app.url,\n    auth: app.authNamespace,\n    cors: app.cors,\n    allowedIpAddresses: app.allowedIpAddresses,\n    disableIntrospection: app.disableIntrospection,\n    createdAt: app.createTime ? timestampDate(app.createTime) : null,\n    updatedAt: app.updateTime ? timestampDate(app.updateTime) : null,\n  };\n}\n\nasync function fetchAIGateways(\n  client: OperatorClient,\n  workspaceId: string,\n  names: string[],\n): Promise<AIGatewayInfo[]> {\n  const gateways = await Promise.all(\n    names.map(async (name) => {\n      try {\n        const { aigateway } = await client.getAIGateway({ workspaceId, aigatewayName: name });\n        return aigateway ? { name: aigateway.name, url: aigateway.url } : undefined;\n      } catch (error) {\n        if (error instanceof ConnectError && error.code === Code.NotFound) {\n          return undefined;\n        }\n        throw error;\n      }\n    }),\n  );\n  return gateways.filter((gateway): gateway is AIGatewayInfo => gateway !== undefined);\n}\n\n/**\n * Show applied application information for the current workspace.\n * @param options - Show options\n * @returns Deployed application, workspace, and AI Gateway information\n */\nexport async function show(options?: ShowOptions): Promise<ShowInfo> {\n  // Load and validate options\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options?.profile,\n    workspaceId: options?.workspaceId,\n  });\n\n  const { config } = await loadConfig(options?.configPath);\n  const aiGatewayNames = config.aiGateways?.length\n    ? [...new Set(config.aiGateways.map((gateway) => gateway.name))]\n    : [];\n  const [workspaceResp, resp, aiGateways] = await Promise.all([\n    client.getWorkspace({\n      workspaceId,\n    }),\n    client.getApplication({\n      workspaceId,\n      applicationName: config.name,\n    }),\n    fetchAIGateways(client, workspaceId, aiGatewayNames),\n  ]);\n  const { name, ...appInfo } = applicationInfo(\n    assertDefined(resp.application, `application \"${config.name}\" not found in workspace`),\n  );\n  const workspace = workspaceResp.workspace;\n  const workspaceFolderName = workspace ? await resolveWorkspaceFolderName(client, workspace) : \"\";\n\n  return {\n    name,\n    workspaceId,\n    workspaceName: workspace?.name ?? \"\",\n    ...(workspaceFolderName ? { workspaceFolderName } : {}),\n    workspaceRegion: workspace?.region ?? \"\",\n    ...appInfo,\n    aiGateways,\n  };\n}\n\nconst showWorkspaceNameTransformer = createWorkspaceNameTransformer(\n  \"workspaceName\",\n  \"workspaceFolderName\",\n);\n\nexport const showCommand = defineAppCommand({\n  name: \"show\",\n  description: \"Show information about the deployed application.\",\n  args: z.strictObject({\n    ...deploymentArgs,\n  }),\n  run: async (args) => {\n    // Execute show logic\n    const appInfo = await show({\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      configPath: args.config,\n    });\n\n    logger.out(appInfo, {\n      display: { workspaceName: showWorkspaceNameTransformer, workspaceFolderName: null },\n    });\n  },\n});\n","import { setTimeout } from \"node:timers/promises\";\n\n/**\n * Create a simple progress reporter that writes updates to stderr.\n * @param label - Label to prefix progress output\n * @param total - Total number of steps\n * @returns Progress helpers\n */\nexport function createProgress(label: string, total: number) {\n  let current = 0;\n\n  const update = () => {\n    current += 1;\n    const percent = Math.round((current / total) * 100);\n    process.stderr.write(`\\r${label} ${current}/${total} (${percent}%)`);\n  };\n\n  const finish = () => {\n    process.stderr.write(\"\\n\");\n  };\n\n  return { update, finish };\n}\n\n/**\n * Wrap a promise with a timeout, rejecting if the timeout elapses first.\n * @template T\n * @param p - Promise to await\n * @param ms - Timeout in milliseconds\n * @param message - Error message on timeout\n * @returns Result of the original promise if it completes in time\n */\nexport async function withTimeout<T>(p: Promise<T>, ms: number, message: string): Promise<T> {\n  const timeoutController = new AbortController();\n  try {\n    return await Promise.race([\n      p,\n      setTimeout(ms, undefined, { signal: timeoutController.signal }).then(() => {\n        throw new Error(message);\n      }),\n    ]);\n  } finally {\n    timeoutController.abort();\n  }\n}\n","import * as fs from \"fs\";\nimport { Code, ConnectError } from \"@connectrpc/connect\";\nimport { arg } from \"@politty/zod\";\nimport { lookup as mimeLookup } from \"mime-types\";\nimport pLimit from \"p-limit\";\nimport * as path from \"pathe\";\nimport { z } from \"zod\";\nimport { workspaceArgs } from \"#/cli/shared/args\";\nimport { initOperatorClient, type OperatorClient } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadAccessToken, loadWorkspaceId } from \"#/cli/shared/context\";\nimport { CLIError, internalError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { createProgress, withTimeout } from \"#/cli/shared/progress\";\nimport { assertWritable } from \"#/cli/shared/readonly-guard\";\nimport type { MessageInitShape } from \"@bufbuild/protobuf\";\nimport type { UploadFileRequestSchema } from \"@tailor-platform/tailor-proto/staticwebsite_pb\";\n\nconst CHUNK_SIZE = 64 * 1024; // 64KB\nconst IGNORED_FILES = new Set([\".DS_Store\", \"thumbs.db\", \"desktop.ini\"]);\nfunction shouldIgnoreFile(filePath: string) {\n  const fileName = path.basename(filePath).toLowerCase();\n  return IGNORED_FILES.has(fileName);\n}\n\nexport type DeployResult = {\n  url: string;\n  skippedFiles: string[];\n};\n\n/**\n * Deploy a static website by creating a deployment, uploading files, and publishing it.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param name - Static website name\n * @param distDir - Directory containing static site files\n * @param showProgress - Whether to show upload progress\n * @returns Deployment result with URL and skipped files\n */\nexport async function deployStaticWebsite(\n  client: OperatorClient,\n  workspaceId: string,\n  name: string,\n  distDir: string,\n  showProgress: boolean = true,\n): Promise<DeployResult> {\n  const { deploymentId } = await client.createDeployment({\n    workspaceId,\n    name,\n  });\n\n  if (!deploymentId) {\n    throw internalError(\"createDeployment returned empty deploymentId\");\n  }\n\n  const skippedFiles = await uploadDirectory(\n    client,\n    workspaceId,\n    deploymentId,\n    distDir,\n    showProgress,\n  );\n\n  const { url } = await client.publishDeployment({\n    workspaceId,\n    deploymentId,\n  });\n\n  if (!url) {\n    throw internalError(\"publishDeployment returned empty url\");\n  }\n\n  return { url, skippedFiles };\n}\n\nasync function uploadDirectory(\n  client: OperatorClient,\n  workspaceId: string,\n  deploymentId: string,\n  rootDir: string,\n  showProgress: boolean,\n): Promise<string[]> {\n  const files = await collectFiles(rootDir);\n  if (files.length === 0) {\n    logger.warn(`No files found under ${rootDir}`);\n    return [];\n  }\n\n  const concurrency = 5;\n  const limit = pLimit(concurrency);\n\n  const total = files.length;\n  const progress = showProgress ? createProgress(\"Uploading files\", total) : undefined;\n  const skippedFiles: string[] = [];\n\n  await Promise.all(\n    files.map((relativePath) =>\n      limit(async () => {\n        await uploadSingleFile(\n          client,\n          workspaceId,\n          deploymentId,\n          rootDir,\n          relativePath,\n          skippedFiles,\n        );\n        if (progress) {\n          progress.update();\n        }\n      }),\n    ),\n  );\n\n  if (progress) {\n    progress.finish();\n  }\n\n  return skippedFiles;\n}\n\n/**\n * Recursively collect all deployable files under the given directory.\n * @param rootDir - Root directory to scan\n * @param currentDir - Current relative directory (for recursion)\n * @returns List of file paths relative to rootDir\n */\nasync function collectFiles(rootDir: string, currentDir = \"\"): Promise<string[]> {\n  const dirPath = path.join(rootDir, currentDir);\n\n  const entries = await fs.promises.readdir(dirPath, {\n    withFileTypes: true,\n  });\n  const files: string[] = [];\n\n  for (const entry of entries) {\n    const rel = path.join(currentDir, entry.name);\n    if (entry.isDirectory()) {\n      const sub = await collectFiles(rootDir, rel);\n      files.push(...sub);\n    } else if (entry.isFile() && !entry.isSymbolicLink() && !shouldIgnoreFile(rel)) {\n      files.push(rel);\n    }\n  }\n\n  return files;\n}\n\nasync function uploadSingleFile(\n  client: OperatorClient,\n  workspaceId: string,\n  deploymentId: string,\n  rootDir: string,\n  filePath: string,\n  skippedFiles: string[],\n): Promise<void> {\n  const absPath = path.join(rootDir, filePath);\n\n  const mime = mimeLookup(filePath);\n\n  if (!mime) {\n    skippedFiles.push(`${filePath} (unsupported content type; no MIME mapping found)`);\n    return;\n  }\n\n  const contentType = mime;\n\n  const readStream = fs.createReadStream(absPath, {\n    highWaterMark: CHUNK_SIZE,\n  });\n\n  async function* requestStream(): AsyncIterable<MessageInitShape<typeof UploadFileRequestSchema>> {\n    yield {\n      payload: {\n        case: \"initialMetadata\",\n        value: {\n          workspaceId,\n          deploymentId,\n          filePath,\n          contentType,\n        },\n      },\n    };\n    for await (const chunk of readStream) {\n      yield {\n        payload: {\n          case: \"chunkData\",\n          value: chunk as Buffer,\n        },\n      };\n    }\n  }\n\n  async function uploadWithLogging() {\n    try {\n      await client.uploadFile(requestStream());\n    } catch (error) {\n      if (error instanceof ConnectError && error.code === Code.InvalidArgument) {\n        skippedFiles.push(`${filePath} (server rejected file as invalid: ${error.message})`);\n        return;\n      }\n      // For non-validation errors, fail the deployment as before.\n      throw error;\n    }\n  }\n\n  await withTimeout(\n    uploadWithLogging(),\n    // 2 minutes per file\n    2 * 60_000,\n    `Upload timed out for \"${filePath}\"`,\n  );\n}\n\n/**\n * Log skipped files after a deployment, including reasons for skipping.\n * @param skippedFiles - List of skipped file descriptions\n */\nfunction logSkippedFiles(skippedFiles: string[]) {\n  if (skippedFiles.length === 0) {\n    return;\n  }\n  logger.warn(\n    \"Deployment completed, but some files failed to upload. These files may have unsupported content types or other validation issues. Please review the list below:\",\n  );\n  for (const file of skippedFiles) {\n    logger.log(`  - ${file}`);\n  }\n}\n\nexport const deployCommand = defineAppCommand({\n  name: \"deploy\",\n  description: \"Deploy a static website from a local build directory.\",\n  args: z.strictObject({\n    ...workspaceArgs,\n    name: arg(z.string(), {\n      alias: \"n\",\n      description: \"Static website name\",\n    }),\n    dir: arg(z.string(), {\n      alias: \"d\",\n      description: \"Path to the static website files\",\n      completion: { type: \"directory\" },\n    }),\n  }),\n  run: async (args) => {\n    await assertWritable({ profile: args.profile });\n    logger.info(`Deploying static website \"${args.name}\" from directory: ${args.dir}`);\n    const accessToken = await loadAccessToken({\n      profile: args.profile,\n    });\n    const client = await initOperatorClient(accessToken);\n\n    const name = args.name;\n    const dir = path.resolve(process.cwd(), args.dir);\n    const workspaceId = await loadWorkspaceId({\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n    });\n\n    if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {\n      throw CLIError({\n        code: \"DIRECTORY_NOT_FOUND\",\n        message: `Directory not found or not a directory: ${dir}`,\n      });\n    }\n\n    const { url, skippedFiles } = await withTimeout(\n      deployStaticWebsite(client, workspaceId, name, dir, !args.json),\n      // 10 minutes\n      10 * 60_000,\n      \"Deployment timed out after 10 minutes.\",\n    );\n\n    if (args.json) {\n      logger.out({ name, workspaceId, url, skippedFiles });\n    } else {\n      logger.success(`Static website \"${name}\" deployed successfully. URL: ${url}`);\n      logSkippedFiles(skippedFiles);\n    }\n  },\n});\n","import { logger } from \"./logger\";\n\n/**\n * Warn that a feature is in beta.\n * @param {string} featureName - Name of the beta feature (e.g., \"tailordb migration\")\n */\nexport function logBetaWarning(featureName: string): void {\n  logger.warn(\n    `The '${featureName}' command is a beta feature and may introduce breaking changes in future releases.`,\n  );\n  logger.newline();\n}\n","import { spawn } from \"node:child_process\";\n\nconst DEFAULT_EDITOR = \"editor\";\n\nfunction normalizeEditorCommand(editor: string | undefined): string | undefined {\n  const normalized = editor?.trim();\n  return normalized && normalized.length > 0 ? normalized : undefined;\n}\n\n/**\n * Resolve an editor command only from explicit environment variables.\n * @returns Configured editor command, if any\n */\nexport function getConfiguredEditorCommand(): string | undefined {\n  return normalizeEditorCommand(process.env.VISUAL) ?? normalizeEditorCommand(process.env.EDITOR);\n}\n\n/**\n * Resolve the editor command used for interactive file editing.\n * @returns Configured editor command or the system default fallback\n */\nexport function getEditorCommand(): string {\n  return getConfiguredEditorCommand() ?? DEFAULT_EDITOR;\n}\n\nfunction parseEditorCommand(editor: string): {\n  command: string;\n  args: string[];\n} {\n  const [command, ...args] = editor.trim().split(/\\s+/);\n\n  if (!command) {\n    throw new Error(\"Editor command is empty.\");\n  }\n\n  return {\n    command,\n    args,\n  };\n}\n\n/**\n * Open a file in the resolved editor and wait for the process to exit.\n * @param filePath - File path to open\n * @param editor - Editor command string\n * @returns Whether an editor process was launched\n */\nexport async function openInEditor(\n  filePath: string,\n  editor = getEditorCommand(),\n): Promise<boolean> {\n  const { command, args } = parseEditorCommand(editor);\n\n  await new Promise<void>((resolve, reject) => {\n    const child = spawn(command, [...args, filePath], {\n      stdio: \"inherit\",\n      detached: false,\n    });\n\n    child.once(\"error\", (error) => reject(error));\n    child.once(\"close\", (code) => {\n      if (code == null || code === 0) {\n        resolve();\n        return;\n      }\n      reject(new Error(`Editor exited with code ${code}.`));\n    });\n  });\n\n  return true;\n}\n\n/**\n * Open a file only when an editor is explicitly configured in the environment.\n * @param filePath - File path to open\n * @returns Whether an editor process was launched\n */\nexport async function openInConfiguredEditor(filePath: string): Promise<boolean> {\n  const editor = getConfiguredEditorCommand();\n  if (!editor) {\n    return false;\n  }\n\n  return await openInEditor(filePath, editor);\n}\n","/**\n * Planning for field type changes that move values through a temporary field.\n *\n * A change that cannot be applied in place is split into two migrations: the\n * first adds a temporary field and converts values into it, the second renames\n * that field back over the original.\n */\n\nimport { parseSync } from \"oxc-parser\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { getExpandContractFieldChangeEligibility, hasFieldShapeChange } from \"./field-type-change\";\nimport { isSnapshotFieldRefOperand } from \"./snapshot-types\";\nimport type { BreakingChangeInfo, DiffChange, MigrationDiff } from \"./diff-calculator\";\nimport type {\n  SchemaSnapshot,\n  SnapshotFieldConfig,\n  SnapshotPermissionCondition,\n  TailorDBSnapshotType,\n} from \"./snapshot-types\";\nimport type { Node, PropertyKey } from \"@oxc-project/types\";\n\n/** Longest field name the platform accepts. */\nconst MAX_FIELD_NAME_LENGTH = 63;\n\nconst TEMP_FIELD_SUFFIX = \"Migrate\";\n\n/** One field type change to carry through a temporary field. */\nexport interface ExpandContractPlan {\n  tableName: string;\n  fieldName: string;\n  /** Field that holds converted values until the contract migration. */\n  tempFieldName: string;\n  before: SnapshotFieldConfig;\n  after: SnapshotFieldConfig;\n}\n\n/** Changes to automate, and the ones that must still be rejected. */\nexport interface ExpandContractPlanning {\n  plans: ExpandContractPlan[];\n  blocked: BreakingChangeInfo[];\n}\n\n/**\n * Key identifying a field across snapshots and user-supplied options.\n * @param tableName - Name of the table holding the field\n * @param fieldName - Name of the field\n * @returns Key in `Table.field` form\n */\nexport function fieldKey(tableName: string, fieldName: string): string {\n  return `${tableName}.${fieldName}`;\n}\n\n/**\n * Derive the temporary field name to carry a field's converted values.\n *\n * Field names cannot hold an underscore, so the suffix is camelCase and a\n * collision is resolved by an ordinal rather than a separator.\n * @param fieldName - Field being converted\n * @param taken - Field names already in use for the same table\n * @returns Unused temporary field name\n * @throws {Error} When no candidate fits within the platform's length limit\n */\nexport function buildTempFieldName(fieldName: string, taken: ReadonlySet<string>): string {\n  const base = `${fieldName}${TEMP_FIELD_SUFFIX}`;\n  for (let ordinal = 1; ordinal <= taken.size + 1; ordinal++) {\n    const candidate = ordinal === 1 ? base : `${base}${ordinal}`;\n    if (candidate.length > MAX_FIELD_NAME_LENGTH) break;\n    if (!taken.has(candidate)) return candidate;\n  }\n  throw CLIError({\n    code: \"MIGRATION_EXPAND_CONTRACT_NAME_UNAVAILABLE\",\n    message: `Cannot derive a temporary field name for \"${fieldName}\": every candidate is taken or exceeds ${MAX_FIELD_NAME_LENGTH} characters.`,\n  });\n}\n\n/** Inputs for {@link planExpandContract}. */\nexport interface PlanExpandContractOptions {\n  previous: SchemaSnapshot;\n  current: SchemaSnapshot;\n  diff: MigrationDiff;\n  /** `Table.field` keys the user approved for automation. */\n  confirmed: ReadonlySet<string>;\n}\n\n/** A field change that may need a temporary field to carry its values. */\nexport type ExpandContractCandidateChange = Extract<\n  DiffChange,\n  { kind: \"field_type_modified\" | \"field_modified\" }\n>;\n\n/**\n * Whether a diff change alters a field's shape, which is what a migration pair\n * exists to carry. A type change is always one; an otherwise modified field\n * qualifies when it turns a single value into an array.\n * @param change - Diff change to test\n * @returns Whether the change is worth offering a conversion for\n */\nexport function isExpandContractCandidate(\n  change: DiffChange,\n): change is ExpandContractCandidateChange {\n  return (\n    change.kind === \"field_type_modified\" ||\n    (change.kind === \"field_modified\" && hasFieldShapeChange(change.before, change.after))\n  );\n}\n\n/**\n * Whether a field type change can be carried by a generated migration pair.\n *\n * The single answer behind the prompt, the flag hint, and planning, so a run\n * cannot recommend a conversion it would then reject.\n * @param options - Snapshots and the field to test\n * @returns Whether the conversion can be generated\n */\nexport function canConvertField(options: CanConvertFieldOptions): boolean {\n  return getExpandContractEligibility(options).eligible;\n}\n\n/** Result of checking whether a field can use expand-contract. */\nexport type ExpandContractEligibility = { eligible: true } | { eligible: false; reason: string };\n\n/**\n * Explain whether a field can be carried by a generated migration pair.\n * @param options - Snapshots and the field to test\n * @returns Eligibility and, when ineligible, the reason\n */\nexport function getExpandContractEligibility(\n  options: CanConvertFieldOptions,\n): ExpandContractEligibility {\n  const { previous, current, tableName, fieldName } = options;\n  const before = previous.tables[tableName]?.fields[fieldName];\n  const after = current.tables[tableName]?.fields[fieldName];\n  if (!before || !after) {\n    return { eligible: false, reason: \"the field does not exist in both schemas\" };\n  }\n  const fieldEligibility = getExpandContractFieldChangeEligibility(before, after);\n  if (!fieldEligibility.eligible) return fieldEligibility;\n  if (\n    isFieldReferenced(previous.tables[tableName], fieldName) ||\n    isFieldReferenced(current.tables[tableName], fieldName)\n  ) {\n    return { eligible: false, reason: \"another schema feature references the field\" };\n  }\n  return { eligible: true };\n}\n\n/** Inputs for {@link canConvertField}. */\nexport interface CanConvertFieldOptions {\n  previous: SchemaSnapshot;\n  current: SchemaSnapshot;\n  tableName: string;\n  fieldName: string;\n}\n\n/**\n * Names a table already exposes, which a temporary field cannot reuse.\n * @param type - Table to enumerate\n * @returns Field, file, and relationship names\n */\nfunction typeMemberNames(type: TailorDBSnapshotType | undefined): string[] {\n  if (!type) return [];\n  return [\n    ...Object.keys(type.fields),\n    ...Object.keys(type.files ?? {}),\n    ...Object.keys(type.forwardRelationships ?? {}),\n    ...Object.keys(type.backwardRelationships ?? {}),\n  ];\n}\n\nfunction staticPropertyName(key: PropertyKey, computed: boolean): string | undefined {\n  if (!computed && key.type === \"Identifier\") return key.name;\n  if (key.type === \"Literal\" && typeof key.value === \"string\") return key.value;\n  if (key.type === \"TemplateLiteral\" && key.expressions.length === 0) {\n    return key.quasis[0]?.value.cooked ?? undefined;\n  }\n  return undefined;\n}\n\nconst SCRIPT_CONTEXT_ARGUMENTS = new Set([\"input\", \"newRecord\", \"oldRecord\", \"invoker\", \"now\"]);\n\nfunction walkScriptAst(\n  node: Node | null | undefined,\n  visit: (node: Node, ancestors: readonly Node[]) => void,\n  ancestors: readonly Node[] = [],\n): void {\n  if (!node) return;\n  visit(node, ancestors);\n  const nestedAncestors = [...ancestors, node];\n  const record = node as unknown as Record<string, unknown>;\n  for (const [key, value] of Object.entries(record)) {\n    if (key === \"type\" || key === \"parent\") continue;\n    if (Array.isArray(value)) {\n      for (const item of value) {\n        if (item && typeof item === \"object\" && \"type\" in item) {\n          walkScriptAst(item as Node, visit, nestedAncestors);\n        }\n      }\n    } else if (value && typeof value === \"object\" && \"type\" in value) {\n      walkScriptAst(value as Node, visit, nestedAncestors);\n    }\n  }\n}\n\nfunction unwrapFunction(node: Node): Node {\n  return node.type === \"ParenthesizedExpression\" ? unwrapFunction(node.expression) : node;\n}\n\nfunction collectIssueBindings(program: Node): Set<string> {\n  const issueBindings = new Set([\"__issues\"]);\n  walkScriptAst(program, (node) => {\n    if (node.type !== \"CallExpression\") return;\n    const callee = unwrapFunction(node.callee);\n    if (\n      (callee.type !== \"ArrowFunctionExpression\" && callee.type !== \"FunctionExpression\") ||\n      node.arguments[1]?.type !== \"Identifier\" ||\n      node.arguments[1].name !== \"__issues\"\n    ) {\n      return;\n    }\n    const issueParameter = callee.params[1];\n    if (issueParameter?.type === \"Identifier\") issueBindings.add(issueParameter.name);\n  });\n\n  let addedBinding: boolean;\n  do {\n    const previousSize = issueBindings.size;\n    walkScriptAst(program, (node) => {\n      if (\n        node.type === \"VariableDeclarator\" &&\n        node.id.type === \"Identifier\" &&\n        node.init?.type === \"Identifier\" &&\n        issueBindings.has(node.init.name)\n      ) {\n        issueBindings.add(node.id.name);\n      }\n    });\n    addedBinding = issueBindings.size > previousSize;\n  } while (addedBinding);\n  return issueBindings;\n}\n\nfunction isWrapperArgumentProperty(node: Node, ancestors: readonly Node[]): boolean {\n  if (node.type !== \"Property\") return false;\n  const propertyName = staticPropertyName(node.key, node.computed);\n  if (!propertyName || !SCRIPT_CONTEXT_ARGUMENTS.has(propertyName)) return false;\n  const object = ancestors.at(-1);\n  const call = ancestors.at(-2);\n  if (object?.type !== \"ObjectExpression\" || call?.type !== \"CallExpression\") return false;\n  return (\n    call.arguments[0] === object &&\n    [\"ArrowFunctionExpression\", \"FunctionExpression\"].includes(unwrapFunction(call.callee).type)\n  );\n}\n\nfunction isWrapperParameterProperty(node: Node, ancestors: readonly Node[]): boolean {\n  if (node.type !== \"Property\") return false;\n  const propertyName = staticPropertyName(node.key, node.computed);\n  if (!propertyName || !SCRIPT_CONTEXT_ARGUMENTS.has(propertyName)) return false;\n  const pattern = ancestors.at(-1);\n  if (pattern?.type !== \"ObjectPattern\") return false;\n\n  for (let index = ancestors.length - 2; index >= 0; index--) {\n    const candidate = ancestors[index];\n    if (\n      candidate &&\n      (candidate.type === \"ArrowFunctionExpression\" || candidate.type === \"FunctionExpression\") &&\n      candidate.params[0] === pattern\n    ) {\n      return ancestors\n        .slice(0, index)\n        .some(\n          (ancestor) =>\n            ancestor.type === \"CallExpression\" &&\n            unwrapFunction(ancestor.callee) === candidate &&\n            ancestor.arguments[0]?.type === \"ObjectExpression\" &&\n            ancestor.arguments[0].properties.some(\n              (property) =>\n                property.type === \"Property\" &&\n                staticPropertyName(property.key, property.computed) === propertyName,\n            ),\n        );\n    }\n  }\n  return false;\n}\n\nfunction isIssueMessage(\n  node: Node,\n  ancestors: readonly Node[],\n  issueBindings: ReadonlySet<string>,\n): boolean {\n  const call = ancestors.at(-1);\n  return (\n    call?.type === \"CallExpression\" &&\n    call.callee.type === \"Identifier\" &&\n    issueBindings.has(call.callee.name) &&\n    call.arguments.findIndex((argument) => argument === node) > 0\n  );\n}\n\nfunction scriptReferencesField(script: string, fieldName: string): boolean {\n  try {\n    const { program, errors } = parseSync(\"expand-contract-reference.js\", script, {\n      sourceType: \"module\",\n    });\n    if (errors.length > 0) return true;\n\n    const issueBindings = collectIssueBindings(program);\n\n    let referenced = false;\n    walkScriptAst(program, (node, ancestors) => {\n      if (referenced) return;\n      if (\n        node.type === \"MemberExpression\" &&\n        (staticPropertyName(node.property, node.computed) === fieldName ||\n          (node.computed && staticPropertyName(node.property, true) === undefined))\n      ) {\n        referenced = true;\n      } else if (\n        node.type === \"Property\" &&\n        (staticPropertyName(node.key, node.computed) === fieldName ||\n          (node.computed && staticPropertyName(node.key, true) === undefined)) &&\n        (node.computed ||\n          (!isWrapperArgumentProperty(node, ancestors) &&\n            !isWrapperParameterProperty(node, ancestors)))\n      ) {\n        referenced = true;\n      } else if (\n        node.type === \"CallExpression\" &&\n        node.callee.type === \"Identifier\" &&\n        issueBindings.has(node.callee.name) &&\n        node.arguments[0] !== undefined &&\n        node.arguments[0].type !== \"SpreadElement\" &&\n        staticPropertyName(node.arguments[0], true) === fieldName\n      ) {\n        referenced = true;\n      } else if (\n        (node.type === \"Literal\" || node.type === \"TemplateLiteral\") &&\n        staticPropertyName(node, true) === fieldName &&\n        !isIssueMessage(node, ancestors, issueBindings)\n      ) {\n        referenced = true;\n      }\n    });\n    return referenced;\n  } catch {\n    return true;\n  }\n}\n\nfunction permissionsReferenceField(\n  permissions: TailorDBSnapshotType[\"permissions\"],\n  fieldName: string,\n): boolean {\n  if (!permissions) return false;\n  const recordPolicies = permissions.record\n    ? Object.values(permissions.record).flatMap((policies) => policies)\n    : [];\n  const policies = [...recordPolicies, ...(permissions.gql ?? [])];\n  return policies.some((policy) =>\n    policy.conditions.some((condition: SnapshotPermissionCondition) => {\n      const [left, , right] = condition;\n      return [left, right].some(\n        (operand) =>\n          isSnapshotFieldRefOperand(operand) &&\n          ((\"record\" in operand && operand.record === fieldName) ||\n            (\"newRecord\" in operand && operand.newRecord === fieldName) ||\n            (\"oldRecord\" in operand && operand.oldRecord === fieldName)),\n      );\n    }),\n  );\n}\n\n/**\n * Whether anything other than the field list names this field.\n *\n * The pair moves values through a differently named field, and only the field\n * list is rewritten. An index, relationship, permission, or script naming the\n * field would keep pointing at the name the pair drops.\n * @param type - Table holding the field\n * @param fieldName - Field being converted\n * @returns Whether another part of the table names the field\n */\nfunction isFieldReferenced(type: TailorDBSnapshotType | undefined, fieldName: string): boolean {\n  if (!type) return false;\n  const indexed = Object.values(type.indexes ?? {}).some((index) =>\n    index.fields.includes(fieldName),\n  );\n  if (indexed) return true;\n  const related = [\n    ...Object.values(type.forwardRelationships ?? {}),\n    ...Object.values(type.backwardRelationships ?? {}),\n  ].some(\n    (relationship) =>\n      relationship.sourceField === fieldName || relationship.targetField === fieldName,\n  );\n  if (related) return true;\n  if (permissionsReferenceField(type.permissions, fieldName)) return true;\n  return [type.typeHookExpr?.create, type.typeHookExpr?.update, type.typeValidateExpr]\n    .filter((script): script is string => script !== undefined)\n    .some((script) => scriptReferencesField(script, fieldName));\n}\n\n/**\n * Split unsupported field type changes into the ones a migration pair can carry\n * and the ones that must still fail.\n * @param options - Snapshots, diff, and the changes the user approved\n * @returns Plans to generate and breaking changes to reject\n */\nexport function planExpandContract(options: PlanExpandContractOptions): ExpandContractPlanning {\n  const { previous, current, diff, confirmed } = options;\n  const plans: ExpandContractPlan[] = [];\n  const planned = new Set<string>();\n\n  for (const change of diff.changes) {\n    if (!isExpandContractCandidate(change)) continue;\n    const key = fieldKey(change.tableName, change.fieldName);\n    if (!confirmed.has(key)) continue;\n    if (\n      !canConvertField({\n        previous,\n        current,\n        tableName: change.tableName,\n        fieldName: change.fieldName,\n      })\n    ) {\n      continue;\n    }\n\n    // A temporary field shares the table's GraphQL namespace with its files and\n    // relationships, so a name taken by either is not available.\n    const taken = new Set([\n      ...typeMemberNames(previous.tables[change.tableName]),\n      ...typeMemberNames(current.tables[change.tableName]),\n      ...plans\n        .filter((plan) => plan.tableName === change.tableName)\n        .map((plan) => plan.tempFieldName),\n    ]);\n    plans.push({\n      tableName: change.tableName,\n      fieldName: change.fieldName,\n      tempFieldName: buildTempFieldName(change.fieldName, taken),\n      before: change.before,\n      after: change.after,\n    });\n    planned.add(key);\n  }\n\n  const blocked = diff.breakingChanges.filter(\n    (change) =>\n      change.unsupported &&\n      !(change.fieldName && planned.has(fieldKey(change.tableName, change.fieldName))),\n  );\n\n  return { plans, blocked };\n}\n","/**\n * DB types generator for TailorDB migrations\n *\n * Generates db.ts file containing Kysely Transaction types\n * based on the schema snapshot at a specific migration point.\n */\n\nimport * as fs from \"node:fs/promises\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { COLUMN_TYPE_ALIASES, mapFieldTypeToColumnType } from \"#/utils/field-column-type\";\nimport {\n  getMigrationFilePath,\n  type SchemaSnapshot,\n  type SnapshotFieldConfig,\n  type TailorDBSnapshotType,\n} from \"./snapshot\";\nimport type { MigrationDiff } from \"./diff-calculator\";\nimport type { ExpandContractPlan } from \"./expand-contract\";\n\n/**\n * Information about enum value changes\n */\ninterface EnumValueChange {\n  /** Allowed values before the change */\n  beforeValues: string[];\n  /** Allowed values after the change */\n  afterValues: string[];\n  /** Whether the field is required after the change */\n  afterRequired: boolean;\n}\n\n/**\n * Information about breaking change fields that need special handling\n */\ninterface BreakingChangeFieldInfo {\n  /** Map of tableName -> Set of fieldNames that are changing from optional to required */\n  optionalToRequired: Map<string, Set<string>>;\n  /** Map of tableName -> Map of fieldName -> SnapshotFieldConfig for newly added required fields */\n  addedRequiredFields: Map<string, Map<string, SnapshotFieldConfig>>;\n  /** Map of tableName -> Map of fieldName -> EnumValueChange for enum value changes */\n  enumValueChanges: Map<string, Map<string, EnumValueChange>>;\n  /** Map of tableName -> Map of new fieldName -> SnapshotFieldConfig for renamed fields */\n  renamedFields: Map<string, Map<string, SnapshotFieldConfig>>;\n  /** Map of tableName -> Set of fieldNames a conversion script clears */\n  clearedFields: Map<string, Set<string>>;\n  /** Map of new tableName -> TailorDBSnapshotType for renamed tables */\n  renamedTypes: Map<string, TailorDBSnapshotType>;\n}\n\n/**\n * Extract breaking change field information from diff\n * @param {MigrationDiff} diff - Migration diff\n * @returns {BreakingChangeFieldInfo} Breaking change field information\n */\nfunction extractBreakingChangeFields(diff: MigrationDiff): BreakingChangeFieldInfo {\n  const optionalToRequired = new Map<string, Set<string>>();\n  const addedRequiredFields = new Map<string, Map<string, SnapshotFieldConfig>>();\n  const enumValueChanges = new Map<string, Map<string, EnumValueChange>>();\n  const renamedFields = new Map<string, Map<string, SnapshotFieldConfig>>();\n  const renamedTypes = new Map<string, TailorDBSnapshotType>();\n\n  for (const change of diff.changes) {\n    if (change.kind === \"field_modified\" || change.kind === \"field_type_modified\") {\n      const { before, after } = change;\n\n      // Check if this is an optional -> required change\n      if (!before.required && after.required) {\n        if (!optionalToRequired.has(change.tableName)) {\n          optionalToRequired.set(change.tableName, new Set());\n        }\n        assertDefined(\n          optionalToRequired.get(change.tableName),\n          \"optionalToRequired entry missing\",\n        ).add(change.fieldName);\n      }\n\n      // Check if this is an enum value change. Snapshots omit allowedValues\n      // when an enum has no values left, so a missing list is an empty one.\n      if (before.type === \"enum\" && after.type === \"enum\") {\n        // Check if there are any differences in allowed values\n        const beforeValues = (before.allowedValues ?? []).map((v) => v.value);\n        const afterValues = (after.allowedValues ?? []).map((v) => v.value);\n        const beforeSet = new Set(beforeValues);\n        const afterSet = new Set(afterValues);\n        const hasChanges =\n          beforeValues.some((v) => !afterSet.has(v)) || afterValues.some((v) => !beforeSet.has(v));\n\n        if (hasChanges) {\n          if (!enumValueChanges.has(change.tableName)) {\n            enumValueChanges.set(change.tableName, new Map());\n          }\n          assertDefined(\n            enumValueChanges.get(change.tableName),\n            \"enumValueChanges entry missing\",\n          ).set(change.fieldName, {\n            beforeValues,\n            afterValues,\n            afterRequired: after.required,\n          });\n        }\n      }\n    } else if (change.kind === \"field_added\") {\n      const { after } = change;\n\n      // Required field added is a breaking change - add it as optional in db.ts\n      // so migration script can set values for existing records\n      if (after.required) {\n        if (!addedRequiredFields.has(change.tableName)) {\n          addedRequiredFields.set(change.tableName, new Map());\n        }\n        assertDefined(\n          addedRequiredFields.get(change.tableName),\n          \"addedRequiredFields entry missing\",\n        ).set(change.fieldName, after);\n      }\n    } else if (change.kind === \"field_renamed\") {\n      // The new field is missing from the pre-migration snapshot; inject it so\n      // the copy script can write it (the old field stays readable as-is).\n      if (!renamedFields.has(change.tableName)) {\n        renamedFields.set(change.tableName, new Map());\n      }\n      assertDefined(renamedFields.get(change.tableName), \"renamedFields entry missing\").set(\n        change.fieldName,\n        change.after,\n      );\n    } else if (change.kind === \"table_renamed\") {\n      // The new table is missing from the pre-migration snapshot; inject it so\n      // the copy script can insert into it (the old type stays readable as-is).\n      renamedTypes.set(change.tableName, change.after);\n    }\n  }\n\n  return {\n    optionalToRequired,\n    addedRequiredFields,\n    enumValueChanges,\n    renamedFields,\n    clearedFields: new Map<string, Set<string>>(),\n    renamedTypes,\n  };\n}\n\n/**\n * Generate the complete db.ts file content from a schema snapshot\n * @param {SchemaSnapshot} snapshot - Schema snapshot to generate types from\n * @param {MigrationDiff} [diff] - Optional migration diff for breaking change info\n * @param expandPlans - Field changes carried through temporary fields\n * @returns {string} Generated db.ts file contents\n */\nfunction generateDbTypesFromSnapshot(\n  snapshot: SchemaSnapshot,\n  diff?: MigrationDiff,\n  expandPlans: readonly ExpandContractPlan[] = [],\n): string {\n  // Extract breaking change field information\n  const breakingChangeFields = diff\n    ? extractBreakingChangeFields(diff)\n    : {\n        optionalToRequired: new Map(),\n        addedRequiredFields: new Map(),\n        enumValueChanges: new Map(),\n        renamedFields: new Map<string, Map<string, SnapshotFieldConfig>>(),\n        clearedFields: new Map<string, Set<string>>(),\n        renamedTypes: new Map<string, TailorDBSnapshotType>(),\n      };\n\n  // The temporary field is absent from the pre-migration snapshot; inject it so\n  // the conversion script can write it, as a renamed field's new name is.\n  for (const plan of expandPlans) {\n    const injected =\n      breakingChangeFields.renamedFields.get(plan.tableName) ??\n      new Map<string, SnapshotFieldConfig>();\n    injected.set(plan.tempFieldName, { ...plan.after, required: false, unique: false });\n    breakingChangeFields.renamedFields.set(plan.tableName, injected);\n\n    const cleared = breakingChangeFields.clearedFields.get(plan.tableName) ?? new Set<string>();\n    cleared.add(plan.fieldName);\n    breakingChangeFields.clearedFields.set(plan.tableName, cleared);\n  }\n\n  const tables = [...Object.values(snapshot.tables), ...breakingChangeFields.renamedTypes.values()];\n  if (tables.length === 0) {\n    return generateEmptyDbTypes(snapshot.namespace);\n  }\n\n  // Track which utility types are used\n  const usedUtilityTypes = new Set<\"Timestamp\" | \"Serial\">();\n  let usedArrayColumnType = false;\n\n  // Generate type definitions\n  const typeDefinitions: string[] = [];\n  for (const type of tables) {\n    const result = generateTableType(type, breakingChangeFields);\n    if (result.usedTimestamp) usedUtilityTypes.add(\"Timestamp\");\n    usedArrayColumnType = usedArrayColumnType || result.usedArrayColumnType;\n    typeDefinitions.push(result.typeDef);\n  }\n\n  // Build imports\n  // ColumnType is always needed for Generated and Timestamp utility types\n  const imports: string[] = [\"type ColumnType\", \"type Transaction as KyselyTransaction\"];\n  if (usedArrayColumnType) {\n    imports.push(\"type ArrayColumnType\");\n  }\n\n  // Build utility type declarations\n  const utilityTypeDeclarations: string[] = [];\n  if (usedUtilityTypes.has(\"Timestamp\")) {\n    utilityTypeDeclarations.push(\n      \"type Timestamp = ColumnType<Date, Date | string, Date | string>;\",\n    );\n  }\n  utilityTypeDeclarations.push(\n    \"type Generated<T> = T extends ColumnType<infer S, infer I, infer U>\\n  ? ColumnType<S, I | undefined, U>\\n  : ColumnType<T, T | undefined, T>;\",\n  );\n  if (usedUtilityTypes.has(\"Serial\")) {\n    utilityTypeDeclarations.push(\"type Serial<T = string | number> = ColumnType<T, never, never>;\");\n  }\n\n  // Build output\n  const lines: string[] = [\n    \"/**\",\n    \" * Auto-generated Kysely types for migration script.\",\n    \" * These types reflect the database schema state at this migration point.\",\n    \" *\",\n    \" * DO NOT EDIT - This file is auto-generated by the migration system.\",\n    \" */\",\n    \"\",\n    `import { ${imports.join(\", \")} } from \"@tailor-platform/sdk/kysely\";`,\n    'import type { Env } from \"@tailor-platform/sdk\";',\n    \"\",\n    ...utilityTypeDeclarations,\n    \"\",\n    \"export interface Database {\",\n    ...typeDefinitions,\n    \"}\",\n    \"\",\n    \"export type Transaction = KyselyTransaction<Database>;\",\n    \"\",\n    \"/** Context passed as the second argument to the migration's `main` function. */\",\n    \"export type MigrationContext = {\",\n    \"  env: keyof Env extends never ? Record<string, string | number | boolean> : Env;\",\n    \"};\",\n  ];\n\n  return lines.join(\"\\n\") + \"\\n\";\n}\n\n/**\n * Generate an empty db.ts file for migrations with no tables\n * @param {string} namespace - Namespace name\n * @returns {string} Empty db.ts file contents\n */\nfunction generateEmptyDbTypes(namespace: string): string {\n  return (\n    [\n      \"/**\",\n      \" * Auto-generated Kysely types for migration script.\",\n      ` * Namespace: ${namespace}`,\n      \" *\",\n      \" * DO NOT EDIT - This file is auto-generated by the migration system.\",\n      \" */\",\n      \"\",\n      'import { type Transaction as KyselyTransaction } from \"@tailor-platform/sdk/kysely\";',\n      'import type { Env } from \"@tailor-platform/sdk\";',\n      \"\",\n      \"// eslint-disable-next-line @typescript-eslint/no-empty-object-type\",\n      \"export interface Database {}\",\n      \"\",\n      \"export type Transaction = KyselyTransaction<Database>;\",\n      \"\",\n      \"/** Context passed as the second argument to the migration's `main` function. */\",\n      \"export type MigrationContext = {\",\n      \"  env: keyof Env extends never ? Record<string, string | number | boolean> : Env;\",\n      \"};\",\n    ].join(\"\\n\") + \"\\n\"\n  );\n}\n\n/**\n * Generate table type definition from a snapshot type\n * @param {TailorDBSnapshotType} type - Table snapshot\n * @param {BreakingChangeFieldInfo} breakingChangeFields - Breaking change field info\n * @returns {{ typeDef: string; usedTimestamp: boolean; usedColumnType: boolean; usedArrayColumnType: boolean }} Generated type and utility type usage\n */\nfunction generateTableType(\n  type: TailorDBSnapshotType,\n  breakingChangeFields: BreakingChangeFieldInfo,\n): {\n  typeDef: string;\n  usedTimestamp: boolean;\n  usedColumnType: boolean;\n  usedArrayColumnType: boolean;\n} {\n  const fieldLines: string[] = [];\n  let usedTimestamp = false;\n  let usedColumnType = false;\n  let usedArrayColumnType = false;\n\n  // Add id field first\n  fieldLines.push(\"    id: Generated<string>;\");\n\n  // Get fields that are changing from optional to required for this table\n  const optionalToRequiredFields =\n    breakingChangeFields.optionalToRequired.get(type.name) || new Set();\n\n  // Get newly added required fields for this table\n  const addedRequiredFields = breakingChangeFields.addedRequiredFields.get(type.name) || new Map();\n\n  // Get enum value changes for this type\n  const enumValueChangesForType = breakingChangeFields.enumValueChanges.get(type.name) || new Map();\n\n  // Fields a conversion script clears once it has carried the value across\n  const clearedFieldsForType =\n    breakingChangeFields.clearedFields.get(type.name) ?? new Set<string>();\n\n  for (const [fieldName, fieldConfig] of Object.entries(type.fields)) {\n    if (fieldName === \"id\") continue;\n\n    const isOptionalToRequired = optionalToRequiredFields.has(fieldName);\n    const enumValueChange = enumValueChangesForType.get(fieldName);\n    const result = generateFieldType(fieldConfig, isOptionalToRequired, enumValueChange);\n    // A conversion script clears its source field, and Kysely reads the third\n    // ColumnType slot for updates.\n    const clearable = clearedFieldsForType.has(fieldName);\n    const emitted = clearable ? generateClearableFieldType(fieldConfig) : result;\n    fieldLines.push(`    ${fieldName}: ${emitted.type};`);\n    usedTimestamp = usedTimestamp || emitted.usedTimestamp;\n    usedColumnType = usedColumnType || result.usedColumnType || clearable;\n    usedArrayColumnType = usedArrayColumnType || (!clearable && result.usedArrayColumnType);\n  }\n\n  // Add newly added required fields with ColumnType (same as optional→required)\n  // These fields are added as nullable in pre-migration, then become required in post-migration\n  for (const [fieldName, fieldConfig] of addedRequiredFields) {\n    // Treat as optional→required change (isOptionalToRequired: true)\n    const result = generateFieldType(fieldConfig, true, undefined);\n    fieldLines.push(`    ${fieldName}: ${result.type};`);\n    usedTimestamp = usedTimestamp || result.usedTimestamp;\n    usedColumnType = usedColumnType || result.usedColumnType;\n    usedArrayColumnType = usedArrayColumnType || result.usedArrayColumnType;\n  }\n\n  // Add rename target fields, which do not exist in the pre-migration snapshot.\n  // A required target reads as nullable until the copy script fills it in\n  // (same shape as optional→required); an optional target is plainly nullable.\n  const renamedFieldsForType = breakingChangeFields.renamedFields.get(type.name) || new Map();\n  for (const [fieldName, fieldConfig] of renamedFieldsForType) {\n    const result = generateFieldType(fieldConfig, fieldConfig.required, undefined);\n    fieldLines.push(`    ${fieldName}: ${result.type};`);\n    usedTimestamp = usedTimestamp || result.usedTimestamp;\n    usedColumnType = usedColumnType || result.usedColumnType;\n    usedArrayColumnType = usedArrayColumnType || result.usedArrayColumnType;\n  }\n\n  const typeDef = `  ${type.name}: {\\n${fieldLines.join(\"\\n\")}\\n  }`;\n\n  return { typeDef, usedTimestamp, usedColumnType, usedArrayColumnType };\n}\n\nfunction mapToTsType(\n  fieldType: string,\n  allowedValues?: SnapshotFieldConfig[\"allowedValues\"],\n): {\n  type: string;\n  usedTimestamp: boolean;\n} {\n  if (fieldType === \"nested\") {\n    return { type: \"Record<string, unknown>\", usedTimestamp: false };\n  }\n  if (fieldType === \"enum\" && allowedValues && allowedValues.length > 0) {\n    return {\n      type: `(${formatEnumUnion(allowedValues.map((v) => v.value))})`,\n      usedTimestamp: false,\n    };\n  }\n  if (fieldType === \"enum\") {\n    return { type: \"string\", usedTimestamp: false };\n  }\n  const type = mapFieldTypeToColumnType(fieldType);\n  return { type, usedTimestamp: type === \"Timestamp\" };\n}\n\nfunction formatEnumUnion(values: string[]): string {\n  return values.map((v) => `\"${v}\"`).join(\" | \");\n}\n\nfunction formatEnumSlot(values: string[], array: boolean, nullable: boolean): string {\n  if (values.length === 0) {\n    if (!array) return nullable ? \"null\" : \"never\";\n    return nullable ? \"never[] | null\" : \"never[]\";\n  }\n  const union = formatEnumUnion(values);\n  if (array) return nullable ? `(${union})[] | null` : `(${union})[]`;\n  return nullable ? `(${union}) | null` : union;\n}\n\n/**\n * Column type for an enum field whose allowed values change.\n *\n * Rows still hold the old values (and null, if either side is optional) until\n * the migration script rewrites them, so the select slot is the union of both\n * states; the write slots only accept what the post-migration schema does.\n * @param enumValueChange - Allowed values before and after, and post-migration required-ness\n * @param config - Field configuration in the pre-migration snapshot\n * @returns {string} Generated column type\n */\nfunction generateEnumChangeColumnType(\n  enumValueChange: EnumValueChange,\n  config: SnapshotFieldConfig,\n): string {\n  const array = config.array ?? false;\n  const allValues = [...new Set([...enumValueChange.beforeValues, ...enumValueChange.afterValues])];\n  const writeNullable = !enumValueChange.afterRequired;\n  const selectType = formatEnumSlot(allValues, array, !config.required || writeNullable);\n  const writeType = formatEnumSlot(enumValueChange.afterValues, array, writeNullable);\n  return `ColumnType<${selectType}, ${writeType}, ${writeType}>`;\n}\n\n/**\n * Column type for a field the migration script both reads and clears.\n *\n * Kysely takes the select, insert, and update types from the three slots in\n * turn, so the update slot has to accept the null the script writes.\n * @param config - Field configuration in the pre-migration snapshot\n * @returns {string} Generated column type\n */\nfunction generateClearableFieldType(config: SnapshotFieldConfig): {\n  type: string;\n  usedTimestamp: boolean;\n} {\n  const { type } = mapToTsType(config.type, config.allowedValues);\n  // A ColumnType cannot nest, so an alias contributes its own select and write\n  // types to the slots rather than the alias itself.\n  const alias = COLUMN_TYPE_ALIASES.get(type);\n  if (alias) {\n    const select = config.array ? `${alias.select}[]` : alias.select;\n    const write = config.array ? `(${alias.write})[]` : alias.write;\n    return {\n      type: `ColumnType<${select} | null, ${write} | null, ${write} | null>`,\n      usedTimestamp: false,\n    };\n  }\n  const base = config.array ? `${type}[]` : type;\n  return {\n    type: `ColumnType<${base} | null, ${base} | null, ${base} | null>`,\n    usedTimestamp: false,\n  };\n}\n\nfunction generateOptionalToRequiredDateColumnType(config: SnapshotFieldConfig): string | null {\n  if (config.type !== \"date\" && config.type !== \"datetime\") return null;\n\n  // The select slot has to stay nullable for existing rows, so the alias cannot\n  // fill the property on its own and its expansion spells out the slots instead.\n  const alias = COLUMN_TYPE_ALIASES.get(mapFieldTypeToColumnType(config.type));\n  if (!alias) return null;\n  const select = config.array ? `${alias.select}[]` : alias.select;\n  const write = config.array ? `(${alias.write})[]` : alias.write;\n\n  return `ColumnType<${select} | null, ${write}, ${write}>`;\n}\n\n/**\n * Generate field type from snapshot field config\n * @param {SnapshotFieldConfig} config - Field configuration\n * @param {boolean} isOptionalToRequired - Whether this field is changing from optional to required\n * @param {EnumValueChange} [enumValueChange] - Enum value change info if applicable\n * @returns {{ type: string; usedTimestamp: boolean; usedColumnType: boolean; usedArrayColumnType: boolean }} Generated type string and utility type usage\n */\nfunction generateFieldType(\n  config: SnapshotFieldConfig,\n  isOptionalToRequired: boolean,\n  enumValueChange?: EnumValueChange,\n): {\n  type: string;\n  usedTimestamp: boolean;\n  usedColumnType: boolean;\n  usedArrayColumnType: boolean;\n} {\n  // Handle enum value changes specially\n  if (enumValueChange) {\n    return {\n      type: generateEnumChangeColumnType(enumValueChange, config),\n      usedTimestamp: false,\n      usedColumnType: true,\n      usedArrayColumnType: false,\n    };\n  }\n\n  // Get base type\n  let baseType: string;\n  let usedTimestamp = false;\n\n  if (config.type === \"enum\") {\n    const enumValues = config.allowedValues?.map((v) => v.value) ?? [];\n    baseType = enumValues.length > 0 ? formatEnumUnion(enumValues) : \"string\";\n  } else {\n    const mapped = mapToTsType(config.type);\n    baseType = mapped.type;\n    usedTimestamp = mapped.usedTimestamp;\n  }\n\n  if (isOptionalToRequired) {\n    const dateColumnType = generateOptionalToRequiredDateColumnType(config);\n    if (dateColumnType) {\n      return {\n        type: dateColumnType,\n        usedTimestamp: false,\n        usedColumnType: true,\n        usedArrayColumnType: false,\n      };\n    }\n  }\n\n  // Apply array modifier. Kysely only unwraps a ColumnType at the top level of a\n  // table property, so an array of a ColumnType-shaped alias wraps the alias in\n  // ArrayColumnType instead of nesting it.\n  let type = baseType;\n  if (config.array) {\n    if (COLUMN_TYPE_ALIASES.has(baseType)) {\n      const arrayType = `ArrayColumnType<${baseType}>`;\n      return {\n        type: config.required ? arrayType : `${arrayType} | null`,\n        usedTimestamp,\n        usedColumnType: false,\n        usedArrayColumnType: true,\n      };\n    }\n    const needsParens =\n      config.type === \"enum\" && config.allowedValues && config.allowedValues.length > 0;\n    type = needsParens ? `(${baseType})[]` : `${baseType}[]`;\n  }\n\n  // Handle nullable/required modifiers\n  if (isOptionalToRequired) {\n    // For fields changing from optional to required:\n    // SELECT returns T | null (existing data might be null)\n    // INSERT/UPDATE requires T (must provide a value)\n    return {\n      type: `ColumnType<${type} | null, ${type}, ${type}>`,\n      usedTimestamp,\n      usedColumnType: true,\n      usedArrayColumnType: false,\n    };\n  }\n\n  if (!config.required) {\n    type = `${type} | null`;\n  }\n\n  return { type, usedTimestamp, usedColumnType: false, usedArrayColumnType: false };\n}\n\n/**\n * Write db.ts file for a migration\n * @param {SchemaSnapshot} snapshot - Schema snapshot to generate types from\n * @param {string} migrationsDir - Migrations directory path\n * @param {number} migrationNumber - Migration number\n * @param {MigrationDiff} [diff] - Optional migration diff for breaking change info\n * @param expandPlans - Field changes carried through temporary fields\n * @returns {Promise<string>} Path to the written file\n */\nexport async function writeDbTypesFile(\n  snapshot: SchemaSnapshot,\n  migrationsDir: string,\n  migrationNumber: number,\n  diff?: MigrationDiff,\n  expandPlans: readonly ExpandContractPlan[] = [],\n): Promise<string> {\n  const content = generateDbTypesFromSnapshot(snapshot, diff, expandPlans);\n  const filePath = getMigrationFilePath(migrationsDir, migrationNumber, \"db\");\n  await fs.writeFile(filePath, content);\n  return filePath;\n}\n","/**\n * PGlite schema for migration tests: the tables as the Pre-phase leaves them\n * while `migrate.ts` runs, rendered as a `CREATE TABLE` script module next to\n * `db.ts`.\n */\n\nimport * as fs from \"node:fs/promises\";\nimport { generatePgliteSchemaModule, type DDLTableConfig } from \"#/utils/tailordb-ddl\";\nimport { writeDbTypesFile } from \"./db-types-generator\";\nimport {\n  applyPreMigrationFieldAdjustmentsToSnapshot,\n  applyPreMigrationIndexAdjustmentsToSnapshot,\n  buildPreMigrationChangesMapFromDiffs,\n  buildPreMigrationIndexChangesMapFromDiffs,\n} from \"./pre-migration-schema\";\nimport { applyDiffToSnapshot, getMigrationFilePath } from \"./snapshot\";\nimport { copySnapshotRecord } from \"./snapshot-normalization\";\nimport type { MigrationDiff } from \"./diff-calculator\";\nimport type { ExpandContractPlan } from \"./expand-contract\";\nimport type { SchemaSnapshot, TailorDBSnapshotType } from \"./snapshot-types\";\n\nfunction toDDLTable(table: TailorDBSnapshotType): DDLTableConfig {\n  return { name: table.name, fields: table.fields, indexes: table.indexes };\n}\n\n/**\n * The tables `migrate.ts` sees: the migration's target schema with the\n * Pre-phase relaxations applied, plus the tables the Pre-phase retains for\n * the script to read (removed tables, and renamed tables under their old name).\n * @param previousSnapshot - Schema before the migration\n * @param diff - The migration's diff\n * @returns Tables in creation order\n */\nexport function buildPreMigrationTables(\n  previousSnapshot: SchemaSnapshot,\n  diff: MigrationDiff,\n): DDLTableConfig[] {\n  const target = applyDiffToSnapshot(previousSnapshot, diff);\n  const fieldChanges = buildPreMigrationChangesMapFromDiffs([diff]);\n  const indexChanges = buildPreMigrationIndexChangesMapFromDiffs([diff]);\n\n  const tables: DDLTableConfig[] = Object.values(target.tables).map((table) => {\n    const fields = copySnapshotRecord(table.fields);\n    const typeChanges = fieldChanges.get(table.name);\n    if (typeChanges) applyPreMigrationFieldAdjustmentsToSnapshot(fields, typeChanges);\n    const indexes = copySnapshotRecord(table.indexes);\n    const typeIndexChanges = indexChanges.get(table.name);\n    if (typeIndexChanges) applyPreMigrationIndexAdjustmentsToSnapshot(indexes, typeIndexChanges);\n    return { name: table.name, fields, indexes };\n  });\n\n  for (const change of diff.changes) {\n    if (change.kind === \"table_removed\" || change.kind === \"table_renamed\") {\n      tables.push(toDDLTable(change.before));\n    }\n  }\n  return tables;\n}\n\n/**\n * Render the `db.pglite.ts` module for a migration.\n * @param previousSnapshot - Schema before the migration\n * @param diff - The migration's diff\n * @returns TypeScript source exporting the namespace's `CREATE TABLE` script\n */\nexport function generateMigrationPgliteSchema(\n  previousSnapshot: SchemaSnapshot,\n  diff: MigrationDiff,\n): string {\n  return generatePgliteSchemaModule(\n    [\n      {\n        namespace: previousSnapshot.namespace,\n        tables: buildPreMigrationTables(previousSnapshot, diff),\n      },\n    ],\n    { generatedBy: \"the migration system\" },\n  );\n}\n\n/**\n * Write `db.pglite.ts` for a migration.\n * @param previousSnapshot - Schema before the migration\n * @param diff - The migration's diff\n * @param migrationsDir - Migrations directory path\n * @param migrationNumber - Migration number\n * @returns Path to the written file\n */\nexport async function writePgliteSchemaFile(\n  previousSnapshot: SchemaSnapshot,\n  diff: MigrationDiff,\n  migrationsDir: string,\n  migrationNumber: number,\n): Promise<string> {\n  const filePath = getMigrationFilePath(migrationsDir, migrationNumber, \"pgliteSchema\");\n  await fs.writeFile(filePath, generateMigrationPgliteSchema(previousSnapshot, diff));\n  return filePath;\n}\n\n/** Inputs for {@link writeMigrationTypeFiles}. */\nexport interface WriteMigrationTypeFilesOptions {\n  /** Schema before the migration */\n  previousSnapshot: SchemaSnapshot;\n  /** The migration's diff */\n  diff: MigrationDiff;\n  migrationsDir: string;\n  migrationNumber: number;\n  /** Field changes carried through temporary fields */\n  expandPlans?: readonly ExpandContractPlan[];\n}\n\n/** Outcome of writing `db.pglite.ts`: the path, or why it was skipped. */\nexport interface PgliteSchemaFileResult {\n  /** Undefined when the schema could not be expressed as DDL; see `pgliteSchemaError`. */\n  pgliteSchemaPath?: string;\n  /** Why `db.pglite.ts` was skipped */\n  pgliteSchemaError?: string;\n}\n\n/** Files written by {@link writeMigrationTypeFiles}. */\nexport interface WriteMigrationTypeFilesResult extends PgliteSchemaFileResult {\n  dbTypesPath: string;\n}\n\n/**\n * Write `db.pglite.ts`, reporting a schema the DDL generator cannot express\n * (an unknown field type, a serial format it cannot reproduce) instead of\n * failing the command that needs the other migration files.\n * @param previousSnapshot - Schema before the migration\n * @param diff - The migration's diff\n * @param migrationsDir - Migrations directory path\n * @param migrationNumber - Migration number\n * @returns The written path, or the reason it was skipped\n */\nexport async function tryWritePgliteSchemaFile(\n  previousSnapshot: SchemaSnapshot,\n  diff: MigrationDiff,\n  migrationsDir: string,\n  migrationNumber: number,\n): Promise<PgliteSchemaFileResult> {\n  try {\n    return {\n      pgliteSchemaPath: await writePgliteSchemaFile(\n        previousSnapshot,\n        diff,\n        migrationsDir,\n        migrationNumber,\n      ),\n    };\n  } catch (error) {\n    return { pgliteSchemaError: error instanceof Error ? error.message : String(error) };\n  }\n}\n\n/**\n * Write `db.ts` and `db.pglite.ts` for a migration.\n * @param options - Snapshot, diff, and destination\n * @returns Paths of the written files\n */\nexport async function writeMigrationTypeFiles(\n  options: WriteMigrationTypeFilesOptions,\n): Promise<WriteMigrationTypeFilesResult> {\n  const { previousSnapshot, diff, migrationsDir, migrationNumber, expandPlans = [] } = options;\n  const dbTypesPath = await writeDbTypesFile(\n    previousSnapshot,\n    migrationsDir,\n    migrationNumber,\n    diff,\n    expandPlans,\n  );\n  return {\n    dbTypesPath,\n    ...(await tryWritePgliteSchemaFile(previousSnapshot, diff, migrationsDir, migrationNumber)),\n  };\n}\n","/**\n * Template generator for TailorDB migrations\n *\n * Generates migration files in directory structure:\n * - XXXX/schema.json - Full schema snapshot (initial migration 0000)\n * - XXXX/diff.json - Schema diff (subsequent migrations 0001+)\n * - XXXX/migrate.ts - Data migration script (when breaking changes exist)\n * - XXXX/db.ts - Generated types for migration script\n * - XXXX/db.pglite.ts - PGlite schema script for testing the migration script\n */\n\nimport * as fs from \"node:fs/promises\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { formatFieldShape, isSingleValueToArrayChange } from \"./field-type-change\";\nimport { writeMigrationTypeFiles } from \"./pglite-schema-generator\";\nimport { isBreakingForeignKeyRetarget } from \"./rename-detection\";\nimport {\n  DEFAULT_DECIMAL_SCALE,\n  getMigrationDirPath,\n  getMigrationFilePath,\n  isBreakingIndexChange,\n  type SchemaSnapshot,\n} from \"./snapshot\";\nimport type {\n  MigrationDiff,\n  DiffChange,\n  FieldModifiedChange,\n  FieldRenamedChange,\n  TableRenamedChange,\n} from \"./diff-calculator\";\nimport type { ExpandContractPlan } from \"./expand-contract\";\n\n/** Marker left in generated migration scripts until their normalization logic is reviewed. */\nexport const MIGRATION_REVIEW_REQUIRED_MARKER = \"TODO(tailor-migration-review)\";\n\n/**\n * Check if a file exists\n * @param {string} filePath - Path to check\n * @returns {Promise<boolean>} True if file exists\n */\nasync function fileExists(filePath: string): Promise<boolean> {\n  try {\n    await fs.access(filePath);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Ensure a file does not already exist, throwing an error if it does\n * @param {string} filePath - Path to check\n * @throws {Error} If file already exists\n */\nasync function ensureFileNotExists(filePath: string): Promise<void> {\n  if (await fileExists(filePath)) {\n    throw CLIError({\n      code: \"MIGRATION_FILE_EXISTS\",\n      message: `Migration file already exists: ${filePath}`,\n    });\n  }\n}\n\ninterface GenerateSchemaResult {\n  filePath: string;\n  migrationNumber: number;\n}\n\ninterface GenerateDiffResult {\n  diffFilePath: string;\n  migrateFilePath?: string;\n  dbTypesFilePath?: string;\n  /** Written with db.ts unless the schema cannot be expressed as DDL; see `pgliteSchemaError`. */\n  pgliteSchemaFilePath?: string;\n  /** Why db.pglite.ts was skipped */\n  pgliteSchemaError?: string;\n  migrationNumber: number;\n}\n\n/**\n * Generate the initial schema snapshot file\n * @param {SchemaSnapshot} snapshot - Schema snapshot to save\n * @param {string} migrationsDir - Migrations directory path\n * @param {number} migrationNumber - Migration number\n * @returns {Promise<GenerateSchemaResult>} Generated file info\n */\nexport async function generateSchemaFile(\n  snapshot: SchemaSnapshot,\n  migrationsDir: string,\n  migrationNumber: number,\n): Promise<GenerateSchemaResult> {\n  // Create migration directory\n  const migrationDir = getMigrationDirPath(migrationsDir, migrationNumber);\n  await fs.mkdir(migrationDir, { recursive: true });\n\n  const filePath = getMigrationFilePath(migrationsDir, migrationNumber, \"schema\");\n\n  // Check if file already exists to prevent accidental overwrite\n  await ensureFileNotExists(filePath);\n\n  await fs.writeFile(filePath, JSON.stringify(snapshot, null, 2));\n\n  return {\n    filePath,\n    migrationNumber,\n  };\n}\n\n/**\n * Generate diff and optional migration script files\n * @param {MigrationDiff} diff - Migration diff to save\n * @param {string} migrationsDir - Migrations directory path\n * @param {number} migrationNumber - Migration number\n * @param {SchemaSnapshot} previousSnapshot - Previous schema snapshot (for db.ts generation)\n * @param {string} [description] - Optional description for the migration\n * @param expandPlans - Field changes carried through temporary fields\n * @returns {Promise<GenerateDiffResult>} Generated file info\n */\nexport async function generateDiffFiles(\n  diff: MigrationDiff,\n  migrationsDir: string,\n  migrationNumber: number,\n  previousSnapshot: SchemaSnapshot,\n  description?: string,\n  expandPlans: readonly ExpandContractPlan[] = [],\n): Promise<GenerateDiffResult> {\n  // Create migration directory\n  const migrationDir = getMigrationDirPath(migrationsDir, migrationNumber);\n  await fs.mkdir(migrationDir, { recursive: true });\n\n  // Build file paths\n  const diffFilePath = getMigrationFilePath(migrationsDir, migrationNumber, \"diff\");\n  const migrateFilePath = getMigrationFilePath(migrationsDir, migrationNumber, \"migrate\");\n  const dbTypesFilePath = getMigrationFilePath(migrationsDir, migrationNumber, \"db\");\n  const pgliteSchemaFilePath = getMigrationFilePath(migrationsDir, migrationNumber, \"pgliteSchema\");\n\n  const writeScript = diff.requiresMigrationScript;\n\n  // Check if files already exist to prevent accidental overwrite\n  await ensureFileNotExists(diffFilePath);\n  if (writeScript) {\n    await ensureFileNotExists(migrateFilePath);\n    await ensureFileNotExists(dbTypesFilePath);\n    await ensureFileNotExists(pgliteSchemaFilePath);\n  }\n\n  // Add description if provided\n  const diffWithDescription = description ? { ...diff, description } : diff;\n\n  // Write diff file\n  await fs.writeFile(diffFilePath, JSON.stringify(diffWithDescription, null, 2));\n\n  const result: GenerateDiffResult = {\n    diffFilePath,\n    migrationNumber,\n  };\n\n  if (writeScript) {\n    const scriptContent = generateMigrationScript(diffWithDescription, expandPlans);\n    await fs.writeFile(migrateFilePath, scriptContent);\n    result.migrateFilePath = migrateFilePath;\n\n    // Generate db.ts with types based on the PREVIOUS schema state\n    // (the state before this migration runs)\n    // Pass diff to generate ColumnType for optional->required fields\n    const typeFiles = await writeMigrationTypeFiles({\n      previousSnapshot,\n      diff: diffWithDescription,\n      migrationsDir,\n      migrationNumber,\n      expandPlans,\n    });\n    result.dbTypesFilePath = typeFiles.dbTypesPath;\n    result.pgliteSchemaFilePath = typeFiles.pgliteSchemaPath;\n    result.pgliteSchemaError = typeFiles.pgliteSchemaError;\n  }\n\n  return result;\n}\n\n/** Inputs for {@link generateDataOnlyMigrationFiles}. */\ninterface GenerateDataOnlyFilesOptions {\n  /** Empty diff marked as requiring a migration script. */\n  diff: MigrationDiff;\n  migrationsDir: string;\n  migrationNumber: number;\n  /** Schema the migration runs against, used for db.ts generation. */\n  snapshot: SchemaSnapshot;\n  description?: string;\n}\n\n/** Files written for a data-only migration. */\ninterface GenerateDataOnlyFilesResult {\n  diffFilePath: string;\n  migrateFilePath: string;\n  dbTypesFilePath: string;\n  /** Written with db.ts unless the schema cannot be expressed as DDL; see `pgliteSchemaError`. */\n  pgliteSchemaFilePath?: string;\n  /** Why db.pglite.ts was skipped */\n  pgliteSchemaError?: string;\n  migrationNumber: number;\n}\n\n/**\n * Generate the files for a data-only migration: an empty diff and a migration\n * script skeleton typed against the unchanged schema.\n * @param {GenerateDataOnlyFilesOptions} options - Diff, output location, and schema for db.ts\n * @returns {Promise<GenerateDataOnlyFilesResult>} Generated file info\n */\nexport async function generateDataOnlyMigrationFiles(\n  options: GenerateDataOnlyFilesOptions,\n): Promise<GenerateDataOnlyFilesResult> {\n  const { migrationsDir, migrationNumber, snapshot, description } = options;\n  const migrationDir = getMigrationDirPath(migrationsDir, migrationNumber);\n  await fs.mkdir(migrationDir, { recursive: true });\n\n  const diffFilePath = getMigrationFilePath(migrationsDir, migrationNumber, \"diff\");\n  const migrateFilePath = getMigrationFilePath(migrationsDir, migrationNumber, \"migrate\");\n  const dbTypesFilePath = getMigrationFilePath(migrationsDir, migrationNumber, \"db\");\n\n  await ensureFileNotExists(diffFilePath);\n  await ensureFileNotExists(migrateFilePath);\n  await ensureFileNotExists(dbTypesFilePath);\n  await ensureFileNotExists(getMigrationFilePath(migrationsDir, migrationNumber, \"pgliteSchema\"));\n\n  const diff = description ? { ...options.diff, description } : options.diff;\n  await fs.writeFile(diffFilePath, JSON.stringify(diff, null, 2));\n  await fs.writeFile(migrateFilePath, generateDataOnlyMigrationScript(diff.namespace));\n  const typeFiles = await writeMigrationTypeFiles({\n    previousSnapshot: snapshot,\n    diff,\n    migrationsDir,\n    migrationNumber,\n  });\n\n  return {\n    diffFilePath,\n    migrateFilePath,\n    dbTypesFilePath,\n    pgliteSchemaFilePath: typeFiles.pgliteSchemaPath,\n    pgliteSchemaError: typeFiles.pgliteSchemaError,\n    migrationNumber,\n  };\n}\n\n/**\n * Generate the script skeleton for a data-only migration\n * @param {string} namespace - TailorDB namespace the migration belongs to\n * @returns {string} Migration script content\n */\nfunction generateDataOnlyMigrationScript(namespace: string): string {\n  return `/**\n * Data-only migration script for ${namespace}\n *\n * This migration carries no schema change; it exists to run this script.\n * Edit this file to implement the data transformation.\n *\n * The transaction is managed by the deploy command.\n * If any operation fails, all changes will be rolled back.\n */\n\nimport type { Transaction } from \"./db\";\n\nexport async function main(trx: Transaction): Promise<void> {\n  // TODO: Implement the data transformation for this migration\n}\n`;\n}\n\n/**\n * Generate migration script content based on diff\n * @param {MigrationDiff} diff - Migration diff\n * @param expandPlans - Field changes carried through temporary fields\n * @returns {string} Migration script content\n */\nexport function generateMigrationScript(\n  diff: MigrationDiff,\n  expandPlans: readonly ExpandContractPlan[] = [],\n): string {\n  const updates: string[] = [];\n  const typeRenameTargets = new Map(\n    diff.changes\n      .filter((change): change is TableRenamedChange => change.kind === \"table_renamed\")\n      .map((change) => [change.previousTableName, change.tableName]),\n  );\n\n  for (const plan of expandPlans) {\n    updates.push(generateExpandConversionScript(plan));\n  }\n\n  for (const change of diff.changes) {\n    const decimalScaleScript = generateDecimalScaleChangeScript(change);\n    updates.push(...generateChangeScripts(change, decimalScaleScript !== null, typeRenameTargets));\n    if (decimalScaleScript) {\n      updates.push(decimalScaleScript);\n\n      const uniqueConstraintScript = generateUniqueConstraintScript(change);\n      if (uniqueConstraintScript) {\n        updates.push(uniqueConstraintScript);\n      }\n    }\n  }\n\n  if (updates.length === 0) {\n    updates.push(`  // No data migration needed for this schema change\n  // Add custom data transformations if required`);\n  }\n\n  const helpers = diff.changes.some(\n    (change) => change.kind === \"field_modified\" && change.memberRenames?.length,\n  )\n    ? `\\n${NESTED_MEMBER_RENAME_HELPER}`\n    : \"\";\n\n  return `/**\n * Migration script for ${diff.namespace}\n *\n * This script runs between the Pre-migration and Post-migration phases of\n * 'tailor deploy'. Use it to transform existing data so that the schema\n * change can complete safely (for breaking changes, this is hard-required;\n * for warning-tier changes it is optional). Edit this file to implement\n * your data migration logic.\n *\n * The transaction is managed by the deploy command.\n * If any operation fails, all changes will be rolled back.\n */\n\nimport type { Transaction } from \"./db\";\n${helpers}\nexport async function main(trx: Transaction): Promise<void> {\n${updates.join(\"\\n\\n\")}\n}\n`;\n}\n\n/**\n * Generate migration test file content\n * @param {MigrationDiff} diff - Migration diff\n * @returns {string} Migration test file content\n */\nexport function generateMigrationTestScript(diff: MigrationDiff): string {\n  return `/**\n * Unit test for the ${diff.namespace} migration script.\n *\n * The mock compiles queries to the same SQL as the deployed migration, so the\n * test verifies the exact statements migrate.ts issues. Stage the rows each\n * query returns, run main() inside a transaction, then assert the executed\n * statements.\n */\n\nimport { createKyselyMock } from \"@tailor-platform/sdk/vitest\";\nimport { describe, expect, test } from \"vitest\";\nimport type { Database } from \"./db\";\nimport { main } from \"./migrate\";\n\ndescribe(${JSON.stringify(`${diff.namespace} migration`)}, () => {\n  test(\"issues the intended statements\", async () => {\n    const mock = createKyselyMock<Database>();\n\n    // Stage the rows each query returns, in execution order:\n    // mock.enqueueResult([{ id: \"record-1\" }]);\n\n    // Pass a MigrationContext when your main uses env: main(trx, { env: { ... } })\n    await mock.withTx((trx) => main(trx));\n\n    // Replace with assertions on the statements the script must issue:\n    // expect(mock.updates).toHaveLength(1);\n    // expect(mock.updates[0]?.updateValues()).toEqual({ field: \"value\" });\n    expect(\n      mock.executedQueries.map((query) => ({ sql: query.sql, parameters: query.parameters })),\n    ).toMatchSnapshot();\n  });\n});\n`;\n}\n\n/**\n * Generate the PGlite test file content\n * @param {MigrationDiff} diff - Migration diff\n * @returns {string} PGlite test file content\n */\nexport function generateMigrationPgliteTestScript(diff: MigrationDiff): string {\n  const schema = /^[A-Za-z_$][\\w$]*$/.test(diff.namespace)\n    ? `pgliteSchema.${diff.namespace}`\n    : `pgliteSchema[${JSON.stringify(diff.namespace)}]`;\n  return `/**\n * PGlite test for the ${diff.namespace} migration script.\n *\n * The generated db.pglite.ts creates the tables as they stand while migrate.ts\n * runs, on an in-memory Postgres. Stage the rows the script converts, run\n * main() inside a transaction, then assert the rows it leaves behind.\n */\n\nimport { PGlite } from \"@electric-sql/pglite\";\nimport { createKyselyPGlite, type Unmigrated } from \"@tailor-platform/sdk/vitest\";\nimport { afterAll, beforeAll, describe, expect, test } from \"vitest\";\nimport type { Database } from \"./db\";\nimport { pgliteSchema } from \"./db.pglite\";\nimport { main } from \"./migrate\";\n\nconst pglite = new PGlite();\nconst db = createKyselyPGlite<Unmigrated<Database>>(pglite);\n\n// PGlite loads Postgres on first use, which can take longer than the default hook timeout.\nbeforeAll(async () => {\n  await pglite.exec(${schema});\n}, 60_000);\n\nafterAll(async () => {\n  await db.destroy();\n});\n\ndescribe(${JSON.stringify(`${diff.namespace} migration (PGlite)`)}, () => {\n  test(\"transforms the staged rows\", async () => {\n    // Stage the rows the script converts:\n    // await db.insertInto(\"Table\").values([{ field: \"before\" }]).execute();\n\n    // Pass a MigrationContext when your main uses env: main(trx, { env: { ... } })\n    await expect(db.transaction().execute((trx) => main(trx))).resolves.toBeUndefined();\n\n    // Add assertions on the rows the script leaves behind:\n    // expect(await db.selectFrom(\"Table\").selectAll().execute()).toEqual([{ field: \"after\" }]);\n  });\n});\n`;\n}\n\n/**\n * Generate scripts for a single change\n * @param {DiffChange} change - Diff change to generate script for\n * @param {boolean} deferUniqueConstraint - Generate the unique check after decimal re-serialization\n * @param {ReadonlyMap<string, string>} [typeRenameTargets] - Confirmed type renames (old name → new name)\n * @returns {string[]} Script contents, or an empty array if no script is needed\n */\nfunction generateChangeScripts(\n  change: DiffChange,\n  deferUniqueConstraint = false,\n  typeRenameTargets?: ReadonlyMap<string, string>,\n): string[] {\n  if (change.kind === \"index_added\" || change.kind === \"index_modified\") {\n    const before = change.kind === \"index_modified\" ? change.before : undefined;\n    if (!isBreakingIndexChange(change.tableName, change.indexName, before, change.after)) {\n      return [];\n    }\n    const fields = change.after.fields;\n    const fieldList = fields.map((f) => `\"${f}\"`).join(\", \");\n    const whereClauses = fields.map((f) => `.where(\"${f}\", \"=\", dup.${f})`).join(\"\\n        \");\n    return [\n      `  // Resolve duplicate (${fields.join(\", \")}) combinations before unique index \"${change.indexName}\" is enforced\n  {\n    const duplicates = await trx\n      .selectFrom(\"${change.tableName}\")\n      .select([${fieldList}])\n      .groupBy([${fieldList}])\n      .having((eb) => eb.fn.count(\"id\"), \">\", 1)\n      .execute();\n    for (const dup of duplicates) {\n      const records = await trx\n        .selectFrom(\"${change.tableName}\")\n        .select([\"id\"])\n        ${whereClauses}\n        .execute();\n      // Keep the first record; update or delete the others so the combination becomes unique\n      for (let i = 1; i < records.length; i++) {\n        await trx\n          .updateTable(\"${change.tableName}\")\n          .set({ ${fields[0]}: null }) // TODO: Set appropriate unique value\n          .where(\"id\", \"=\", records[i].id)\n          .execute();\n      }\n    }\n  }`,\n    ];\n  }\n\n  if (change.kind === \"field_added\") {\n    const field = change.after;\n    if (field.required) {\n      return [\n        `  // Populate ${change.fieldName} for existing ${change.tableName} records\n  await trx\n    .updateTable(\"${change.tableName}\")\n    .set({\n      ${change.fieldName}: null, // TODO: Set appropriate default value\n    })\n    .execute();`,\n      ];\n    }\n    return [];\n  }\n\n  if (change.kind === \"field_renamed\") {\n    const scripts = [generateFieldRenameCopyScript(change)];\n    // The unique constraint is deferred to the post-migration phase, so\n    // duplicates in the copied values must be resolved before it is enforced.\n    // A previously unique source still needs the check when the copy itself\n    // can collapse distinct values (e.g. a decreased decimal scale rounds\n    // 1.231 and 1.232 both to 1.23).\n    if (\n      (change.after.unique ?? false) &&\n      (!(change.before.unique ?? false) || renameCopyCanCollapseValues(change))\n    ) {\n      scripts.push(generateUniqueDedupeScript(change.tableName, change.fieldName, \"suffix\"));\n    }\n    return scripts;\n  }\n\n  if (change.kind === \"table_renamed\") {\n    return [generateTypeRenameCopyScript(change)];\n  }\n\n  if (change.kind !== \"field_modified\" && change.kind !== \"field_type_modified\") {\n    // No data migration needed for table_added, table_removed, or field_removed\n    return [];\n  }\n\n  const { before, after } = change;\n  const scripts: string[] = [];\n\n  if (change.kind === \"field_type_modified\") {\n    scripts.push(generateFieldTypeChangeScript(change));\n  }\n\n  if (change.kind === \"field_modified\" && change.memberRenames?.length) {\n    scripts.push(generateNestedMemberRenameCopyScript(change));\n  }\n\n  // Optional to required\n  if (!before.required && after.required) {\n    scripts.push(`  // Set ${change.fieldName} for ${change.tableName} records where it is null\n  await trx\n    .updateTable(\"${change.tableName}\")\n    .set({\n      ${change.fieldName}: null, // TODO: Set appropriate default value\n    })\n    .where(\"${change.fieldName}\", \"is\", null)\n    .execute();`);\n  }\n\n  // Note: Array to single value change is rejected in generate.ts\n  // No script generation needed here\n\n  // Unique constraint added\n  if (!deferUniqueConstraint) {\n    const uniqueConstraintScript = generateUniqueConstraintScript(change);\n    if (uniqueConstraintScript) {\n      scripts.push(uniqueConstraintScript);\n    }\n  }\n\n  // Enum values removed\n  if (before.type === \"enum\" && after.type === \"enum\") {\n    const beforeValues = (before.allowedValues ?? []).map((v) => v.value);\n    const afterValues = (after.allowedValues ?? []).map((v) => v.value);\n    const removedValues = beforeValues.filter((v) => !afterValues.includes(v));\n    if (removedValues.length > 0) {\n      const [firstValue] = afterValues;\n      const replacement =\n        firstValue !== undefined\n          ? JSON.stringify(firstValue)\n          : after.required\n            ? '\"NEW_VALUE\"'\n            : \"null\";\n      scripts.push(`  // Migrate records with removed enum values: ${removedValues.join(\", \")}\n  await trx\n    .updateTable(\"${change.tableName}\")\n    .set({ ${change.fieldName}: ${replacement} }) // TODO: Set appropriate value\n    .where(\"${change.fieldName}\", \"in\", [${removedValues.map((v) => JSON.stringify(v)).join(\", \")}])\n    .execute();`);\n    }\n  }\n\n  // Foreign key relationship changed. A retarget that follows a confirmed\n  // type rename needs no fixup: record ids are preserved by the rename copy.\n  if (isBreakingForeignKeyRetarget(before, after, typeRenameTargets)) {\n    scripts.push(`  // Migrate ${change.fieldName} references from ${before.foreignKeyType} to ${after.foreignKeyType}\n  // Find records that don't have a valid reference in the new target table\n  {\n    const orphanedRecords = await trx\n      .selectFrom(\"${change.tableName}\")\n      .leftJoin(\"${after.foreignKeyType}\", \"${change.tableName}.${change.fieldName}\", \"${after.foreignKeyType}.id\")\n      .select([\"${change.tableName}.id\", \"${change.tableName}.${change.fieldName}\"])\n      .where(\"${after.foreignKeyType}.id\", \"is\", null)\n      .where(\"${change.tableName}.${change.fieldName}\", \"is not\", null)\n      .execute();\n    for (const record of orphanedRecords) {\n      await trx\n        .updateTable(\"${change.tableName}\")\n        .set({ ${change.fieldName}: null }) // TODO: Set appropriate new reference\n        .where(\"id\", \"=\", record.id)\n        .execute();\n    }\n  }`);\n  }\n\n  return scripts;\n}\n\nfunction renameCopyCanCollapseValues(change: FieldRenamedChange): boolean {\n  const { before, after } = change;\n  if (before.type !== \"decimal\" || after.type !== \"decimal\") return false;\n  return (after.scale ?? DEFAULT_DECIMAL_SCALE) < (before.scale ?? DEFAULT_DECIMAL_SCALE);\n}\n\nfunction generateFieldRenameCopyScript(change: FieldRenamedChange): string {\n  const { tableName, fieldName, previousFieldName, before, after } = change;\n  const requiredTodo =\n    !before.required && after.required\n      ? `\n  // TODO: ${previousFieldName} is optional but ${fieldName} is required.\n  // Resolve null values, or the post-migration phase will fail.`\n      : \"\";\n  const roundingWarning = renameCopyCanCollapseValues(change)\n    ? `\n  // WARNING: ${fieldName} has a smaller decimal scale than ${previousFieldName}, so\n  // copied values that exceed it may be rounded half-up. Review the resulting\n  // precision before deploying.`\n    : \"\";\n\n  return `  // Copy ${tableName}.${previousFieldName} into ${fieldName} for every row.\n  // Overwrite unconditionally: stored values of previously removed fields are\n  // not pruned, so a stale value could otherwise resurface under ${fieldName}.${requiredTodo}${roundingWarning}\n  await trx\n    .updateTable(\"${tableName}\")\n    .set((eb) => ({ ${fieldName}: eb.ref(\"${previousFieldName}\") }))\n    .execute();`;\n}\n\nfunction generateNestedMemberRenameCopyScript(change: FieldModifiedChange): string {\n  const { tableName, fieldName } = change;\n  const renames = change.memberRenames ?? [];\n  const summary = renames\n    .map((rename) => `${rename.previousPath.join(\".\")} → ${rename.path.join(\".\")}`)\n    .join(\", \");\n  // A fixed local name keeps the generated code valid for any field name.\n  const steps = renames\n    .map(\n      (rename) =>\n        `        value = renameNestedMember(value, [${rename.previousPath.map((segment) => JSON.stringify(segment)).join(\", \")}], ${JSON.stringify(rename.path[rename.path.length - 1])});`,\n    )\n    .join(\"\\n\");\n  const column = JSON.stringify(fieldName);\n\n  return `  // Copy renamed members inside ${tableName}.${fieldName}: ${summary}.\n  // The old members stay on the schema until the post-migration phase drops\n  // them, so they are kept in the written value.\n  {\n    let lastId: string | undefined;\n    while (true) {\n      let query = trx\n        .selectFrom(\"${tableName}\")\n        .select([\"id\", ${column}])\n        .orderBy(\"id\", \"asc\")\n        .limit(100);\n      if (lastId) {\n        query = query.where(\"id\", \">\", lastId);\n      }\n      const rows = await query.execute();\n      if (rows.length === 0) break;\n\n      for (const row of rows) {\n        let value: unknown = row[${column}];\n${steps}\n        await trx\n          .updateTable(\"${tableName}\")\n          .set({ [${column}]: value as never })\n          .where(\"id\", \"=\", row.id)\n          .execute();\n      }\n      lastId = rows[rows.length - 1]!.id;\n    }\n  }`;\n}\n\n// Emitted once per script that copies renamed nested members. Nested values\n// reach the script as objects (or arrays of objects for array members).\nconst NESTED_MEMBER_RENAME_HELPER = `/**\n * Return a copy of a nested value with the member at \\`path\\` also stored under\n * \\`newName\\`, descending into arrays at every level.\n *\n * When the source member is absent, any value already stored under\n * \\`newName\\` is dropped rather than kept: stored values of previously removed\n * members are not pruned, so a stale value could otherwise resurface under\n * \\`newName\\`. This mirrors the unconditional overwrite of a top-level field\n * rename.\n */\nfunction renameNestedMember(value: unknown, path: readonly string[], newName: string): unknown {\n  if (value === null || value === undefined) return value;\n  if (Array.isArray(value)) return value.map((item) => renameNestedMember(item, path, newName));\n  if (typeof value !== \"object\") {\n    throw new Error(\\`Expected an object while renaming nested member \\${path.join(\".\")}, got \\${typeof value}\\`);\n  }\n  const record = value as Record<string, unknown>;\n  const [head, ...rest] = path;\n  if (head === undefined || !Object.hasOwn(record, head)) {\n    const copy = { ...record };\n    if (rest.length === 0) delete copy[newName];\n    return copy;\n  }\n  if (rest.length > 0) {\n    return { ...record, [head]: renameNestedMember(record[head], rest, newName) };\n  }\n  const copy = { ...record };\n  Object.defineProperty(copy, newName, {\n    value: record[head],\n    enumerable: true,\n    writable: true,\n    configurable: true,\n  });\n  return copy;\n}\n`;\n\nfunction generateTypeRenameCopyScript(change: TableRenamedChange): string {\n  const { tableName, previousTableName } = change;\n  const columns = [\"id\", ...Object.keys(change.before.fields).filter((name) => name !== \"id\")];\n  const columnList = columns.map((name) => JSON.stringify(name)).join(\", \");\n  // Self-referential foreign keys may point at rows in later batches, so they\n  // are inserted as null and backfilled once every row exists.\n  const selfRefColumns = Object.entries(change.after.fields)\n    .filter(([, field]) => field.foreignKeyType === tableName)\n    .map(([name]) => name);\n  const insertValues =\n    selfRefColumns.length > 0\n      ? `rows.map((row) => ({ ...row, ${selfRefColumns.map((name) => `${name}: null`).join(\", \")} }))`\n      : \"rows\";\n  const selfRefBackfill =\n    selfRefColumns.length > 0\n      ? `\n\n  // Backfill the self-referential column(s) now that every row exists.\n  await trx\n    .updateTable(\"${tableName}\")\n    .set((eb) => ({\n${selfRefColumns\n  .map(\n    (name) => `      ${name}: eb\n        .selectFrom(\"${previousTableName}\")\n        .select(\"${previousTableName}.${name}\")\n        .whereRef(\"${previousTableName}.id\", \"=\", \"${tableName}.id\"),`,\n  )\n  .join(\"\\n\")}\n    }))\n    .execute();`\n      : \"\";\n\n  return `  // Copy every ${previousTableName} row into ${tableName}, preserving ids so that\n  // stored foreign key references remain valid. ${previousTableName} stays readable\n  // until the post-migration phase drops it.\n  {\n    let lastId: string | undefined;\n    while (true) {\n      let query = trx\n        .selectFrom(\"${previousTableName}\")\n        .select([${columnList}])\n        .orderBy(\"id\", \"asc\")\n        .limit(100);\n      if (lastId) {\n        query = query.where(\"id\", \">\", lastId);\n      }\n      const rows = await query.execute();\n      if (rows.length === 0) break;\n\n      await trx.insertInto(\"${tableName}\").values(${insertValues}).execute();\n      lastId = rows[rows.length - 1]!.id;\n    }\n  }${selfRefBackfill}`;\n}\n\nfunction generateFieldTypeChangeScript(\n  change: Extract<DiffChange, { kind: \"field_type_modified\" }>,\n): string {\n  return `  // Normalize ${change.tableName}.${change.fieldName} from ${change.before.type} to ${change.after.type} while the previous type is still active\n  {\n    let lastId: string | undefined;\n    while (true) {\n      let query = trx\n        .selectFrom(\"${change.tableName}\")\n        .select([\"id\", \"${change.fieldName}\"])\n        .where(\"${change.fieldName}\", \"is not\", null)\n        .orderBy(\"id\", \"asc\")\n        .limit(100);\n      if (lastId) {\n        query = query.where(\"id\", \">\", lastId);\n      }\n      const rows = await query.execute();\n      if (rows.length === 0) break;\n\n      for (const row of rows) {\n        // ${MIGRATION_REVIEW_REQUIRED_MARKER}: Remove this marker and the \\`never\\` annotation after reviewing the normalization.\n        // Keep the value accepted by the active ${change.before.type} type and castable to ${change.after.type}.\n        const sourceValue = row.${change.fieldName};\n        if (sourceValue === null) continue;\n        const normalizedValue: never = sourceValue;\n        if (Object.is(normalizedValue, sourceValue)) continue;\n        await trx\n          .updateTable(\"${change.tableName}\")\n          .set({ [${JSON.stringify(change.fieldName)}]: normalizedValue })\n          .where(\"id\", \"=\", row.id)\n          .execute();\n      }\n      lastId = rows[rows.length - 1]!.id;\n    }\n  }`;\n}\n\n/**\n * Lines that derive the value the conversion writes into the temporary field.\n *\n * Wrapping needs review when the element type changes or its accepted values narrow.\n * @param plan - Field change carried through a temporary field\n * @returns Script lines binding `convertedValue`\n */\nfunction generateExpandConversionValue(plan: ExpandContractPlan): string {\n  if (isSingleValueToArrayChange(plan.before, plan.after)) {\n    return `        // Store the ${plan.before.type} value as the only element of the ${formatFieldShape(plan.after)} field.\n        const sourceValue = row.${plan.fieldName};\n        if (sourceValue === null) continue;\n        const convertedValue = [sourceValue];`;\n  }\n  const target = plan.after.array\n    ? `an element of the ${formatFieldShape(plan.after)} field`\n    : `the ${plan.after.type} type`;\n  return `        // ${MIGRATION_REVIEW_REQUIRED_MARKER}: Remove this marker and the \\`never\\` annotation after reviewing the conversion.\n        // Produce a value accepted by ${target} from the stored ${plan.before.type} value.\n        const sourceValue = row.${plan.fieldName};\n        const convertedValue: never = sourceValue;`;\n}\n\nfunction generateExpandConversionScript(plan: ExpandContractPlan): string {\n  const wrapsElement =\n    (plan.after.array ?? false) && !isSingleValueToArrayChange(plan.before, plan.after);\n  return `  // Convert ${plan.tableName}.${plan.fieldName} into ${plan.tempFieldName}, which the next migration renames back to ${plan.fieldName}\n  {\n    let lastId: string | undefined;\n    while (true) {\n      let query = trx\n        .selectFrom(\"${plan.tableName}\")\n        .select([\"id\", \"${plan.fieldName}\"])\n        .where(\"${plan.fieldName}\", \"is not\", null)\n        .orderBy(\"id\", \"asc\")\n        .limit(100);\n      if (lastId) {\n        query = query.where(\"id\", \">\", lastId);\n      }\n      const rows = await query.execute();\n      if (rows.length === 0) break;\n\n      for (const row of rows) {\n${generateExpandConversionValue(plan)}\n        // Clearing ${plan.fieldName} keeps a re-run from converting the row twice.\n        await trx\n          .updateTable(\"${plan.tableName}\")\n          .set({\n            [${JSON.stringify(plan.tempFieldName)}]: ${wrapsElement ? \"[convertedValue]\" : \"convertedValue\"},\n            [${JSON.stringify(plan.fieldName)}]: null,\n          })\n          .where(\"id\", \"=\", row.id)\n          .execute();\n      }\n      lastId = rows[rows.length - 1]!.id;\n    }\n  }`;\n}\n\nfunction generateUniqueConstraintScript(change: DiffChange): string | null {\n  if (change.kind !== \"field_modified\" && change.kind !== \"field_type_modified\") return null;\n\n  const { before, after } = change;\n  if ((before.unique ?? false) || !(after.unique ?? false)) return null;\n\n  return generateUniqueDedupeScript(\n    change.tableName,\n    change.fieldName,\n    change.kind === \"field_type_modified\" ? \"throw\" : \"suffix\",\n  );\n}\n\nfunction generateUniqueDedupeScript(\n  tableName: string,\n  fieldName: string,\n  resolution: \"suffix\" | \"throw\",\n): string {\n  const duplicateResolution =\n    resolution === \"throw\"\n      ? `      if (records.length > 1) {\n        throw new Error(\n          \"TODO: Resolve duplicate ${tableName}.${fieldName} values before adding the unique constraint\",\n        );\n      }`\n      : `      // Keep first record, add suffix to others\n      for (let i = 1; i < records.length; i++) {\n        await trx\n          .updateTable(\"${tableName}\")\n          .set({ ${fieldName}: \\`\\${records[i].${fieldName}}_\\${i}\\` }) // TODO: Set appropriate unique value\n          .where(\"id\", \"=\", records[i].id)\n          .execute();\n      }`;\n\n  return `  // Ensure ${fieldName} values are unique before adding constraint\n  {\n    const duplicates = await trx\n      .selectFrom(\"${tableName}\")\n      .select([\"${fieldName}\"])\n      .groupBy(\"${fieldName}\")\n      .having((eb) => eb.fn.count(\"id\"), \">\", 1)\n      .execute();\n    for (const dup of duplicates) {\n      // Load every record in this duplicate group before resolving it\n      const records = await trx\n        .selectFrom(\"${tableName}\")\n        .select([\"id\", \"${fieldName}\"])\n        .where(\"${fieldName}\", \"=\", dup.${fieldName})\n        .execute();\n${duplicateResolution}\n    }\n  }`;\n}\n\nfunction generateDecimalScaleChangeScript(change: DiffChange): string | null {\n  if (change.kind !== \"field_modified\") return null;\n\n  const { before, after } = change;\n  if (before.type !== \"decimal\" || after.type !== \"decimal\" || before.scale === after.scale)\n    return null;\n\n  const valueExpression =\n    !before.required && after.required ? `row.${change.fieldName}!` : `row.${change.fieldName}`;\n  const beforeScale = before.scale ?? DEFAULT_DECIMAL_SCALE;\n  const afterScale = after.scale ?? DEFAULT_DECIMAL_SCALE;\n  const roundingWarning =\n    afterScale < beforeScale\n      ? `\n  // WARNING: Values that exceed the new scale may be rounded half-up, so\n  // review the resulting precision before deploying.`\n      : \"\";\n\n  return `  // Re-save existing ${change.tableName} rows so ${change.fieldName} is stored under the new scale.\n  // This is a workaround for a platform-side gap where rows written under the\n  // previous scale could fail on later updates until re-saved. Keep it unless\n  // your platform is confirmed to handle stored values across scale changes.${roundingWarning}\n  {\n    let lastId: string | undefined;\n    while (true) {\n      let query = trx\n        .selectFrom(\"${change.tableName}\")\n        .select([\"id\", \"${change.fieldName}\"])\n        .where(\"${change.fieldName}\", \"is not\", null)\n        .orderBy(\"id\", \"asc\")\n        .limit(100);\n      if (lastId) {\n        query = query.where(\"id\", \">\", lastId);\n      }\n      const rows = await query.execute();\n      if (rows.length === 0) break;\n\n      for (const row of rows) {\n        await trx\n          .updateTable(\"${change.tableName}\")\n          .set({ ${change.fieldName}: ${valueExpression} })\n          .where(\"id\", \"=\", row.id)\n          .where(\"${change.fieldName}\", \"=\", ${valueExpression})\n          .execute();\n      }\n      lastId = rows[rows.length - 1]!.id;\n    }\n  }`;\n}\n\n/**\n * Check if a migration script exists for a given migration number\n * @param {string} migrationsDir - Migrations directory path\n * @param {number} migrationNumber - Migration number\n * @returns {Promise<boolean>} True if script exists\n */\nexport async function migrationScriptExists(\n  migrationsDir: string,\n  migrationNumber: number,\n): Promise<boolean> {\n  const filePath = getMigrationFilePath(migrationsDir, migrationNumber, \"migrate\");\n  return fileExists(filePath);\n}\n\n/**\n * Get the migration script path for a given migration number\n * @param {string} migrationsDir - Migrations directory path\n * @param {number} migrationNumber - Migration number\n * @returns {string} Full path to migration script\n */\nexport function getMigrationScriptPath(migrationsDir: string, migrationNumber: number): string {\n  return getMigrationFilePath(migrationsDir, migrationNumber, \"migrate\");\n}\n","/**\n * Script command for TailorDB migrations\n *\n * Adds a `migrate.ts` (and supporting `db.ts`) template to an existing\n * migration directory, optionally with a `migrate.test.ts` unit-test\n * scaffold. Useful for warning-tier changes where users may want to\n * write a custom data migration even though the change does not\n * automatically require one.\n */\n\nimport * as fs from \"node:fs\";\nimport * as fsPromises from \"node:fs/promises\";\nimport { arg } from \"@politty/zod\";\nimport * as path from \"pathe\";\nimport { z } from \"zod\";\nimport { configArg } from \"#/cli/shared/args\";\nimport { logBetaWarning } from \"#/cli/shared/beta\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadConfig } from \"#/cli/shared/config-loader\";\nimport { getConfiguredEditorCommand, openInConfiguredEditor } from \"#/cli/shared/editor\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger, styles } from \"#/cli/shared/logger\";\nimport { assertDefined } from \"#/utils/assert\";\nimport {\n  getNamespacesWithMigrations,\n  migrationConfigNotFoundError,\n  type NamespaceWithMigrations,\n} from \"./config\";\nimport { parseMigrationNumberArg } from \"./migration-number\";\nimport { tryWritePgliteSchemaFile, writeMigrationTypeFiles } from \"./pglite-schema-generator\";\nimport {\n  formatMigrationNumber,\n  getMigrationFilePath,\n  loadDiff,\n  reconstructSnapshotFromMigrations,\n  INITIAL_SCHEMA_NUMBER,\n} from \"./snapshot\";\nimport {\n  generateMigrationPgliteTestScript,\n  generateMigrationScript,\n  generateMigrationTestScript,\n} from \"./template-generator\";\nimport type { ScriptSkippedInfo } from \"./diff-calculator\";\n\ninterface ScriptOptions {\n  configPath?: string;\n  number: string;\n  namespace?: string;\n  noScript?: boolean;\n  reason?: string;\n  withTest?: boolean;\n}\n\nexport interface MarkScriptSkippedOptions {\n  migrationsDir: string;\n  migrationNumber: number;\n  reason: string;\n}\n\nexport interface AddMigrationScriptFilesOptions {\n  migrationsDir: string;\n  migrationNumber: number;\n  withTest?: boolean;\n  /** Whether the project has `@electric-sql/pglite` installed; gates the PGlite test scaffold. */\n  pgliteAvailable?: boolean;\n}\n\nexport interface AddMigrationScriptFilesResult {\n  /** Created migrate.ts path; undefined when the script already existed. */\n  migratePath?: string;\n  /** Created db.ts path; undefined when the script already existed. */\n  dbTypesPath?: string;\n  /** Created db.pglite.ts path; undefined when it already existed or could not be generated. */\n  pgliteSchemaPath?: string;\n  /** Why db.pglite.ts could not be generated */\n  pgliteSchemaError?: string;\n  /** Created migrate.test.ts path; undefined unless withTest was set. */\n  testPath?: string;\n  /** Created migrate.pglite.test.ts path; undefined unless withTest was set and PGlite is available. */\n  pgliteTestPath?: string;\n  /** True when this run was asked for a PGlite test that migrate.pglite.test.ts did not already have. */\n  pgliteTestRequested?: boolean;\n  /** True when a stale --no-script acknowledgment was cleared because migrate.ts already exists. */\n  clearedScriptSkip?: boolean;\n}\n\n/**\n * Record in diff.json that a migration requiring a script, or one with\n * data-loss warnings, intentionally has none.\n * @param {MarkScriptSkippedOptions} options - Target migration and skip reason\n * @returns {ScriptSkippedInfo} The recorded acknowledgment\n */\nexport function markMigrationScriptSkipped(options: MarkScriptSkippedOptions): ScriptSkippedInfo {\n  const { migrationsDir, migrationNumber, reason } = options;\n  const label = formatMigrationNumber(migrationNumber);\n  const normalizedReason = reason.trim();\n  if (!normalizedReason) {\n    throw CLIError({\n      code: \"MIGRATION_SCRIPT_REASON_REQUIRED\",\n      message: \"Migration script skip reason must not be empty.\",\n      command: \"tailordb migration script\",\n    });\n  }\n\n  const diffPath = getMigrationFilePath(migrationsDir, migrationNumber, \"diff\");\n  if (!fs.existsSync(diffPath)) {\n    throw CLIError({\n      code: \"MIGRATION_NOT_FOUND\",\n      message: `Migration ${label} not found in ${migrationsDir}. Expected ${diffPath}.`,\n    });\n  }\n\n  const diff = loadDiff(diffPath);\n  if (!diff.requiresMigrationScript && !diff.hasWarnings) {\n    throw CLIError({\n      code: \"MIGRATION_SCRIPT_NOT_REQUIRED\",\n      message: `Migration ${label} does not require a migration script and has no data-loss warnings; nothing to skip.`,\n    });\n  }\n  if (diff.scriptSkipped) {\n    throw CLIError({\n      code: \"MIGRATION_SCRIPT_SKIP_EXISTS\",\n      message:\n        `Migration ${label} already has a script skip recorded ` +\n        `(${diff.scriptSkipped.acknowledgedAt}: ${diff.scriptSkipped.reason}).`,\n    });\n  }\n\n  const migratePath = getMigrationFilePath(migrationsDir, migrationNumber, \"migrate\");\n  if (fs.existsSync(migratePath)) {\n    throw CLIError({\n      code: \"MIGRATION_SCRIPT_EXISTS\",\n      message: `Migration script exists at ${migratePath}.`,\n      suggestion: \"Delete migrate.ts first if this migration should run without a script.\",\n    });\n  }\n\n  const scriptSkipped: ScriptSkippedInfo = {\n    reason: normalizedReason,\n    acknowledgedAt: new Date().toISOString(),\n  };\n\n  // Edit the raw JSON so keys unknown to this SDK version survive the rewrite.\n  const raw = JSON.parse(fs.readFileSync(diffPath, \"utf-8\")) as Record<string, unknown>;\n  raw.scriptSkipped = scriptSkipped;\n  fs.writeFileSync(diffPath, JSON.stringify(raw, null, 2));\n\n  return scriptSkipped;\n}\n\n/**\n * Remove a script skip acknowledgment after a real migration script is created.\n * @param diffPath - Migration diff file to update\n */\nexport function clearMigrationScriptSkipped(diffPath: string): void {\n  const raw = JSON.parse(fs.readFileSync(diffPath, \"utf-8\")) as Record<string, unknown>;\n  if (!Object.hasOwn(raw, \"scriptSkipped\")) return;\n  delete raw.scriptSkipped;\n  fs.writeFileSync(diffPath, JSON.stringify(raw, null, 2));\n}\n\n/**\n * Create migration script files (migrate.ts, db.ts, db.pglite.ts, and optionally\n * migrate.test.ts plus migrate.pglite.test.ts) in an existing migration\n * directory. When migrate.ts already exists and withTest is set, only the test\n * files are added, and a missing db.pglite.ts is written for them. An existing\n * migrate.ts clears a stale --no-script acknowledgment instead of failing.\n * @param {AddMigrationScriptFilesOptions} options - Target migration and file selection\n * @returns {Promise<AddMigrationScriptFilesResult>} Paths of the created files\n */\nexport async function addMigrationScriptFiles(\n  options: AddMigrationScriptFilesOptions,\n): Promise<AddMigrationScriptFilesResult> {\n  const { migrationsDir, migrationNumber, withTest = false, pgliteAvailable = false } = options;\n  const label = formatMigrationNumber(migrationNumber);\n\n  const diffPath = getMigrationFilePath(migrationsDir, migrationNumber, \"diff\");\n  if (!fs.existsSync(diffPath)) {\n    throw CLIError({\n      code: \"MIGRATION_NOT_FOUND\",\n      message: `Migration ${label} not found in ${migrationsDir}. Expected ${diffPath}.`,\n    });\n  }\n\n  const diff = loadDiff(diffPath);\n  const migratePath = getMigrationFilePath(migrationsDir, migrationNumber, \"migrate\");\n  const migrateExists = fs.existsSync(migratePath);\n  const result: AddMigrationScriptFilesResult = {};\n\n  if (migrateExists && diff.scriptSkipped) {\n    // Deploy refuses to run while both a --no-script acknowledgment and\n    // migrate.ts exist; clearing the stale record here is the remediation.\n    clearMigrationScriptSkipped(diffPath);\n    result.clearedScriptSkip = true;\n    if (!withTest) return result;\n  } else if (migrateExists && !withTest) {\n    throw CLIError({\n      code: \"MIGRATION_SCRIPT_EXISTS\",\n      message: `Migration script already exists at ${migratePath}.`,\n    });\n  }\n\n  const testPath = getMigrationFilePath(migrationsDir, migrationNumber, \"test\");\n  const pgliteTestPath = getMigrationFilePath(migrationsDir, migrationNumber, \"pgliteTest\");\n  const pgliteSchemaPath = getMigrationFilePath(migrationsDir, migrationNumber, \"pgliteSchema\");\n  // Existing tests are kept; only the requested ones that are missing are added.\n  const writeUnitTest = withTest && !fs.existsSync(testPath);\n  const pgliteTestRequested = withTest && pgliteAvailable && !fs.existsSync(pgliteTestPath);\n  if (withTest && !writeUnitTest && !pgliteTestRequested) {\n    throw CLIError({\n      code: \"MIGRATION_TEST_EXISTS\",\n      message: pgliteAvailable\n        ? `Migration tests already exist at ${testPath} and ${pgliteTestPath}.`\n        : `Migration test already exists at ${testPath}.`,\n    });\n  }\n\n  if (migrateExists && withTest) {\n    const dbTypesPath = getMigrationFilePath(migrationsDir, migrationNumber, \"db\");\n    if (!fs.existsSync(dbTypesPath)) {\n      throw CLIError({\n        code: \"GENERATED_TYPES_NOT_FOUND\",\n        message: `Generated types not found at ${dbTypesPath}.`,\n        suggestion:\n          \"The test scaffold imports Database from ./db; restore db.ts before adding a test.\",\n      });\n    }\n  }\n\n  // The schema state immediately before this migration types db.ts and shapes\n  // db.pglite.ts. Resolved before anything is written so a broken history\n  // leaves no half-created migration behind.\n  const needsPreviousSnapshot = !migrateExists || (withTest && !fs.existsSync(pgliteSchemaPath));\n  const previousSnapshot = needsPreviousSnapshot\n    ? reconstructSnapshotFromMigrations(migrationsDir, migrationNumber - 1)\n    : null;\n  if (needsPreviousSnapshot && !previousSnapshot) {\n    throw CLIError({\n      code: \"MIGRATION_HISTORY_INVALID\",\n      message: `Could not reconstruct previous schema for migration ${label}.`,\n      suggestion: `Make sure migration ${INITIAL_SCHEMA_NUMBER} exists.`,\n    });\n  }\n\n  if (!migrateExists && previousSnapshot) {\n    await fsPromises.writeFile(migratePath, generateMigrationScript(diff));\n    result.migratePath = migratePath;\n    const typeFiles = await writeMigrationTypeFiles({\n      previousSnapshot,\n      diff,\n      migrationsDir,\n      migrationNumber,\n    });\n    result.dbTypesPath = typeFiles.dbTypesPath;\n    result.pgliteSchemaPath = typeFiles.pgliteSchemaPath;\n    result.pgliteSchemaError = typeFiles.pgliteSchemaError;\n    clearMigrationScriptSkipped(diffPath);\n  } else if (withTest && previousSnapshot) {\n    // A script created before db.pglite.ts existed gets the schema its tests need.\n    Object.assign(\n      result,\n      await tryWritePgliteSchemaFile(previousSnapshot, diff, migrationsDir, migrationNumber),\n    );\n  }\n\n  if (writeUnitTest) {\n    await fsPromises.writeFile(testPath, generateMigrationTestScript(diff));\n    result.testPath = testPath;\n  }\n  result.pgliteTestRequested = pgliteTestRequested;\n  // The PGlite scaffold imports ./db.pglite, so it is only written when that file exists.\n  if (pgliteTestRequested && fs.existsSync(pgliteSchemaPath)) {\n    await fsPromises.writeFile(pgliteTestPath, generateMigrationPgliteTestScript(diff));\n    result.pgliteTestPath = pgliteTestPath;\n  }\n\n  return result;\n}\n\n/**\n * Whether the project has installed `@electric-sql/pglite` for PGlite-backed\n * tests: a `node_modules` on the way up from the migrations directory holds it.\n * @param migrationsDir - Migrations directory of the project\n * @returns True when the package is installed\n */\nexport function isPgliteAvailable(migrationsDir: string): boolean {\n  let dir = path.resolve(migrationsDir);\n  for (;;) {\n    if (fs.existsSync(path.join(dir, \"node_modules\", \"@electric-sql\", \"pglite\", \"package.json\"))) {\n      return true;\n    }\n    const parent = path.dirname(dir);\n    if (parent === dir) return false;\n    dir = parent;\n  }\n}\n\n/**\n * Add a migrate.ts template to an existing migration directory.\n * @param {ScriptOptions} options - Command options\n */\nasync function script(options: ScriptOptions): Promise<void> {\n  logBetaWarning(\"tailordb migration\");\n\n  const migrationNumber = parseMigrationNumberArg(options.number);\n\n  if (migrationNumber === INITIAL_SCHEMA_NUMBER) {\n    throw CLIError({\n      code: \"MIGRATION_SCRIPT_NOT_ALLOWED\",\n      message: `Migration ${options.number} is the initial schema snapshot and cannot have a migration script.`,\n    });\n  }\n\n  const { config } = await loadConfig(options.configPath);\n  const configDir = path.dirname(config.path);\n\n  const namespacesWithMigrations = getNamespacesWithMigrations(config, configDir);\n  if (namespacesWithMigrations.length === 0) {\n    throw migrationConfigNotFoundError();\n  }\n\n  const targetNamespace = resolveTargetNamespace(namespacesWithMigrations, options.namespace);\n  const { migrationsDir } = assertDefined(\n    namespacesWithMigrations.find((ns) => ns.namespace === targetNamespace),\n    \"namespace with migrations not found\",\n  );\n\n  if (options.noScript) {\n    if (options.withTest) {\n      throw CLIError({\n        code: \"MIGRATION_SCRIPT_OPTIONS_CONFLICT\",\n        message: \"--with-test cannot be used together with --no-script.\",\n        command: \"tailordb migration script\",\n      });\n    }\n    const reason = options.reason?.trim();\n    if (!reason) {\n      throw CLIError({\n        code: \"MIGRATION_SCRIPT_REASON_REQUIRED\",\n        message: \"--reason is required with --no-script.\",\n        command: \"tailordb migration script\",\n      });\n    }\n    const scriptSkipped = markMigrationScriptSkipped({\n      migrationsDir,\n      migrationNumber,\n      reason,\n    });\n    logger.success(\n      `Recorded that migration ${styles.bold(options.number)} in namespace ${styles.bold(targetNamespace)} intentionally has no migration script`,\n    );\n    logger.info(`  Reason: ${scriptSkipped.reason}`);\n    logger.info(`  Diff file: ${getMigrationFilePath(migrationsDir, migrationNumber, \"diff\")}`);\n    return;\n  }\n  if (options.reason !== undefined) {\n    throw CLIError({\n      code: \"MIGRATION_SCRIPT_OPTIONS_CONFLICT\",\n      message: \"--reason can only be used together with --no-script.\",\n      command: \"tailordb migration script\",\n    });\n  }\n\n  const pgliteAvailable = isPgliteAvailable(migrationsDir);\n  const result = await addMigrationScriptFiles({\n    migrationsDir,\n    migrationNumber,\n    withTest: options.withTest,\n    pgliteAvailable,\n  });\n\n  if (result.clearedScriptSkip) {\n    logger.success(\n      `Cleared the stale script skip record for migration ${styles.bold(options.number)} in namespace ${styles.bold(targetNamespace)}`,\n    );\n    if (!result.testPath && !result.pgliteTestRequested) {\n      logger.info(\n        `  Migration script: ${getMigrationFilePath(migrationsDir, migrationNumber, \"migrate\")}`,\n      );\n      return;\n    }\n  }\n\n  const testCount = [result.testPath, result.pgliteTestPath].filter(Boolean).length;\n  const added = [\n    result.migratePath && \"migration script\",\n    testCount > 0 && (testCount > 1 ? \"migration tests\" : \"migration test\"),\n  ]\n    .filter(Boolean)\n    .join(\" and \");\n  const target = `for migration ${styles.bold(options.number)} in namespace ${styles.bold(targetNamespace)}`;\n  if (added) {\n    logger.success(`Added ${added} ${target}`);\n  } else {\n    logger.warn(`Added no files ${target}`);\n  }\n  if (result.migratePath) {\n    logger.info(`  Migration script: ${result.migratePath}`);\n    logger.info(`  DB types: ${result.dbTypesPath}`);\n  }\n  if (result.pgliteSchemaPath) {\n    logger.info(`  PGlite schema: ${result.pgliteSchemaPath}`);\n  }\n  if (result.pgliteSchemaError) {\n    logger.warn(`  PGlite schema skipped: ${result.pgliteSchemaError}`);\n  }\n  if (result.testPath) {\n    logger.info(`  Migration test: ${result.testPath}`);\n  }\n  if (result.pgliteTestPath) {\n    logger.info(`  PGlite test: ${result.pgliteTestPath}`);\n  } else if (result.testPath && !pgliteAvailable) {\n    logger.info(\n      \"  Install @electric-sql/pglite as a devDependency to also scaffold a PGlite test (migrate.pglite.test.ts).\",\n    );\n  } else if (result.pgliteTestRequested && result.pgliteSchemaError) {\n    logger.info(\"  PGlite test skipped: it needs the db.pglite.ts that could not be generated.\");\n  }\n\n  logger.newline();\n  if (result.migratePath) {\n    logger.log(\"Edit the script to implement your data migration logic.\");\n    logger.log(\"It will be executed by 'tailor deploy' between Pre and Post phases.\");\n  }\n  if (result.testPath) {\n    logger.log(\"Fill in the test with the rows to stage and the statements to assert.\");\n  }\n\n  const fileToOpen = result.migratePath ?? result.testPath;\n  if (!fileToOpen) return;\n\n  const editor = getConfiguredEditorCommand();\n  if (!editor) return;\n\n  logger.newline();\n  logger.info(`Opening ${path.basename(fileToOpen)} in ${editor}...`);\n  try {\n    await openInConfiguredEditor(fileToOpen);\n  } catch {\n    return;\n  }\n}\n\n/**\n * Resolve the namespace a single-namespace operation targets: the requested\n * one when given, the only configured one otherwise.\n * @param {NamespaceWithMigrations[]} namespacesWithMigrations - Namespaces with migrations config\n * @param {string} [requested] - Namespace requested via --namespace\n * @returns {string} Target namespace\n */\nexport function resolveTargetNamespace(\n  namespacesWithMigrations: NamespaceWithMigrations[],\n  requested?: string,\n): string {\n  if (requested) {\n    if (!namespacesWithMigrations.some((ns) => ns.namespace === requested)) {\n      throw CLIError({\n        code: \"TAILORDB_NAMESPACE_NOT_FOUND\",\n        message: `Namespace \"${requested}\" not found or does not have migrations configured`,\n      });\n    }\n    return requested;\n  }\n  if (namespacesWithMigrations.length === 1) {\n    const [ns] = namespacesWithMigrations;\n    return assertDefined(ns, \"namespace with migrations missing\").namespace;\n  }\n  throw CLIError({\n    code: \"MIGRATION_NAMESPACE_REQUIRED\",\n    message: `Multiple TailorDB services found. Please specify namespace with --namespace flag: ${namespacesWithMigrations.map((ns) => ns.namespace).join(\", \")}`,\n    command: \"tailordb migration script\",\n  });\n}\n\nexport const scriptCommand = defineAppCommand({\n  name: \"script\",\n  description:\n    \"Add a migration script (migrate.ts) template to an existing migration directory, or record with --no-script that a migration intentionally has none.\",\n  notes: `When \\`migrate.ts\\` already exists, running the command clears a previously recorded \\`--no-script\\` acknowledgment, and \\`--with-test\\` adds only the tests that do not exist yet (writing \\`db.pglite.ts\\` if it is missing). \\`migrate.pglite.test.ts\\` is scaffolded only when \\`@electric-sql/pglite\\` is installed in the project.`,\n  args: z.strictObject({\n    ...configArg,\n    number: arg(z.string(), {\n      positional: true,\n      description: \"Migration number to add a script to (e.g., 0001 or 1)\",\n    }),\n    namespace: arg(z.string().optional(), {\n      alias: \"n\",\n      description: \"Target TailorDB namespace (required if multiple namespaces exist)\",\n    }),\n    \"no-script\": arg(z.boolean().optional(), {\n      description:\n        \"Record that this migration intentionally runs without a migration script (requires --reason)\",\n    }),\n    reason: arg(z.string().optional(), {\n      description: \"Reason why no migration script is needed (used with --no-script)\",\n    }),\n    \"with-test\": arg(z.boolean().optional(), {\n      description: \"Also add the migrate.test.ts and migrate.pglite.test.ts scaffolds\",\n    }),\n  }),\n  run: async (args) => {\n    await script({\n      configPath: args.config,\n      number: args.number,\n      namespace: args.namespace,\n      noScript: args[\"no-script\"],\n      reason: args.reason,\n      withTest: args[\"with-test\"],\n    });\n  },\n});\n","/**\n * Generate command for TailorDB migrations\n *\n * Generates migration files based on local schema snapshots:\n * - First run: Creates initial schema snapshot (0000/schema.json)\n * - Subsequent runs: Creates diff from previous snapshot (0001/diff.json, etc.)\n */\n\nimport * as fs from \"node:fs\";\nimport * as fsPromises from \"node:fs/promises\";\nimport { arg } from \"@politty/zod\";\nimport * as path from \"pathe\";\nimport { z } from \"zod\";\nimport { configArg, confirmationArgs } from \"#/cli/shared/args\";\nimport { logBetaWarning } from \"#/cli/shared/beta\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadConfig } from \"#/cli/shared/config-loader\";\nimport { getConfiguredEditorCommand, openInConfiguredEditor } from \"#/cli/shared/editor\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger, styles } from \"#/cli/shared/logger\";\nimport { canPrompt, prompt } from \"#/cli/shared/prompt\";\nimport { PluginManager } from \"#/plugin/manager\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { getNamespacesWithMigrations, type NamespaceWithMigrations } from \"./config\";\nimport {\n  formatMigrationDiff,\n  formatBreakingChanges,\n  formatDiffSummary,\n  formatWarnings,\n  hasChanges,\n  type MigrationDiff,\n} from \"./diff-calculator\";\nimport {\n  canConvertField,\n  fieldKey,\n  getExpandContractEligibility,\n  isExpandContractCandidate,\n  planExpandContract,\n  type ExpandContractPlan,\n} from \"./expand-contract\";\nimport { formatFieldShape, hasFieldShapeChange } from \"./field-type-change\";\nimport { formatMigrationScriptCommand } from \"./hints\";\nimport {\n  dropSpecApplies,\n  findNestedMemberRenameCandidates,\n  findRenameCandidates,\n  findTypeRenameCandidates,\n  nestedMemberDropSpecApplies,\n  nestedMemberRenameSpecApplies,\n  parseDropOption,\n  parseExpandContractOption,\n  parseNestedMemberDropOption,\n  parseNestedMemberRenameOption,\n  parseRenameOption,\n  parseTypeDropOption,\n  parseTypeRenameOption,\n  renameSpecApplies,\n  typeDropSpecApplies,\n  typeRenameSpecApplies,\n  type FieldDropSpec,\n  type FieldExpandContractSpec,\n  type FieldRenameCandidate,\n  type FieldRenameSpec,\n  type NestedMemberDropSpec,\n  type NestedMemberRenameCandidate,\n  type NestedMemberRenameSpec,\n  type TypeDropSpec,\n  type TypeRenameCandidate,\n  type TypeRenameSpec,\n} from \"./rename-detection\";\nimport { markMigrationScriptSkipped, resolveTargetNamespace } from \"./script\";\nimport {\n  buildExpandDiff,\n  buildIntermediateSnapshot,\n  createSnapshotFromLocalTypes,\n  reconstructSnapshotFromMigrations,\n  compareSnapshots,\n  getNextMigrationNumber,\n  assertValidMigrationFiles,\n  formatMigrationNumber,\n  INITIAL_SCHEMA_NUMBER,\n  MAX_MIGRATION_NUMBER,\n  type NormalizedSchemaSnapshot,\n  type SchemaSnapshot,\n} from \"./snapshot\";\nimport {\n  generateSchemaFile,\n  generateDiffFiles,\n  generateDataOnlyMigrationFiles,\n} from \"./template-generator\";\n\nexport interface GenerateOptions {\n  configPath?: string;\n  name?: string;\n  yes?: boolean;\n  init?: boolean;\n  /** Create a migration with no schema changes that exists to run a migration script. */\n  dataOnly?: boolean;\n  /** Namespace the `--data-only` migration targets. */\n  namespace?: string;\n  /**\n   * `--rename Table.oldField:newField` / `--rename OldTable:NewTable` /\n   * `--rename Table.field.oldMember:newMember` values confirming renames non-interactively.\n   */\n  renames?: string[];\n  /** `--drop Table.field` / `--drop Table` / `--drop Table.field.member` values confirming removals non-interactively. */\n  drops?: string[];\n  /** `--expand-contract Table.field` values approving a field type conversion. */\n  expandContracts?: string[];\n}\n\n/**\n * Build the safety-critical manual migration guidance for unsupported changes.\n * @returns Lines to write through the CLI logger\n */\nexport function getUnsupportedMigrationHintLines(): string[] {\n  return [\n    \"These changes require a manual 3-step migration process:\",\n    \"  Migration 1: Add an optional temporary field with the desired structure\",\n    \"               If the old field is required, make the old field optional\",\n    \"               For each non-null old value, copy and convert it to the temporary field\",\n    \"               and set the old field to null in the same update\",\n    \"               Verify every old value is null before continuing\",\n    \"  Migration 2: Remove the old field\",\n    \"  Migration 3: Add the field with the original name and new structure,\",\n    \"               migrate data from the temporary field, then remove it\",\n    \"  Important: Reusing the name while stored old values remain can make subsequent reads fail\",\n  ];\n}\n\n/**\n * Handle --init option: delete existing migrations directories\n * @param {NamespaceWithMigrations[]} namespaces - Namespaces with migrations\n * @param {boolean} skipConfirmation - Whether to skip confirmation prompt\n * @returns {Promise<void>}\n */\nasync function handleInitOption(\n  namespaces: NamespaceWithMigrations[],\n  skipConfirmation?: boolean,\n): Promise<void> {\n  // Find directories that exist\n  const existingDirs = namespaces.filter(({ migrationsDir }) => fs.existsSync(migrationsDir));\n\n  if (existingDirs.length === 0) {\n    logger.info(\"No existing migration directories found.\");\n    return;\n  }\n\n  // Show warning\n  logger.newline();\n  logger.warn(\"This will DELETE all existing migration files:\");\n  for (const { namespace, migrationsDir } of existingDirs) {\n    logger.log(`  - ${namespace}: ${migrationsDir}`);\n  }\n  logger.newline();\n\n  // Confirmation prompt\n  if (!skipConfirmation) {\n    const confirmation = await prompt.confirm({\n      message: \"Are you sure you want to delete these directories and start fresh?\",\n      default: false,\n    });\n\n    if (!confirmation) {\n      logger.info(\"Operation cancelled.\");\n      process.exit(0);\n    }\n    logger.newline();\n  }\n\n  // Delete directories\n  for (const { namespace, migrationsDir } of existingDirs) {\n    try {\n      await fsPromises.rm(migrationsDir, { recursive: true, force: true });\n      logger.success(`Deleted migration directory for ${styles.bold(namespace)}`);\n    } catch (error) {\n      logger.error(`Failed to delete ${migrationsDir}: ${error}`);\n      throw error;\n    }\n  }\n\n  logger.newline();\n  logger.info(\"Migration directories cleared. Generating initial snapshot...\");\n  logger.newline();\n}\n\n/**\n * Generate migration files for TailorDB schema changes\n * @param {GenerateOptions} options - Generation options\n * @returns {Promise<void>} Promise that resolves when generation is complete\n */\nexport async function generate(options: GenerateOptions): Promise<void> {\n  logBetaWarning(\"tailordb migration\");\n\n  // Load configuration\n  const { config, plugins } = await loadConfig(options.configPath);\n  const configDir = path.dirname(config.path);\n\n  // Get namespaces with migrations config\n  const namespacesWithMigrations: NamespaceWithMigrations[] = getNamespacesWithMigrations(\n    config,\n    configDir,\n  );\n\n  if (namespacesWithMigrations.length === 0) {\n    logger.warn(\"No TailorDB namespaces with migrations config found.\");\n    logger.info(\n      'Add \"migration: { directory: \\\\\"./migrations\\\\\" }\" to your db config to enable migrations.',\n    );\n    return;\n  }\n\n  // Parse --rename/--drop flags before any destructive step so a malformed\n  // value fails the command while the migrations directories are still intact.\n  // The dots before any \":\" pick the target: none for a table, one for a\n  // field, two or more for a member inside a nested field.\n  const renameFlags: RenameFlag[] = [];\n  const typeRenameFlags: TypeRenameFlag[] = [];\n  const nestedRenameFlags: NestedMemberRenameFlag[] = [];\n  for (const raw of options.renames ?? []) {\n    const depth = targetDepth(raw);\n    if (depth >= 2) {\n      nestedRenameFlags.push({ raw, spec: parseNestedMemberRenameOption(raw) });\n    } else if (depth === 1) {\n      renameFlags.push({ raw, spec: parseRenameOption(raw) });\n    } else {\n      typeRenameFlags.push({ raw, spec: parseTypeRenameOption(raw) });\n    }\n  }\n  const dropFlags: DropFlag[] = [];\n  const typeDropFlags: TypeDropFlag[] = [];\n  const nestedDropFlags: NestedMemberDropFlag[] = [];\n  for (const raw of options.drops ?? []) {\n    const depth = targetDepth(raw);\n    if (depth >= 2) {\n      nestedDropFlags.push({ raw, spec: parseNestedMemberDropOption(raw) });\n    } else if (depth === 1) {\n      dropFlags.push({ raw, spec: parseDropOption(raw) });\n    } else {\n      typeDropFlags.push({ raw, spec: parseTypeDropOption(raw) });\n    }\n  }\n  const expandContractFlags: ExpandContractFlag[] = (options.expandContracts ?? []).map((raw) => ({\n    raw,\n    spec: parseExpandContractOption(raw),\n  }));\n  // --init regenerates the baseline from scratch, so there is no previous\n  // schema a rename, drop, or field conversion could apply to\n  const hasRenameOrDropFlags =\n    renameFlags.length > 0 ||\n    typeRenameFlags.length > 0 ||\n    nestedRenameFlags.length > 0 ||\n    dropFlags.length > 0 ||\n    typeDropFlags.length > 0 ||\n    nestedDropFlags.length > 0;\n  if (options.init && (hasRenameOrDropFlags || expandContractFlags.length > 0)) {\n    throw CLIError({\n      code: \"MIGRATION_GENERATE_OPTIONS_CONFLICT\",\n      message: \"--rename, --drop, and --expand-contract cannot be used together with --init.\",\n      command: \"tailordb migration generate\",\n    });\n  }\n  const droppedFieldKeys = new Set(\n    dropFlags.map(({ spec }) => `${spec.tableName}.${spec.fieldName}`),\n  );\n  const conflictingFlags = renameFlags.filter(({ spec }) =>\n    droppedFieldKeys.has(`${spec.tableName}.${spec.previousFieldName}`),\n  );\n  if (conflictingFlags.length > 0) {\n    throw CLIError({\n      code: \"MIGRATION_RENAME_DROP_CONFLICT\",\n      message: `--rename and --drop conflict for: ${conflictingFlags\n        .map(({ spec }) => `${spec.tableName}.${spec.previousFieldName}`)\n        .join(\", \")}`,\n      command: \"tailordb migration generate\",\n    });\n  }\n  const droppedMemberKeys = new Set(nestedDropFlags.map(({ spec }) => nestedMemberKey(spec)));\n  const conflictingNestedFlags = nestedRenameFlags.filter(({ spec }) =>\n    droppedMemberKeys.has(nestedMemberKey({ ...spec, path: spec.previousPath })),\n  );\n  if (conflictingNestedFlags.length > 0) {\n    throw CLIError({\n      code: \"MIGRATION_RENAME_DROP_CONFLICT\",\n      message: `--rename and --drop conflict for: ${conflictingNestedFlags\n        .map(({ spec }) => nestedMemberKey({ ...spec, path: spec.previousPath }))\n        .join(\", \")}`,\n      command: \"tailordb migration generate\",\n    });\n  }\n  const droppedTypeNames = new Set(typeDropFlags.map(({ spec }) => spec.tableName));\n  const conflictingTypeFlags = typeRenameFlags.filter(({ spec }) =>\n    droppedTypeNames.has(spec.previousTableName),\n  );\n  if (conflictingTypeFlags.length > 0) {\n    throw CLIError({\n      code: \"MIGRATION_RENAME_DROP_CONFLICT\",\n      message: `--rename and --drop conflict for: ${conflictingTypeFlags\n        .map(({ spec }) => spec.previousTableName)\n        .join(\", \")}`,\n      command: \"tailordb migration generate\",\n    });\n  }\n  if (options.namespace !== undefined && !options.dataOnly) {\n    throw CLIError({\n      code: \"MIGRATION_GENERATE_OPTIONS_CONFLICT\",\n      message: \"--namespace can only be used together with --data-only.\",\n      command: \"tailordb migration generate\",\n    });\n  }\n  // A data-only migration must not carry schema changes, so every flag that\n  // shapes a schema diff is meaningless with it\n  if (\n    options.dataOnly &&\n    (options.init || hasRenameOrDropFlags || expandContractFlags.length > 0)\n  ) {\n    throw CLIError({\n      code: \"MIGRATION_GENERATE_OPTIONS_CONFLICT\",\n      message:\n        \"--init, --rename, --drop, and --expand-contract cannot be used together with --data-only.\",\n      command: \"tailordb migration generate\",\n    });\n  }\n\n  const dataOnlyTargetNamespace = options.dataOnly\n    ? resolveTargetNamespace(namespacesWithMigrations, options.namespace)\n    : undefined;\n  const namespacesToLoad =\n    dataOnlyTargetNamespace === undefined\n      ? namespacesWithMigrations\n      : namespacesWithMigrations.filter(({ namespace }) => namespace === dataOnlyTargetNamespace);\n\n  // Handle --init option: delete existing migrations directory\n  if (options.init) {\n    await handleInitOption(namespacesWithMigrations, options.yes);\n  }\n\n  // Initialize plugin manager if plugins are provided\n  let pluginManager: PluginManager | undefined;\n  if (plugins.length > 0) {\n    pluginManager = new PluginManager(plugins);\n  }\n\n  // Load application and all tables\n  const { defineApplication } = await import(\"#/cli/services/application\");\n  const application = defineApplication({ config, pluginManager });\n\n  // Schema generation loads every namespace before writing so --rename flags\n  // can be validated globally; data-only generation loads only its target.\n  const generations: NamespaceGeneration[] = [];\n  for (const { namespace, migrationsDir } of namespacesToLoad) {\n    logger.info(`Processing namespace: ${styles.bold(namespace)}`);\n\n    // Validate existing migration files before generating new ones\n    assertValidMigrationFiles(migrationsDir, namespace);\n\n    // Find the TailorDB service for this namespace\n    const tailordbService = application.tailorDBServices.find((s) => s.namespace === namespace);\n    if (!tailordbService) {\n      logger.warn(`No TailorDB service found for namespace \"${namespace}\"`);\n      continue;\n    }\n\n    // Load tables for this service\n    await tailordbService.loadTypes();\n    await tailordbService.processNamespacePlugins();\n\n    const localTypesObj = tailordbService.types;\n\n    generations.push({\n      namespace,\n      migrationsDir,\n      // Create snapshot from current local tables\n      currentSnapshot: createSnapshotFromLocalTypes(localTypesObj, namespace),\n      // Returns null when the migrations directory is missing or empty;\n      // throws when existing migration files are invalid.\n      previousSnapshot: reconstructSnapshotFromMigrations(migrationsDir),\n    });\n  }\n\n  if (dataOnlyTargetNamespace !== undefined) {\n    await generateDataOnlyMigration(generations, dataOnlyTargetNamespace, options);\n    return;\n  }\n\n  // A flag applies to a namespace only when that namespace actually removed\n  // the old field or table (and, for renames, added the new one); another\n  // namespace may define a table with the same name\n  const renameSpecsByNamespace = matchFlagsToNamespaces(\n    renameFlags,\n    generations,\n    renameSpecApplies,\n    \"--rename does not match a removed + added field pair\",\n  );\n  const typeRenameSpecsByNamespace = matchFlagsToNamespaces(\n    typeRenameFlags,\n    generations,\n    typeRenameSpecApplies,\n    \"--rename does not match a removed + added table pair\",\n  );\n  const dropSpecsByNamespace = matchFlagsToNamespaces(\n    dropFlags,\n    generations,\n    dropSpecApplies,\n    \"--drop does not match a removed field\",\n  );\n  const typeDropSpecsByNamespace = matchFlagsToNamespaces(\n    typeDropFlags,\n    generations,\n    typeDropSpecApplies,\n    \"--drop does not match a removed table\",\n  );\n  const nestedRenameSpecsByNamespace = matchFlagsToNamespaces(\n    nestedRenameFlags,\n    generations,\n    nestedMemberRenameSpecApplies,\n    \"--rename does not match a removed + added nested member pair\",\n  );\n  const nestedDropSpecsByNamespace = matchFlagsToNamespaces(\n    nestedDropFlags,\n    generations,\n    nestedMemberDropSpecApplies,\n    \"--drop does not match a removed nested member\",\n  );\n\n  const expandContractKeysByNamespace = new Map<string, Set<string>>();\n  const matchedExpandContractFlags = new Set<ExpandContractFlag>();\n  const ineligibleExpandContracts: string[] = [];\n  for (const { namespace, previousSnapshot, currentSnapshot } of generations) {\n    if (!previousSnapshot) continue;\n    const applicable: ExpandContractFlag[] = [];\n    for (const flag of expandContractFlags) {\n      const { spec } = flag;\n      const before = previousSnapshot.tables[spec.tableName]?.fields[spec.fieldName];\n      const after = currentSnapshot.tables[spec.tableName]?.fields[spec.fieldName];\n      if (!before || !after || !hasFieldShapeChange(before, after)) continue;\n      matchedExpandContractFlags.add(flag);\n      const eligibility = getExpandContractEligibility({\n        previous: previousSnapshot,\n        current: currentSnapshot,\n        tableName: spec.tableName,\n        fieldName: spec.fieldName,\n      });\n      if (!eligibility.eligible) {\n        ineligibleExpandContracts.push(\n          `--expand-contract cannot convert ${flag.raw} (namespace: ${namespace}): ${eligibility.reason}`,\n        );\n        continue;\n      }\n      applicable.push(flag);\n    }\n    expandContractKeysByNamespace.set(\n      namespace,\n      new Set(applicable.map(({ spec }) => fieldKey(spec.tableName, spec.fieldName))),\n    );\n  }\n  const unusedExpandContracts = expandContractFlags.filter(\n    (flag) => !matchedExpandContractFlags.has(flag),\n  );\n  if (unusedExpandContracts.length > 0) {\n    throw CLIError({\n      code: \"MIGRATION_EXPAND_CONTRACT_UNMATCHED\",\n      message: `--expand-contract does not match a field whose type or array-ness changed: ${unusedExpandContracts\n        .map((flag) => flag.raw)\n        .join(\", \")}`,\n      command: \"tailordb migration generate\",\n    });\n  }\n  if (ineligibleExpandContracts.length > 0) {\n    throw CLIError({\n      code: \"MIGRATION_EXPAND_CONTRACT_INELIGIBLE\",\n      message: ineligibleExpandContracts.join(\"\\n\"),\n    });\n  }\n\n  // Resolve renames for every namespace before any migration file is written,\n  // so all candidates are reported in one run and an abort (a decline, an\n  // unresolved candidate, or an invalid spec in a later namespace) leaves no\n  // namespace partially generated. compareSnapshots validates the specs.\n  const unresolvedCandidates: UnresolvedRenameCandidate[] = [];\n  for (const generation of generations) {\n    const { namespace, previousSnapshot, currentSnapshot } = generation;\n    if (!previousSnapshot) continue;\n    const diff = compareSnapshots(previousSnapshot, currentSnapshot);\n    if (!hasChanges(diff)) {\n      generation.diff = diff;\n      continue;\n    }\n    const resolution = await resolveRenames(previousSnapshot, currentSnapshot, diff, options, {\n      fieldRenames: renameSpecsByNamespace.get(namespace) ?? [],\n      typeRenames: typeRenameSpecsByNamespace.get(namespace) ?? [],\n      fieldDrops: dropSpecsByNamespace.get(namespace) ?? [],\n      typeDrops: typeDropSpecsByNamespace.get(namespace) ?? [],\n      nestedMemberRenames: nestedRenameSpecsByNamespace.get(namespace) ?? [],\n      nestedMemberDrops: nestedDropSpecsByNamespace.get(namespace) ?? [],\n    });\n    generation.diff = resolution.diff;\n    unresolvedCandidates.push(...resolution.unresolved);\n    generation.expandPlans = await resolveExpandContractPlans({\n      previousSnapshot,\n      currentSnapshot,\n      diff: resolution.diff,\n      options,\n      confirmedKeys: expandContractKeysByNamespace.get(namespace) ?? new Set(),\n    });\n  }\n\n  // Failing beats warning here: a candidate left unresolved in a\n  // non-interactive run would be written as remove + add and silently drop\n  // the field's or table's data at deploy\n  if (unresolvedCandidates.length > 0) {\n    const details = unresolvedCandidates\n      .map(\n        ({ namespace, label, targets }) =>\n          `  - ${label} → ${targets.join(\", \")}? (namespace: ${namespace})`,\n      )\n      .join(\"\\n\");\n    throw CLIError({\n      code: \"MIGRATION_RENAME_UNRESOLVED\",\n      message: `Possible rename(s) detected:\\n${details}`,\n      suggestion:\n        'Re-run with --rename \"Table.oldField:newField\" (field), --rename \"OldTable:NewTable\" (table), or --rename \"Table.field.oldMember:newMember\" (nested member) to record a rename and scaffold a data copy script, or --drop \"Table.field\" / --drop \"Table\" / --drop \"Table.field.member\" to confirm the removal.',\n      command: \"tailordb migration generate\",\n    });\n  }\n\n  for (const {\n    migrationsDir,\n    currentSnapshot,\n    previousSnapshot,\n    diff,\n    expandPlans,\n  } of generations) {\n    if (!previousSnapshot) {\n      // First migration - generate initial schema snapshot\n      await generateInitialSnapshot(currentSnapshot, migrationsDir);\n    } else {\n      await generateDiffFromSnapshot(\n        previousSnapshot,\n        assertDefined(diff, \"Migration diff was not resolved during preflight\"),\n        migrationsDir,\n        options,\n        currentSnapshot,\n        expandPlans ?? [],\n      );\n    }\n  }\n}\n\n/**\n * Generate a data-only migration: a numbered entry with an empty diff that\n * exists to run a migration script against the unchanged schema.\n * @param {readonly NamespaceGeneration[]} generations - Snapshots per namespace\n * @param {string} namespace - Target namespace\n * @param {GenerateOptions} options - Generate options\n * @returns {Promise<void>} Promise that resolves when the migration is written\n */\nasync function generateDataOnlyMigration(\n  generations: readonly NamespaceGeneration[],\n  namespace: string,\n  options: GenerateOptions,\n): Promise<void> {\n  const generation = generations.find((g) => g.namespace === namespace);\n  if (!generation) {\n    throw CLIError({\n      code: \"TAILORDB_NAMESPACE_NOT_FOUND\",\n      message: `No TailorDB service found for namespace \"${namespace}\"`,\n    });\n  }\n  const { migrationsDir, previousSnapshot, currentSnapshot } = generation;\n  if (!previousSnapshot) {\n    throw CLIError({\n      code: \"MIGRATION_BASELINE_NOT_FOUND\",\n      message: `Namespace \"${namespace}\" has no migration baseline.`,\n      suggestion: \"Create the initial schema snapshot first.\",\n    });\n  }\n\n  const diff = compareSnapshots(previousSnapshot, currentSnapshot);\n  if (hasChanges(diff)) {\n    logger.newline();\n    logger.log(formatMigrationDiff(diff));\n    logger.newline();\n    throw CLIError({\n      code: \"MIGRATION_SCHEMA_CHANGES_PENDING\",\n      message: `Namespace \"${namespace}\" has schema changes that are not in migration files.`,\n      suggestion: \"Generate the schema migration first by running without --data-only.\",\n    });\n  }\n\n  const migrationNumber = getNextMigrationNumber(migrationsDir);\n  const result = await generateDataOnlyMigrationFiles({\n    diff: { ...diff, requiresMigrationScript: true },\n    migrationsDir,\n    migrationNumber,\n    snapshot: previousSnapshot,\n    description: options.name,\n  });\n\n  logger.success(\n    `Generated data-only migration ${styles.bold(formatMigrationNumber(result.migrationNumber))}`,\n  );\n  logger.info(`  Diff file: ${result.diffFilePath}`);\n  logger.info(`  Migration script: ${result.migrateFilePath}`);\n  logger.info(`  DB types: ${result.dbTypesFilePath}`);\n  logPgliteSchemaResult(result);\n  logger.newline();\n  logger.log(\"This migration carries no schema changes.\");\n  logger.log(\n    \"Edit the script to implement the data transformation before running 'tailor deploy'.\",\n  );\n\n  await openMigrationScriptInEditor(result.migrateFilePath);\n}\n\n/**\n * Report where db.pglite.ts landed, or why it was skipped.\n * @param result - Files written for the migration\n */\nfunction logPgliteSchemaResult(result: {\n  pgliteSchemaFilePath?: string;\n  pgliteSchemaError?: string;\n}): void {\n  if (result.pgliteSchemaFilePath) {\n    logger.info(`  PGlite schema: ${result.pgliteSchemaFilePath}`);\n  }\n  if (result.pgliteSchemaError) {\n    logger.warn(`  PGlite schema skipped: ${result.pgliteSchemaError}`);\n  }\n}\n\n/**\n * Open a generated migrate.ts in the configured editor, silently skipping\n * when no editor is configured, the file is missing, or the editor fails.\n * @param {string} migrateFilePath - Path of the generated migration script\n * @returns {Promise<void>} Promise that resolves when the editor is closed or skipped\n */\nasync function openMigrationScriptInEditor(migrateFilePath: string): Promise<void> {\n  const editor = getConfiguredEditorCommand();\n  if (!editor) {\n    return;\n  }\n\n  try {\n    await fsPromises.access(migrateFilePath);\n  } catch {\n    return;\n  }\n\n  logger.newline();\n  logger.info(`Opening ${path.basename(migrateFilePath)} in ${editor}...`);\n\n  try {\n    await openInConfiguredEditor(migrateFilePath);\n  } catch {\n    return;\n  }\n}\n\n/** Inputs for {@link resolveExpandContractPlans}. */\ninterface ResolveExpandContractOptions {\n  previousSnapshot: NormalizedSchemaSnapshot;\n  currentSnapshot: NormalizedSchemaSnapshot;\n  diff: MigrationDiff;\n  options: GenerateOptions;\n  confirmedKeys: ReadonlySet<string>;\n}\n\n/**\n * Decide which unsupported field type changes to carry through a migration\n * pair, asking about each one that was not already named by a flag.\n * @param input - Snapshots, diff, command options, and flag-approved fields\n * @returns Approved plans, empty when nothing was confirmed\n */\nasync function resolveExpandContractPlans(\n  input: ResolveExpandContractOptions,\n): Promise<ExpandContractPlan[]> {\n  const { previousSnapshot, currentSnapshot, diff, options, confirmedKeys } = input;\n  const confirmed = new Set(confirmedKeys);\n\n  if (!options.yes && canPrompt()) {\n    for (const change of diff.changes) {\n      if (!isExpandContractCandidate(change)) continue;\n      const key = fieldKey(change.tableName, change.fieldName);\n      if (confirmed.has(key)) continue;\n      if (\n        !canConvertField({\n          previous: previousSnapshot,\n          current: currentSnapshot,\n          tableName: change.tableName,\n          fieldName: change.fieldName,\n        })\n      ) {\n        continue;\n      }\n\n      logger.newline();\n      logger.info(\n        `${change.tableName}.${change.fieldName} changes from ${formatFieldShape(change.before)} to ${formatFieldShape(change.after)}, which cannot be applied in one step.`,\n      );\n      const approved = await prompt.confirm({\n        message: `Generate two migrations to convert ${change.tableName}.${change.fieldName} through a temporary field?`,\n        default: true,\n      });\n      if (approved) confirmed.add(key);\n    }\n  }\n\n  return planExpandContract({\n    previous: previousSnapshot,\n    current: currentSnapshot,\n    diff,\n    confirmed,\n  }).plans;\n}\n\n/**\n * Generate the initial schema snapshot\n * @param {SchemaSnapshot} snapshot - Schema snapshot to save\n * @param {string} migrationsDir - Migrations directory path\n * @returns {Promise<void>} Promise that resolves when snapshot is generated\n */\nasync function generateInitialSnapshot(\n  snapshot: SchemaSnapshot,\n  migrationsDir: string,\n): Promise<void> {\n  const result = await generateSchemaFile(snapshot, migrationsDir, INITIAL_SCHEMA_NUMBER);\n\n  logger.success(`Generated initial schema snapshot`);\n  logger.info(`  File: ${result.filePath}`);\n  logger.info(`  Tables: ${Object.keys(snapshot.tables).length}`);\n\n  logger.log(\"\\nThis is the baseline schema. Future changes will be tracked as diffs.\");\n}\n\n/** A parsed field-form `--rename` flag together with its raw value. */\ninterface RenameFlag {\n  raw: string;\n  spec: FieldRenameSpec;\n}\n\n/** A parsed nested-member-form `--rename` flag together with its raw value. */\ninterface NestedMemberRenameFlag {\n  raw: string;\n  spec: NestedMemberRenameSpec;\n}\n\n/** A parsed nested-member-form `--drop` flag together with its raw value. */\ninterface NestedMemberDropFlag {\n  raw: string;\n  spec: NestedMemberDropSpec;\n}\n\n/**\n * Number of dots in the target part of a `--rename` / `--drop` value: 0 for a\n * table, 1 for a field, 2 or more for a member inside a nested field.\n * @param {string} raw - Raw option value\n * @returns {number} Dot count before any \":\"\n */\nfunction targetDepth(raw: string): number {\n  return (raw.split(\":\")[0] ?? \"\").split(\".\").length - 1;\n}\n\n/** Location of a member inside a nested field. */\ninterface NestedMemberLocation {\n  tableName: string;\n  /** Top-level nested field containing the member. */\n  fieldName: string;\n  /** Member path relative to the top-level field. */\n  path: readonly string[];\n}\n\n/**\n * Dotted key of a member inside a nested field, e.g. `User.address.zip`.\n * @param {NestedMemberLocation} member - Member location\n * @returns {string} Dotted key\n */\nfunction nestedMemberKey(member: NestedMemberLocation): string {\n  return `${member.tableName}.${member.fieldName}.${member.path.join(\".\")}`;\n}\n\n/**\n * Match `--rename` / `--drop` flags against every namespace's snapshots.\n * Throws when a flag applies to no namespace, so a typo cannot silently fall\n * back to remove + add.\n * @param {readonly { raw: string; spec: S }[]} flags - Parsed flags of one form\n * @param {readonly NamespaceGeneration[]} generations - Snapshots per namespace\n * @param {(spec: S, previous: SchemaSnapshot, current: SchemaSnapshot) => boolean} applies - Whether a spec matches a namespace's snapshot pair\n * @param {string} unmatchedError - Error prefix for flags that match no namespace\n * @returns {Map<string, S[]>} Applicable specs keyed by namespace\n */\nfunction matchFlagsToNamespaces<S>(\n  flags: readonly { raw: string; spec: S }[],\n  generations: readonly NamespaceGeneration[],\n  applies: (spec: S, previous: SchemaSnapshot, current: SchemaSnapshot) => boolean,\n  unmatchedError: string,\n): Map<string, S[]> {\n  const specsByNamespace = new Map<string, S[]>();\n  const matched = new Set<(typeof flags)[number]>();\n  for (const { namespace, previousSnapshot, currentSnapshot } of generations) {\n    if (!previousSnapshot) continue;\n    const applicable = flags.filter(({ spec }) => applies(spec, previousSnapshot, currentSnapshot));\n    for (const flag of applicable) {\n      matched.add(flag);\n    }\n    specsByNamespace.set(\n      namespace,\n      applicable.map((flag) => flag.spec),\n    );\n  }\n  const unused = flags.filter((flag) => !matched.has(flag));\n  if (unused.length > 0) {\n    throw CLIError({\n      code: \"MIGRATION_FLAG_UNMATCHED\",\n      message: `${unmatchedError}: ${unused.map((flag) => flag.raw).join(\", \")}`,\n      command: \"tailordb migration generate\",\n    });\n  }\n  return specsByNamespace;\n}\n\n/** A parsed table-form `--rename` flag together with its raw value. */\ninterface TypeRenameFlag {\n  raw: string;\n  spec: TypeRenameSpec;\n}\n\n/** A parsed field-form `--drop` flag together with its raw value. */\ninterface DropFlag {\n  raw: string;\n  spec: FieldDropSpec;\n}\n\n/** A parsed `--expand-contract` flag together with its raw value. */\ninterface ExpandContractFlag {\n  raw: string;\n  spec: FieldExpandContractSpec;\n}\n\n/** A parsed table-form `--drop` flag together with its raw value. */\ninterface TypeDropFlag {\n  raw: string;\n  spec: TypeDropSpec;\n}\n\n/** Snapshots collected for one namespace before any migration file is written. */\ninterface NamespaceGeneration {\n  namespace: string;\n  migrationsDir: string;\n  currentSnapshot: NormalizedSchemaSnapshot;\n  previousSnapshot: NormalizedSchemaSnapshot | null;\n  /** Diff with confirmed renames, set during preflight when a previous snapshot exists. */\n  diff?: MigrationDiff;\n  /** Field type changes confirmed for a migration pair during preflight. */\n  expandPlans?: ExpandContractPlan[];\n}\n\n/** A rename candidate that a non-interactive run could not resolve. */\ninterface UnresolvedRenameCandidate {\n  namespace: string;\n  /** Removed field, table, or nested member (`Table.field.member`) with rename candidates. */\n  label: string;\n  targets: string[];\n}\n\n/** The outcome of resolving one namespace's rename candidates. */\ninterface RenameResolution {\n  diff: MigrationDiff;\n  unresolved: UnresolvedRenameCandidate[];\n}\n\n/** One namespace's `--rename` / `--drop` specs. */\ninterface NamespaceRenameSpecs {\n  fieldRenames: readonly FieldRenameSpec[];\n  typeRenames: readonly TypeRenameSpec[];\n  fieldDrops: readonly FieldDropSpec[];\n  typeDrops: readonly TypeDropSpec[];\n  nestedMemberRenames: readonly NestedMemberRenameSpec[];\n  nestedMemberDrops: readonly NestedMemberDropSpec[];\n}\n\nfunction availableNestedMemberRenameTargets(\n  candidate: NestedMemberRenameCandidate,\n  claimedMembers: ReadonlySet<string>,\n): string[] {\n  const parent = candidate.previousPath.slice(0, -1);\n  return candidate.added.filter(\n    (name) => !claimedMembers.has(nestedMemberKey({ ...candidate, path: [...parent, name] })),\n  );\n}\n\n/**\n * Ask the user whether a removed nested member was renamed to one of the\n * compatible added siblings. Returns the confirmed new member name, or undefined.\n * @param {NestedMemberRenameCandidate} candidate - Candidate to confirm\n * @param {string[]} addedNames - Added sibling names still available as rename targets\n * @returns {Promise<string | undefined>} Confirmed new member name, if any\n */\nasync function promptNestedMemberRenameCandidate(\n  candidate: NestedMemberRenameCandidate,\n  addedNames: string[],\n): Promise<string | undefined> {\n  const oldLabel = nestedMemberKey({ ...candidate, path: candidate.previousPath });\n  const oldName = candidate.previousPath[candidate.previousPath.length - 1] ?? \"\";\n  const [firstName] = addedNames;\n  if (addedNames.length === 1 && firstName) {\n    const isRename = await prompt.confirm({\n      message: `${oldLabel} was removed and ${firstName} was added with a compatible type. Was it renamed to ${firstName}?`,\n      default: true,\n    });\n    return isRename ? firstName : undefined;\n  }\n  const selected = await prompt.select({\n    message: `${oldLabel} was removed. Was it renamed to one of these added members?`,\n    choices: [\n      ...addedNames.map((name) => ({\n        name: `Yes, renamed to ${name}`,\n        value: name as string | null,\n      })),\n      { name: `No, ${oldName} was removed`, value: null },\n    ],\n  });\n  return selected ?? undefined;\n}\n\nfunction availableRenameTargets(\n  candidate: FieldRenameCandidate,\n  claimedFields: ReadonlySet<string>,\n): string[] {\n  return candidate.added\n    .filter((added) => !claimedFields.has(`${candidate.tableName}.${added.fieldName}`))\n    .map((added) => added.fieldName);\n}\n\n/**\n * Ask the user whether a removed field was renamed to one of the compatible\n * added fields. Returns the confirmed new field name, or undefined.\n * @param {FieldRenameCandidate} candidate - Candidate to confirm\n * @param {string[]} addedFieldNames - Added field names still available as rename targets\n * @returns {Promise<string | undefined>} Confirmed new field name, if any\n */\nasync function promptRenameCandidate(\n  candidate: FieldRenameCandidate,\n  addedFieldNames: string[],\n): Promise<string | undefined> {\n  const oldLabel = `${candidate.tableName}.${candidate.removed.fieldName}`;\n  const [firstFieldName] = addedFieldNames;\n  if (addedFieldNames.length === 1 && firstFieldName) {\n    const isRename = await prompt.confirm({\n      message: `${oldLabel} was removed and ${firstFieldName} was added with a compatible type. Was it renamed to ${firstFieldName}?`,\n      default: true,\n    });\n    return isRename ? firstFieldName : undefined;\n  }\n  const selected = await prompt.select({\n    message: `${oldLabel} was removed. Was it renamed to one of these added fields?`,\n    choices: [\n      ...addedFieldNames.map((fieldName) => ({\n        name: `Yes, renamed to ${fieldName}`,\n        value: fieldName as string | null,\n      })),\n      { name: `No, ${candidate.removed.fieldName} was removed`, value: null },\n    ],\n  });\n  return selected ?? undefined;\n}\n\nfunction availableTypeRenameTargets(\n  candidate: TypeRenameCandidate,\n  claimedTypes: ReadonlySet<string>,\n): string[] {\n  return candidate.added\n    .filter((added) => !claimedTypes.has(added.tableName))\n    .map((added) => added.tableName);\n}\n\n/**\n * Ask the user whether a removed type was renamed to one of the compatible\n * added tables. Returns the confirmed new table name, or undefined.\n * @param {TypeRenameCandidate} candidate - Candidate to confirm\n * @param {string[]} addedTypeNames - Added table names still available as rename targets\n * @returns {Promise<string | undefined>} Confirmed new table name, if any\n */\nasync function promptTypeRenameCandidate(\n  candidate: TypeRenameCandidate,\n  addedTypeNames: string[],\n): Promise<string | undefined> {\n  const oldTypeName = candidate.removed.tableName;\n  const [firstTypeName] = addedTypeNames;\n  if (addedTypeNames.length === 1 && firstTypeName) {\n    const isRename = await prompt.confirm({\n      message: `${oldTypeName} was removed and ${firstTypeName} was added with a compatible schema. Was it renamed to ${firstTypeName}?`,\n      default: true,\n    });\n    return isRename ? firstTypeName : undefined;\n  }\n  const selected = await prompt.select({\n    message: `${oldTypeName} was removed. Was it renamed to one of these added tables?`,\n    choices: [\n      ...addedTypeNames.map((tableName) => ({\n        name: `Yes, renamed to ${tableName}`,\n        value: tableName as string | null,\n      })),\n      { name: `No, ${oldTypeName} was removed`, value: null },\n    ],\n  });\n  return selected ?? undefined;\n}\n\n/**\n * Resolve field, table, and nested member renames for a diff: apply\n * `--rename` flags, skip candidates whose removal is confirmed by `--drop`,\n * confirm the rest interactively, and recompute the diff with the confirmed\n * renames. When prompting is unavailable (`--yes` or no TTY), the remaining\n * candidates are returned as unresolved for the caller to fail on.\n * @param {NormalizedSchemaSnapshot} previousSnapshot - Previous normalized schema snapshot\n * @param {NormalizedSchemaSnapshot} currentSnapshot - Current normalized schema snapshot\n * @param {MigrationDiff} diff - Diff computed without rename knowledge\n * @param {GenerateOptions} options - Generate options\n * @param {NamespaceRenameSpecs} specs - This namespace's `--rename` / `--drop` specs\n * @returns {Promise<RenameResolution>} Diff with confirmed renames and any unresolved candidates\n */\nasync function resolveRenames(\n  previousSnapshot: NormalizedSchemaSnapshot,\n  currentSnapshot: NormalizedSchemaSnapshot,\n  diff: MigrationDiff,\n  options: GenerateOptions,\n  specs: NamespaceRenameSpecs,\n): Promise<RenameResolution> {\n  const confirmed: FieldRenameSpec[] = [...specs.fieldRenames];\n  const claimedFields = new Set(\n    confirmed.flatMap((spec) => [\n      `${spec.tableName}.${spec.previousFieldName}`,\n      `${spec.tableName}.${spec.fieldName}`,\n    ]),\n  );\n  const droppedFields = new Set(\n    specs.fieldDrops.map((spec) => `${spec.tableName}.${spec.fieldName}`),\n  );\n  const confirmedTypes: TypeRenameSpec[] = [...specs.typeRenames];\n  const claimedTypes = new Set(\n    confirmedTypes.flatMap((spec) => [spec.previousTableName, spec.tableName]),\n  );\n  const droppedTypes = new Set(specs.typeDrops.map((spec) => spec.tableName));\n  const confirmedNested: NestedMemberRenameSpec[] = [...specs.nestedMemberRenames];\n  const claimedMembers = new Set(\n    confirmedNested.flatMap((spec) => [\n      nestedMemberKey({ ...spec, path: spec.previousPath }),\n      nestedMemberKey(spec),\n    ]),\n  );\n  const droppedMembers = new Set(specs.nestedMemberDrops.map((spec) => nestedMemberKey(spec)));\n\n  const typeCandidates = findTypeRenameCandidates(diff).filter(\n    (candidate) =>\n      !droppedTypes.has(candidate.removed.tableName) &&\n      !claimedTypes.has(candidate.removed.tableName) &&\n      availableTypeRenameTargets(candidate, claimedTypes).length > 0,\n  );\n  const candidates = findRenameCandidates(diff).filter(\n    (candidate) =>\n      !droppedFields.has(`${candidate.tableName}.${candidate.removed.fieldName}`) &&\n      !claimedFields.has(`${candidate.tableName}.${candidate.removed.fieldName}`) &&\n      availableRenameTargets(candidate, claimedFields).length > 0,\n  );\n  const nestedCandidates = findNestedMemberRenameCandidates(diff).filter((candidate) => {\n    const key = nestedMemberKey({ ...candidate, path: candidate.previousPath });\n    return (\n      !droppedMembers.has(key) &&\n      !claimedMembers.has(key) &&\n      availableNestedMemberRenameTargets(candidate, claimedMembers).length > 0\n    );\n  });\n\n  const unresolved: UnresolvedRenameCandidate[] = [];\n  if (options.yes || !canPrompt()) {\n    for (const candidate of typeCandidates) {\n      unresolved.push({\n        namespace: diff.namespace,\n        label: candidate.removed.tableName,\n        targets: availableTypeRenameTargets(candidate, claimedTypes),\n      });\n    }\n    for (const candidate of candidates) {\n      unresolved.push({\n        namespace: diff.namespace,\n        label: `${candidate.tableName}.${candidate.removed.fieldName}`,\n        targets: availableRenameTargets(candidate, claimedFields),\n      });\n    }\n    for (const candidate of nestedCandidates) {\n      unresolved.push({\n        namespace: diff.namespace,\n        label: nestedMemberKey({ ...candidate, path: candidate.previousPath }),\n        targets: availableNestedMemberRenameTargets(candidate, claimedMembers),\n      });\n    }\n  } else {\n    for (const candidate of typeCandidates) {\n      const addedTypeNames = availableTypeRenameTargets(candidate, claimedTypes);\n      if (addedTypeNames.length === 0) continue;\n      const newTypeName = await promptTypeRenameCandidate(candidate, addedTypeNames);\n      if (newTypeName) {\n        confirmedTypes.push({\n          previousTableName: candidate.removed.tableName,\n          tableName: newTypeName,\n        });\n        claimedTypes.add(candidate.removed.tableName);\n        claimedTypes.add(newTypeName);\n      }\n    }\n    for (const candidate of candidates) {\n      const addedFieldNames = availableRenameTargets(candidate, claimedFields);\n      if (addedFieldNames.length === 0) continue;\n      const newFieldName = await promptRenameCandidate(candidate, addedFieldNames);\n      if (newFieldName) {\n        confirmed.push({\n          tableName: candidate.tableName,\n          previousFieldName: candidate.removed.fieldName,\n          fieldName: newFieldName,\n        });\n        claimedFields.add(`${candidate.tableName}.${candidate.removed.fieldName}`);\n        claimedFields.add(`${candidate.tableName}.${newFieldName}`);\n      }\n    }\n    for (const candidate of nestedCandidates) {\n      const addedNames = availableNestedMemberRenameTargets(candidate, claimedMembers);\n      if (addedNames.length === 0) continue;\n      const newName = await promptNestedMemberRenameCandidate(candidate, addedNames);\n      if (newName) {\n        const spec: NestedMemberRenameSpec = {\n          tableName: candidate.tableName,\n          fieldName: candidate.fieldName,\n          previousPath: candidate.previousPath,\n          path: [...candidate.previousPath.slice(0, -1), newName],\n        };\n        confirmedNested.push(spec);\n        claimedMembers.add(nestedMemberKey({ ...spec, path: spec.previousPath }));\n        claimedMembers.add(nestedMemberKey(spec));\n      }\n    }\n  }\n\n  if (confirmed.length === 0 && confirmedTypes.length === 0 && confirmedNested.length === 0) {\n    return { diff, unresolved };\n  }\n  return {\n    diff: compareSnapshots(previousSnapshot, currentSnapshot, {\n      fieldRenames: confirmed,\n      typeRenames: confirmedTypes,\n      nestedMemberRenames: confirmedNested,\n    }),\n    unresolved,\n  };\n}\n\n/**\n * Generate migration files from a diff resolved during preflight\n * @param {SchemaSnapshot} previousSnapshot - Previous schema snapshot\n * @param {MigrationDiff} diff - Diff with confirmed renames recorded\n * @param {string} migrationsDir - Migrations directory path\n * @param {GenerateOptions} options - Generate options\n * @param currentSnapshot - Schema the user now declares\n * @param expandPlans - Field changes confirmed for a migration pair\n * @returns {Promise<void>} Promise that resolves when diff is generated\n */\nasync function generateDiffFromSnapshot(\n  previousSnapshot: NormalizedSchemaSnapshot,\n  diff: MigrationDiff,\n  migrationsDir: string,\n  options: GenerateOptions,\n  currentSnapshot: NormalizedSchemaSnapshot,\n  expandPlans: readonly ExpandContractPlan[] = [],\n): Promise<void> {\n  if (!hasChanges(diff)) {\n    logger.info(\"No schema differences detected.\");\n    return;\n  }\n\n  // Display diff\n  logger.newline();\n  logger.log(formatMigrationDiff(diff));\n  logger.newline();\n  logger.info(`Summary: ${formatDiffSummary(diff)}`);\n\n  const plannedKeys = new Set(expandPlans.map((plan) => fieldKey(plan.tableName, plan.fieldName)));\n  const unsupportedChanges = diff.breakingChanges.filter(\n    (change) =>\n      change.unsupported &&\n      !(change.fieldName && plannedKeys.has(fieldKey(change.tableName, change.fieldName))),\n  );\n  if (unsupportedChanges.length > 0) {\n    for (const change of unsupportedChanges) {\n      logger.newline();\n      logger.error(`Unsupported change: ${change.tableName}.${change.fieldName}`);\n      logger.error(`  ${change.reason}`);\n    }\n\n    // A field whose type and array-ness both change is reported twice above.\n    const convertible = new Set<string>();\n    for (const { tableName, fieldName } of unsupportedChanges) {\n      if (\n        fieldName !== undefined &&\n        canConvertField({\n          previous: previousSnapshot,\n          current: currentSnapshot,\n          tableName,\n          fieldName,\n        })\n      ) {\n        convertible.add(fieldKey(tableName, fieldName));\n      }\n    }\n    if (convertible.size > 0) {\n      logger.newline();\n      logger.info(\"Convert these fields through a temporary field with:\");\n      for (const key of convertible) {\n        logger.info(`  --expand-contract \"${key}\"`);\n      }\n    }\n\n    // Show 3-step migration hint if any unsupported change requires it\n    if (unsupportedChanges.some((change) => change.showThreeStepHint)) {\n      logger.newline();\n      for (const line of getUnsupportedMigrationHintLines()) {\n        logger.info(line);\n      }\n    }\n\n    const details = unsupportedChanges\n      .map((c) => `  - ${c.tableName}.${c.fieldName}: ${c.reason}`)\n      .join(\"\\n\");\n    throw CLIError({\n      code: \"MIGRATION_UNSUPPORTED_SCHEMA_CHANGE\",\n      message: `Unsupported schema changes detected:\\n${details}`,\n    });\n  }\n\n  // Warn about breaking changes\n  if (diff.hasBreakingChanges) {\n    logger.newline();\n    logger.warn(formatBreakingChanges(diff.breakingChanges));\n\n    if (!options.yes) {\n      const confirmation = await prompt.confirm({\n        message: \"Continue generating migration?\",\n        default: true,\n      });\n\n      if (!confirmation) {\n        logger.info(\"Migration generation cancelled.\");\n        return;\n      }\n      logger.newline();\n    }\n  }\n\n  // Warn about non-breaking but data-loss-possible changes (e.g. field/table removal)\n  if (diff.hasWarnings) {\n    logger.newline();\n    logger.warn(formatWarnings(diff.warnings));\n  }\n\n  if (expandPlans.length > 0) {\n    await generateExpandContractMigrations({\n      previousSnapshot,\n      currentSnapshot,\n      resolvedDiff: diff,\n      plans: expandPlans,\n      migrationsDir,\n      description: options.name,\n    });\n    return;\n  }\n\n  // Get next migration number\n  const migrationNumber = getNextMigrationNumber(migrationsDir);\n\n  // Generate diff and optional migration script (pass previousSnapshot for db.ts generation)\n  const result = await generateDiffFiles(\n    diff,\n    migrationsDir,\n    migrationNumber,\n    previousSnapshot,\n    options.name,\n  );\n\n  logger.success(\n    `Generated migration ${styles.bold(formatMigrationNumber(result.migrationNumber))}`,\n  );\n  logger.info(`  Diff file: ${result.diffFilePath}`);\n\n  if (result.migrateFilePath) {\n    logger.info(`  Migration script: ${result.migrateFilePath}`);\n    if (result.dbTypesFilePath) {\n      logger.info(`  DB types: ${result.dbTypesFilePath}`);\n      logPgliteSchemaResult(result);\n    }\n    logger.newline();\n    logger.log(\"A migration script was generated for breaking changes.\");\n    logger.log(\"Please review and edit the script before running 'tailor deploy'.\");\n\n    await openMigrationScriptInEditor(result.migrateFilePath);\n  } else if (diff.hasWarnings) {\n    await acknowledgeWarnings({\n      namespace: diff.namespace,\n      migrationsDir,\n      migrationNumber: result.migrationNumber,\n      skipPrompt: options.yes,\n      configPath: options.configPath,\n    });\n  }\n}\n\n/** Inputs for {@link generateExpandContractMigrations}. */\ninterface GenerateExpandContractOptions {\n  previousSnapshot: NormalizedSchemaSnapshot;\n  currentSnapshot: NormalizedSchemaSnapshot;\n  resolvedDiff: MigrationDiff;\n  plans: readonly ExpandContractPlan[];\n  migrationsDir: string;\n  description?: string;\n}\n\n/**\n * Write the two migrations that carry a field type change: one that converts\n * values into a temporary field, and one that renames it back.\n * @param input - Snapshots, confirmed plans, and output location\n * @returns {Promise<void>} Promise that resolves when both migrations are written\n */\nasync function generateExpandContractMigrations(\n  input: GenerateExpandContractOptions,\n): Promise<void> {\n  const { previousSnapshot, currentSnapshot, resolvedDiff, plans, migrationsDir, description } =\n    input;\n  const intermediateSnapshot = buildIntermediateSnapshot(previousSnapshot, plans);\n  // Comparing from the relaxed base records the removal with an optional\n  // contract, which is what the deploy restores while the script clears it.\n  const expandDiff = buildExpandDiff(previousSnapshot, intermediateSnapshot, plans);\n  const confirmedFieldRenames: FieldRenameSpec[] = resolvedDiff.changes\n    .filter((change) => change.kind === \"field_renamed\")\n    .map(({ tableName, previousFieldName, fieldName }) => ({\n      tableName,\n      previousFieldName,\n      fieldName,\n    }));\n  const confirmedTypeRenames: TypeRenameSpec[] = resolvedDiff.changes\n    .filter((change) => change.kind === \"table_renamed\")\n    .map(({ previousTableName, tableName }) => ({ previousTableName, tableName }));\n  const confirmedNestedRenames: NestedMemberRenameSpec[] = resolvedDiff.changes.flatMap((change) =>\n    change.kind === \"field_modified\"\n      ? (change.memberRenames ?? []).map((rename) => ({\n          tableName: change.tableName,\n          fieldName: change.fieldName,\n          ...rename,\n        }))\n      : [],\n  );\n  const contractDiff = compareSnapshots(intermediateSnapshot, currentSnapshot, {\n    nestedMemberRenames: confirmedNestedRenames,\n    fieldRenames: [\n      ...confirmedFieldRenames,\n      ...plans.map((plan) => ({\n        tableName: plan.tableName,\n        previousFieldName: plan.tempFieldName,\n        fieldName: plan.fieldName,\n      })),\n    ],\n    typeRenames: confirmedTypeRenames,\n  });\n\n  const expandNumber = getNextMigrationNumber(migrationsDir);\n  if (expandNumber + 1 > MAX_MIGRATION_NUMBER) {\n    throw CLIError({\n      code: \"MIGRATION_NUMBER_EXHAUSTED\",\n      message: `Converting a field type needs two migration numbers, and ${formatMigrationNumber(MAX_MIGRATION_NUMBER)} is the last one available.`,\n      suggestion: \"Re-baseline the migration history first.\",\n    });\n  }\n  const expand = await generateDiffFiles(\n    expandDiff,\n    migrationsDir,\n    expandNumber,\n    previousSnapshot,\n    description,\n    plans,\n  );\n  const contract = await generateDiffFiles(\n    contractDiff,\n    migrationsDir,\n    expandNumber + 1,\n    intermediateSnapshot,\n    description,\n  );\n\n  const fields = plans.map((plan) => `${plan.tableName}.${plan.fieldName}`).join(\", \");\n  logger.success(\n    `Generated migrations ${styles.bold(formatMigrationNumber(expand.migrationNumber))} and ${styles.bold(\n      formatMigrationNumber(contract.migrationNumber),\n    )} to convert ${fields}`,\n  );\n  logger.info(`  Diff files: ${expand.diffFilePath}, ${contract.diffFilePath}`);\n  if (expand.migrateFilePath) {\n    logger.info(`  Conversion script: ${expand.migrateFilePath}`);\n  }\n  if (contract.migrateFilePath) {\n    logger.info(`  Copy script: ${contract.migrateFilePath}`);\n  }\n  logger.newline();\n  logger.info(\n    `Edit the conversion in ${formatMigrationNumber(expand.migrationNumber)} before deploying. The copy script in ${formatMigrationNumber(\n      contract.migrationNumber,\n    )} is complete, though that migration also carries any other change in this run.`,\n    { mode: \"plain\" },\n  );\n  logger.info(\"Both migrations are applied by 'tailor deploy'.\", { mode: \"plain\" });\n}\n\ninterface AcknowledgeWarningsOptions {\n  namespace: string;\n  migrationsDir: string;\n  migrationNumber: number;\n  skipPrompt?: boolean;\n  configPath?: string;\n}\n\n/**\n * Offer to record a --no-script acknowledgment for a warning-only migration,\n * or print the follow-up commands when the session is non-interactive\n * @param {AcknowledgeWarningsOptions} options - Target migration and prompt behavior\n */\nasync function acknowledgeWarnings(options: AcknowledgeWarningsOptions): Promise<void> {\n  const { namespace, migrationsDir, migrationNumber, skipPrompt, configPath } = options;\n  const label = formatMigrationNumber(migrationNumber);\n\n  logger.newline();\n  logger.log(\"Data loss is possible for this migration but no script was generated.\");\n\n  if (!skipPrompt && canPrompt()) {\n    const record = await prompt.confirm({\n      message: \"Record a reason acknowledging that this migration intentionally has no script?\",\n      default: true,\n    });\n    if (record) {\n      const reason = await prompt.text({\n        message: \"Reason:\",\n        validate: (value) => value.trim() !== \"\" || \"Reason must not be empty.\",\n      });\n      const scriptSkipped = markMigrationScriptSkipped({ migrationsDir, migrationNumber, reason });\n      logger.success(\n        `Recorded that migration ${styles.bold(label)} intentionally has no migration script`,\n      );\n      logger.info(`  Reason: ${scriptSkipped.reason}`);\n      return;\n    }\n  }\n\n  const commandOptions = { migrationNumber, namespace, configPath };\n  logger.log(\"To add a custom migrate.ts, run:\");\n  logger.log(`  ${styles.bold(formatMigrationScriptCommand(commandOptions))}`);\n  logger.log(\"To record that this migration intentionally has no script, run:\");\n  logger.log(\n    `  ${styles.bold(formatMigrationScriptCommand({ ...commandOptions, noScript: true }))}`,\n  );\n}\n\n/**\n * CLI command definition for generate\n */\nexport const generateCommand = defineAppCommand({\n  name: \"generate\",\n  description:\n    \"Generate migration files by detecting schema differences between current local tables and the previous migration snapshot.\",\n  args: z.strictObject({\n    ...confirmationArgs,\n    ...configArg,\n    name: arg(z.string().optional(), {\n      alias: \"n\",\n      description: \"Optional description for the migration\",\n    }),\n    init: arg(z.boolean().default(false), {\n      description: \"Delete existing migrations and start fresh\",\n    }),\n    \"data-only\": arg(z.boolean().default(false), {\n      description:\n        \"Create a migration with no schema changes whose migration script runs a standalone data transformation\",\n    }),\n    namespace: arg(z.string().optional(), {\n      description:\n        \"Target TailorDB namespace for --data-only (required if multiple namespaces exist)\",\n    }),\n    rename: arg(z.array(z.string()).optional(), {\n      description:\n        'Record a field, table, or nested member rename instead of remove + add (format: \"Table.oldField:newField\", \"OldTable:NewTable\", or \"Table.field.oldMember:newMember\"; repeatable). Renames require a migration script that copies the data.',\n    }),\n    drop: arg(z.array(z.string()).optional(), {\n      description:\n        'Confirm that a removed field, table, or nested member is a genuine removal, not a rename (format: \"Table.field\", \"Table\", or \"Table.field.member\"; repeatable). Required in non-interactive runs for a removal with rename candidates.',\n    }),\n    \"expand-contract\": arg(z.array(z.string()).optional(), {\n      description:\n        'Convert a field type, or a single value into an array, through a temporary field (format: \"Table.field\"; repeatable). Generates two migrations.',\n    }),\n  }),\n  run: async (args) => {\n    await generate({\n      configPath: args.config,\n      name: args.name,\n      yes: args.yes,\n      init: args.init,\n      dataOnly: args[\"data-only\"],\n      namespace: args.namespace,\n      renames: args.rename,\n      drops: args.drop,\n      expandContracts: args[\"expand-contract\"],\n    });\n  },\n});\n","/**\n * Seed script bundler for TailorDB seed data\n *\n * Bundles seed scripts for server-side execution\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"pathe\";\nimport { resolveTSConfig } from \"pkg-types\";\nimport * as rolldown from \"rolldown\";\nimport { createBundleLog } from \"#/cli/shared/bundle-log\";\nimport { getDistDir } from \"#/cli/shared/dist-dir\";\nimport { platformBundleDefinePlugin } from \"#/cli/shared/platform-bundle-plugin\";\nimport { createTsconfigPathsPlugin } from \"#/cli/shared/tsconfig-paths-plugin\";\nimport { createGeneratedEntryResolverPlugin } from \"#/cli/shared/virtual-entry\";\nimport ml from \"#/utils/multiline\";\n\nexport type SeedBundleResult = {\n  namespace: string;\n  bundledCode: string;\n  typesIncluded: string[];\n};\n\n/**\n * Result of bundling a seed dump script.\n */\nexport type SeedDumpBundleResult = {\n  namespace: string;\n  bundledCode: string;\n};\n\nconst BATCH_SIZE = 100;\n\n/**\n * Generate seed script content for server-side execution\n * @param namespace - TailorDB namespace\n * @returns Generated seed script content\n */\nfunction generateSeedScriptContent(namespace: string): string {\n  return ml /* ts */ `\n    import { Kysely, TailordbDialect } from \"@tailor-platform/sdk/kysely\";\n\n    type SeedInput = {\n      data: Record<string, Record<string, unknown>[]>;\n      order: string[];\n      selfRefTypes: string[];\n      selfRefFields?: Record<string, string[]>;\n      selfRefKeys?: Record<string, Record<string, string>>;\n      upsert?: boolean;\n    };\n\n    type SeedResult = {\n      success: boolean;\n      processed: Record<string, { inserted: number; updated: number; skipped: number }>;\n      errors: string[];\n    };\n\n    function getDB(namespace: string) {\n      const client = new tailordb.Client({ namespace });\n      return new Kysely<Record<string, Record<string, unknown>>>({\n        dialect: new TailordbDialect(client),\n      });\n    }\n\n    /**\n     * Order records of a self-referencing table so a row referenced by\n     * another row in the same batch is always inserted first.\n     *\n     * Dumped seed data is ordered by id (a UUID), which has no relationship\n     * to parent/child order, so a naive one-by-one insert in file order can\n     * insert a child before the parent it points to. This does a Kahn\n     * topological sort over the in-batch rows using \\`fields\\` (the table's\n     * own self-referencing field names) as the edges; a row referencing a\n     * parent outside the batch (already applied, or null) has no edge to\n     * resolve. Rows that form a cycle (which a real hierarchy should never\n     * produce) are appended in their original order rather than dropped, so\n     * a run never silently loses data.\n     *\n     * \\`record.id\\` is used as the map key for the row itself, so it must be\n     * present and unique across the batch. If any id is missing (allowed\n     * when not using \\`--upsert\\`) or duplicated, the map would collapse\n     * distinct rows onto the same key and silently drop them from the\n     * result; fall back to the original file order instead.\n     *\n     * A self-reference field does not always hold the parent's \\`id\\` — a\n     * relation's \\`toward.key\\` (or a \\`keyOnly\\` relation's \\`foreignKeyField\\`)\n     * can target a different unique field, e.g. \\`parentCode -> Category.code\\`.\n     * \\`fieldKeys\\` names the field each self-reference field is keyed to\n     * (default \\`\"id\"\\`), so edges resolve against the right value instead of\n     * assuming every self-reference points at \\`id\\`.\n     */\n    function sortBySelfReference(\n      records: Record<string, unknown>[],\n      fields: string[],\n      fieldKeys: Record<string, string> = {},\n    ): Record<string, unknown>[] {\n      if (fields.length === 0 || records.length <= 1) return records;\n\n      const byId = new Map<unknown, Record<string, unknown>>();\n      for (const record of records) byId.set(record.id, record);\n      if (byId.size !== records.length) return records;\n\n      const idsByKeyValue = new Map<string, Map<unknown, unknown>>();\n      for (const field of fields) {\n        const targetKey = fieldKeys[field] ?? \"id\";\n        if (idsByKeyValue.has(targetKey)) continue;\n        const map = new Map<unknown, unknown>();\n        for (const record of records) {\n          const keyValue = targetKey === \"id\" ? record.id : record[targetKey];\n          if (keyValue !== null && keyValue !== undefined) map.set(keyValue, record.id);\n        }\n        idsByKeyValue.set(targetKey, map);\n      }\n\n      const inDegree = new Map<unknown, number>();\n      const dependents = new Map<unknown, unknown[]>();\n      for (const record of records) {\n        inDegree.set(record.id, 0);\n        dependents.set(record.id, []);\n      }\n      for (const record of records) {\n        const id = record.id;\n        for (const field of fields) {\n          const refValue = record[field];\n          if (refValue === null || refValue === undefined) continue;\n          const targetKey = fieldKeys[field] ?? \"id\";\n          const parentId = idsByKeyValue.get(targetKey)?.get(refValue);\n          if (parentId === undefined || parentId === id) continue;\n          inDegree.set(id, (inDegree.get(id) ?? 0) + 1);\n          dependents.get(parentId)?.push(id);\n        }\n      }\n\n      const queue: unknown[] = [];\n      for (const record of records) {\n        if ((inDegree.get(record.id) ?? 0) === 0) queue.push(record.id);\n      }\n\n      const seen = new Set<unknown>();\n      const orderedIds: unknown[] = [];\n      // A head index is used instead of \\`queue.shift()\\`, which would\n      // reindex the remaining array on every dequeue and make this Kahn\n      // traversal O(n²) over a large batch.\n      let head = 0;\n      while (head < queue.length) {\n        const id = queue[head++];\n        if (seen.has(id)) continue;\n        seen.add(id);\n        orderedIds.push(id);\n        for (const dependentId of dependents.get(id) ?? []) {\n          const remaining = (inDegree.get(dependentId) ?? 0) - 1;\n          inDegree.set(dependentId, remaining);\n          if (remaining === 0) queue.push(dependentId);\n        }\n      }\n      for (const record of records) {\n        if (!seen.has(record.id)) orderedIds.push(record.id);\n      }\n\n      return orderedIds\n        .map((id) => byId.get(id))\n        .filter((record): record is Record<string, unknown> => record !== undefined);\n    }\n\n    export async function main(input: SeedInput): Promise<SeedResult> {\n      const db = getDB(\"${namespace}\");\n      const processed: Record<\n        string,\n        { inserted: number; updated: number; skipped: number }\n      > = {};\n      const errors: string[] = [];\n      const BATCH_SIZE = ${String(BATCH_SIZE)};\n      const upsert = input.upsert === true;\n\n      for (const tableName of input.order) {\n        const records = input.data[tableName];\n        if (!records || records.length === 0) {\n          console.log(\\`[${namespace}] \\${tableName}: skipped (no data)\\`);\n          continue;\n        }\n\n        processed[tableName] = { inserted: 0, updated: 0, skipped: 0 };\n        const hasSelfRef = (input.selfRefTypes || []).includes(tableName);\n\n        try {\n          let recordsToInsert = records;\n          let recordsToUpdate: Record<string, unknown>[] = [];\n          if (upsert) {\n            const existing = await db\n              .selectFrom(tableName)\n              .select(\"id\")\n              .where(\n                \"id\",\n                \"in\",\n                records.map((record) => record.id),\n              )\n              .execute();\n            const existingIds = new Set(existing.map((record) => record.id));\n            recordsToInsert = records.filter((record) => !existingIds.has(record.id));\n            recordsToUpdate = records.filter((record) => existingIds.has(record.id));\n          }\n\n          if (hasSelfRef) {\n            // Insert one-by-one, in dependency order, to respect\n            // self-referencing foreign keys.\n            const selfRefFieldNames = (input.selfRefFields || {})[tableName] || [];\n            const selfRefFieldKeys = (input.selfRefKeys || {})[tableName] || {};\n            const orderedRecords = sortBySelfReference(\n              recordsToInsert,\n              selfRefFieldNames,\n              selfRefFieldKeys,\n            );\n            for (const record of orderedRecords) {\n              await db.insertInto(tableName).values(record).execute();\n              processed[tableName].inserted += 1;\n            }\n            if (!upsert) {\n              console.log(\n                \\`[${namespace}] \\${tableName}: \\${processed[tableName].inserted}/\\${records.length} (one-by-one)\\`,\n              );\n            }\n          } else {\n            for (let i = 0; i < recordsToInsert.length; i += BATCH_SIZE) {\n              const batch = recordsToInsert.slice(i, i + BATCH_SIZE);\n              await db.insertInto(tableName).values(batch).execute();\n              processed[tableName].inserted += batch.length;\n              if (!upsert) {\n                console.log(\n                  \\`[${namespace}] \\${tableName}: \\${processed[tableName].inserted}/\\${records.length}\\`,\n                );\n              }\n            }\n          }\n\n          for (const record of recordsToUpdate) {\n            const { id, ...values } = record;\n            if (Object.keys(values).length === 0) {\n              processed[tableName].skipped += 1;\n              continue;\n            }\n            await db.updateTable(tableName).set(values).where(\"id\", \"=\", id).execute();\n            processed[tableName].updated += 1;\n          }\n\n          const counts = processed[tableName];\n          if (upsert) {\n            const skipped = counts.skipped > 0 ? \\`, \\${counts.skipped} skipped\\` : \"\";\n            console.log(\n              \\`[${namespace}] \\${tableName}: \\${counts.inserted} inserted, \\${counts.updated} updated\\${skipped}\\`,\n            );\n          }\n        } catch (error) {\n          const message = error instanceof Error ? error.message : String(error);\n          errors.push(\\`\\${tableName}: \\${message}\\`);\n          console.error(\\`[${namespace}] \\${tableName}: failed - \\${message}\\`);\n        }\n      }\n\n      return {\n        success: errors.length === 0,\n        processed,\n        errors,\n      };\n    }\n  `;\n}\n\n/**\n * Generate seed dump script content for server-side execution\n * @param namespace - TailorDB namespace\n * @returns Generated seed dump script content\n */\nfunction generateSeedDumpScriptContent(namespace: string): string {\n  return ml /* ts */ `\n    import { Kysely, TailordbDialect } from \"@tailor-platform/sdk/kysely\";\n\n    type DumpInput = {\n      table: string;\n      limit: number;\n      after?: string | null;\n    };\n\n    type DumpResult = {\n      success: boolean;\n      rows: Record<string, unknown>[];\n      cursor: string | null;\n      errors: string[];\n    };\n\n    function getDB(namespace: string) {\n      const client = new tailordb.Client({ namespace });\n      return new Kysely<Record<string, Record<string, unknown>>>({\n        dialect: new TailordbDialect(client),\n      });\n    }\n\n    export async function main(input: DumpInput): Promise<DumpResult> {\n      const db = getDB(\"${namespace}\");\n\n      try {\n        let query = db.selectFrom(input.table).selectAll().orderBy(\"id\", \"asc\").limit(input.limit);\n        if (input.after !== null && input.after !== undefined) {\n          query = query.where(\"id\", \">\", input.after);\n        }\n        const rows = (await query.execute()) as Record<string, unknown>[];\n\n        // A full page may have more rows behind it; page again from the last id.\n        const lastRow = rows.length === input.limit ? rows[rows.length - 1] : undefined;\n        if (lastRow && typeof lastRow.id !== \"string\") {\n          // Paging past this row is impossible, and reporting no cursor would\n          // silently drop every row behind it.\n          // Left unprefixed with the table name: the caller (dump.ts) already\n          // prefixes every error it throws with the table.\n          const message = \"cannot page rows whose id is not a string\";\n          return { success: false, rows: [], cursor: null, errors: [message] };\n        }\n        const lastId = lastRow ? (lastRow.id as string) : null;\n\n        console.log(\\`[${namespace}] \\${input.table}: \\${rows.length} rows read\\`);\n\n        return { success: true, rows, cursor: lastId, errors: [] };\n      } catch (error) {\n        const message = error instanceof Error ? error.message : String(error);\n        console.error(\\`[${namespace}] \\${input.table}: failed - \\${message}\\`);\n        // Left unprefixed with the table name: the caller (dump.ts) already\n        // prefixes every error it throws with the table.\n        return { success: false, rows: [], cursor: null, errors: [message] };\n      }\n    }\n  `;\n}\n\n/**\n * Bundle a seed script for server-side execution\n *\n * Creates an entry that:\n * 1. Defines getDB() function inline\n * 2. Processes data in batches using Kysely\n * 3. Reports progress via console.log\n * 4. Exports main() as the server-side entry point\n * @param namespace - TailorDB namespace\n * @param tableNames - List of table names to include in the seed\n * @param baseDir - Directory whose dependencies and tsconfig the generated entry uses\n * @returns Bundled seed script result\n */\nexport async function bundleSeedScript(\n  namespace: string,\n  tableNames: string[],\n  baseDir: string = process.cwd(),\n): Promise<SeedBundleResult> {\n  const bundledCode = await bundleGeneratedEntry({\n    entryFileName: `seed_${namespace}.entry.ts`,\n    entryContent: generateSeedScriptContent(namespace),\n    baseDir,\n  });\n\n  return {\n    namespace,\n    bundledCode,\n    typesIncluded: tableNames,\n  };\n}\n\n/**\n * Bundle a seed dump script for server-side execution\n *\n * The read-only counterpart of the seed script: it selects one page of rows\n * from a single table ordered by id, so a caller can page through a table with\n * a keyset cursor instead of holding it all in one message.\n * @param namespace - TailorDB namespace\n * @param baseDir - Directory whose dependencies and tsconfig the generated entry uses\n * @returns Bundled seed dump script result\n */\nexport async function bundleSeedDumpScript(\n  namespace: string,\n  baseDir: string = process.cwd(),\n): Promise<SeedDumpBundleResult> {\n  const bundledCode = await bundleGeneratedEntry({\n    entryFileName: `seed_dump_${namespace}.entry.ts`,\n    entryContent: generateSeedDumpScriptContent(namespace),\n    baseDir,\n  });\n\n  return { namespace, bundledCode };\n}\n\ninterface BundleGeneratedEntryParams {\n  /** File name the generated entry is written under the seed dist directory */\n  entryFileName: string;\n  /** Source of the generated entry */\n  entryContent: string;\n  /** Directory whose dependencies and tsconfig the generated entry uses */\n  baseDir: string;\n}\n\n/**\n * Write a generated server-side entry and bundle it for script execution.\n * @param params - Entry file name, its source, and the base directory\n * @returns Bundled script code\n */\nasync function bundleGeneratedEntry(params: BundleGeneratedEntryParams): Promise<string> {\n  const { entryFileName, entryContent, baseDir } = params;\n\n  // Output directory in .tailor (relative to project root)\n  const outputDir = path.resolve(getDistDir(), \"seed\");\n  fs.mkdirSync(outputDir, { recursive: true });\n\n  const entryPath = path.join(outputDir, entryFileName);\n  fs.writeFileSync(entryPath, entryContent);\n\n  let tsconfig: string | undefined;\n  try {\n    tsconfig = await resolveTSConfig(baseDir);\n  } catch {\n    tsconfig = undefined;\n  }\n\n  // Bundle with tree-shaking (write: false to avoid unnecessary disk I/O)\n  const bundleLog = createBundleLog({ tsconfig });\n  const result = await rolldown.build({\n    plugins: [\n      createGeneratedEntryResolverPlugin(entryPath, baseDir),\n      createTsconfigPathsPlugin(),\n      platformBundleDefinePlugin,\n    ],\n    input: entryPath,\n    write: false,\n    output: {\n      format: \"esm\",\n      sourcemap: false,\n      minify: false,\n      codeSplitting: false,\n      globals: {\n        tailordb: \"tailordb\",\n      },\n    },\n    external: [\"tailordb\"],\n    resolve: {\n      conditionNames: [\"node\", \"import\"],\n    },\n    tsconfig,\n    treeshake: {\n      moduleSideEffects: false,\n      annotations: true,\n      unknownGlobalSideEffects: false,\n    },\n    ...bundleLog.options,\n  } as rolldown.BuildOptions);\n  bundleLog.assertAllResolved();\n\n  return result.output[0].code;\n}\n","/**\n * Seed data chunker for splitting large seed data into manageable message sizes.\n *\n * When seed data exceeds the gRPC message size limit, this module splits the data\n * into multiple chunks at type boundaries (or record boundaries for large types).\n */\n\nimport { assertDefined } from \"#/utils/assert\";\nimport type { JsonObject } from \"type-fest\";\n\n/**\n * Seed data keyed by table name, with an array of records per table.\n */\nexport type SeedData = Record<string, JsonObject[]>;\n\n/**\n * A single chunk of seed data with metadata for ordered execution.\n */\nexport type SeedChunk = {\n  data: SeedData;\n  order: string[];\n  index: number;\n  total: number;\n};\n\n/**\n * Options for chunking seed data.\n */\nexport type ChunkSeedDataOptions = {\n  /** Seed data keyed by type name */\n  data: SeedData;\n  /** Ordered list of type names (dependency order) */\n  order: string[];\n  /** Byte size of the bundled seed script code */\n  codeByteSize: number;\n  /** Maximum gRPC message size in bytes (default: 3.5MB) */\n  maxMessageSize?: number;\n};\n\n/** Default maximum message size: 3.5MB (conservative limit for gRPC) */\nexport const DEFAULT_MAX_MESSAGE_SIZE = 3.5 * 1024 * 1024;\n\n/** Reserved bytes for message metadata overhead */\nconst METADATA_OVERHEAD = 1024;\n\n/**\n * Split seed data into chunks that fit within the gRPC message size limit.\n *\n * Algorithm:\n * 1. Calculate the available budget for the arg field (maxMessageSize - codeByteSize - overhead)\n * 2. If all data fits in one message, return a single chunk\n * 3. Otherwise, iterate through tables in dependency order:\n *    - If a table fits in the current chunk, add it\n *    - If adding a table would exceed the budget, finalize the current chunk and start a new one\n *    - If a single table exceeds the budget, split its records across multiple chunks\n *    - If a single record exceeds the budget, throw an error\n * @param options - Chunking options\n * @returns Array of seed chunks\n */\nexport function chunkSeedData(options: ChunkSeedDataOptions): SeedChunk[] {\n  const { data, order, codeByteSize, maxMessageSize = DEFAULT_MAX_MESSAGE_SIZE } = options;\n\n  const argBudget = maxMessageSize - codeByteSize - METADATA_OVERHEAD;\n  if (argBudget <= 0) {\n    throw new Error(\n      `Code size (${codeByteSize} bytes) exceeds the message size limit (${maxMessageSize} bytes). ` +\n        `No space left for seed data.`,\n    );\n  }\n\n  // Filter to tables that have data\n  const typesWithData = order.filter((type) => (data[type]?.length ?? 0) > 0);\n\n  if (typesWithData.length === 0) {\n    return [];\n  }\n\n  // Check if all data fits in a single message\n  const fullArg = JSON.stringify({ data, order });\n  if (byteSize(fullArg) <= argBudget) {\n    return [{ data, order, index: 0, total: 1 }];\n  }\n\n  // Split into multiple chunks\n  const chunks: Omit<SeedChunk, \"total\">[] = [];\n  let currentData: SeedData = {};\n  let currentOrder: string[] = [];\n\n  for (const type of typesWithData) {\n    const typeRecords = assertDefined(data[type], `seed data missing for type: ${type}`);\n\n    // Check if the type fits in the current chunk\n    if (currentOrder.length > 0) {\n      const testData = { ...currentData, [type]: typeRecords };\n      const testOrder = [...currentOrder, type];\n      if (byteSize(JSON.stringify({ data: testData, order: testOrder })) > argBudget) {\n        // Finalize the current chunk\n        chunks.push({ data: currentData, order: currentOrder, index: chunks.length });\n        currentData = {};\n        currentOrder = [];\n      }\n    }\n\n    // Check if the entire type fits in an empty chunk\n    if (byteSize(JSON.stringify({ data: { [type]: typeRecords }, order: [type] })) <= argBudget) {\n      currentData[type] = typeRecords;\n      currentOrder.push(type);\n      continue;\n    }\n\n    // Type is too large — split by records\n    if (currentOrder.length > 0) {\n      chunks.push({ data: currentData, order: currentOrder, index: chunks.length });\n      currentData = {};\n      currentOrder = [];\n    }\n\n    let recordBatch: JsonObject[] = [];\n    for (const record of typeRecords) {\n      if (byteSize(JSON.stringify({ data: { [type]: [record] }, order: [type] })) > argBudget) {\n        const singleRecordSize = byteSize(JSON.stringify(record));\n        throw new Error(\n          `A single record in table \"${type}\" (${singleRecordSize} bytes) exceeds the message size budget ` +\n            `(${argBudget} bytes). Consider increasing maxMessageSize or reducing the record size.`,\n        );\n      }\n\n      const testBatch = [...recordBatch, record];\n      const testData = { ...currentData, [type]: testBatch };\n      const testOrder = currentOrder.includes(type) ? currentOrder : [...currentOrder, type];\n      const testSize = byteSize(JSON.stringify({ data: testData, order: testOrder }));\n\n      if (testSize > argBudget && recordBatch.length > 0) {\n        // Finalize current chunk with accumulated records\n        currentData[type] = recordBatch;\n        if (!currentOrder.includes(type)) {\n          currentOrder.push(type);\n        }\n        chunks.push({ data: currentData, order: currentOrder, index: chunks.length });\n        currentData = {};\n        currentOrder = [];\n        recordBatch = [record];\n      } else {\n        recordBatch = testBatch;\n      }\n    }\n\n    // Add remaining records\n    if (recordBatch.length > 0) {\n      currentData[type] = recordBatch;\n      if (!currentOrder.includes(type)) {\n        currentOrder.push(type);\n      }\n    }\n  }\n\n  // Finalize the last chunk\n  if (currentOrder.length > 0) {\n    chunks.push({ data: currentData, order: currentOrder, index: chunks.length });\n  }\n\n  const total = chunks.length;\n  return chunks.map((chunk) => ({ ...chunk, total }));\n}\n\nfunction byteSize(str: string): number {\n  return new TextEncoder().encode(str).length;\n}\n","import { assertDefined } from \"#/utils/assert\";\nimport { processLinesDb } from \"./lines-db-processor\";\nimport type { TailorDBType } from \"#/parser/service/tailordb/types\";\nimport type { TailorDBNamespaceData } from \"#/plugin/types\";\nimport type { SeedTypeInfo } from \"./types\";\n\n/**\n * Processes TailorDB tables to extract seed table information\n * @param type - Parsed TailorDB table\n * @param namespace - Namespace of the table\n * @returns Seed table information\n */\nfunction processSeedTypeInfo(type: TailorDBType, namespace: string): SeedTypeInfo {\n  // Extract dependencies from relations (including keyOnly which only sets foreignKeyType)\n  const dependencies: Set<string> = new Set();\n  const selfRefFields: string[] = [];\n  // A null-prototype object is used because field names are user-defined and\n  // a field can be named `__proto__`: assigning that key on a plain `{}`\n  // would invoke `Object.prototype`'s `__proto__` setter instead of creating\n  // an enumerable own property, silently dropping the entry.\n  const selfRefKeys: Record<string, string> = Object.create(null);\n\n  for (const [fieldName, field] of Object.entries(type.fields)) {\n    const targetType = field.relation?.targetType ?? field.config.foreignKeyType;\n    if (!targetType) continue;\n\n    if (targetType === type.name) {\n      selfRefFields.push(fieldName);\n      // A relation's `toward.key` (or a keyOnly relation's foreignKeyField)\n      // can target a non-`id` unique field (e.g. `code`); default to `id`\n      // only when the field truly targets the row's id.\n      selfRefKeys[fieldName] = field.relation?.key ?? field.config.foreignKeyField ?? \"id\";\n    } else {\n      dependencies.add(targetType);\n    }\n  }\n\n  return {\n    name: type.name,\n    namespace,\n    dependencies: Array.from(dependencies),\n    selfRefFields,\n    selfRefKeys,\n    dataFile: `data/${type.name}.jsonl`,\n  };\n}\n\n/**\n * Seed ordering information for a TailorDB namespace.\n */\nexport interface SeedNamespaceConfig {\n  /** TailorDB namespace name. */\n  namespace: string;\n  /** Table names in the namespace, in definition order. */\n  types: string[];\n  /** Seed dependencies (referenced table names) per table. */\n  dependencies: Record<string, string[]>;\n  /** Tables with self-referencing fields, seeded in two passes. */\n  selfRefTypes: string[];\n  /** Field names a seed row must supply per table, enforced with `--upsert`. */\n  requiredFields: Record<string, string[]>;\n  /** Field names the platform assigns rather than the seed row, per table. */\n  omitFields?: Record<string, string[]>;\n  /**\n   * Self-referencing field names per table (a subset of the table's own\n   * fields, e.g. `parentId`). Lets the seed script order same-table inserts\n   * so a row is never inserted before the row it points to.\n   */\n  selfRefFields?: Record<string, string[]>;\n  /**\n   * The field each self-referencing field is keyed to, per table (e.g.\n   * `{ Category: { parentCode: \"code\" } }`). A self-reference does not\n   * always target the row's `id` — `toward.key` (or a `keyOnly` relation's\n   * `foreignKeyField`) can point at another unique field — so the seed\n   * script needs this to resolve parent/child edges by the right value\n   * instead of assuming `id`.\n   */\n  selfRefKeys?: Record<string, Record<string, string>>;\n}\n\n/**\n * Field names, per target table, that some relation elsewhere is keyed to\n * (`field.relation.key`, or `field.config.foreignKeyField` for a `keyOnly`\n * relation, which never populates `field.relation`) rather than the target's\n * `id`. A `serial` field this set names must survive the dump even though it\n * is otherwise platform-assigned: `apply --truncate` gives the row a fresh\n * serial value, and a relation keyed to the old one would otherwise break\n * silently.\n * @param tailordb - TailorDB namespaces with their tables\n * @returns Relation-targeted field names per target table name\n */\nfunction collectRelationTargetKeys(tailordb: TailorDBNamespaceData[]): Map<string, Set<string>> {\n  const targetKeysByType = new Map<string, Set<string>>();\n  for (const ns of tailordb) {\n    for (const type of Object.values(ns.tables)) {\n      for (const field of Object.values(type.fields)) {\n        const targetType = field.relation?.targetType ?? field.config.foreignKeyType;\n        const key = field.relation?.key ?? field.config.foreignKeyField;\n        if (!targetType || !key) continue;\n        const keys = targetKeysByType.get(targetType) ?? new Set<string>();\n        keys.add(key);\n        targetKeysByType.set(targetType, keys);\n      }\n    }\n  }\n  return targetKeysByType;\n}\n\n/**\n * Build per-namespace seed ordering information from TailorDB namespace data.\n * @param tailordb - TailorDB namespaces with their tables\n * @returns Seed namespace configs, in namespace order\n */\nexport function buildSeedNamespaceConfigs(\n  tailordb: TailorDBNamespaceData[],\n): SeedNamespaceConfig[] {\n  const relationTargetKeys = collectRelationTargetKeys(tailordb);\n\n  return tailordb.map((ns) => {\n    const types: string[] = [];\n    const dependencies: Record<string, string[]> = {};\n    const selfRefTypes: string[] = [];\n    const selfRefFields: Record<string, string[]> = {};\n    const selfRefKeys: Record<string, Record<string, string>> = {};\n    const requiredFields: Record<string, string[]> = {};\n    const omitFields: Record<string, string[]> = {};\n\n    for (const [tableName, type] of Object.entries(ns.tables)) {\n      const typeInfo = processSeedTypeInfo(type, ns.namespace);\n      types.push(typeInfo.name);\n      dependencies[typeInfo.name] = typeInfo.dependencies;\n      selfRefFields[typeInfo.name] = typeInfo.selfRefFields;\n      selfRefKeys[typeInfo.name] = typeInfo.selfRefKeys;\n      if (typeInfo.selfRefFields.length > 0) {\n        selfRefTypes.push(typeInfo.name);\n      }\n\n      const source = assertDefined(\n        ns.sourceInfo.get(tableName),\n        `source info missing for table: ${tableName}`,\n      );\n      const linesDb = processLinesDb(type, source);\n      const keptRelationKeys = relationTargetKeys.get(typeInfo.name);\n      omitFields[typeInfo.name] = keptRelationKeys\n        ? linesDb.omitFields.filter((fieldName) => !keptRelationKeys.has(fieldName))\n        : linesDb.omitFields;\n      requiredFields[typeInfo.name] = Object.entries(type.fields)\n        .filter(\n          ([fieldName, field]) =>\n            field.config.required !== false &&\n            !linesDb.optionalFields.includes(fieldName) &&\n            !linesDb.omitFields.includes(fieldName),\n        )\n        .map(([fieldName]) => fieldName);\n    }\n\n    return {\n      namespace: ns.namespace,\n      types,\n      dependencies,\n      selfRefTypes,\n      selfRefFields,\n      selfRefKeys,\n      requiredFields,\n      omitFields,\n    };\n  });\n}\n","import * as path from \"pathe\";\nimport { assertUniqueLocalTailorDBTypeNames } from \"#/cli/services/tailordb/type-name-validation\";\nimport {\n  generateIdpListUsersScriptCode,\n  generateIdpSeedScriptCode,\n  generateIdpTruncateScriptCode,\n  processIdpUser,\n} from \"#/plugin/builtin/seed/idp-user-processor\";\nimport { SeedGeneratorID } from \"#/plugin/builtin/seed/index\";\nimport {\n  buildSeedNamespaceConfigs,\n  type SeedNamespaceConfig,\n} from \"#/plugin/builtin/seed/seed-type-processor\";\nimport { resolvePluginConfig } from \"#/plugin/get-plugin-config\";\nimport { getAuthInput } from \"./auth-input\";\nimport { loadApplicationNamespaces } from \"./tailordb-namespaces\";\nimport type { LoadedConfig } from \"./config-loader\";\n\nexport type { SeedNamespaceConfig };\n\n/**\n * IdP `_User` seeding context, present when the config uses the built-in IdP\n * with a user profile type.\n */\nexport interface SeedIdpUserContext {\n  /** IdP namespace the `_User` records belong to. */\n  idpNamespace: string;\n  /** Server-side script that creates `_User` records from seed rows. */\n  seedScriptCode: string;\n  /** Server-side script that lists every `_User` record to delete. */\n  listScriptCode: string;\n  /** Server-side script that deletes one chunk of listed `_User` records. */\n  truncateScriptCode: string;\n}\n\n/**\n * Everything a seed run needs from the local config: the seed data location,\n * per-namespace seeding order, and IdP user context.\n */\nexport interface SeedContext {\n  /** The loaded Tailor config. */\n  config: LoadedConfig;\n  /** Absolute path to the seedPlugin output directory. */\n  distPath: string;\n  /** Default machine user name from seedPlugin options, if configured. */\n  machineUserName?: string | undefined;\n  /** Seed ordering information per TailorDB namespace. */\n  namespaces: SeedNamespaceConfig[];\n  /** IdP `_User` seeding context, or null when not applicable. */\n  idpUser: SeedIdpUserContext | null;\n}\n\n/**\n * Options for {@link loadSeedContext}.\n */\nexport interface LoadSeedContextOptions {\n  /** Path to tailor.config.ts. Defaults to searching from the current directory. */\n  configPath?: string;\n}\n\n/**\n * Load the seed context from the local config. Requires `seedPlugin` to be\n * configured in the config's plugins. A relative `distPath` in the seedPlugin\n * options is resolved against the current working directory — the same base\n * `tailor generate` writes it to.\n * @param options - Seed context loading options.\n * @returns The seed context computed from the local config.\n */\nexport async function loadSeedContext(options: LoadSeedContextOptions = {}): Promise<SeedContext> {\n  const { config, plugins, application, namespaces } = await loadApplicationNamespaces({\n    configPath: options.configPath,\n  });\n\n  // Seed files and type filters identify types by bare name, so enforce the\n  // same cross-namespace uniqueness that generation and deploy enforce.\n  assertUniqueLocalTailorDBTypeNames({ tailorDBServices: application.tailorDBServices });\n\n  const pluginOptions = resolvePluginConfig(plugins, SeedGeneratorID);\n  if (!pluginOptions) {\n    throw new Error(\n      `seedPlugin is not configured in ${config.path}. ` +\n        'Add seedPlugin({ distPath: \"./seed\" }) from \"@tailor-platform/sdk/plugin/seed\" to definePlugins().',\n    );\n  }\n  if (typeof pluginOptions.distPath !== \"string\" || pluginOptions.distPath === \"\") {\n    throw new Error(\n      `seedPlugin in ${config.path} has no distPath option. ` +\n        'Pass seedPlugin({ distPath: \"./seed\" }) so seed data has a location.',\n    );\n  }\n\n  // userProfile is only populated once auth namespaces are resolved (the\n  // generate flow does the same after loading TailorDB namespaces).\n  await application.authService?.resolveNamespaces();\n  const authInput = getAuthInput(application);\n  const idpUserMeta = authInput ? processIdpUser(authInput) : undefined;\n  const idpUser: SeedIdpUserContext | null = idpUserMeta\n    ? {\n        idpNamespace: idpUserMeta.idpNamespace,\n        seedScriptCode: generateIdpSeedScriptCode(idpUserMeta.idpNamespace),\n        listScriptCode: generateIdpListUsersScriptCode(idpUserMeta.idpNamespace),\n        truncateScriptCode: generateIdpTruncateScriptCode(idpUserMeta.idpNamespace),\n      }\n    : null;\n\n  return {\n    config,\n    distPath: path.resolve(pluginOptions.distPath),\n    machineUserName: pluginOptions.machineUserName,\n    namespaces: buildSeedNamespaceConfigs(namespaces),\n    idpUser,\n  };\n}\n","type ListTailorDBTypesClient = {\n  listTailorDBTypes(args: { workspaceId: string; namespaceName: string }): Promise<{\n    tailordbTypes: Array<{ name: string }>;\n  }>;\n};\n\ntype ResolveTableNamespacesArgs = {\n  workspaceId: string;\n  namespaces: string[];\n  tableNames: string[];\n  client: ListTailorDBTypesClient;\n};\n\n/**\n * Resolve TailorDB table names to namespace names.\n * @param args - Resolution inputs\n * @returns Table to namespace map for found tables\n */\nexport async function resolveTableNamespaces(\n  args: ResolveTableNamespacesArgs,\n): Promise<Map<string, string>> {\n  const requestedTablesByLowercase = new Map<string, string[]>();\n  for (const tableName of args.tableNames) {\n    const key = tableName.toLowerCase();\n    const existing = requestedTablesByLowercase.get(key);\n    if (existing) {\n      existing.push(tableName);\n      continue;\n    }\n    requestedTablesByLowercase.set(key, [tableName]);\n  }\n\n  const unresolvedTables = new Set(args.tableNames);\n  const tableNamespaceMap = new Map<string, string>();\n\n  for (const namespace of args.namespaces) {\n    if (unresolvedTables.size === 0) {\n      break;\n    }\n\n    try {\n      const { tailordbTypes } = await args.client.listTailorDBTypes({\n        workspaceId: args.workspaceId,\n        namespaceName: namespace,\n      });\n\n      for (const type of tailordbTypes) {\n        const matchedRequestedTypes = requestedTablesByLowercase.get(type.name.toLowerCase());\n        if (!matchedRequestedTypes) {\n          continue;\n        }\n\n        for (const requestedTableName of matchedRequestedTypes) {\n          if (tableNamespaceMap.has(requestedTableName)) {\n            continue;\n          }\n          tableNamespaceMap.set(requestedTableName, namespace);\n          unresolvedTables.delete(requestedTableName);\n        }\n      }\n    } catch {\n      continue;\n    }\n  }\n\n  return tableNamespaceMap;\n}\n\ntype ResolveTableNamespaceArgs = {\n  workspaceId: string;\n  namespaces: string[];\n  tableName: string;\n  client: ListTailorDBTypesClient;\n};\n\n/**\n * Resolve a single TailorDB table name to namespace.\n * @param args - Resolution inputs\n * @returns Namespace name if found\n */\nexport async function resolveTableNamespace(\n  args: ResolveTableNamespaceArgs,\n): Promise<string | null> {\n  const tableNamespaceMap = await resolveTableNamespaces({\n    workspaceId: args.workspaceId,\n    namespaces: args.namespaces,\n    tableNames: [args.tableName],\n    client: args.client,\n  });\n\n  return tableNamespaceMap.get(args.tableName) ?? null;\n}\n","import { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { confirmationArgs, deploymentArgs } from \"#/cli/shared/args\";\nimport { type initOperatorClient } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { extractOwnedNamespaces } from \"#/cli/shared/config\";\nimport { loadConfig } from \"#/cli/shared/config-loader\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { prompt } from \"#/cli/shared/prompt\";\nimport { assertWritable } from \"#/cli/shared/readonly-guard\";\nimport { resolveTableNamespaces } from \"#/cli/shared/tailordb-namespace\";\nimport { assertDefined } from \"#/utils/assert\";\n\nexport interface TruncateOptions {\n  workspaceId?: string;\n  profile?: string;\n  configPath?: string;\n  all?: boolean;\n  namespace?: string;\n  tables?: string[];\n}\n\ninterface InternalTruncateOptions extends TruncateOptions {\n  yes?: boolean;\n}\n\ninterface TruncateSingleTypeOptions {\n  workspaceId: string;\n  namespaceName: string;\n  tableName: string;\n}\n\nasync function truncateSingleType(\n  options: TruncateSingleTypeOptions,\n  client: Awaited<ReturnType<typeof initOperatorClient>>,\n): Promise<void> {\n  await client.truncateTailorDBType({\n    workspaceId: options.workspaceId,\n    namespaceName: options.namespaceName,\n    tailordbTypeName: options.tableName,\n  });\n\n  logger.success(`Truncated table \"${options.tableName}\" in namespace \"${options.namespaceName}\"`);\n}\n\nasync function truncateNamespace(\n  workspaceId: string,\n  namespaceName: string,\n  client: Awaited<ReturnType<typeof initOperatorClient>>,\n): Promise<void> {\n  await client.truncateTailorDBTypes({\n    workspaceId,\n    namespaceName,\n  });\n\n  logger.success(`Truncated all tables in namespace \"${namespaceName}\"`);\n}\n\n/**\n * Truncate TailorDB data based on the given options.\n * @param options - Truncate options (all, namespace, or tables)\n * @returns Promise that resolves when truncation completes\n */\nexport async function truncate(options?: TruncateOptions): Promise<void> {\n  return await $truncate({ ...options, yes: true });\n}\n\nasync function $truncate(options: InternalTruncateOptions = {}): Promise<void> {\n  // Load and validate options\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options.profile,\n    workspaceId: options.workspaceId,\n  });\n\n  // Validate arguments\n  const hasTables = options.tables && options.tables.length > 0;\n  const hasNamespace = !!options.namespace;\n  const hasAll = !!options.all;\n\n  // All options are mutually exclusive\n  const optionCount = [hasAll, hasNamespace, hasTables].filter(Boolean).length;\n  if (optionCount === 0) {\n    throw CLIError({\n      code: \"TRUNCATE_TARGET_REQUIRED\",\n      message: \"Please specify one of: --all, --namespace <name>, or table names\",\n      command: \"tailordb truncate\",\n    });\n  }\n  if (optionCount > 1) {\n    throw CLIError({\n      code: \"TRUNCATE_OPTIONS_CONFLICT\",\n      message:\n        \"Options --all, --namespace, and table names are mutually exclusive. Please specify only one.\",\n      command: \"tailordb truncate\",\n    });\n  }\n\n  // Validate config and get namespaces before confirmation\n  const { config } = await loadConfig(options.configPath);\n  const namespaces = extractOwnedNamespaces(config);\n\n  // Handle --all flag\n  if (hasAll) {\n    if (namespaces.length === 0) {\n      logger.warn(\"No namespaces found in config file.\");\n      return;\n    }\n\n    if (!options.yes) {\n      const namespaceList = namespaces.join(\", \");\n      const confirmation = await prompt.confirm({\n        message: `This will truncate ALL tables in the following owned namespaces (external namespaces are excluded): ${namespaceList}. Continue?`,\n        default: false,\n      });\n      if (!confirmation) {\n        logger.info(\"Truncate cancelled.\");\n        return;\n      }\n    }\n\n    for (const namespace of namespaces) {\n      await truncateNamespace(workspaceId, namespace, client);\n    }\n    logger.success(\"Truncated all tables in all owned namespaces\");\n    return;\n  }\n\n  // Handle --namespace flag\n  if (hasNamespace) {\n    const namespace = assertDefined(options.namespace, \"namespace option missing\");\n\n    // Validate namespace exists in config and is not external\n    if (!namespaces.includes(namespace)) {\n      const dbConfig = config.db?.[namespace];\n      if (dbConfig && \"external\" in dbConfig) {\n        throw CLIError({\n          code: \"TAILORDB_NAMESPACE_EXTERNAL\",\n          message: `Namespace \"${namespace}\" is declared as external in this app's config and cannot be truncated from here.`,\n          suggestion: \"Run truncate from the app that owns the namespace.\",\n        });\n      }\n      throw CLIError({\n        code: \"TAILORDB_NAMESPACE_NOT_FOUND\",\n        message: `Namespace \"${namespace}\" not found in config. Available owned namespaces (external namespaces are excluded): ${namespaces.join(\", \")}`,\n      });\n    }\n\n    if (!options.yes) {\n      const confirmation = await prompt.confirm({\n        message: `This will truncate ALL tables in namespace \"${namespace}\". Continue?`,\n        default: false,\n      });\n      if (!confirmation) {\n        logger.info(\"Truncate cancelled.\");\n        return;\n      }\n    }\n\n    await truncateNamespace(workspaceId, namespace, client);\n    return;\n  }\n\n  // Handle specific tables\n  if (hasTables) {\n    const tableNames = assertDefined(options.tables, \"tables option missing\");\n\n    // Validate all tables exist and get their namespaces before confirmation\n    const tableNamespaceMap = await resolveTableNamespaces({\n      workspaceId,\n      namespaces,\n      tableNames,\n      client,\n    });\n    const notFoundTables = tableNames.filter((tableName) => !tableNamespaceMap.has(tableName));\n\n    if (notFoundTables.length > 0) {\n      throw CLIError({\n        code: \"TAILORDB_TABLE_NOT_FOUND\",\n        message: `The following tables were not found in any namespace: ${notFoundTables.join(\", \")}`,\n      });\n    }\n\n    if (!options.yes) {\n      const tableList = tableNames.join(\", \");\n      const confirmation = await prompt.confirm({\n        message: `This will truncate the following tables: ${tableList}. Continue?`,\n        default: false,\n      });\n      if (!confirmation) {\n        logger.info(\"Truncate cancelled.\");\n        return;\n      }\n    }\n\n    for (const tableName of tableNames) {\n      const namespace = tableNamespaceMap.get(tableName);\n      if (!namespace) {\n        continue;\n      }\n\n      await truncateSingleType(\n        {\n          workspaceId,\n          namespaceName: namespace,\n          tableName,\n        },\n        client,\n      );\n    }\n  }\n}\n\nexport const truncateCommand = defineAppCommand({\n  name: \"truncate\",\n  description: \"Truncate (delete all records from) TailorDB tables.\",\n  args: z.strictObject({\n    ...deploymentArgs,\n    ...confirmationArgs,\n    tables: arg(z.string().array().optional(), {\n      positional: true,\n      description: \"Table names to truncate\",\n    }),\n    all: arg(z.boolean().default(false), {\n      alias: \"a\",\n      description: \"Truncate all tables in all owned namespaces (excludes external namespaces)\",\n    }),\n    namespace: arg(z.string().optional(), {\n      alias: \"n\",\n      description: \"Truncate all tables in specified namespace\",\n    }),\n  }),\n  run: async (args) => {\n    await assertWritable({ profile: args.profile });\n    const tables = args.tables && args.tables.length > 0 ? args.tables : undefined;\n    await $truncate({\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      configPath: args.config,\n      all: args.all,\n      namespace: args.namespace,\n      tables,\n      yes: args.yes,\n    });\n  },\n});\n","import { z } from \"zod\";\nimport { type Order, paginationArgs, toPageDirection, workspaceArgs } from \"#/cli/shared/args\";\nimport { fetchPaged } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { type WorkflowListInfo, toWorkflowListInfo } from \"./transform\";\n\nexport interface ListWorkflowsOptions {\n  workspaceId?: string;\n  profile?: string;\n  order?: Order;\n  limit?: number;\n}\n\n/**\n * List workflows in the workspace and return CLI-friendly info.\n * @param options - Workflow listing options\n * @returns List of workflows\n */\nexport async function listWorkflows(options?: ListWorkflowsOptions): Promise<WorkflowListInfo[]> {\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options?.profile,\n    workspaceId: options?.workspaceId,\n  });\n\n  const pageDirection = toPageDirection(options?.order);\n  const workflows = await fetchPaged(\n    async (pageToken, pageSize) => {\n      const { workflows, nextPageToken } = await client.listWorkflows({\n        workspaceId,\n        pageToken,\n        pageSize,\n        pageDirection,\n      });\n      return [workflows, nextPageToken];\n    },\n    { limit: options?.limit },\n  );\n\n  return workflows.map(toWorkflowListInfo);\n}\n\nexport const listCommand = defineAppCommand({\n  name: \"list\",\n  description: \"List all workflows in the workspace.\",\n  args: z.strictObject({\n    ...workspaceArgs,\n    ...paginationArgs(),\n  }),\n  run: async (args) => {\n    const jsonOutput = logger.jsonMode;\n    const workflows = await listWorkflows({\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      order: args.order,\n      limit: args.limit,\n    });\n\n    if (workflows.length === 0) {\n      logger.info(\"No workflows found.\");\n      if (!jsonOutput) {\n        return;\n      }\n    }\n    logger.out(workflows);\n  },\n});\n","import { Code, ConnectError } from \"@connectrpc/connect\";\nimport { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { parseDuration, workspaceArgs } from \"#/cli/shared/args\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { waitArgs } from \"./args\";\nimport { getWorkflowExecution, printExecutionWithLogs } from \"./executions\";\nimport { waitForExecution, type WaitOptions } from \"./start\";\nimport { getWorkflowWaitFailure, type WorkflowWaitResult } from \"./waiter\";\n\nexport interface ResumeWorkflowOptions {\n  executionId: string;\n  workspaceId?: string;\n  profile?: string;\n  interval?: number;\n}\n\nexport interface ResumeWorkflowResultWithWait {\n  executionId: string;\n  wait: (options?: WaitOptions) => Promise<WorkflowWaitResult>;\n}\n\n/**\n * Resume a suspended workflow execution and return a handle to wait for completion.\n * @param options - Resume options\n * @returns Resume result with wait helper\n */\nexport async function resumeWorkflow(\n  options: ResumeWorkflowOptions,\n): Promise<ResumeWorkflowResultWithWait> {\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: options.profile,\n    workspaceId: options.workspaceId,\n  });\n\n  try {\n    const { executionId } = await client.resumeWorkflowExecution({\n      workspaceId,\n      executionId: options.executionId,\n    });\n\n    return {\n      executionId,\n      wait: (waitOptions?: WaitOptions) =>\n        waitForExecution({\n          client,\n          workspaceId,\n          executionId,\n          interval: options.interval ?? 3000,\n          timeout: waitOptions?.timeout,\n          until: waitOptions?.until,\n          showProgress: waitOptions?.showProgress,\n        }),\n    };\n  } catch (error) {\n    if (error instanceof ConnectError) {\n      if (error.code === Code.NotFound) {\n        throw CLIError({\n          code: \"WORKFLOW_EXECUTION_NOT_FOUND\",\n          message: `Execution '${options.executionId}' not found.`,\n          cause: error,\n        });\n      }\n      if (error.code === Code.FailedPrecondition) {\n        throw CLIError({\n          code: \"WORKFLOW_EXECUTION_NOT_RESUMABLE\",\n          message: `Execution '${options.executionId}' is not in a resumable state.`,\n          cause: error,\n        });\n      }\n    }\n    throw error;\n  }\n}\n\nexport const resumeCommand = defineAppCommand({\n  name: \"resume\",\n  description: \"Resume a failed or pending workflow execution.\",\n  args: z.strictObject({\n    ...workspaceArgs,\n    \"execution-id\": arg(z.string(), {\n      positional: true,\n      description: \"Failed execution ID\",\n    }),\n    ...waitArgs,\n  }),\n  run: async (args) => {\n    const jsonOutput = logger.jsonMode || args.json;\n    const { executionId, wait } = await resumeWorkflow({\n      executionId: args.executionId,\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      interval: parseDuration(args.interval),\n    });\n\n    if (!jsonOutput) {\n      logger.info(`Execution ID: ${executionId}`, { mode: \"stream\" });\n    }\n\n    if (args.wait) {\n      const result = await wait({\n        showProgress: !jsonOutput,\n        timeout: parseDuration(args.timeout),\n        until: args.until,\n      });\n      if (args.logs && !jsonOutput) {\n        const { execution } = await getWorkflowExecution({\n          executionId,\n          workspaceId: args[\"workspace-id\"],\n          profile: args.profile,\n          logs: true,\n        });\n        printExecutionWithLogs(execution);\n      } else if (args.logs) {\n        const { execution } = await getWorkflowExecution({\n          executionId,\n          workspaceId: args[\"workspace-id\"],\n          profile: args.profile,\n          logs: true,\n        });\n        logger.out({ ...result, jobDetails: execution.jobDetails });\n      } else {\n        logger.out(result);\n      }\n      const failure = getWorkflowWaitFailure(result, args.until);\n      if (failure) {\n        throw failure;\n      }\n    } else {\n      logger.out({ executionId });\n    }\n  },\n});\n","import { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { parseDuration, workspaceArgs } from \"#/cli/shared/args\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { workflowWaitControlArgs } from \"./args\";\nimport { getWorkflowExecution, printExecutionWithLogs } from \"./executions\";\nimport {\n  getWorkflowWaitFailure,\n  waitForWorkflowExecutionById,\n  type WaitWorkflowExecutionOptions,\n  type WorkflowWaitResult,\n} from \"./waiter\";\n\nexport interface WorkflowWaitOutput extends WorkflowWaitResult {\n  jobDetails?: Awaited<ReturnType<typeof getWorkflowExecution>>[\"execution\"][\"jobDetails\"];\n}\n\n/**\n * Wait for an existing workflow execution by ID.\n * @param options - Workflow wait options\n * @returns Workflow wait result\n */\nexport async function waitWorkflowExecution(\n  options: WaitWorkflowExecutionOptions,\n): Promise<WorkflowWaitResult> {\n  return await waitForWorkflowExecutionById({\n    ...options,\n    showProgress: options.showProgress ?? !logger.jsonMode,\n    trackJobs: options.trackJobs ?? true,\n  });\n}\n\n/**\n * Attach workflow job logs to a wait result when requested.\n * @param result - Workflow wait result\n * @param options - Workflow wait options\n * @returns Workflow wait result with optional job details\n */\nasync function addWorkflowLogsToWaitResult(\n  result: WorkflowWaitResult,\n  options: WaitWorkflowExecutionOptions,\n): Promise<WorkflowWaitOutput> {\n  const { execution } = await getWorkflowExecution({\n    executionId: options.executionId,\n    workspaceId: options.workspaceId,\n    profile: options.profile,\n    logs: true,\n  });\n\n  return {\n    ...result,\n    jobDetails: execution.jobDetails,\n  };\n}\n\nexport const waitCommand = defineAppCommand({\n  name: \"wait\",\n  description: \"Wait for a workflow execution.\",\n  examples: [\n    {\n      cmd: \"execution-id --until success --timeout 10m --json\",\n      desc: \"Wait for workflow success\",\n    },\n    {\n      cmd: \"execution-id --until suspended --timeout 6m --logs --json\",\n      desc: \"Wait for a workflow wait point\",\n    },\n    {\n      cmd: \"execution-id --until terminal\",\n      desc: \"Wait for success, failure, or suspension\",\n    },\n  ],\n  args: z.strictObject({\n    ...workspaceArgs,\n    \"execution-id\": arg(z.string(), {\n      positional: true,\n      description: \"Execution ID\",\n    }),\n    ...workflowWaitControlArgs,\n  }),\n  run: async (args) => {\n    const jsonOutput = logger.jsonMode || args.json;\n    const result = await waitWorkflowExecution({\n      executionId: args.executionId,\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      interval: parseDuration(args.interval),\n      timeout: parseDuration(args.timeout),\n      until: args.until,\n      showProgress: !jsonOutput,\n    });\n\n    const output: WorkflowWaitOutput = args.logs\n      ? await addWorkflowLogsToWaitResult(result, {\n          executionId: args.executionId,\n          workspaceId: args[\"workspace-id\"],\n          profile: args.profile,\n        })\n      : result;\n\n    if (!jsonOutput && output.jobDetails) {\n      printExecutionWithLogs({\n        id: output.id,\n        workflowName: output.workflowName,\n        status: output.status,\n        jobExecutions: output.jobExecutions,\n        startedAt: output.startedAt,\n        finishedAt: output.finishedAt,\n        jobDetails: output.jobDetails,\n      });\n    } else {\n      logger.out(output);\n    }\n\n    const failure = getWorkflowWaitFailure(result, args.until);\n    if (failure) {\n      throw failure;\n    }\n  },\n});\n","import {\n  type GetApplicationSchemaHealthResponse,\n  GetApplicationSchemaHealthResponse_ApplicationSchemaHealthStatus,\n} from \"@tailor-platform/tailor-proto/application_pb\";\nimport { ApplicationSchemaUpdateAttemptStatus } from \"@tailor-platform/tailor-proto/application_resource_pb\";\nimport { formatTimestamp } from \"#/cli/shared/format\";\nimport type { Application } from \"@tailor-platform/tailor-proto/application_resource_pb\";\n\nexport interface AppInfo {\n  name: string;\n  domain: string;\n  authNamespace: string;\n  createdAt: Date | null;\n  updatedAt: Date | null;\n}\n\nexport interface AppHealthInfo {\n  name: string;\n  status: string;\n  currentServingSchemaUpdatedAt: Date | null;\n  lastAttemptStatus: string;\n  lastAttemptAt: Date | null;\n  lastAttemptError: string;\n}\n\nconst statusToString = (\n  status: GetApplicationSchemaHealthResponse_ApplicationSchemaHealthStatus,\n): string => {\n  switch (status) {\n    case GetApplicationSchemaHealthResponse_ApplicationSchemaHealthStatus.OK:\n      return \"ok\";\n    case GetApplicationSchemaHealthResponse_ApplicationSchemaHealthStatus.COMPOSITION_ERROR:\n      return \"composition_error\";\n    default:\n      return \"unknown\";\n  }\n};\n\nconst attemptStatusToString = (status: ApplicationSchemaUpdateAttemptStatus): string => {\n  switch (status) {\n    case ApplicationSchemaUpdateAttemptStatus.SUCCEEDED:\n      return \"success\";\n    case ApplicationSchemaUpdateAttemptStatus.FAILED:\n      return \"failure\";\n    default:\n      return \"unknown\";\n  }\n};\n\nexport const appInfo = (app: Application): AppInfo => {\n  return {\n    name: app.name,\n    domain: app.domain,\n    authNamespace: app.authNamespace,\n    createdAt: formatTimestamp(app.createTime),\n    updatedAt: formatTimestamp(app.updateTime),\n  };\n};\n\nexport const appHealthInfo = (\n  name: string,\n  health: GetApplicationSchemaHealthResponse,\n): AppHealthInfo => {\n  const attempt = health.lastSchemaUpdateAttempt;\n  return {\n    name,\n    status: statusToString(health.status),\n    currentServingSchemaUpdatedAt: formatTimestamp(health.currentServingSchemaUpdateTime),\n    lastAttemptStatus: attempt ? attemptStatusToString(attempt.status) : \"N/A\",\n    lastAttemptAt: formatTimestamp(attempt?.attemptTime),\n    lastAttemptError: attempt?.error ?? \"\",\n  };\n};\n","import { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { workspaceArgs } from \"#/cli/shared/args\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { humanizeRelativeTime } from \"#/cli/shared/format\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { appHealthInfo, type AppHealthInfo } from \"./transform\";\n\n// strip unknown keys\nconst healthOptionsSchema = z.object({\n  workspaceId: z.uuid({ message: \"workspace-id must be a valid UUID\" }).optional(),\n  profile: z.string().optional(),\n  name: z.string().min(1, { message: \"name is required\" }),\n});\n\nexport type HealthOptions = z.input<typeof healthOptionsSchema>;\n\nasync function loadOptions(options: HealthOptions) {\n  const validated = parseOptions(healthOptionsSchema, options);\n\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: validated.profile,\n    workspaceId: validated.workspaceId,\n  });\n\n  return {\n    client,\n    workspaceId,\n    name: validated.name,\n  };\n}\n\n/**\n * Get application schema health status.\n * @param options - Health check options\n * @returns Application health information\n */\nexport async function getAppHealth(options: HealthOptions): Promise<AppHealthInfo> {\n  const { client, workspaceId, name } = await loadOptions(options);\n\n  const response = await client.getApplicationSchemaHealth({\n    workspaceId,\n    applicationName: name,\n  });\n\n  return appHealthInfo(name, response);\n}\n\nexport const healthCommand = defineAppCommand({\n  name: \"health\",\n  description: \"Check application schema health\",\n  args: z.strictObject({\n    ...workspaceArgs,\n    name: arg(z.string(), {\n      description: \"Application name\",\n      alias: \"n\",\n    }),\n  }),\n  run: async (args) => {\n    const health = await getAppHealth({\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      name: args.name,\n    });\n\n    const formattedHealth = args.json\n      ? health\n      : {\n          ...health,\n          currentServingSchemaUpdatedAt: humanizeRelativeTime(health.currentServingSchemaUpdatedAt),\n          lastAttemptAt: humanizeRelativeTime(health.lastAttemptAt),\n        };\n\n    logger.out(formattedHealth);\n  },\n});\n","import { z } from \"zod\";\nimport { orderArg, paginationArgs, toPageDirection, workspaceArgs } from \"#/cli/shared/args\";\nimport { fetchPaged } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { humanizeRelativeTime } from \"#/cli/shared/format\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { appInfo, type AppInfo } from \"./transform\";\n\n// strip unknown keys\nconst listAppsOptionsSchema = z.object({\n  workspaceId: z.uuid({ message: \"workspace-id must be a valid UUID\" }).optional(),\n  profile: z.string().optional(),\n  order: orderArg.optional(),\n  limit: z.coerce.number().int().nonnegative().optional(),\n});\n\nexport type ListAppsOptions = z.input<typeof listAppsOptionsSchema>;\n\nasync function loadOptions(options: ListAppsOptions) {\n  const validated = parseOptions(listAppsOptionsSchema, options);\n\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: validated.profile,\n    workspaceId: validated.workspaceId,\n  });\n\n  return {\n    client,\n    workspaceId,\n    order: validated.order,\n    limit: validated.limit,\n  };\n}\n\n/**\n * List applications in a workspace with an optional order and limit.\n * @param options - Application listing options\n * @returns List of applications\n */\nexport async function listApps(options: ListAppsOptions): Promise<AppInfo[]> {\n  const { client, workspaceId, order, limit } = await loadOptions(options);\n\n  const pageDirection = toPageDirection(order);\n  const applications = await fetchPaged(\n    async (pageToken, pageSize) => {\n      const { applications, nextPageToken } = await client.listApplications({\n        workspaceId,\n        pageToken,\n        pageSize,\n        pageDirection,\n      });\n      return [applications, nextPageToken];\n    },\n    { limit },\n  );\n\n  return applications.map(appInfo);\n}\n\nexport const listCommand = defineAppCommand({\n  name: \"list\",\n  description: \"List applications in a workspace\",\n  args: z.strictObject({\n    ...workspaceArgs,\n    ...paginationArgs(),\n  }),\n  run: async (args) => {\n    const jsonOutput = logger.jsonMode;\n    const apps = await listApps({\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      order: args.order,\n      limit: args.limit,\n    });\n\n    const formattedApps = jsonOutput\n      ? apps\n      : apps.map(({ updatedAt: _, createdAt, ...rest }) => ({\n          ...rest,\n          createdAt: humanizeRelativeTime(createdAt),\n        }));\n\n    logger.out(formattedApps);\n  },\n});\n","import { readPlatformConfig, writePlatformConfig } from \"#/cli/shared/context\";\n\n/**\n * Remove local profiles that point at workspaces which no longer exist.\n * @param workspaceIds - Ids of the deleted workspaces\n * @returns Names of the removed profiles\n */\nexport async function removeProfilesForWorkspaces(\n  workspaceIds: ReadonlySet<string>,\n): Promise<string[]> {\n  const pfConfig = await readPlatformConfig();\n  const removed = Object.entries(pfConfig.profiles)\n    .filter(([, profile]) => profile?.workspace_id && workspaceIds.has(profile.workspace_id))\n    .map(([name]) => name);\n  if (removed.length === 0) return removed;\n  for (const name of removed) {\n    delete pfConfig.profiles[name];\n  }\n  writePlatformConfig(pfConfig);\n  return removed;\n}\n","import { Code, ConnectError } from \"@connectrpc/connect\";\nimport { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { confirmationArgs } from \"#/cli/shared/args\";\nimport { initOperatorClient } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadAccessToken } from \"#/cli/shared/context\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { prompt } from \"#/cli/shared/prompt\";\nimport { assertWritable } from \"#/cli/shared/readonly-guard\";\nimport { removeProfilesForWorkspaces } from \"./profile-cleanup\";\nimport { resolveWorkspaceFolderName, workspaceDisplayName } from \"./transform\";\n\n// strip unknown keys\nconst deleteWorkspaceOptionsSchema = z.object({\n  workspaceId: z.uuid({ message: \"workspace-id must be a valid UUID\" }),\n});\n\nexport type DeleteWorkspaceOptions = z.input<typeof deleteWorkspaceOptionsSchema>;\n\nasync function loadOptions(options: DeleteWorkspaceOptions) {\n  // Validate options with zod schema\n  const validated = parseOptions(deleteWorkspaceOptionsSchema, options);\n\n  const accessToken = await loadAccessToken();\n  const client = await initOperatorClient(accessToken);\n\n  return {\n    client,\n    workspaceId: validated.workspaceId,\n  };\n}\n\n/**\n * Delete a workspace by ID.\n * @param options - Workspace deletion options\n * @returns Promise that resolves when deletion completes\n */\nexport async function deleteWorkspace(options: DeleteWorkspaceOptions): Promise<void> {\n  // Load and validate options\n  const { client, workspaceId } = await loadOptions(options);\n\n  // Delete workspace\n  await client.deleteWorkspace({\n    workspaceId,\n  });\n}\n\nexport const deleteCommand = defineAppCommand({\n  name: \"delete\",\n  description: \"Delete a Tailor Platform workspace.\",\n  args: z.strictObject({\n    \"workspace-id\": arg(z.string(), {\n      alias: \"w\",\n      description: \"Workspace ID\",\n    }),\n    ...confirmationArgs,\n  }),\n  run: async (args) => {\n    await assertWritable();\n    // Load and validate options\n    const { client, workspaceId } = await loadOptions({\n      workspaceId: args[\"workspace-id\"],\n    });\n\n    // Check if workspace exists\n    let workspace;\n    try {\n      workspace = await client.getWorkspace({\n        workspaceId,\n      });\n    } catch (error) {\n      if (error instanceof ConnectError && error.code === Code.NotFound) {\n        throw CLIError({\n          code: \"WORKSPACE_NOT_FOUND\",\n          message: `Workspace \"${workspaceId}\" not found.`,\n          cause: error,\n        });\n      }\n      throw error;\n    }\n\n    const workspaceResource = workspace.workspace;\n    const workspaceName = workspaceResource?.name ?? workspaceId;\n    const folderName = workspaceResource\n      ? await resolveWorkspaceFolderName(client, workspaceResource)\n      : \"\";\n    const displayName = workspaceDisplayName({ name: workspaceName, folderName });\n\n    // Confirm deletion if not forced\n    if (!args.yes) {\n      const confirmation = await prompt.text({\n        message: `Enter the workspace name to confirm deletion (${displayName}):`,\n      });\n      if (confirmation !== workspaceName && confirmation !== displayName) {\n        logger.info(\"Workspace deletion cancelled.\");\n        return;\n      }\n    }\n\n    // Delete workspace\n    try {\n      await client.deleteWorkspace({\n        workspaceId,\n      });\n    } catch (error) {\n      // A failed call can still have removed the workspace server-side (a timeout after the\n      // server committed), so the local profile is cleaned up before the error propagates.\n      await removeProfilesForWorkspaces(new Set([workspaceId]));\n      throw error;\n    }\n\n    const profilesToDelete = await removeProfilesForWorkspaces(new Set([workspaceId]));\n\n    // Show success message\n    if (profilesToDelete.length > 0) {\n      logger.success(\n        `Workspace \"${displayName}\" and ${profilesToDelete.length} associated profile(s) deleted successfully.`,\n      );\n    } else {\n      logger.success(`Workspace \"${displayName}\" deleted successfully.`);\n    }\n  },\n});\n","import { z } from \"zod\";\nimport { workspaceArgs } from \"#/cli/shared/args\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport { humanizeRelativeTime } from \"#/cli/shared/format\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { fetchWorkspaceExpiry, reportedExpiry, type ReportedExpiry } from \"./expiry\";\nimport {\n  workspaceDetailsWithFolderName,\n  workspaceNameTransformer,\n  type WorkspaceDetails,\n} from \"./transform\";\n\n// strip unknown keys\nconst getWorkspaceOptionsSchema = z.object({\n  workspaceId: z.uuid({ message: \"workspace-id must be a valid UUID\" }).optional(),\n  profile: z.string().optional(),\n});\n\nexport type GetWorkspaceOptions = z.input<typeof getWorkspaceOptionsSchema>;\n\nasync function loadOptions(options: GetWorkspaceOptions) {\n  const validated = parseOptions(getWorkspaceOptionsSchema, options);\n\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: validated.profile,\n    workspaceId: validated.workspaceId,\n  });\n\n  return {\n    client,\n    workspaceId,\n  };\n}\n\n/** A workspace's details, plus the prune expiry it records. */\nexport type WorkspaceDetailsWithExpiry = WorkspaceDetails & { expiresAt: ReportedExpiry };\n\n/**\n * Get detailed information about a workspace.\n * @param options - Workspace get options\n * @returns Workspace details\n */\nexport async function getWorkspace(\n  options: GetWorkspaceOptions,\n): Promise<WorkspaceDetailsWithExpiry> {\n  const { client, workspaceId } = await loadOptions(options);\n\n  const response = await client.getWorkspace({\n    workspaceId,\n  });\n\n  if (!response.workspace) {\n    throw CLIError({\n      code: \"WORKSPACE_NOT_FOUND\",\n      message: `Workspace \"${workspaceId}\" not found.`,\n    });\n  }\n\n  const [details, expiry] = await Promise.all([\n    workspaceDetailsWithFolderName(client, response.workspace),\n    fetchWorkspaceExpiry(client, workspaceId, new Date()),\n  ]);\n\n  return { ...details, expiresAt: reportedExpiry(expiry) };\n}\n\nexport const getCommand = defineAppCommand({\n  name: \"get\",\n  description: \"Show detailed information about a workspace\",\n  args: z.strictObject({\n    ...workspaceArgs,\n  }),\n  run: async (args) => {\n    const workspace = await getWorkspace({\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n    });\n\n    const formattedWorkspace = args.json\n      ? workspace\n      : {\n          ...workspace,\n          createdAt: humanizeRelativeTime(workspace.createdAt),\n          updatedAt: humanizeRelativeTime(workspace.updatedAt),\n        };\n\n    logger.out(formattedWorkspace, {\n      display: { name: workspaceNameTransformer, folderName: null },\n    });\n  },\n});\n","import { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { confirmationArgs } from \"#/cli/shared/args\";\nimport { initOperatorClient } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { loadAccessToken } from \"#/cli/shared/context\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { prompt } from \"#/cli/shared/prompt\";\nimport { assertWritable } from \"#/cli/shared/readonly-guard\";\n\n// strip unknown keys\nconst restoreWorkspaceOptionsSchema = z.object({\n  workspaceId: z.uuid({ message: \"workspace-id must be a valid UUID\" }),\n});\n\nexport type RestoreWorkspaceOptions = z.input<typeof restoreWorkspaceOptionsSchema>;\n\nasync function loadOptions(options: RestoreWorkspaceOptions) {\n  const validated = parseOptions(restoreWorkspaceOptionsSchema, options);\n\n  const accessToken = await loadAccessToken();\n  const client = await initOperatorClient(accessToken);\n\n  return {\n    client,\n    workspaceId: validated.workspaceId,\n  };\n}\n\n/**\n * Restore a deleted workspace by ID.\n * @param options - Workspace restore options\n * @returns Promise that resolves when restoration completes\n */\nexport async function restoreWorkspace(options: RestoreWorkspaceOptions): Promise<void> {\n  const { client, workspaceId } = await loadOptions(options);\n\n  await client.restoreWorkspace({\n    workspaceId,\n  });\n}\n\nexport const restoreCommand = defineAppCommand({\n  name: \"restore\",\n  description: \"Restore a deleted workspace\",\n  args: z.strictObject({\n    \"workspace-id\": arg(z.string(), {\n      alias: \"w\",\n      description: \"Workspace ID\",\n    }),\n    ...confirmationArgs,\n  }),\n  run: async (args) => {\n    await assertWritable();\n    const { client, workspaceId } = await loadOptions({\n      workspaceId: args[\"workspace-id\"],\n    });\n\n    if (!args.yes) {\n      const confirmation = await prompt.text({\n        message: `Are you sure you want to restore workspace \"${workspaceId}\"? (yes/no):`,\n      });\n      if (confirmation !== \"yes\") {\n        logger.info(\"Workspace restoration cancelled.\");\n        return;\n      }\n    }\n\n    await client.restoreWorkspace({\n      workspaceId,\n    });\n\n    logger.success(`Workspace \"${workspaceId}\" restored successfully.`);\n  },\n});\n","import { WorkspacePlatformUserRole } from \"@tailor-platform/tailor-proto/workspace_resource_pb\";\nimport { CLIError } from \"#/cli/shared/errors\";\nimport type { WorkspacePlatformUser } from \"@tailor-platform/tailor-proto/workspace_resource_pb\";\n\nexport interface UserInfo {\n  userId: string;\n  email: string;\n  role: string;\n}\n\nconst roleToString = (role: WorkspacePlatformUserRole): string => {\n  switch (role) {\n    case WorkspacePlatformUserRole.ADMIN:\n      return \"admin\";\n    case WorkspacePlatformUserRole.EDITOR:\n      return \"editor\";\n    case WorkspacePlatformUserRole.VIEWER:\n      return \"viewer\";\n    default:\n      return \"unknown\";\n  }\n};\n\nexport const stringToRole = (role: string): WorkspacePlatformUserRole => {\n  switch (role.toLowerCase()) {\n    case \"admin\":\n      return WorkspacePlatformUserRole.ADMIN;\n    case \"editor\":\n      return WorkspacePlatformUserRole.EDITOR;\n    case \"viewer\":\n      return WorkspacePlatformUserRole.VIEWER;\n    default:\n      throw CLIError({\n        code: \"WORKSPACE_ROLE_INVALID\",\n        message: `Invalid role: ${role}. Valid roles: admin, editor, viewer`,\n      });\n  }\n};\n\nexport const userInfo = (user: WorkspacePlatformUser): UserInfo => {\n  return {\n    userId: user.platformUser?.userId ?? \"\",\n    email: user.platformUser?.email ?? \"\",\n    role: roleToString(user.role),\n  };\n};\n\nexport const validRoles = [\"admin\", \"editor\", \"viewer\"] as const;\n","import { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { workspaceArgs } from \"#/cli/shared/args\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { assertWritable } from \"#/cli/shared/readonly-guard\";\nimport { stringToRole, validRoles } from \"./transform\";\n\n// strip unknown keys\nconst inviteUserOptionsSchema = z.object({\n  workspaceId: z.uuid({ message: \"workspace-id must be a valid UUID\" }).optional(),\n  profile: z.string().optional(),\n  email: z.email({ message: \"email must be a valid email address\" }),\n  role: z.enum(validRoles, { message: `role must be one of: ${validRoles.join(\", \")}` }),\n});\n\nexport type InviteUserOptions = z.input<typeof inviteUserOptionsSchema>;\n\nasync function loadOptions(options: InviteUserOptions) {\n  const validated = parseOptions(inviteUserOptionsSchema, options);\n\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: validated.profile,\n    workspaceId: validated.workspaceId,\n  });\n\n  return {\n    client,\n    workspaceId,\n    email: validated.email,\n    role: stringToRole(validated.role),\n  };\n}\n\n/**\n * Invite a user to a workspace.\n * @param options - User invite options\n * @returns Promise that resolves when invitation is sent\n */\nexport async function inviteUser(options: InviteUserOptions): Promise<void> {\n  const { client, workspaceId, email, role } = await loadOptions(options);\n\n  await client.inviteWorkspacePlatformUser({\n    workspaceId,\n    email,\n    role,\n  });\n}\n\nexport const inviteCommand = defineAppCommand({\n  name: \"invite\",\n  description: \"Invite a user to a workspace\",\n  args: z.strictObject({\n    ...workspaceArgs,\n    email: arg(z.email(), {\n      description: \"Email address of the user to invite\",\n    }),\n    role: arg(z.enum(validRoles), {\n      description: `Role to assign (${validRoles.join(\", \")})`,\n      alias: \"r\",\n    }),\n  }),\n  run: async (args) => {\n    await assertWritable({ profile: args.profile });\n    await inviteUser({\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      email: args.email,\n      role: args.role,\n    });\n\n    logger.success(`User \"${args.email}\" invited successfully with role \"${args.role}\".`);\n  },\n});\n","import { z } from \"zod\";\nimport { orderArg, paginationArgs, toPageDirection, workspaceArgs } from \"#/cli/shared/args\";\nimport { fetchPaged } from \"#/cli/shared/client\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { userInfo, type UserInfo } from \"./transform\";\n\n// strip unknown keys\nconst listUsersOptionsSchema = z.object({\n  workspaceId: z.uuid({ message: \"workspace-id must be a valid UUID\" }).optional(),\n  profile: z.string().optional(),\n  order: orderArg.optional(),\n  limit: z.coerce.number().int().nonnegative().optional(),\n});\n\nexport type ListUsersOptions = z.input<typeof listUsersOptionsSchema>;\n\nasync function loadOptions(options: ListUsersOptions) {\n  const validated = parseOptions(listUsersOptionsSchema, options);\n\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: validated.profile,\n    workspaceId: validated.workspaceId,\n  });\n\n  return {\n    client,\n    workspaceId,\n    order: validated.order,\n    limit: validated.limit,\n  };\n}\n\n/**\n * List users in a workspace with an optional order and limit.\n * @param options - User listing options\n * @returns List of workspace users\n */\nexport async function listUsers(options: ListUsersOptions): Promise<UserInfo[]> {\n  const { client, workspaceId, order, limit } = await loadOptions(options);\n\n  const pageDirection = toPageDirection(order);\n  const users = await fetchPaged(\n    async (pageToken, pageSize) => {\n      const { workspacePlatformUsers, nextPageToken } = await client.listWorkspacePlatformUsers({\n        workspaceId,\n        pageToken,\n        pageSize,\n        pageDirection,\n      });\n      return [workspacePlatformUsers, nextPageToken];\n    },\n    { limit },\n  );\n\n  return users.map(userInfo);\n}\n\nexport const listCommand = defineAppCommand({\n  name: \"list\",\n  description: \"List users in a workspace\",\n  args: z.strictObject({\n    ...workspaceArgs,\n    ...paginationArgs(),\n  }),\n  run: async (args) => {\n    const users = await listUsers({\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      order: args.order,\n      limit: args.limit,\n    });\n\n    logger.out(users);\n  },\n});\n","import { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { confirmationArgs, workspaceArgs } from \"#/cli/shared/args\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { prompt } from \"#/cli/shared/prompt\";\nimport { assertWritable } from \"#/cli/shared/readonly-guard\";\n\n// strip unknown keys\nconst removeUserOptionsSchema = z.object({\n  workspaceId: z.uuid({ message: \"workspace-id must be a valid UUID\" }).optional(),\n  profile: z.string().optional(),\n  email: z.email({ message: \"email must be a valid email address\" }),\n});\n\nexport type RemoveUserOptions = z.input<typeof removeUserOptionsSchema>;\n\nasync function loadOptions(options: RemoveUserOptions) {\n  const validated = parseOptions(removeUserOptionsSchema, options);\n\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: validated.profile,\n    workspaceId: validated.workspaceId,\n  });\n\n  return {\n    client,\n    workspaceId,\n    email: validated.email,\n  };\n}\n\n/**\n * Remove a user from a workspace.\n * @param options - User remove options\n * @returns Promise that resolves when removal completes\n */\nexport async function removeUser(options: RemoveUserOptions): Promise<void> {\n  const { client, workspaceId, email } = await loadOptions(options);\n\n  await client.removeWorkspacePlatformUser({\n    workspaceId,\n    email,\n  });\n}\n\nexport const removeCommand = defineAppCommand({\n  name: \"remove\",\n  description: \"Remove a user from a workspace\",\n  args: z.strictObject({\n    ...workspaceArgs,\n    email: arg(z.email(), {\n      description: \"Email address of the user to remove\",\n    }),\n    ...confirmationArgs,\n  }),\n  run: async (args) => {\n    await assertWritable({ profile: args.profile });\n    if (!args.yes) {\n      const confirmation = await prompt.text({\n        message: `Are you sure you want to remove user \"${args.email}\" from the workspace? (yes/no):`,\n      });\n      if (confirmation !== \"yes\") {\n        logger.info(\"User removal cancelled.\");\n        return;\n      }\n    }\n\n    await removeUser({\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      email: args.email,\n    });\n\n    logger.success(`User \"${args.email}\" removed from workspace.`);\n  },\n});\n","import { arg } from \"@politty/zod\";\nimport { z } from \"zod\";\nimport { workspaceArgs } from \"#/cli/shared/args\";\nimport { defineAppCommand } from \"#/cli/shared/command\";\nimport { logger } from \"#/cli/shared/logger\";\nimport { loadOperatorWorkspaceContext } from \"#/cli/shared/operator-context\";\nimport { parseOptions } from \"#/cli/shared/parse-options\";\nimport { assertWritable } from \"#/cli/shared/readonly-guard\";\nimport { stringToRole, validRoles } from \"./transform\";\n\n// strip unknown keys\nconst updateUserOptionsSchema = z.object({\n  workspaceId: z.uuid({ message: \"workspace-id must be a valid UUID\" }).optional(),\n  profile: z.string().optional(),\n  email: z.email({ message: \"email must be a valid email address\" }),\n  role: z.enum(validRoles, { message: `role must be one of: ${validRoles.join(\", \")}` }),\n});\n\nexport type UpdateUserOptions = z.input<typeof updateUserOptionsSchema>;\n\nasync function loadOptions(options: UpdateUserOptions) {\n  const validated = parseOptions(updateUserOptionsSchema, options);\n\n  const { client, workspaceId } = await loadOperatorWorkspaceContext({\n    profile: validated.profile,\n    workspaceId: validated.workspaceId,\n  });\n\n  return {\n    client,\n    workspaceId,\n    email: validated.email,\n    role: stringToRole(validated.role),\n  };\n}\n\n/**\n * Update a user's role in a workspace.\n * @param options - User update options\n * @returns Promise that resolves when update completes\n */\nexport async function updateUser(options: UpdateUserOptions): Promise<void> {\n  const { client, workspaceId, email, role } = await loadOptions(options);\n\n  await client.updateWorkspacePlatformUser({\n    workspaceId,\n    email,\n    role,\n  });\n}\n\nexport const updateCommand = defineAppCommand({\n  name: \"update\",\n  description: \"Update a user's role in a workspace\",\n  args: z.strictObject({\n    ...workspaceArgs,\n    email: arg(z.email(), {\n      description: \"Email address of the user to update\",\n    }),\n    role: arg(z.enum(validRoles), {\n      description: `New role to assign (${validRoles.join(\", \")})`,\n      alias: \"r\",\n    }),\n  }),\n  run: async (args) => {\n    await assertWritable({ profile: args.profile });\n    await updateUser({\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      email: args.email,\n      role: args.role,\n    });\n\n    logger.success(`User \"${args.email}\" updated to role \"${args.role}\".`);\n  },\n});\n","import * as fs from \"node:fs\";\nimport * as path from \"pathe\";\nimport * as rolldown from \"rolldown\";\nimport { createBundleLog } from \"#/cli/shared/bundle-log\";\nimport { getDistDir } from \"#/cli/shared/dist-dir\";\nimport { platformBundleDefinePlugin } from \"#/cli/shared/platform-bundle-plugin\";\nimport { resolveTSConfigWithFallback } from \"#/cli/shared/resolve-tsconfig\";\nimport { createTsconfigPathsPlugin } from \"#/cli/shared/tsconfig-paths-plugin\";\nimport { createGeneratedEntryResolverPlugin } from \"#/cli/shared/virtual-entry\";\nimport ml from \"#/utils/multiline\";\nimport type { QueryEngine } from \"#/cli/query/types\";\n\nfunction createSqlEntry(): string {\n  return ml /* ts */ `\n    import { Kysely, sql, TailordbDialect } from \"@tailor-platform/sdk/kysely\";\n\n    type QueryInput = {\n      namespace: string;\n      queries: string[];\n    };\n\n    function getDB(namespace: string) {\n      const client = new tailordb.Client({ namespace });\n      return new Kysely<Record<string, Record<string, unknown>>>({\n        dialect: new TailordbDialect(client),\n      });\n    }\n\n    export async function main(input: QueryInput) {\n      const db = getDB(input.namespace);\n      const results = [];\n      for (const query of input.queries) {\n        const result = await sql.raw(query).execute(db);\n        const rows = result.rows ?? [];\n        results.push({ rows, rowCount: rows.length });\n      }\n      if (results.length === 1) {\n        return results[0];\n      }\n      return results;\n    }\n  `;\n}\n\nfunction createGqlEntry(): string {\n  return ml /* ts */ `\n    type QueryInput = {\n      endpoint: string;\n      accessToken: string;\n      query: string;\n    };\n\n    export async function main(input: QueryInput) {\n      const response = await fetch(input.endpoint, {\n        method: \"POST\",\n        headers: {\n          \"Content-Type\": \"application/json\",\n          Authorization: \\`Bearer \\${input.accessToken}\\`,\n        },\n        body: JSON.stringify({\n          query: input.query,\n        }),\n      });\n      if (!response.ok) {\n        let message = \\`HTTP \\${response.status}\\`;\n        try {\n          const errorJson = await response.json();\n          if (errorJson && typeof errorJson === \"object\" && \"message\" in errorJson) {\n            message = String(errorJson.message);\n          }\n        } catch {\n          // Keep default HTTP status message when response body is not JSON.\n        }\n        throw new Error(\\`GraphQL request failed: \\${message}\\`);\n      }\n\n      const json = await response.json();\n      return json;\n    }\n  `;\n}\n\n/**\n * Bundle a query executor script for server-side execution.\n * @param engine - Query engine type\n * @param baseDir - Directory to resolve the bundler's tsconfig against\n * @returns Bundled code\n */\nexport async function bundleQueryScript(engine: QueryEngine, baseDir: string): Promise<string> {\n  const outputDir = path.resolve(getDistDir(), \"query\");\n  fs.mkdirSync(outputDir, { recursive: true });\n\n  const entryPath = path.join(outputDir, `query_${engine}.entry.ts`);\n  const entryContent = engine === \"sql\" ? createSqlEntry() : createGqlEntry();\n  fs.writeFileSync(entryPath, entryContent);\n\n  const tsconfig = await resolveTSConfigWithFallback(baseDir);\n\n  const bundleLog = createBundleLog({ tsconfig });\n  const result = await rolldown.build({\n    plugins: [\n      createGeneratedEntryResolverPlugin(entryPath, baseDir),\n      createTsconfigPathsPlugin(),\n      platformBundleDefinePlugin,\n    ],\n    input: entryPath,\n    write: false,\n    output: {\n      format: \"esm\",\n      sourcemap: false,\n      minify: false,\n      codeSplitting: false,\n      globals: {\n        tailordb: \"tailordb\",\n      },\n    },\n    external: engine === \"sql\" ? [\"tailordb\"] : [],\n    resolve: {\n      conditionNames: [\"node\", \"import\"],\n    },\n    tsconfig,\n    treeshake: {\n      moduleSideEffects: false,\n      annotations: true,\n      unknownGlobalSideEffects: false,\n    },\n    ...bundleLog.options,\n  } as rolldown.BuildOptions);\n  bundleLog.assertAllResolved();\n\n  return result.output[0].code;\n}\n","import { CLIError } from \"../shared/errors\";\nimport type { QueryEngine } from \"./types\";\n\nfunction toErrorMessage(error: unknown): string {\n  if (error instanceof Error) {\n    return error.message;\n  }\n  return String(error);\n}\n\ntype MapQueryExecutionErrorArgs = {\n  error: unknown;\n  engine: QueryEngine;\n  namespace: string | undefined;\n  machineUser?: string;\n};\n\n/**\n * Maps errors from query execution to user-friendly CLI errors with suggestions when possible.\n * @param args - The error and context information for mapping\n * @returns A CLIError with a user-friendly message\n */\nexport function mapQueryExecutionError(args: MapQueryExecutionErrorArgs): Error {\n  const message = toErrorMessage(args.error);\n\n  if (message.includes(\"machine user does not exist\")) {\n    return CLIError({\n      code: \"not_found\",\n      message: `Machine user '${args.machineUser ?? \"unknown\"}' was not found.`,\n      suggestion: \"Run `tailor machineuser list` and use an existing name.\",\n    });\n  }\n\n  if (\n    args.engine === \"sql\" &&\n    message.includes(\n      \"sqlaccess error: failed to fetch schema: query returned an unexpected number of rows\",\n    )\n  ) {\n    return CLIError({\n      code: \"invalid_namespace\",\n      message: `Failed to load TailorDB schema for namespace '${args.namespace}'.`,\n      suggestion:\n        \"Ensure the query references TailorDB tables from a single namespace and re-apply if needed.\",\n    });\n  }\n\n  if (args.engine === \"sql\" && message.includes(\"sqlaccess error: failed to parse:\")) {\n    const parserReason = message\n      .split(\"sqlaccess error: failed to parse:\")\n      .at(1)\n      ?.split(\"\\n\")\n      .at(0)\n      ?.trim();\n\n    return CLIError({\n      code: \"invalid_sql\",\n      message: \"SQL parse error.\",\n      suggestion: parserReason ?? \"The SQL query contains unsupported syntax.\",\n    });\n  }\n\n  return args.error instanceof Error ? args.error : new Error(message);\n}\n","import { parse } from \"@0no-co/graphql.web\";\n\n/**\n * Return true when the buffered GraphQL input parses as a complete document.\n * @param input - Buffered GraphQL input\n * @returns True when the GraphQL document is complete and ready to execute\n */\nexport function isGraphQLInputComplete(input: string): boolean {\n  if (input.trim().length === 0) {\n    return false;\n  }\n\n  try {\n    parse(input);\n    return true;\n  } catch {\n    return false;\n  }\n}\n","import { assertDefined } from \"#/utils/assert\";\n\n/**\n * Return true when the buffered SQL input ends with a real statement terminator.\n * @param input - Buffered SQL input\n * @returns True when the SQL statement is complete and ready to execute\n */\nexport function isSqlInputComplete(input: string): boolean {\n  let inSingleQuote = false;\n  let inDoubleQuote = false;\n  let inLineComment = false;\n  let blockCommentDepth = 0;\n  let dollarQuoteTag: string | null = null;\n  let lastSignificantTokenWasSemicolon = false;\n\n  for (let i = 0; i < input.length; i += 1) {\n    const char = assertDefined(input[i], `character at index ${i} missing`);\n    const next = input[i + 1];\n\n    if (inLineComment) {\n      if (char === \"\\n\") {\n        inLineComment = false;\n      }\n      continue;\n    }\n\n    if (blockCommentDepth > 0) {\n      if (char === \"/\" && next === \"*\") {\n        blockCommentDepth += 1;\n        i += 1;\n        continue;\n      }\n      if (char === \"*\" && next === \"/\") {\n        blockCommentDepth -= 1;\n        i += 1;\n      }\n      continue;\n    }\n\n    if (dollarQuoteTag != null) {\n      if (input.startsWith(dollarQuoteTag, i)) {\n        i += dollarQuoteTag.length - 1;\n        dollarQuoteTag = null;\n      }\n      continue;\n    }\n\n    if (inSingleQuote) {\n      if (char === \"'\" && next === \"'\") {\n        i += 1;\n        continue;\n      }\n      if (char === \"'\") {\n        inSingleQuote = false;\n      }\n      continue;\n    }\n\n    if (inDoubleQuote) {\n      if (char === '\"' && next === '\"') {\n        i += 1;\n        continue;\n      }\n      if (char === '\"') {\n        inDoubleQuote = false;\n      }\n      continue;\n    }\n\n    if (char === \"-\" && next === \"-\") {\n      inLineComment = true;\n      i += 1;\n      continue;\n    }\n\n    if (char === \"/\" && next === \"*\") {\n      blockCommentDepth = 1;\n      i += 1;\n      continue;\n    }\n\n    if (char === \"'\") {\n      lastSignificantTokenWasSemicolon = false;\n      inSingleQuote = true;\n      continue;\n    }\n\n    if (char === '\"') {\n      lastSignificantTokenWasSemicolon = false;\n      inDoubleQuote = true;\n      continue;\n    }\n\n    if (char === \"$\") {\n      const rest = input.slice(i);\n      const match = rest.match(/^\\$[A-Za-z_][A-Za-z0-9_]*\\$/) ?? rest.match(/^\\$\\$/);\n      if (match != null) {\n        lastSignificantTokenWasSemicolon = false;\n        dollarQuoteTag = match[0];\n        i += match[0].length - 1;\n        continue;\n      }\n    }\n\n    if (char === \";\") {\n      lastSignificantTokenWasSemicolon = true;\n      continue;\n    }\n\n    if (!/\\s/.test(char)) {\n      lastSignificantTokenWasSemicolon = false;\n    }\n  }\n\n  return (\n    lastSignificantTokenWasSemicolon &&\n    !inSingleQuote &&\n    !inDoubleQuote &&\n    blockCommentDepth === 0 &&\n    dollarQuoteTag == null\n  );\n}\n","import { astVisitor, parse, type From, type Statement } from \"pgsql-ast-parser\";\n\n/**\n * Extract TailorDB table names from SQL query.\n * @param query - SQL query\n * @returns Table names referenced by query\n */\nexport function extractTableNamesFromSql(query: string): string[] {\n  let statements: Statement[];\n  try {\n    statements = parse(query);\n  } catch (error) {\n    const message = error instanceof Error ? error.message : String(error);\n    throw new Error(\n      `SQL parse error: ${message}\\nIf your table name is a reserved keyword (e.g. User), wrap it in double quotes: SELECT * FROM \"User\"`,\n      { cause: error },\n    );\n  }\n  const tableNames = new Set<string>();\n\n  const visitor = astVisitor((mapper) => ({\n    tableRef: (tableRef) => {\n      tableNames.add(tableRef.name);\n\n      mapper.super().tableRef(tableRef);\n      return tableRef;\n    },\n  }));\n\n  for (const statement of statements) {\n    visitor.statement(statement);\n  }\n\n  return [...tableNames];\n}\n\nfunction collectAliasMap(fromClauses: From[]): Map<string, string> {\n  const aliasMap = new Map<string, string>();\n\n  for (const from of fromClauses) {\n    if (from.type === \"table\") {\n      const tableName = from.name.name;\n      const alias = from.name.alias ?? tableName;\n      aliasMap.set(alias, tableName);\n    }\n  }\n\n  return aliasMap;\n}\n\nexport type ColumnSlot =\n  | { type: \"explicit\"; name: string }\n  | { type: \"wildcard\"; tableNames: string[] };\n\n/**\n * Extract the column template from a SQL query's SELECT clause.\n * Returns an ordered list of column slots representing explicit columns\n * and wildcard expansions with their resolved type names.\n *\n * Only inspects the top-level SELECT statement, not subqueries.\n * TailorDB's sqlaccess does not currently support subqueries in FROM clauses,\n * but we intentionally avoid recursing into nested SELECTs to prevent\n * false positives if the parser accepts such queries.\n * @param query - SQL query\n * @returns Column slots if wildcards are present, null otherwise\n */\nexport function extractColumnTemplate(query: string): ColumnSlot[] | null {\n  try {\n    const statements = parse(query);\n\n    for (const statement of statements) {\n      if (statement.type !== \"select\" || !statement.columns) {\n        continue;\n      }\n\n      const aliasMap = collectAliasMap(statement.from ?? []);\n      const slots: ColumnSlot[] = [];\n      let hasWildcard = false;\n\n      for (const column of statement.columns) {\n        if (column.expr.type === \"ref\" && column.expr.name === \"*\") {\n          hasWildcard = true;\n          if (column.expr.table) {\n            const tableName = aliasMap.get(column.expr.table.name);\n            slots.push({ type: \"wildcard\", tableNames: tableName ? [tableName] : [] });\n          } else {\n            slots.push({ type: \"wildcard\", tableNames: [...new Set(aliasMap.values())] });\n          }\n        } else {\n          const name = column.alias?.name ?? (column.expr.type === \"ref\" ? column.expr.name : null);\n          if (name) {\n            slots.push({ type: \"explicit\", name });\n          }\n        }\n      }\n\n      return hasWildcard ? slots : null;\n    }\n\n    return null;\n  } catch {\n    return null;\n  }\n}\n","import { pathToFileURL } from \"node:url\";\nimport * as path from \"pathe\";\nimport { loadFilesWithIgnores } from \"#/cli/services/file-loader\";\nimport { stripTailorDBTypeBuilderHelpers } from \"#/parser/service/tailordb/builder-helpers\";\nimport { TailorDBTypeSchema } from \"#/parser/service/tailordb/index\";\nimport type { LoadedConfig } from \"#/cli/shared/config-loader\";\n\ntype TypeFieldOrderMap = Map<string, string[]>;\n\n/**\n * Load field definition order for all TailorDB tables in a namespace.\n * @param config - Loaded application configuration\n * @param namespace - TailorDB namespace name\n * @returns Map of table name to field names in definition order\n */\nexport async function loadTypeFieldOrder(\n  config: LoadedConfig,\n  namespace: string,\n): Promise<TypeFieldOrderMap> {\n  const fieldOrder: TypeFieldOrderMap = new Map();\n  const dbConfig = config.db?.[namespace];\n\n  if (!dbConfig || !(\"files\" in dbConfig) || dbConfig.files.length === 0) {\n    return fieldOrder;\n  }\n\n  const baseDir = path.dirname(config.path);\n  const typeFiles = loadFilesWithIgnores(dbConfig, baseDir);\n\n  await Promise.all(\n    typeFiles.map(async (typeFile) => {\n      try {\n        const module = await import(pathToFileURL(typeFile).href);\n\n        for (const exportedValue of Object.values(module)) {\n          const result = TailorDBTypeSchema.safeParse(\n            stripTailorDBTypeBuilderHelpers(exportedValue),\n          );\n          if (!result.success) {\n            continue;\n          }\n\n          fieldOrder.set(result.data.name, Object.keys(result.data.fields));\n        }\n      } catch {\n        // Skip files that fail to load\n      }\n    }),\n  );\n\n  return fieldOrder;\n}\n","export const queryEngines = [\"sql\", \"gql\"] as const;\n\nexport type QueryEngine = (typeof queryEngines)[number];\n","import * as fs from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { create } from \"@bufbuild/protobuf\";\nimport { arg } from \"@politty/zod\";\nimport {\n  AuthInvokerSchema,\n  type AuthInvoker,\n  type MachineUser,\n} from \"@tailor-platform/tailor-proto/auth_resource_pb\";\nimport { createPrompt } from \"@toiroakr/read-multiline\";\nimport * as path from \"pathe\";\nimport { parse as parseSql } from \"pgsql-ast-parser\";\nimport { xdgConfig } from \"xdg-basedir\";\nimport { z } from \"zod\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { bundleQueryScript } from \"../bundler/query/query-bundler\";\nimport { deploymentArgs, resolveMachineUserInputSource } from \"../shared/args\";\nimport { fetchMachineUserToken, initOperatorClient } from \"../shared/client\";\nimport { defineAppCommand } from \"../shared/command\";\nimport { extractAllNamespaces } from \"../shared/config\";\nimport { loadConfig, type LoadedConfig } from \"../shared/config-loader\";\nimport { loadAccessToken, loadMachineUserName, loadWorkspaceId } from \"../shared/context\";\nimport { getEditorCommand, openInEditor } from \"../shared/editor\";\nimport { isCLIError } from \"../shared/errors\";\nimport { logger } from \"../shared/logger\";\nimport { parseBoolean } from \"../shared/parse-boolean\";\nimport { parseOptions } from \"../shared/parse-options\";\nimport { executeScript } from \"../shared/script-executor\";\nimport { resolveTableNamespaces } from \"../shared/tailordb-namespace\";\nimport { mapQueryExecutionError } from \"./errors\";\nimport { isGraphQLInputComplete } from \"./graphql-repl\";\nimport { isSqlInputComplete } from \"./sql-repl\";\nimport {\n  extractColumnTemplate,\n  extractTableNamesFromSql,\n  type ColumnSlot,\n} from \"./sql-type-extractor\";\nimport { loadTypeFieldOrder } from \"./type-field-order\";\nimport { queryEngines, type QueryEngine } from \"./types\";\nimport type { Application } from \"@tailor-platform/tailor-proto/application_resource_pb\";\n\nexport type { QueryEngine } from \"./types\";\n\nconst queryEngineSchema = z.enum(queryEngines);\n// strip unknown keys\nconst queryBaseOptionsSchema = z.object({\n  workspaceId: z.string().optional(),\n  profile: z.string().optional(),\n  configPath: z.string().optional(),\n  engine: queryEngineSchema,\n  machineUser: z.string().optional(),\n  machineUserSource: z.enum([\"option\", \"env\"]).optional(),\n});\nconst queryOptionsSchema = queryBaseOptionsSchema.extend({\n  query: z.string(),\n});\n\ntype QueryOptions = z.input<typeof queryOptionsSchema>;\ntype QueryBaseOptions = z.input<typeof queryBaseOptionsSchema>;\ntype QuerySharedOptions = Omit<QueryOptions, \"engine\">;\ntype Client = Awaited<ReturnType<typeof initOperatorClient>>;\n\ntype SQLQueryDispatchResult = {\n  engine: \"sql\";\n  namespace: string;\n  query: string;\n  result: unknown;\n};\n\ntype GQLQueryDispatchResult = {\n  engine: \"gql\";\n  query: string;\n  result: unknown;\n};\n\ntype QueryDispatchResult = SQLQueryDispatchResult | GQLQueryDispatchResult;\n\ntype SQLResultRow = Record<string, unknown>;\ntype SQLExecutionResult = {\n  rows: SQLResultRow[];\n  rowCount: number;\n};\n\ntype QueryCommandInput =\n  | {\n      mode: \"query\";\n      query: string;\n    }\n  | {\n      mode: \"repl\";\n    }\n  | {\n      mode: \"abort\";\n    };\n\ntype ReplCommand = \"quit\" | \"help\" | \"clear\" | \"unknown\";\n\nasync function getNamespaceFromSqlQuery(\n  workspaceId: string,\n  query: string,\n  client: Client,\n  namespaces: string[],\n): Promise<string> {\n  if (namespaces.length === 0) {\n    throw new Error(\"No namespaces found in configuration.\");\n  }\n\n  if (namespaces.length === 1) {\n    return assertDefined(namespaces[0], \"namespace missing\");\n  }\n\n  const tableNames = extractTableNamesFromSql(query);\n  if (tableNames.length === 0) {\n    throw new Error(\n      `Could not infer namespace from query. Detected namespaces: ${namespaces.join(\", \")}.`,\n    );\n  }\n\n  const tableNamespaceMap = await resolveTableNamespaces({\n    workspaceId,\n    namespaces,\n    tableNames,\n    client,\n  });\n\n  const notFoundTables = tableNames.filter((tableName) => !tableNamespaceMap.has(tableName));\n  if (notFoundTables.length > 0) {\n    throw new Error(`Could not find namespace for tables in query: ${notFoundTables.join(\", \")}.`);\n  }\n\n  const namespacesFromTables = new Set(tableNamespaceMap.values());\n  if (namespacesFromTables.size === 1) {\n    return assertDefined([...namespacesFromTables][0], \"namespace from types missing\");\n  }\n\n  throw new Error(\n    `Query references tables from multiple namespaces: ${[...namespacesFromTables].join(\", \")}.`,\n  );\n}\n\nasync function loadOptions(options: QueryBaseOptions) {\n  const validated = parseOptions(queryBaseOptionsSchema, options);\n\n  const machineUser = await loadMachineUserName({\n    machineUser: validated.machineUser,\n    machineUserSource: validated.machineUserSource,\n    profile: validated.profile,\n  });\n  if (!machineUser) {\n    throw new Error(\n      \"Machine user is required. Specify --machine-user, set TAILOR_PLATFORM_MACHINE_USER_NAME, or set a profile default with 'tailor profile update <profile> --machine-user <name>'.\",\n    );\n  }\n\n  const accessToken = await loadAccessToken({\n    profile: validated.profile,\n  });\n  const client = await initOperatorClient(accessToken);\n  const workspaceId = await loadWorkspaceId({\n    workspaceId: validated.workspaceId,\n    profile: validated.profile,\n  });\n  const { config } = await loadConfig(options.configPath);\n  const namespaces = extractAllNamespaces(config);\n  const { application } = await client.getApplication({\n    workspaceId,\n    applicationName: config.name,\n  });\n\n  if (!application?.authNamespace) {\n    throw new Error(`Application ${config.name} does not have an auth configuration.`);\n  }\n\n  const { machineUser: machineUserResource } = await client.getAuthMachineUser({\n    workspaceId: workspaceId,\n    authNamespace: application.authNamespace,\n    name: machineUser,\n  });\n\n  if (!machineUserResource) {\n    throw new Error(`Machine user ${machineUser} not found.`);\n  }\n\n  return {\n    engine: validated.engine,\n    client,\n    workspaceId,\n    config,\n    application,\n    machineUserResource,\n    namespaces,\n  };\n}\n\nasync function sqlQuery(\n  client: Client,\n  invoker: AuthInvoker,\n  args: {\n    workspaceId: string;\n    namespace: string;\n    bundledCode: string;\n    query: string;\n  },\n): Promise<SQLQueryDispatchResult> {\n  const queries = splitSqlStatements(args.query);\n  const executed = await executeScript({\n    client,\n    workspaceId: args.workspaceId,\n    name: `query-sql-${args.namespace}.js`,\n    code: args.bundledCode,\n    arg: {\n      namespace: args.namespace,\n      queries,\n    },\n    invoker,\n  });\n\n  if (!executed.success) {\n    throw new Error(executed.error);\n  }\n\n  return {\n    engine: \"sql\" as const,\n    namespace: args.namespace,\n    query: args.query,\n    result: parseExecutionResult(executed.result),\n  };\n}\n\nasync function gqlQuery(\n  client: Client,\n  invoker: AuthInvoker,\n  application: Application,\n  machineUser: MachineUser,\n  args: {\n    workspaceId: string;\n    bundledCode: string;\n    query: string;\n  },\n): Promise<GQLQueryDispatchResult> {\n  const { access_token: accessToken } = await fetchMachineUserToken(\n    application.url,\n    machineUser.clientId,\n    machineUser.clientSecret,\n  );\n\n  const executed = await executeScript({\n    client,\n    workspaceId: args.workspaceId,\n    name: `query-gql.js`,\n    code: args.bundledCode,\n    arg: {\n      endpoint: `${application.url}/query`,\n      accessToken,\n      query: args.query,\n    },\n    invoker,\n  });\n\n  if (!executed.success) {\n    throw new Error(executed.error);\n  }\n\n  return {\n    engine: \"gql\" as const,\n    query: args.query,\n    result: parseExecutionResult(executed.result),\n  };\n}\n\nfunction parseExecutionResult(result: string): unknown {\n  if (!result) {\n    return null;\n  }\n\n  try {\n    return JSON.parse(result);\n  } catch {\n    return result;\n  }\n}\n\n/**\n * Resolve query input mode from CLI args.\n * @param args - Query input flags\n * @param args.query - Direct query string\n * @param args.file - File path containing query text\n * @param args.edit - Open a query editor instead of REPL\n * @param args.engine - Query engine used to choose temp file extension\n * @returns Normalized input mode\n */\nexport async function resolveQueryCommandInput(args: {\n  query?: string;\n  file?: string;\n  edit?: boolean;\n  engine: QueryEngine;\n}): Promise<QueryCommandInput> {\n  if (args.query != null) {\n    return {\n      mode: \"query\",\n      query: args.query,\n    };\n  }\n\n  if (args.file != null) {\n    return {\n      mode: \"query\",\n      query: await fs.readFile(args.file, \"utf-8\"),\n    };\n  }\n\n  if (args.edit) {\n    return await resolveEditedQueryInput(args.engine);\n  }\n\n  return {\n    mode: \"repl\",\n  };\n}\n\nasync function resolveEditedQueryInput(engine: QueryEngine): Promise<QueryCommandInput> {\n  if (!process.stdin.isTTY || !process.stdout.isTTY) {\n    throw new Error(\n      \"Non-interactive terminals are not supported. Pass -q/--query or -f/--file to run a query.\",\n    );\n  }\n\n  const editor = getEditorCommand();\n\n  const tempDir = await fs.mkdtemp(path.join(tmpdir(), \"tailor-query-\"));\n  const fileExtension = engine === \"sql\" ? \"sql\" : \"graphql\";\n  const filePath = path.join(tempDir, `query.${fileExtension}`);\n  const initialQuery = \"\";\n\n  try {\n    await fs.writeFile(filePath, initialQuery, \"utf-8\");\n    try {\n      await openInEditor(filePath, editor);\n    } catch (error) {\n      throw new Error(\n        `Failed to open query editor \"${editor}\": ${error instanceof Error ? error.message : String(error)}`,\n        { cause: error },\n      );\n    }\n\n    const editedQuery = await fs.readFile(filePath, \"utf-8\");\n    if (editedQuery.trim().length === 0 || editedQuery === initialQuery) {\n      return {\n        mode: \"abort\",\n      };\n    }\n\n    return {\n      mode: \"query\",\n      query: editedQuery,\n    };\n  } finally {\n    await fs.rm(tempDir, { recursive: true, force: true });\n  }\n}\n\n/**\n * Dispatch query execution.\n * @param options - Query command options\n * @returns Dispatch result\n */\nexport async function query(options: QueryOptions): Promise<QueryDispatchResult> {\n  const validated = parseOptions(queryOptionsSchema, options);\n\n  const executor = await prepareQueryExecutor(validated);\n  return await executor(validated.query);\n}\n\nasync function prepareQueryExecutor(\n  options: QueryBaseOptions,\n): Promise<(query: string) => Promise<QueryDispatchResult>> {\n  const { client, workspaceId, config, application, machineUserResource, engine, namespaces } =\n    await loadOptions(options);\n  const bundledCode = await bundleQueryScript(engine, path.dirname(config.path));\n  const invoker = create(AuthInvokerSchema, {\n    namespace: application.authNamespace,\n    machineUserName: machineUserResource.name,\n  });\n\n  return async (queryString: string) => {\n    let namespace: string | undefined;\n\n    try {\n      switch (engine) {\n        case \"sql\": {\n          namespace = await getNamespaceFromSqlQuery(workspaceId, queryString, client, namespaces);\n          const result = await sqlQuery(client, invoker, {\n            workspaceId,\n            namespace,\n            bundledCode,\n            query: queryString,\n          });\n          return reorderSqlColumns(result, config, namespace, queryString);\n        }\n        case \"gql\":\n          return await gqlQuery(client, invoker, application, machineUserResource, {\n            workspaceId,\n            bundledCode,\n            query: queryString,\n          });\n        default:\n          throw new Error(`Unsupported query engine: ${engine satisfies never}`);\n      }\n    } catch (error) {\n      throw mapQueryExecutionError({\n        error,\n        engine,\n        namespace,\n        machineUser: machineUserResource.name,\n      });\n    }\n  };\n}\n\n/**\n * Resolve a backslash REPL command into its normalized action.\n * @param input - Raw user input\n * @returns Normalized REPL command, or null for non-command input\n */\nexport function resolveReplCommand(input: string): ReplCommand | null {\n  const trimmed = input.trim();\n  if (!trimmed.startsWith(\"\\\\\")) {\n    return null;\n  }\n\n  if (trimmed === \"\\\\q\" || trimmed === \"\\\\quit\") {\n    return \"quit\";\n  }\n\n  if (trimmed === \"\\\\help\" || trimmed === \"\\\\h\" || trimmed === \"\\\\?\") {\n    return \"help\";\n  }\n\n  if (trimmed === \"\\\\clear\" || trimmed === \"\\\\c\") {\n    return \"clear\";\n  }\n\n  return \"unknown\";\n}\n\n/**\n * Clear the interactive terminal screen and move the cursor to the top-left.\n */\nfunction clearReplScreen(): void {\n  process.stdout.write(\"\\u001Bc\");\n}\n\nfunction sanitizeHistoryScope(value: string): string {\n  return value.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n}\n\nexport function getReplHistoryPath(\n  engine: QueryEngine,\n  profile: string | undefined,\n  workspaceId: string | undefined,\n): string | undefined {\n  if (!xdgConfig) {\n    return undefined;\n  }\n  const scope = [profile, workspaceId]\n    .filter((value): value is string => Boolean(value))\n    .map(sanitizeHistoryScope)\n    .join(\"-\");\n  const engineSlug = engine === \"sql\" ? \"sql\" : \"gql\";\n  const suffix = scope ? `-${scope}` : \"\";\n  return path.join(xdgConfig, \"tailor-platform\", `query-history-${engineSlug}${suffix}.json`);\n}\n\n// TODO: Empty input and REPL commands (e.g. \\help, \\q) are treated as valid by\n// the validator, so read-multiline saves them to history on submit. The library\n// does not expose a history filter hook; a clean fix requires upstream support.\nfunction createReplValidator(engine: QueryEngine): (value: string) => string | undefined {\n  return (value: string) => {\n    const trimmed = value.trim();\n    if (trimmed === \"\") {\n      return undefined;\n    }\n    if (resolveReplCommand(trimmed) !== null) {\n      return undefined;\n    }\n    if (engine === \"sql\") {\n      return isSqlInputComplete(value) ? undefined : \"SQL statement is incomplete (missing ';').\";\n    }\n    return isGraphQLInputComplete(value) ? undefined : \"GraphQL document is incomplete.\";\n  };\n}\n\nasync function runRepl(\n  options: QueryBaseOptions & {\n    json?: boolean;\n    newlineOnEnter: boolean;\n  },\n): Promise<void> {\n  if (!process.stdin.isTTY || !process.stdout.isTTY) {\n    throw new Error(\n      \"Non-interactive terminals are not supported. Pass -q/--query or -f/--file to run a query.\",\n    );\n  }\n\n  const execute = await prepareQueryExecutor(options);\n  const historyPath = getReplHistoryPath(options.engine, options.profile, options.workspaceId);\n  const validate = createReplValidator(options.engine);\n  // Lazy-load the editor module so the `graphql` and `sql-highlight` libs are\n  // only pulled in when the REPL is actually entered, not on every CLI startup.\n  const { highlightSqlLine, highlightGraphqlLine, replTransform } = await import(\"./repl-editor\");\n  const highlight = options.engine === \"sql\" ? highlightSqlLine : highlightGraphqlLine;\n\n  // NOTE: Each prompt() call reloads history from the file synchronously while the\n  // previous call's async save may still be in-flight. In practice the race window\n  // is only visible on fast paths (\\help, \\clear) whose entries are already non-ideal\n  // for history (see createReplValidator TODO). Actual queries include network latency\n  // that closes the window. A clean fix requires the library to export history utilities.\n  const prompt = createPrompt({\n    prefix: \"\",\n    preferNewlineOnEnter: options.newlineOnEnter,\n    validate,\n    highlight,\n    transform: replTransform,\n    theme: { submitRender: \"preserve\" },\n    history: historyPath ? { filePath: historyPath, maxEntries: 100 } : [],\n    helpFooter: { items: [\"submit\", \"newline\"], maxLines: 1 },\n  });\n\n  logger.info(`Entering ${options.engine.toUpperCase()} REPL mode.`);\n  logger.info(\"Type \\\\help for usage, \\\\q to quit.\");\n\n  // loop exits when the user types the quit command\n  // oxlint-disable-next-line typescript/no-unnecessary-condition\n  while (true) {\n    const [value, error] = await prompt(`${options.engine}> `);\n\n    if (error?.kind === \"cancel\") {\n      if (value.length === 0) {\n        return;\n      }\n      continue;\n    }\n\n    if (error?.kind === \"eof\") {\n      return;\n    }\n\n    const trimmed = value.trim();\n    if (trimmed === \"\") {\n      continue;\n    }\n\n    const command = resolveReplCommand(trimmed);\n    if (command === \"quit\") {\n      return;\n    }\n    if (command === \"help\") {\n      printReplHelp(options.engine);\n      continue;\n    }\n    if (command === \"clear\") {\n      clearReplScreen();\n      continue;\n    }\n    if (command === \"unknown\") {\n      logger.warn(`Unknown command: ${trimmed}`);\n      continue;\n    }\n\n    try {\n      const result = await execute(trimmed);\n      if (result.engine === \"sql\") {\n        printSqlResult(result, { json: options.json });\n      } else {\n        printGqlResult(result, { json: options.json });\n      }\n    } catch (error) {\n      if (isCLIError(error)) {\n        logger.log(error.format());\n        continue;\n      }\n      if (error instanceof Error) {\n        logger.error(error.message);\n        continue;\n      }\n      logger.error(String(error));\n    }\n  }\n}\n\nfunction printReplHelp(engine: QueryEngine): void {\n  logger.log(\"REPL commands:\");\n  logger.log(\"  \\\\help, \\\\h, \\\\?              Show this help\");\n  logger.log(\"  \\\\q, \\\\quit                  Exit REPL\");\n  logger.log(\"  \\\\clear, \\\\c                 Clear the screen\");\n  logger.log(\"\");\n  logger.log(\"Key bindings (see footer for terminal-specific submit/newline keys):\");\n  logger.log(\"  Ctrl+J                     Insert newline (always available)\");\n  logger.log(\"  Ctrl+C                     Cancel current input\");\n  logger.log(\"  Ctrl+D                     Exit REPL (on empty input)\");\n  logger.log(\"  Ctrl+Z / Ctrl+Y            Undo / Redo\");\n  logger.log(\"  Up/Down (first/last line)  Navigate history\");\n  logger.log(\"\");\n  logger.log(\"Editing aids:\");\n  logger.log(\"  Syntax highlighting        Enabled for the current engine\");\n  logger.log(\"  ( [ {                      Auto-inserts the matching closing bracket\");\n  logger.log(\"  Enter after open bracket   Adds one indent level and closes the block\");\n  logger.log(\"\");\n  logger.log(\n    engine === \"sql\"\n      ? \"Input must end with ';' to submit.\"\n      : \"Input must be a complete GraphQL document to submit.\",\n  );\n}\n\n/**\n * Execute SQL query directly.\n * @param options - Shared query options\n * @returns SQL query result\n */\nasync function querySql(options: QuerySharedOptions): Promise<SQLQueryDispatchResult> {\n  const result = await query({\n    ...options,\n    engine: \"sql\",\n  });\n\n  if (result.engine !== \"sql\") {\n    throw new Error(`Expected sql engine result but got: ${result.engine}`);\n  }\n\n  return result;\n}\n\n/**\n * Execute GraphQL query directly.\n * @param options - Shared query options\n * @returns GraphQL query result\n */\nasync function queryGql(options: QuerySharedOptions): Promise<GQLQueryDispatchResult> {\n  const result = await query({\n    ...options,\n    engine: \"gql\",\n  });\n\n  if (result.engine !== \"gql\") {\n    throw new Error(`Expected gql engine result but got: ${result.engine}`);\n  }\n\n  return result;\n}\n\nasync function reorderSqlColumns(\n  result: SQLQueryDispatchResult,\n  config: LoadedConfig,\n  namespace: string,\n  sqlQuery: string,\n): Promise<SQLQueryDispatchResult> {\n  if (!isSQLExecutionResult(result.result) || result.result.rows.length === 0) {\n    return result;\n  }\n\n  const template = extractColumnTemplate(sqlQuery);\n  if (!template) {\n    return result;\n  }\n\n  try {\n    const fieldOrder = await loadTypeFieldOrder(config, namespace);\n    const expectedOrder = buildExpectedColumnOrder(template, fieldOrder);\n    if (expectedOrder.length === 0) {\n      return result;\n    }\n\n    const orderedRows = result.result.rows.map((row) => reorderRowByTemplate(row, expectedOrder));\n\n    return {\n      ...result,\n      result: {\n        ...result.result,\n        rows: orderedRows,\n      },\n    };\n  } catch {\n    return result;\n  }\n}\n\nconst SYSTEM_FIELD_ORDER = [\"id\"];\n\nfunction buildExpectedColumnOrder(\n  template: ColumnSlot[],\n  fieldOrder: Map<string, string[]>,\n): string[] {\n  const order: string[] = [];\n\n  for (const slot of template) {\n    if (slot.type === \"explicit\") {\n      order.push(slot.name);\n    } else {\n      for (const tableName of slot.tableNames) {\n        order.push(...SYSTEM_FIELD_ORDER);\n        order.push(...(fieldOrder.get(tableName) ?? []));\n      }\n    }\n  }\n\n  return order;\n}\n\nfunction reorderRowByTemplate(row: SQLResultRow, expectedOrder: string[]): SQLResultRow {\n  const ordered: SQLResultRow = {};\n  const rowKeys = new Set(Object.keys(row));\n\n  // Build case-insensitive lookup: lowercased key → original key in row.\n  // pgsql-ast-parser lowercases unquoted identifiers (PostgreSQL standard),\n  // but TailorDB preserves the original case, so we need case-insensitive matching.\n  const lowerToOriginal = new Map<string, string>();\n  for (const key of rowKeys) {\n    lowerToOriginal.set(key.toLowerCase(), key);\n  }\n\n  for (const key of expectedOrder) {\n    const original = lowerToOriginal.get(key.toLowerCase());\n    if (original != null && rowKeys.has(original)) {\n      ordered[original] = row[original];\n      rowKeys.delete(original);\n      lowerToOriginal.delete(key.toLowerCase());\n    }\n  }\n\n  for (const key of rowKeys) {\n    ordered[key] = row[key];\n  }\n\n  return ordered;\n}\n\nexport const queryCommand = defineAppCommand({\n  name: \"query\",\n  description: \"Run SQL/GraphQL query.\",\n  args: z\n    .strictObject({\n      ...deploymentArgs,\n      engine: arg(queryEngineSchema, {\n        description: \"Query engine (sql or gql)\",\n      }),\n      query: arg(z.string().optional(), {\n        alias: \"q\",\n        description: \"Query string to execute directly; omit to start REPL mode\",\n      }),\n      file: arg(z.string().optional(), {\n        alias: \"f\",\n        description: \"Read query string from file; omit to start REPL mode\",\n      }),\n      edit: arg(z.boolean().default(false), {\n        description: \"Open a temporary file in your editor; omit to start REPL mode\",\n      }),\n      \"machine-user\": arg(z.string().optional(), {\n        alias: \"m\",\n        description:\n          \"Machine user name for query execution. Falls back to the active profile's default machine user.\",\n        env: \"TAILOR_PLATFORM_MACHINE_USER_NAME\",\n      }),\n      \"newline-on-enter\": arg(z.boolean().optional(), {\n        description:\n          \"REPL: when true, Enter inserts a newline and Shift+Enter submits. Use --no-newline-on-enter to swap.\",\n      }),\n    })\n    .superRefine((args, ctx) => {\n      if (args.query != null && args.file != null) {\n        ctx.addIssue({\n          code: \"custom\",\n          path: [\"file\"],\n          message: \"Pass either -q/--query or -f/--file, not both.\",\n        });\n      }\n\n      if (args.edit && args.query != null) {\n        ctx.addIssue({\n          code: \"custom\",\n          path: [\"edit\"],\n          message: \"Pass only one of --edit, -q/--query, or -f/--file.\",\n        });\n      }\n\n      if (args.edit && args.file != null) {\n        ctx.addIssue({\n          code: \"custom\",\n          path: [\"edit\"],\n          message: \"Pass only one of --edit, -q/--query, or -f/--file.\",\n        });\n      }\n    }),\n  run: async (args) => {\n    const mode = await resolveQueryCommandInput({\n      query: args.query,\n      file: args.file,\n      edit: args.edit,\n      engine: args.engine,\n    });\n\n    const sharedOptions: QueryBaseOptions = {\n      workspaceId: args[\"workspace-id\"],\n      profile: args.profile,\n      configPath: args.config,\n      engine: args.engine,\n      machineUser: args[\"machine-user\"],\n      machineUserSource: resolveMachineUserInputSource(args[\"machine-user\"]),\n    };\n\n    if (mode.mode === \"abort\") {\n      logger.info(\"Editor closed without a query. Nothing was executed.\");\n      return;\n    }\n\n    if (mode.mode === \"repl\") {\n      const newlineOnEnter =\n        args[\"newline-on-enter\"] ?? parseBoolean(process.env.TAILOR_QUERY_NEWLINE_ON_ENTER) ?? true;\n      await runRepl({\n        ...sharedOptions,\n        json: args.json,\n        newlineOnEnter,\n      });\n      return;\n    }\n\n    const directQuery = mode.query;\n\n    if (args.engine === \"sql\") {\n      const result = await querySql({\n        ...sharedOptions,\n        query: directQuery,\n      });\n      printSqlResult(result, { json: args.json });\n      return;\n    }\n\n    const result = await queryGql({\n      ...sharedOptions,\n      query: directQuery,\n    });\n    printGqlResult(result, { json: args.json });\n  },\n});\n\nfunction isSQLExecutionResult(value: unknown): value is SQLExecutionResult {\n  if (!value || typeof value !== \"object\") {\n    return false;\n  }\n\n  const candidate = value as Partial<SQLExecutionResult>;\n  return Array.isArray(candidate.rows) && typeof candidate.rowCount === \"number\";\n}\n\nfunction printSingleSqlResult(\n  execResult: SQLExecutionResult,\n  options: { json?: boolean } = {},\n): void {\n  if (execResult.rows.length === 0) {\n    if (options.json) {\n      logger.out({ results: [], rowCount: 0 });\n      return;\n    }\n    logger.info(\"No rows returned.\");\n    return;\n  }\n\n  if (options.json) {\n    logger.out({ results: execResult.rows, rowCount: execResult.rowCount });\n    return;\n  }\n\n  logger.out(execResult.rows, { showNull: true });\n  logger.out(`rows: ${execResult.rowCount}`);\n}\n\nfunction splitSqlStatements(query: string): string[] {\n  const statements = parseSql(query, { locationTracking: true });\n  // Extract original SQL text using AST location info instead of re-serializing\n  // to preserve the user's original casing and syntax.\n  // _location.end is unreliable for INSERT/UPDATE statements (https://github.com/oguimbal/pgsql-ast-parser/issues/135),\n  // so we use the next statement's start (or end of string) as the boundary.\n  return statements.map((s, i) => {\n    const start = assertDefined(s._location, \"SQL statement location missing\").start;\n    const nextStmt = statements[i + 1];\n    const end =\n      nextStmt !== undefined\n        ? assertDefined(nextStmt._location, \"SQL statement location missing\").start\n        : query.length;\n    return query.substring(start, end);\n  });\n}\n\nfunction isSQLExecutionResultArray(value: unknown): value is SQLExecutionResult[] {\n  return Array.isArray(value) && value.length > 0 && value.every(isSQLExecutionResult);\n}\n\nfunction printSqlResult(result: SQLQueryDispatchResult, options: { json?: boolean } = {}): void {\n  if (isSQLExecutionResultArray(result.result)) {\n    if (options.json) {\n      logger.out(result.result.map((r) => ({ results: r.rows, rowCount: r.rowCount })));\n      return;\n    }\n    const queries = splitSqlStatements(result.query);\n    for (let i = 0; i < result.result.length; i++) {\n      if (i > 0) logger.log(\"\");\n      logger.info(queries[i] ?? `Statement ${i + 1}`);\n      printSingleSqlResult(\n        assertDefined(result.result[i], `SQL result at index ${i} missing`),\n        options,\n      );\n    }\n    return;\n  }\n\n  if (isSQLExecutionResult(result.result)) {\n    printSingleSqlResult(result.result, options);\n    return;\n  }\n\n  logger.out({\n    engine: result.engine,\n    query: result.query,\n    result: result.result,\n  });\n}\n\nfunction printGqlResult(result: GQLQueryDispatchResult, options: { json?: boolean } = {}): void {\n  if (options.json) {\n    logger.out({\n      result: result.result,\n    });\n    return;\n  }\n\n  logger.out(JSON.stringify(result.result, null, 2));\n}\n","import { realpathSync } from \"node:fs\";\nimport { stripVTControlCharacters } from \"node:util\";\nimport { isAbsolute, relative, resolve, sep } from \"pathe\";\nimport {\n  getErrorDiagnostics,\n  withErrorDiagnostics,\n  type ErrorSourceLocation,\n} from \"./error-diagnostics\";\nimport { isCLIError } from \"./errors\";\nimport { parseBoolean } from \"./parse-boolean\";\n\n/** Properties attached to a GitHub Actions annotation. */\nexport interface AnnotationProperties {\n  /** Short heading shown above the annotation body. */\n  title?: string;\n  /** Path of the file the annotation points at, relative to the workspace. */\n  file?: string;\n  /** 1-based line number within `file`. */\n  line?: number;\n}\n\n/** Annotation severities supported by the GitHub Actions runner. */\nexport type AnnotationLevel = \"error\" | \"warning\" | \"notice\";\n\n/**\n * Escape a workflow command message body.\n *\n * The runner parses commands line by line, so a literal `%` and any line\n * break must be percent-encoded or the remainder of the message is dropped.\n * @param value - Raw message text\n * @returns Escaped message safe to place after `::`\n */\nfunction escapeData(value: string): string {\n  return value.replaceAll(\"%\", \"%25\").replaceAll(\"\\r\", \"%0D\").replaceAll(\"\\n\", \"%0A\");\n}\n\n/**\n * Escape a workflow command property value.\n *\n * Property values additionally delimit on `:` and `,`, so both are encoded on\n * top of the message-body escapes.\n * @param value - Raw property value\n * @returns Escaped value safe to place inside the property list\n */\nfunction escapeProperty(value: string): string {\n  return escapeData(value).replaceAll(\":\", \"%3A\").replaceAll(\",\", \"%2C\");\n}\n\n/**\n * Report whether `--json` was requested on the command line.\n *\n * A failure during argument validation ends the command before the `--json`\n * effect sets the logger's mode, so the flag is read from argv instead.\n * Tokens after `--` are positional values, never flags.\n * @returns True when argv requests JSON output\n */\nfunction jsonRequestedInArgv(): boolean {\n  const args = process.argv.slice(2);\n  const separator = args.indexOf(\"--\");\n  const options = separator === -1 ? args : args.slice(0, separator);\n  return options.some((value) => {\n    const assignment = value.indexOf(\"=\");\n    const name = assignment === -1 ? value : value.slice(0, assignment);\n    if (name !== \"--json\" && name !== \"-j\") return false;\n    return assignment === -1 || parseBoolean(value.slice(assignment + 1)) !== false;\n  });\n}\n\n/**\n * Report whether workflow commands should be written.\n *\n * Read at emission time rather than at import time so values loaded from\n * `--env-file` are honored.\n * @param jsonMode - Whether the CLI is producing a JSON document\n * @returns True when annotations should be emitted\n */\nexport function annotationsEnabled(jsonMode: boolean): boolean {\n  if (jsonMode || jsonRequestedInArgv()) return false;\n  if (process.env.GITHUB_ACTIONS !== \"true\") return false;\n  return parseBoolean(process.env.TAILOR_GITHUB_ACTIONS_ANNOTATIONS) !== false;\n}\n\n/**\n * Resolve a path through any symlinks on the way to it.\n *\n * A runner can export `GITHUB_WORKSPACE` through a symlink while paths arrive\n * already resolved, which leaves two spellings of one location. A path that\n * does not exist keeps its lexical form.\n * @param value - Path to resolve\n * @returns Real path, or the resolved lexical path when it cannot be read\n */\nfunction realPath(value: string): string {\n  try {\n    return realpathSync(resolve(value));\n  } catch {\n    return resolve(value);\n  }\n}\n\n/**\n * Render a path the way GitHub Actions resolves annotation locations.\n *\n * Steps run with `working-directory` set, so a cwd-relative path points at the\n * wrong file; the runner resolves annotation paths against the workspace root.\n * Containment is decided by the relative path rather than a prefix match, so a\n * sibling such as `/repo-other` is not read as living inside `/repo`, and both\n * sides are resolved through symlinks so one location has one spelling.\n * @param file - Absolute path to the file the failure points at\n * @returns Workspace-relative path, or undefined when it lies outside\n */\nexport function workspaceRelativePath(file: string): string | undefined {\n  const workspace = process.env.GITHUB_WORKSPACE;\n  if (!workspace || !isAbsolute(file)) return undefined;\n  const rel = relative(realPath(workspace), realPath(file));\n  if (rel === \"\" || isAbsolute(rel)) return undefined;\n  const segments = rel.split(sep);\n  // A leading \"..\" segment means the file escapes the workspace; a directory\n  // merely named \"..data\" does not.\n  if (segments[0] === \"..\") return undefined;\n  return segments.join(\"/\");\n}\n\n/**\n * Render a GitHub Actions annotation command line.\n *\n * Colors are stripped unconditionally: the runner renders the annotation as\n * text, and `FORCE_COLOR` keeps escapes alive even on a non-TTY stream.\n * @param level - Annotation severity\n * @param message - Annotation body\n * @param properties - Optional title and source location\n * @returns A single workflow command line, newline terminated\n */\nexport function formatAnnotation(\n  level: AnnotationLevel,\n  message: string,\n  properties: AnnotationProperties = {},\n): string {\n  const entries: string[] = [];\n  if (properties.title !== undefined) {\n    entries.push(`title=${escapeProperty(stripVTControlCharacters(properties.title))}`);\n  }\n  if (properties.file !== undefined) {\n    entries.push(`file=${escapeProperty(properties.file)}`);\n  }\n  if (properties.line !== undefined) {\n    entries.push(`line=${properties.line}`);\n  }\n  const propertyList = entries.length > 0 ? ` ${entries.join(\",\")}` : \"\";\n  return `::${level}${propertyList}::${escapeData(stripVTControlCharacters(message))}\\n`;\n}\n\nfunction formattedMessage(error: Error): string | undefined {\n  const format = (error as { format?: unknown }).format;\n  if (typeof format !== \"function\") return undefined;\n  const formatted: unknown = format.call(error);\n  return typeof formatted === \"string\" ? formatted : undefined;\n}\n\n/**\n * Build the annotation body and title for a terminal CLI failure.\n *\n * Reuses the same text the CLI already prints so the annotation and the log\n * cannot drift: a `CLIError` renders through its own `format()`, which already\n * carries details, suggestion, help, and the next action.\n * @param error - Failure that ended the command\n * @param fallbackSuggestion - Suggestion shown for a plain error, when one exists\n * @returns Annotation body and optional title\n */\nexport function describeTerminalError(\n  error: unknown,\n  fallbackSuggestion?: string,\n): { message: string; title?: string } {\n  if (isCLIError(error)) {\n    return { message: error.format(), title: error.code || \"CLI_ERROR\" };\n  }\n  if (error instanceof Error) {\n    // Commands outside this package (the seed plugin's validate report) throw a\n    // plain Error carrying its own `format()`, which holds the whole report.\n    const title = getErrorDiagnostics(error).code ?? (error.name || \"Error\");\n    const formatted = formattedMessage(error);\n    if (formatted !== undefined) {\n      return { message: formatted, title };\n    }\n    const suggestion = fallbackSuggestion ? `\\nSuggestion: ${fallbackSuggestion}` : \"\";\n    return { message: `${error.message}${suggestion}`, title };\n  }\n  return { message: `Unknown error: ${String(error)}`, title: \"UNKNOWN_ERROR\" };\n}\n\n/**\n * Attach the source location a failure points at.\n *\n * Consumed when the command's failure is annotated; the error is otherwise\n * unchanged, so its message and formatting stay the caller's own.\n * @param error - Failure to annotate\n * @param location - Absolute file, and the 1-based line when known\n * @returns The same error\n */\nexport function withSourceLocation<T extends Error>(error: T, location: ErrorSourceLocation): T {\n  return withErrorDiagnostics(error, { location });\n}\n\n/**\n * Annotate the failure that ended the command, when running in GitHub Actions.\n * @param error - Failure that ended the command\n * @param options - JSON mode state and the suggestion shown for a plain error\n * @param options.jsonMode - Whether the CLI is producing a JSON document\n * @param options.suggestion - Suggestion shown for a plain error\n */\nexport function annotateTerminalError(\n  error: unknown,\n  options: { jsonMode: boolean; suggestion?: string },\n): void {\n  if (!annotationsEnabled(options.jsonMode)) return;\n  const { message, title } = describeTerminalError(error, options.suggestion);\n  process.stderr.write(formatAnnotation(\"error\", message, { title, ...sourceLocation(error) }));\n}\n\n/**\n * Read an error's source location as annotation properties.\n *\n * A location outside the workspace is dropped rather than guessed at, so the\n * annotation still reports the failure without pointing at the wrong file.\n * @param error - Failure that ended the command\n * @returns `file`/`line` properties, or an empty object when unavailable\n */\nfunction sourceLocation(error: unknown): { file?: string; line?: number } {\n  if (!(error instanceof Error)) return {};\n  const location = getErrorDiagnostics(error).location;\n  if (!location) return {};\n  const file = workspaceRelativePath(location.file);\n  if (file === undefined) return {};\n  return location.line === undefined ? { file } : { file, line: location.line };\n}\n","/**\n * Check if the current runtime natively supports TypeScript execution.\n * Bun and Deno can execute TypeScript without tsx or other loaders.\n *\n * Note: Deno is detected here for correct loader/transport selection, but\n * the CLI is not fully tested on Deno yet. Other dependencies may fail.\n * @returns true if running on Bun or Deno\n */\nexport function isNativeTypeScriptRuntime(): boolean {\n  return isBun() || isDeno();\n}\n\n/**\n * Check if the current runtime is Bun.\n * @returns true if running on Bun\n */\nexport function isBun(): boolean {\n  return \"Bun\" in globalThis;\n}\n\n/**\n * Check if the current runtime is Deno.\n * @returns true if running on Deno\n */\nexport function isDeno(): boolean {\n  return \"Deno\" in globalThis;\n}\n","import * as mod from \"node:module\";\nimport { isNativeTypeScriptRuntime } from \"./runtime\";\n\nexport async function registerTsHook(tsHookUrl: URL): Promise<void> {\n  if (isNativeTypeScriptRuntime()) return;\n  const { resolveSync, loadSync } = (await import(tsHookUrl.href)) as {\n    resolveSync: Parameters<typeof mod.registerHooks>[0][\"resolve\"];\n    loadSync: Parameters<typeof mod.registerHooks>[0][\"load\"];\n  };\n  mod.registerHooks({ resolve: resolveSync, load: loadSync });\n}\n"],"mappings":"opIAsBA,MAAM,GAAyC,CAC7C,GAAI,EACJ,EAAG,IACH,EAAG,GACL,EAEM,GAAkB,kBAMX,GAAc,EACxB,OAAO,CAAC,CACR,OAAQ,GAAQ,GAAgB,KAAK,CAAG,EAAG,CAC1C,QAAS,+DACX,CAAC,CAAC,CACD,OACE,GAAQ,CACP,IAAM,EAAQ,EAAI,MAAM,EAAe,EACvC,GAAI,CAAC,EAAO,MAAO,GACnB,IAAM,EAAS,EAAM,GACrB,OAAO,IAAW,IAAA,IAAa,SAAS,EAAQ,EAAE,EAAI,CACxD,EACA,CAAE,QAAS,iCAAkC,CAC/C,EAOF,SAAgB,cAAc,EAA0B,CACtD,IAAM,EAAQ,EACZ,EAAS,MAAM,EAAe,EAC9B,4BAA4B,GAC9B,EACM,EAAQ,SAAS,EAAc,EAAM,GAAI,+BAA+B,EAAG,EAAE,EAC7E,EAAO,EAAc,EAAM,GAAI,6BAA6B,EAClE,OAAO,EAAQ,GAAS,EAC1B,CAMA,MAAa,GAAiB,EAAE,OAAO,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAMlD,GAAoB,EAAE,OAAO,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAKxD,GAAW,EAAE,KAAK,CAAC,MAAO,MAAM,CAAC,EAW9C,SAAgB,gBAAgB,EAAqD,CAC/E,OAAU,IAAA,GACd,OAAO,IAAU,MAAQ,GAAc,IAAM,GAAc,IAC7D,CAEA,SAAS,mBAAmB,EAAkC,CAE5D,OADmB,EAAK,MAAM,EAAG,EAAK,QAAQ,IAAI,IAAM,GAAK,EAAK,OAAS,EAAK,QAAQ,IAAI,CAC5E,CAAC,CAAC,KACf,GACC,IAAU,MACV,EAAM,WAAW,KAAK,GACtB,IAAU,kBACV,EAAM,WAAW,iBAAiB,GAClC,IAAU,iBACV,EAAM,WAAW,gBAAgB,GACjC,IAAU,iBACV,EAAM,WAAW,gBAAgB,CACrC,CACF,CASA,SAAgB,8BACd,EACA,EAA0B,QAAQ,KAAK,MAAM,CAAC,EAC9C,EAAgD,CAAC,EACb,CAChC,OAAgB,IAAA,GAGpB,OAFI,EAAQ,iBACR,mBAAmB,CAAI,EAAU,SAC9B,QAAQ,IAAI,oCAAsC,EAAc,MAAQ,QACjF,CAkBA,SAAgB,aAAa,EAAsB,EAAoC,CAErF,IAAM,EAAkB,IAAI,IAAI,OAAO,KAAK,QAAQ,GAAG,CAAC,EAElD,MAAQ,EAAmB,IAAsB,CACrD,IAAK,IAAM,IAAQ,CAAC,GAAS,CAAC,CAAC,CAAC,CAAC,KAAK,EAAG,CACvC,IAAM,EAAU,EAAK,QAAQ,QAAQ,IAAI,EAAG,CAAI,EAChD,GAAI,CAACA,EAAG,WAAW,CAAO,EAAG,CAC3B,GAAI,EACF,MAAU,MAAM,+BAA+B,GAAS,EAE1D,QACF,CACA,IAAM,EAAUA,EAAG,aAAa,EAAS,OAAO,EAC1C,EAAS,GAAS,CAAO,EAC/B,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAM,EAE1C,EAAgB,IAAI,CAAG,IAI3B,QAAQ,IAAI,GAAO,EAEvB,CACF,EAEA,KAAK,EAAU,EAAI,EACnB,KAAK,EAAkB,EAAK,CAC9B,CAsBA,SAAgB,iBAAiB,EAA6B,CAAC,EAAG,CAChE,MAAO,CACL,WAAY,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CACrC,MAAO,IACP,YAAa,oDACb,WAAY,CAAE,KAAM,OAAQ,QAAS,CAAC,SAAU,MAAM,CAAE,CAC1D,CAAC,EACD,qBAAsB,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CAC/C,YAAa,sDACb,WAAY,CAAE,KAAM,OAAQ,QAAS,CAAC,SAAU,MAAM,CAAE,EACxD,QAAS,EAAQ,CAAE,UAAW,CAC5B,aACE,EAAK,YACL,EAAK,qBACP,CACF,CACF,CAAC,EACD,QAAS,EAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAK,EAAG,CACvC,GAAI,EAAQ,eAAiB,IAAA,GAAY,CAAC,EAAI,CAAE,MAAO,EAAQ,YAAa,EAC5E,YAAa,yBACb,OAAS,GAAU,CACjB,EAAO,QAAU,CACnB,CACF,CAAC,EACD,KAAM,EAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAK,EAAG,CACpC,MAAO,IACP,YAAa,iBACb,OAAS,GAAU,CACjB,EAAO,SAAW,CACpB,CACF,CAAC,CACH,CACF,CAKA,MAAa,GAAa,iBAAiB,EAK9B,EAAgB,CAC3B,eAAgB,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CACzC,MAAO,IACP,YAAa,eACb,IAAK,+BACL,WAAY,CAAE,KAAM,MAAO,CAC7B,CAAC,EACD,QAAS,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CAClC,MAAO,IACP,YAAa,oBACb,IAAK,0BACL,WAAY,CAAE,KAAM,MAAO,CAC7B,CAAC,CACH,EAKa,GAAsB,mBASnC,SAAgB,gBAAgB,EAAyC,CACvE,GAAI,CAAC,EAAY,OACjB,IAAM,EAAqB,EAAK,SAAS,QAAQ,IAAI,EAAG,CAAU,EAC9D,OAAA,mBACJ,MAAO,YAAY,GACrB,CAeA,SAAgB,oBAAoB,EAA6C,CAC/E,MAAO,CACL,GAAI,EAAQ,YAAc,CAAC,kBAAkB,EAAQ,aAAa,EAAI,CAAC,EACvE,GAAI,EAAQ,QAAU,CAAC,aAAa,EAAQ,SAAS,EAAI,CAAC,CAC5D,CACF,CAKA,MAAa,GAAY,CACvB,OAAQ,EAAI,EAAE,OAAO,CAAC,CAAC,QAAQ,EAAmB,EAAG,CACnD,MAAO,IACP,YAAa,6BACb,IAAK,qBACL,WAAY,CAAE,KAAM,OAAQ,WAAY,CAAC,IAAI,CAAE,CACjD,CAAC,CACH,EAKa,GAAiB,CAC5B,OAAQ,EAAI,EAAE,OAAO,CAAC,CAAC,QAAQ,EAAmB,EAAG,CACnD,MAAO,IACP,YACE,uFACF,IAAK,kCACL,WAAY,CAAE,KAAM,OAAQ,WAAY,CAAC,IAAI,CAAE,CACjD,CAAC,CACH,EAKa,GAAiB,CAC5B,GAAG,EACH,GAAG,EACL,EAKa,GAAmB,CAC9B,IAAK,EAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAK,EAAG,CACnC,MAAO,IACP,YAAa,2BACf,CAAC,CACH,EAKa,GAAmB,CAC9B,kBAAmB,EAAI,EAAE,OAAO,EAAG,CACjC,MAAO,IACP,YAAa,kBACb,IAAK,kCACL,WAAY,CAAE,KAAM,MAAO,CAC7B,CAAC,CACH,EAWa,gBAAkB,EAAsB,UAClD,CACC,MAAO,EAAI,GAAS,QAAQ,CAAY,EAAG,CACzC,YAAa,0BACf,CAAC,EACD,MAAO,EAAI,GAAkB,SAAS,EAAG,CACvC,MAAO,IACP,YAAa,0DACf,CAAC,CACH,GAOW,GAAe,CAC1B,MAAO,EAAI,GAAS,QAAQ,MAAM,EAAG,CACnC,YAAa,0BACf,CAAC,EACD,MAAO,EAAI,GAAkB,QAAQ,EAAE,EAAG,CACxC,MAAO,IACP,YAAa,kDACf,CAAC,CACH,EAKa,GAAa,CACxB,YAAa,EAAI,EAAE,OAAO,EAAG,CAC3B,MAAO,IACP,YAAa,YACb,IAAK,4BACL,WAAY,CAAE,KAAM,MAAO,CAC7B,CAAC,CACH,EC5Xa,EACX,GAAoC,EAStC,eAAsB,qBACpB,EACA,EAAiB,CAAC,EACH,CACf,IAAM,EAAS,MAAM,GAAW,EAAS,CAAI,EAC7C,GAAI,CAAC,EAAO,QACV,MAAM,EAAO,KAEjB,CCzBA,MAAM,GAAiB,EAAE,MAAM,CAAC,EAAE,OAAO,EAAG,EAAE,OAAO,EAAG,EAAE,QAAQ,CAAC,CAAC,EAG9D,GAA2B,EAAE,MAAM,CAAC,EAAE,OAAO,EAAG,EAAE,OAAO,CAAC,CAAC,EAE3D,GAAiB,EAAE,MAAM,CAC7B,GACA,EAAE,aAAa,CACb,MAAO,GACP,kBAAmB,EAAE,OAAO,CAAC,CAAC,IAAI,EAAG,CACnC,QAAS,wEACX,CAAC,CACH,CAAC,CACH,CAAC,EAEY,GAAiB,EAAE,KAAK,EAAU,EAEzC,GAAuB,0BACvB,GAAyB,6BACzB,GAA+B,OAI/B,GAAsB,EAAE,OAAO,CAAC,CAAC,MAAM,GAAwB,CACnE,QAAS,gCAAgC,GAAuB,OAAO,EACzE,CAAC,EAIK,GAAiB,EAAE,OAAO,EAAE,OAAO,EAAG,EAAmB,CAAC,CAAC,aAAa,EAAU,IAAQ,CAC9F,IAAM,EAAO,OAAO,KAAK,CAAQ,EAC7B,EAAK,OAAS,IAChB,EAAI,SAAS,CACX,KAAM,SACN,QAAS,yCACX,CAAC,EAEH,IAAK,IAAM,KAAO,EACX,GAAqB,KAAK,CAAG,EAMvB,EAAI,WAAW,EAA4B,GACpD,EAAI,SAAS,CACX,KAAM,SACN,KAAM,CAAC,CAAG,EACV,QAAS,kCAAkC,GAA6B,4BAC1E,CAAC,EAVD,EAAI,SAAS,CACX,KAAM,SACN,KAAM,CAAC,CAAG,EACV,QAAS,8BAA8B,GAAqB,OAAO,EACrE,CAAC,CASP,CAAC,EAEK,GAAiB,EACpB,OAAO,CAAC,CACR,OAAQ,GAAU,GAAe,UAAU,EAAM,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,QAAS,CAC/E,QAAS,8BAA8B,GAAW,KAAK,IAAI,EAAE,EAC/D,CAAC,EAaU,GAAkB,EAAE,aAAa,CAC5C,GAAI,EAAE,KAAK,CAAE,QAAS,sBAAuB,CAAC,CAAC,CAAC,SAAS,EACzD,KAAM,EAAE,OAAO,CAAC,CAAC,IAAI,EAAG,CAAE,QAAS,oCAAqC,CAAC,EACzE,IAAK,EAAE,OAAO,EAAE,OAAO,EAAG,EAAc,CAAC,CAAC,SAAS,EACnD,KAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,EACnC,mBAAoB,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,EACjD,qBAAsB,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC3C,gBAAiB,EAAE,QAAQ,CAAC,CAAC,SAAS,EACtC,SAAU,GAAe,SAAS,EAClC,SAAU,GAAe,SAAS,EAClC,GAAI,EAAE,QAAQ,CAAC,CAAC,SAAS,EACzB,SAAU,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC/B,IAAK,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC1B,KAAM,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC3B,SAAU,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC/B,SAAU,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC/B,YAAa,EAAE,QAAQ,CAAC,CAAC,SAAS,EAClC,eAAgB,EAAE,QAAQ,CAAC,CAAC,SAAS,EACrC,WAAY,EAAE,QAAQ,CAAC,CAAC,SAAS,EACjC,QAAS,EAAE,QAAQ,CAAC,CAAC,SAAS,CAChC,CAAC,ECxFY,GAAqB,EAC/B,YAAY,CACX,GAAI,EAAE,OAAO,EACb,YAAa,EAAE,OAAO,EACtB,WAAY,EAAE,OAAO,CAAC,CAAC,SAAS,EAChC,aAAc,EAAE,QAAQ,CAAC,CAAC,SAAS,EACnC,oBAAqB,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAG,EAAc,CAAC,CAAC,CAAC,SAAS,EAErE,cAAe,GAAe,SAAS,EACvC,kBAAmB,GAAe,SAAS,EAE3C,gBAAiB,GAAe,SAAS,EACzC,gBAAiB,GAAe,SAAS,EACzC,gBAAiB,GAAe,SAAS,CAC3C,CAAC,CAAC,CACD,OACE,GAGQ,EADgB,EAAE,eAAiB,EAAE,oBAClB,CAAC,CAAC,EAAE,WAEhC,CACE,QACE,gGACJ,CACF,CAAC,CACA,UACE,GACC,CASJ,ECzCI,GAAe,sBAerB,IAAI,GAEJ,eAAe,eAAmD,CAChE,GAAI,KAAe,IAAA,GAAW,OAAO,GAErC,GAAI,CAEF,IAAa,MADK,OAAO,oBAAA,CACR,KACnB,MAAQ,CACN,EAAO,KACL,gJACF,EACA,GAAa,EACf,CAEA,OAAO,EACT,CAMA,eAAsB,oBAAuC,CAC3D,OAAQ,MAAM,cAAc,IAAO,EACrC,CAQA,eAAsB,kBAAkB,EAAiD,CACvF,IAAM,EAAQ,MAAM,cAAc,EAClC,GAAI,CAAC,EAAO,MAAU,MAAM,kCAAkC,EAG9D,IAAM,EAAM,IADM,EAAM,GAAc,CACtB,CAAC,CAAC,YAAY,EAC1B,OAAQ,KACZ,GAAI,CACF,OAAO,KAAK,MAAM,CAAG,CACvB,MAAQ,CACN,MACF,CACF,CAOA,eAAsB,kBAAkB,EAAiB,EAAkC,CACzF,IAAM,EAAQ,MAAM,cAAc,EAClC,GAAI,CAAC,EAAO,MAAU,MAAM,kCAAkC,EAG9D,IADkB,EAAM,GAAc,CAClC,CAAC,CAAC,YAAY,KAAK,UAAU,CAAM,CAAC,CAC1C,CAMA,eAAsB,oBAAoB,EAAgC,CACxE,IAAM,EAAQ,MAAM,cAAc,EAC7B,KAEL,GAAI,CAEF,IADkB,EAAM,GAAc,CAClC,CAAC,CAAC,eAAe,CACvB,MAAQ,CAER,CACF,CC1DA,MAAM,GAAkB,EAAE,OAAO,CAC/B,KAAM,EAAE,OAAO,EACf,aAAc,EAAE,OAAO,EACvB,SAAU,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC/B,aAAc,EAAE,OAAO,CAAC,CAAC,SAAS,EAClC,sBAAuB,EAAE,KAAK,CAAC,QAAS,MAAM,CAAC,CAAC,CAAC,SAAS,EAC1D,aAAc,EAAE,IAAI,CAAC,CAAC,SAAS,EAC/B,iBAAkB,EAAE,OAAO,CAAC,CAAC,SAAS,EACtC,YAAa,EAAE,IAAI,CAAC,CAAC,SAAS,CAChC,CAAC,EAGK,GAAiB,EAAE,OAAO,CAC9B,aAAc,EAAE,OAAO,EACvB,cAAe,EAAE,OAAO,CAAC,CAAC,SAAS,EACnC,iBAAkB,EAAE,OAAO,CAC7B,CAAC,EAGK,GAAsB,EAAE,OAAO,CACnC,QAAS,EAAE,QAAQ,SAAS,EAC5B,iBAAkB,EAAE,OAAO,CAC7B,CAAC,EAGK,GAAmB,EAAE,OAAO,CAChC,QAAS,EAAE,QAAQ,MAAM,EACzB,iBAAkB,EAAE,OAAO,EAC3B,aAAc,EAAE,OAAO,EACvB,cAAe,EAAE,OAAO,CAAC,CAAC,SAAS,CACrC,CAAC,EAEK,GAAiB,EAAE,mBAAmB,UAAW,CAAC,GAAqB,EAAgB,CAAC,EAExF,GAAwB,GAAoB,OAAO,CACvD,MAAO,EAAE,OAAO,CAAC,CAAC,SAAS,CAC7B,CAAC,EAEK,GAAqB,GAAiB,OAAO,CACjD,MAAO,EAAE,OAAO,CAAC,CAAC,SAAS,CAC7B,CAAC,EAEK,GAAiB,EAAE,mBAAmB,UAAW,CAAC,GAAuB,EAAkB,CAAC,EAG5F,GAAmB,EAAE,OAAO,CAChC,QAAS,EAAE,QAAQ,CAAC,EACpB,MAAO,EAAE,cAAc,EAAE,OAAO,EAAG,EAAc,EACjD,SAAU,EAAE,cAAc,EAAE,OAAO,EAAG,EAAe,EACrD,aAAc,EAAE,OAAO,CAAC,CAAC,SAAS,CACpC,CAAC,EAKK,GAAqB,QAErB,GAAe,EAAE,gBAAgB,CACrC,EAAE,OAAO,CAAC,CAAC,IAAI,EACf,IACA,EAAE,OAAO,CAAC,CAAC,IAAI,EACf,IACA,EAAE,OAAO,CAAC,CAAC,IAAI,CACjB,CAAC,EAGK,GAAmB,EAAE,OAAO,CAChC,QAAS,EAAE,QAAQ,CAAiB,EACpC,gBAAiB,GACjB,eAAgB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAC1C,uBAAwB,GAAa,SAAS,EAC9C,MAAO,EAAE,cAAc,EAAE,OAAO,EAAG,EAAc,EACjD,SAAU,EAAE,cAAc,EAAE,OAAO,EAAG,EAAe,EACrD,aAAc,EAAE,OAAO,CAAC,CAAC,SAAS,CACpC,CAAC,EAGK,GAAmB,EAAE,OAAO,CAChC,QAAS,EAAE,QAAQ,CAAqB,EACxC,gBAAiB,GACjB,eAAgB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAC1C,uBAAwB,GAAa,SAAS,EAC9C,MAAO,EAAE,cAAc,EAAE,OAAO,EAAG,EAAc,EACjD,SAAU,EAAE,cAAc,EAAE,OAAO,EAAG,EAAe,EACrD,aAAc,EAAE,OAAO,CAAC,CAAC,SAAS,CACpC,CAAC,EA4CD,SAAS,oBAAqB,CAC5B,GAAI,CAAC,GACH,MAAU,MAAM,+BAA+B,EAEjD,OAAO,EAAK,KAAK,GAAW,kBAAmB,aAAa,CAC9D,CAaA,SAAgB,0BACd,EACkC,CAClC,IAAM,EAAS,CACb,GAAI,GAAS,aAAe,CAAE,YAAa,EAAQ,YAAa,EAAI,CAAC,EACrE,GAAI,GAAS,iBAAmB,CAAE,eAAgB,EAAQ,gBAAiB,EAAI,CAAC,EAChF,GAAI,GAAS,YAAc,CAAE,WAAY,EAAQ,WAAY,EAAI,CAAC,CACpE,EACA,OAAO,OAAO,KAAK,CAAM,CAAC,CAAC,OAAS,EAAI,EAAS,IAAA,EACnD,CAEA,SAAS,gBAAgB,EAAc,EAAuC,CAC5E,IAAM,EAAc,GAAmB,CAAM,EAI7C,OAHI,IAAgB,GAAA,yBAAuC,EAClD,EAEF,GAAG,EAAY,GAAG,GAC3B,CAEA,SAAS,wBAAwB,EAAiB,EAAuC,CACvF,IAAM,EAAiB,GAAG,GAAmB,CAAM,EAAE,GACrD,OAAO,EAAQ,WAAW,CAAc,EAAI,EAAQ,MAAM,EAAe,MAAM,EAAI,CACrF,CAEA,SAAS,oBAAoB,EAA8B,CACzD,GAAI,CACF,OAAO,GAAmB,IAAM,CAClC,MAAQ,CACN,MAAO,EACT,CACF,CAMA,SAAS,gBACP,EACA,EACA,EACA,CACA,IAAM,EAAc,GAAmB,CAAc,EAC/C,EAAiB,GAAG,EAAY,GAChC,EAAkB,IAAgB,GAAiB,EAAsB,EAC/E,OAAO,OAAO,QAAQ,CAAK,CAAC,CAAC,MAAM,CAAC,EAAK,KACnC,GAAO,QAAU,EACd,EAAkB,CAAC,EAAI,SAAS,GAAG,EAAI,EAAI,WAAW,CAAc,EADxC,EAEpC,CACH,CAEA,SAAS,cACP,EACA,EACA,EACA,EAA+B,CAAC,EAChC,CACA,IAAM,EAAU,gBAAgB,EAAM,CAAc,EAC9C,EAAY,EAAO,MAAM,GAC/B,GAAI,EACF,MAAO,CAAE,UAAS,WAAU,EAE9B,IAAM,EAAa,gBAAgB,EAAO,MAAO,EAAM,CAAc,EACrE,GAAI,IAAa,GACf,MAAO,CAAE,QAAS,EAAW,GAAI,UAAW,EAAW,EAAG,EAE5D,IAAM,EAAc,GAAmB,CAAc,EACrD,GACE,IAAY,IACX,EAAK,qBAAuB,IAAS,CAAC,oBAAoB,CAAW,GAEtE,MAAO,CAAE,UAAS,WAAU,EAE9B,IAAM,EAAc,EAAO,MAAM,GACjC,OAAO,EAAc,CAAE,QAAS,EAAM,UAAW,CAAY,EAAI,CAAE,UAAS,WAAU,CACxF,CAUA,SAAgB,oBACd,EACA,EACA,EACA,EACQ,CACR,OAAO,cAAc,EAAQ,EAAM,EAAgB,CAAI,CAAC,CAAC,OAC3D,CAEA,SAAgB,kBACd,EACA,EACA,EACA,EACoB,CACpB,GAAM,CAAE,UAAS,aAAc,cAAc,EAAQ,EAAM,EAAgB,CAAI,EAC/E,OAAO,EAAY,wBAAwB,EAAS,CAAc,EAAI,IAAA,EACxE,CAUA,SAAgB,kBACd,EACA,EACA,EACA,EACS,CACT,OAAO,cAAc,EAAQ,EAAM,EAAgB,CAAI,CAAC,CAAC,YAAc,IAAA,EACzE,CAEA,SAAS,kBAAkB,EAAgC,EAAuB,CAChF,OAAO,EAAM,KAAU,IAAA,IAAa,OAAO,KAAK,CAAK,CAAC,CAAC,KAAM,GAAQ,EAAI,SAAS,IAAI,GAAM,CAAC,CAC/F,CAEA,SAAS,kBAAkB,EAA0B,EAAuB,CAC1E,OAAO,OAAO,OAAO,CAAK,CAAC,CAAC,KAAM,GAAU,GAAO,QAAU,CAAI,CACnE,CAQA,SAAgB,qBAAqB,EAAiC,EAAuB,CAC3F,OAAO,kBAAkB,EAAO,MAAO,CAAI,GAAK,kBAAkB,EAAO,MAAO,CAAI,CACtF,CAEA,SAAS,oBAAoB,EAA4B,EAA8B,CACrF,OAAO,kBAAkB,EAAO,CAAW,CAC7C,CASA,SAAS,cAAc,EAAkC,CACvD,IAAM,EAA6B,CAAC,EAEpC,IAAK,GAAM,CAAC,EAAM,KAAW,OAAO,QAAQ,EAAS,KAAK,EACnD,IAEL,EAAM,GAAQ,CACZ,aAAc,EAAO,aACrB,cAAe,EAAO,cACtB,iBAAkB,EAAO,iBACzB,QAAS,MACX,GAGF,MAAO,CACL,QAAS,EACT,gBAAiB,SACjB,QACA,SAAU,EAAS,SACnB,aAAc,EAAS,YACzB,CACF,CAEA,SAAS,qBAAqB,EAAkC,CAC9D,OAAO,EAAE,MAAM,CAAC,CAAC,UAAU,CAAI,CAAC,CAAC,QAAU,EAAO,IAAA,EACpD,CAEA,SAAS,cAAc,EAAgC,CACrD,IAAM,EAA2B,CAAC,EAElC,IAAK,GAAM,CAAC,EAAM,KAAU,OAAO,QAAQ,EAAS,KAAK,EAAG,CAC1D,GAAI,CAAC,EAAO,SACZ,IAAM,EAAQ,qBAAqB,CAAI,EACvC,EAAM,GAAQ,CACZ,GAAG,EACH,GAAI,EAAQ,CAAE,OAAM,EAAI,CAAC,CAC3B,CACF,CAEA,MAAO,CACL,QAAS,EACT,gBAAiB,GACjB,QACA,SAAU,EAAS,SACnB,aAAc,EAAS,YACzB,CACF,CAEA,SAAS,cAAc,EAAgC,CACrD,OAAO,cAAc,cAAc,CAAQ,CAAC,CAC9C,CAEA,SAAS,mBAAmB,EAAwB,CAClD,OAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAC9D,CAEA,eAAe,uBAAuB,EAAc,EAAsC,CACxF,GAAI,CAAE,MAAM,mBAAmB,EAAI,MAAO,GAC1C,GAAI,CAEF,OADA,MAAM,kBAAkB,EAAM,CAAM,EAC7B,EACT,OAAS,EAAO,CAId,OAHA,EAAO,KACL,yFAAyF,mBAAmB,CAAK,GACnH,EACO,EACT,CACF,CAEA,eAAe,2BAA2B,EAGvC,CACD,GAAI,CAAC,EAAO,uBAAwB,OAEpC,IAAM,GAAa,MADO,GAAgB,EAAA,CACX,SAAW,QACtCC,GAAS,EAAY,EAAO,sBAAsB,GACpD,EAAO,KAAK,CAAE;gCACc,OAAO,EAAO,cAAc,EAAE;qCACzB,EAAO,uBAAuB;KAC9D,CAEL,CAMA,eAAsB,oBAAwC,CAC5D,IAAM,EAAa,mBAAmB,EAEtC,GAAI,CAACC,EAAG,WAAW,CAAU,EAAG,CAC9B,IAAM,EAAmB,CACvB,QAAS,EACT,gBAAiB,GACjB,MAAO,CAAC,EACR,SAAU,CAAC,EACX,aAAc,IAChB,EAEA,OADA,oBAAoB,CAAM,EACnB,CACT,CAEA,IAAM,EAAY,GAAUA,EAAG,aAAa,EAAY,OAAO,CAAC,EAKhE,GAA6B,CAAU,EAGvC,IAAM,EACiB,OAAO,GAAc,UAA1C,GAAsD,YAAa,EAC/D,EAAU,QACV,IAAA,GACN,GAAI,OAAO,GAAY,UAAY,EAAU,EAAuB,CAClE,IAAM,EACJ,oBAAsB,EAClB,OAAQ,EAA2C,eAAe,EAClE,IAAA,GACA,EAAa,EACf,gCAAgC,EAAO,oCACvC,2DACJ,MAAU,MAAM,CAAE;iCACW,OAAO,CAAO,EAAE,6CAA6C,IAA8B;QACpH,EAAW;KACd,CACH,CAGA,IAAM,EAAW,GAAiB,UAAU,CAAS,EACrD,GAAI,EAAS,QAEX,OADA,MAAM,2BAA2B,EAAS,IAAI,EACvC,EAAS,KAIlB,IAAM,EAAW,GAAiB,UAAU,CAAS,EACrD,GAAI,EAAS,QAEX,OADA,MAAM,2BAA2B,EAAS,IAAI,EACvC,cAAc,EAAS,IAAI,EAIpC,IAAM,EAAW,GAAiB,UAAU,CAAS,EACrD,GAAI,EAAS,QACX,OAAO,cAAc,EAAS,IAAI,EAIpC,MAAU,MAAM,CAAE;qCACiB,EAAW;;GAE7C,CACH,CAEA,SAAS,YAAY,EAAgC,CACnD,IAAM,EAA6B,CAAC,EACpC,IAAK,GAAM,CAAC,EAAM,KAAU,OAAO,QAAQ,EAAO,KAAK,EAChD,GAAS,EAAM,UAAY,YAChC,EAAM,GAAQ,CACZ,aAAc,EAAM,aACpB,cAAe,EAAM,cACrB,iBAAkB,EAAM,gBAC1B,GAEF,IAAM,EACJ,EAAO,cAAgB,oBAAoB,EAAO,EAAO,YAAY,EACjE,EAAO,aACP,KACN,MAAO,CACL,QAAS,EACT,QACA,SAAU,EAAO,SACjB,aAAc,CAChB,CACF,CAEA,SAAS,2BAA2B,EAA0D,CAC5F,OAAO,OAAO,OAAO,EAAO,QAAQ,CAAC,CAAC,KACnC,GACC,GAAS,eAAiB,IAAA,IAC1B,GAAS,mBAAqB,IAAA,IAC9B,GAAS,cAAgB,IAAA,EAC7B,CACF,CAEA,SAAS,kBAAkB,EAAuD,CAChF,OAAO,OAAO,KAAK,EAAO,KAAK,CAAC,CAAC,KAAM,GAAY,EAAQ,SAAS,GAAG,CAAC,CAC1E,CAEA,SAAS,qBAAqB,EAAuD,CACnF,OAAO,OAAO,OAAO,EAAO,KAAK,CAAC,CAAC,KAChC,GAAS,GAAQ,MAAQ,UAAW,GAAQ,EAAK,QAAU,IAAA,EAC9D,CACF,CAEA,SAAS,gBAAgB,EAAwD,CAE/E,MAAO,CACL,GAFkB,EAAO,UAAY,EAAI,cAAc,CAAM,EAAI,EAGjE,QAAS,EACT,gBAAiB,EACnB,CACF,CAiBA,SAAgB,oBAAoB,EAA4C,CAC9E,IAAM,EAAa,mBAAmB,EAChC,EACJ,EAAO,UAAY,GAAK,OAAO,OAAO,EAAO,KAAK,CAAC,CAAC,KAAM,GAAM,GAAG,UAAY,SAAS,EACpF,EACJ,EAAO,UAAY,GACnB,2BAA2B,CAAM,GACjC,kBAAkB,CAAM,GACxB,qBAAqB,CAAM,EACvB,gBAAgB,CAAM,EACtB,EAAO,UAAY,GAAqB,CAAC,EACvC,YAAY,CAAM,EAClB,EACR,GAAgB,EAAY,GAAc,CAAU,CAAC,CACvD,CAEA,SAAS,aAAa,EAAe,EAAwB,CAC3D,IAAM,EAAS,EAAE,KAAK,CAAC,CAAC,UAAU,CAAK,EACvC,GAAI,CAAC,EAAO,QACV,MAAU,MAAM,sBAAsB,EAAO,uBAAuB,EAEtE,OAAO,EAAO,IAChB,CASA,eAAsB,gBAAgB,EAAgD,CACpF,IAAM,EAAc,MAAM,mBAAmB,CAAI,EACjD,GAAI,EAAa,OAAO,EAExB,MAAU,MAAM,CAAE;;;GAGjB,CACH,CAOA,eAAsB,mBACpB,EAC6B,CAC7B,IAAM,EAAU,GAAM,SAAW,QAAQ,IAAI,wBAE7C,GAAI,GAAM,cAAgB,IAAA,GACxB,OAAO,aAAa,EAAK,YAAa,uBAAuB,EAG/D,GAAI,QAAQ,IAAI,6BACd,OAAO,aACL,QAAQ,IAAI,6BACZ,mDACF,EAGF,GAAI,EAAS,CAGX,IAAM,GADe,MADE,mBAAmB,EAAA,CACZ,SAAS,EACd,EAAE,aAC3B,GAAI,CAAC,EACH,MAAU,MAAM,YAAY,EAAQ,YAAY,EAElD,OAAO,aAAa,EAAM,YAAY,EAAQ,EAAE,CAClD,CAGF,CAWA,eAAsB,oBACpB,EAC6B,CAC7B,GAAI,GAAM,cAAgB,GACxB,MAAM,EAAS,CACb,KAAM,0BACN,QAAS,qCACT,WACE,4GACJ,CAAC,EAGH,IAAM,EAAiB,QAAQ,IAAI,mCAAqC,IAAA,GAClE,EAAuD,GAAM,YAC/D,CACE,OAAQ,EAAK,mBAAqB,SAClC,MAAO,EAAK,WACd,EACA,EACE,CAAE,OAAQ,MAAO,MAAO,CAAe,EACvC,IAAA,GACA,EAAW,GAAqB,MAEhC,EAAU,GAAM,SAAW,QAAQ,IAAI,wBAC7C,GAAI,CAAC,EAAS,OAAO,EAGrB,IAAM,GAAQ,MADS,mBAAmB,EAAA,CACnB,SAAS,GAChC,GAAI,CAAC,EAAO,CACV,GAAI,EAAU,OAAO,EACrB,MAAU,MAAM,YAAY,EAAQ,YAAY,CAClD,CAEA,GAAI,EAAM,cAAgB,EAAM,wBAA0B,OAAQ,CAChE,GAAI,GAAY,IAAa,EAAM,aAAc,CAC/C,IAAM,EACJ,EAAoB,SAAW,MAC3B,qCAAqC,EAAS,6HAA6H,EAAM,aAAa,IAC9L,2CAA2C,EAAM,aAAa,kCACpE,MAAM,EAAS,CACb,KAAM,uCACN,QAAS,YAAY,EAAQ,uCAC7B,UACA,WAAY,wGAAwG,EAAQ,iCAC9H,CAAC,CACH,CACA,OAAO,EAAM,YACf,CAEA,OAAO,GAAY,EAAM,YAC3B,CASA,eAAsB,gBAAgB,EAA+B,CACnE,IAAM,EAAU,GAAM,SAAW,QAAQ,IAAI,wBACvC,EAAW,QAAQ,IAAI,uBAAyB,QAAQ,IAAI,aAKlE,GAJI,GAAY,CAAC,QAAQ,IAAI,uBAC3B,EAAO,KAAK,uEAAuE,EAGjF,EAAU,CACZ,EAAO,eAAe,CAAQ,EAC9B,IAAM,EAAiB,MAAM,yBAAyB,CAAE,UAAS,oBAAqB,EAAK,CAAC,EAE5F,OADA,GAA+B,EAAU,CAAc,EAChD,CACT,CAEA,IAAM,EAAW,MAAM,mBAAmB,EACpC,EAAe,EAAU,EAAS,SAAS,GAAW,IAAA,GAC5D,GAAI,GAAW,CAAC,EACd,MAAU,MAAM,YAAY,EAAQ,YAAY,EAElD,IAAM,EAAO,GAAc,MAAQ,EAAS,aAC5C,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,uBACN,QAAS,mCACT,WAAY,kEACZ,KAAM,CAAE,QAAS,SAAU,KAAM,CAAC,QAAS,GAAG,oBAAoB,CAAE,SAAQ,CAAC,CAAC,CAAE,EAChF,QAAS,CAAE,QAAS,GAAW,IAAK,CACtC,CAAC,EAGH,OAAQ,MAAM,iBAAiB,EAAU,EADrB,EAAe,0BAA0B,CAAY,EAAI,IAAA,GACjB,CAAO,EAAA,CAAG,WACxE,CAOA,eAAsB,eAAe,EAAoD,CACvF,IAAM,EAAU,GAAM,SAAW,QAAQ,IAAI,wBACvC,EAAW,QAAQ,IAAI,uBAAyB,QAAQ,IAAI,aAKlE,GAJI,GAAY,CAAC,QAAQ,IAAI,uBAC3B,EAAO,KAAK,uEAAuE,EAGjF,EAAU,CACZ,EAAO,eAAe,CAAQ,EAC9B,IAAM,EAAS,MAAM,mBAAmB,CAAC,CAAC,UAAY,IAAA,EAAS,EACzD,EAAe,EAAU,GAAQ,SAAS,GAAW,IAAA,GACrD,EAAiB,EAAe,0BAA0B,CAAY,EAAI,IAAA,GAChF,MAAO,CACL,cAAe,GACf,SAAU,KACV,eAAgB,cAChB,QAAS,GAAW,KACpB,YAAa,QAAQ,IAAI,8BAAgC,GAAc,cAAgB,KACvF,WAAY,GAAc,WAAa,GAAO,OAAS,QACvD,YAAa,GAAmB,CAAc,EAC9C,YAAa,aACf,CACF,CAEA,IAAM,EAAS,MAAM,mBAAmB,EAClC,EAAe,EAAU,EAAO,SAAS,GAAW,IAAA,GAC1D,GAAI,GAAW,CAAC,EACd,MAAU,MAAM,YAAY,EAAQ,YAAY,EAGlD,IAAM,EAAiB,EAAe,0BAA0B,CAAY,EAAI,IAAA,GAC1E,EAAc,GAAmB,CAAc,EAC/C,EACJ,QAAQ,IAAI,8BAAgC,GAAc,cAAgB,KAEtE,EAAW,GAAc,MAAQ,EAAO,aACxC,EAAiB,GAAc,KAAO,UAAY,EAAW,UAAY,OAC3E,EAAyC,UAC7C,GAAI,EAAU,CACZ,GAAM,CAAE,UAAS,aAAc,cAAc,EAAQ,EAAU,CAAc,EAC7E,GAAI,EAAW,CACb,IAAM,EAAS,MAAM,cAAc,EAAW,EAAS,CAAQ,CAAC,CAAC,UAAY,IAAA,EAAS,EAClF,IAEF,AACE,EAFc,IAAI,KAAK,EAAU,gBAAgB,GAAK,IAAI,KAI5C,EAAO,aAAe,cAAgB,UAFtC,QAKpB,CACF,CAEA,MAAO,CACL,cAAe,IAAgB,SAAW,IAAgB,cAC1D,SAAU,GAAY,KACtB,iBACA,QAAS,GAAW,KACpB,cACA,WAAY,GAAc,WAAa,GAAO,OAAS,QACvD,cACA,aACF,CACF,CAOA,eAAsB,yBACpB,EAC2C,CAC3C,IAAM,EAAU,GAAM,SAAW,QAAQ,IAAI,wBAC7C,GAAI,CAAC,EACH,OAGF,IAAI,EACJ,GAAI,CACF,EAAW,MAAM,mBAAmB,CACtC,OAAS,EAAO,CACd,GAAI,GAAM,oBACR,OAEF,MAAM,CACR,CACA,IAAM,EAAe,EAAS,SAAS,GACvC,GAAI,CAAC,EAAc,CACjB,GAAI,GAAM,oBACR,OAEF,MAAU,MAAM,YAAY,EAAQ,YAAY,CAClD,CACA,OAAO,0BAA0B,CAAY,CAC/C,CAOA,eAAsB,mBAAmB,EAAmD,CAC1F,IAAM,EAAiB,MAAM,yBAAyB,CAAI,EAC1D,OAAO,GAAkB,CAAc,CACzC,CASA,SAAgB,qBAAqB,EAA0B,CAC7D,EAAO,eAAe,EAAO,WAAW,EACpC,EAAO,cAAc,EAAO,eAAe,EAAO,YAAY,CACpE,CASA,eAAsB,cACpB,EACA,EACA,EAAQ,EACiD,CACzD,GAAI,EAAU,UAAY,UAAW,CACnC,IAAI,EACJ,GAAI,CACF,EAAS,MAAM,kBAAkB,CAAI,CACvC,OAAS,EAAO,CACd,MAAU,MACR,CAAE;4DACkD,EAAM,KAAK,mBAAmB,CAAK,EAAE;;;UAIzF,CAAE,MAAO,CAAM,CACjB,CACF,CACA,GAAI,CAAC,EACH,MAAU,MAAM,CAAE;mDAC2B,EAAM;;;;OAIlD,EAGH,OADA,qBAAqB,CAAM,EACpB,CACT,CAEA,IAAM,EAAS,CACb,YAAa,EAAU,aACvB,aAAc,EAAU,aAC1B,EAEA,OADA,qBAAqB,CAAM,EACpB,CACT,CAYA,eAAsB,eACpB,EACA,EACA,EACA,EACA,EAAkE,CAAC,EACpD,CACf,qBAAqB,CAAM,EAC3B,IAAM,EAAU,gBAAgB,EAAM,EAAK,cAAc,EACnD,EAAQ,EAAK,OAAS,EAAO,MAAM,EAAQ,EAAE,MAC/C,MAAM,uBAAuB,EAAS,CAAM,EAC9C,EAAO,MAAM,GAAW,CACtB,iBAAkB,EAClB,QAAS,UACT,GAAI,EAAQ,CAAE,OAAM,EAAI,CAAC,CAC3B,GAEI,EAAO,MAAM,EAAQ,EAAE,UAAY,WACrC,MAAM,oBAAoB,CAAO,EAEnC,EAAO,MAAM,GAAW,CACtB,aAAc,EAAO,YACrB,cAAe,EAAO,aACtB,iBAAkB,EAClB,QAAS,OACT,GAAI,EAAQ,CAAE,OAAM,EAAI,CAAC,CAC3B,EAEJ,CASA,eAAsB,iBACpB,EACA,EACA,EACA,EACe,CACf,GAAM,CAAE,UAAS,aAAc,cAAc,EAAQ,EAAM,EAAgB,CAAI,EAC3E,GAAW,UAAY,WACzB,MAAM,oBAAoB,CAAO,EAEnC,OAAO,EAAO,MAAM,EACtB,CAUA,eAAsB,qBACpB,EACA,EACA,EACA,EAQA,CACA,GAAM,CAAE,UAAS,aAAc,cAAc,EAAQ,EAAM,EAAgB,CAAI,EAC1E,KAEL,MAAO,CAAE,YAAW,GAAG,MADF,cAAc,EAAW,EAAS,CAAI,CAC7B,CAChC,CAEA,SAAS,qBAAqB,EAAkB,EAAkB,EAAgB,CAC5E,OAAa,EACjB,CAAI,EAAO,eAAiB,IAC1B,EAAO,aAAe,GAExB,IAAK,IAAM,KAAW,OAAO,OAAO,EAAO,QAAQ,EAC7C,GAAS,OAAS,IACpB,EAAQ,KAAO,EAJK,CAO1B,CASA,eAAsB,sBACpB,EACA,EACA,EACA,EACe,CACf,GAAI,IAAe,EAAe,OAClC,qBAAqB,EAAQ,EAAY,CAAa,EACtD,IAAM,EAAe,gBAAgB,EAAe,CAAc,EAC5D,EAAa,IAAI,IAAI,CAAC,EAAY,gBAAgB,EAAY,CAAc,CAAC,CAAC,EACpF,IAAK,IAAM,KAAa,EAClB,IAAc,IACJ,EAAO,MAAM,EAClB,EAAE,UAAY,WACrB,MAAM,oBAAoB,CAAS,EAErC,OAAO,EAAO,MAAM,GAExB,CAEA,SAAS,8BAA8B,EAAc,EAA4B,CAC/E,MAAO,GAAQ,EAAU,OAAS,qBAAqB,CAAI,EAC7D,CAYA,eAAsB,iBACpB,EACA,EACA,EACA,EACgD,CAChD,IAAM,EAAY,EAAU,CAAC,YAAa,CAAO,EAAI,CAAC,EAChD,cAAgB,EAAc,EAAiB,IACnD,EAAS,CACP,OACA,UACA,aACA,KAAM,CAAE,QAAS,SAAU,KAAM,CAAC,QAAS,GAAG,EAAW,QAAQ,CAAE,EACnE,QAAS,CAAE,QAAS,GAAW,IAAK,CACtC,CAAC,EACG,CAAE,QAAS,EAAY,aAAc,cAAc,EAAQ,EAAM,CAAc,EACrF,GAAI,CAAC,EACH,MAAM,aACJ,sBACA,SAAS,EAAK,cACd,8GACF,EAGF,IAAM,EAAmB,wBAAwB,EAAY,CAAc,EACrE,EAAS,MAAM,cAAc,EAAW,EAAY,CAAI,EAE9D,GAAI,IAAI,KAAK,EAAU,gBAAgB,EAAI,IAAI,KAE7C,OADA,GAA+B,EAAO,YAAa,CAAc,EAC1D,CAAE,YAAa,EAAO,YAAa,KAAM,CAAiB,EAGnE,GAAI,CAAC,EAAO,aACV,MAAM,aACJ,qBACA,iBACA,uGACF,EAGF,IAAM,EAAS,GAAiB,CAAc,EAC1C,EACJ,GAAI,CACF,EAAO,MAAM,EAAO,aAAa,CAC/B,YAAa,EAAO,YACpB,aAAc,EAAO,aACrB,UAAW,KAAK,MAAM,EAAU,gBAAgB,CAClD,CAAC,CACH,MAAQ,CACN,MAAM,aACJ,4BACA,0DACA,sJACF,CACF,CACA,qBAAqB,CACnB,YAAa,EAAK,YAClB,aAAc,EAAK,cAAgB,IAAA,EACrC,CAAC,EAED,IAAM,EAAe,IAAI,KACvB,EAAc,EAAK,UAAW,0CAA0C,CAC1E,CAAC,CAAC,YAAY,EAEV,EAAe,EACb,EACJ,EAAU,OAAS,qBAAqB,CAAI,GAAK,qBAAqB,CAAgB,EACpF,EAAQ,EACZ,GACE,8BAA8B,EAAM,CAAS,GAC7C,8BAA8B,EAAkB,CAAS,EAEzD,GAAI,CACF,IAAM,EAAW,MAAM,GAAc,EAAK,YAAa,CAAc,EACrE,EAAe,EAAS,IACxB,EAAQ,EAAS,KACnB,OAAS,EAAO,CACd,EAAO,MAAM,gDAAgD,OAAO,CAAK,GAAG,CAC9E,CA2BF,OAxBA,MAAM,eACJ,EACA,EACA,CACE,YAAa,EAAK,YAClB,aAAc,EAAK,cAAgB,EAAO,YAC5C,EACA,EACA,CAAE,iBAAgB,OAAM,CAC1B,EACA,MAAM,sBAAsB,EAAQ,EAAM,EAAc,CAAc,EAElE,IADiB,gBAAgB,EAAc,CACrB,IACd,EAAO,MAAM,EAClB,EAAE,UAAY,WACrB,MAAM,oBAAoB,CAAU,EAEtC,OAAO,EAAO,MAAM,IAElB,GAAiB,GAAS,IAAkB,GAC9C,EAAO,KAAK,kCAAkC,EAAc,QAAQ,EAAM,GAAG,EAE/E,oBAAoB,CAAM,EAC1B,GAA+B,EAAK,YAAa,CAAc,EACxD,CAAE,YAAa,EAAK,YAAa,KAAM,CAAa,CAC7D,CAWA,SAAgB,eAAe,EAAyC,CAStE,OARI,IAGA,QAAQ,IAAI,mBACP,QAAQ,IAAI,mBAId,GAAW,kBAAuB,EAC3C,CCtoCA,MA4BM,GAAmB,uBAWnB,GAAQ,IAAI,IAwClB,SAAgB,gBAAgB,EAA2B,CACzD,OAAO,gBAAgB,CAAK,EAAI,EAAM,MAAQ,CAChD,CAWA,eAAsB,kBAAkB,EAAwD,CAC9F,IAAM,EAA0B,OAAO,QAAQ,EAAM,KAAO,CAAC,CAAC,CAAC,CAC5D,QAAQ,EAAG,KAAW,CAAC,gBAAgB,CAAK,CAAC,CAAC,CAC9C,KAAK,CAAC,EAAK,KAAW,CAAC,EAAK,gBAAgB,CAAK,CAAC,CAAC,EACtD,GAAI,EAAQ,SAAW,EACrB,MAAO,CAAC,EAGV,IAAM,EAAW,MAAM,sBAAsB,CAAO,EAC9C,EAAe,IAAI,IAAI,EAAS,IAAK,GAAY,EAAQ,GAAG,CAAC,EAEnE,IAAK,GAAM,CAAC,EAAK,KAAU,EACrB,EAAa,IAAI,CAAG,GAAK,OAAO,GAAU,UAC1C,uBAAuB,CAAK,GAC9B,EAAS,KAAK,CAAE,MAAK,SAAU,eAAuB,SAAU,SAAU,CAAC,EAI/E,OAAO,CACT,CAWA,eAAsB,sBAAsB,EAA0C,CACpF,IAAM,EAAM,GAAW,QAAQ,CAAC,CAC7B,OAAO,KAAK,UAAU,CAAC,EAAM,YAAc,GAAI,EAAM,KAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CACjE,OAAO,KAAK,EACT,EAAU,GAAM,IAAI,CAAG,EAC7B,GAAI,EACF,OAAO,EAGT,IAAM,EAAO,iBAAiB,CAAK,EAEnC,OADA,GAAM,IAAI,EAAK,CAAI,EACZ,CACT,CAOA,eAAe,iBAAiB,EAA0C,CACxE,IAAM,EAAW,MAAM,kBAAkB,CAAK,EAE9C,IAAK,IAAM,KAAW,EAChB,EAAQ,WAAa,WACzB,EAAO,KACL,OAAO,EAAQ,IAAI,gHACmD,EAAO,KAAK,mBAAmB,EAAE,EACzG,EAGF,IAAM,EAAS,EAAS,OAAQ,GAAY,EAAQ,WAAa,OAAO,EACxE,GAAI,EAAO,SAAW,EACpB,OAGF,IAAM,EAAW,EAAM,WAAa,OAAO,EAAM,aAAe,GAC1D,EAAO,EACV,IAAK,GAAU,CACd,IAAM,EAAU,EAAM,KAAO,GAAG,EAAM,SAAS,IAAI,EAAM,OAAS,EAAM,SAClE,EAAY,EAAM,QAAU,SAAS,EAAM,UAAY,GAC7D,MAAO,WAAW,EAAM,IAAI,YAAY,EAAQ,GAAG,GACrD,CAAC,CAAC,CACD,KAAK;CAAI,EACN,EAAU,EAAO,EAAE,EAAE,KAAO,MAClC,MAAU,MACR,2BAA2B,EAAS,KAAK,EAAK;+EAIzC,EAAQ,0DACf,CACF,CAYA,eAAe,sBACb,EAC6B,CAC7B,GAAM,CAAC,CAAE,cAAc,CAAE,UAAW,MAAM,QAAQ,IAAI,CACpD,OAAO,oBACP,OAAO,+CACT,CAAC,EAEK,EAAuB,CAAC,EAC1B,EAAU,GACd,IAAK,GAAM,CAAC,EAAK,KAAU,EAAS,CAClC,IAAM,EAAO,GAAG,EAAI,GAAG,OAAO,CAAK,IACnC,EAAO,KAAK,CAAE,MAAK,MAAO,EAAQ,OAAQ,IAAK,EAAQ,OAAS,EAAK,MAAO,CAAC,EAC7E,GAAW,GAAG,EAAK,GACrB,CAEA,IAAM,EAAS,MAAM,EAAW,CAC9B,OAAQ,CAAE,SAAU,qBAAqB,UAAS,YAAa,MAAO,EACtE,QAAS,CAGP,YAAa,GACb,iBAAkB,GAClB,OAAQ,CAGN,MAAO,EACJ,OAAQ,GAAS,EAAK,KAAK,KAAO,6CAAyB,CAAC,CAC5D,IAAK,IAAU,CACd,GAAI,EAAK,KAAK,GACd,OAEA,GAAI,EAAK,KAAK,KAAO,kCAAc,CAAE,QAAS,CAAE,iBAAkB,EAAK,CAAE,EAAI,CAAC,CAChF,EAAE,CACN,CACF,CACF,CAAC,EAEK,EAA+B,CAAC,EAChC,EAAO,IAAI,IACjB,IAAK,IAAM,KAAW,EAAO,SAAU,CACrC,IAAM,EAAQ,EAAO,KAClB,GAAU,EAAQ,MAAM,IAAM,EAAM,OAAS,EAAQ,MAAM,GAAK,EAAM,GACzE,EACA,GAAI,CAAC,EAAO,SAEZ,IAAM,EAAW,EAAQ,OAAO,WAAW,8BAAc,EACrD,EAAQ,OAAO,MAAM,EAAqB,EAC1C,EAAQ,OACN,EAAY,KAAK,UAAU,CAAC,EAAM,IAAK,EAAU,EAAQ,SAAS,CAAC,EACrE,EAAK,IAAI,CAAS,IACtB,EAAK,IAAI,CAAS,EAGlB,EAAS,KAAK,CACZ,IAAK,EAAM,IACX,WACA,KAAM,EAAQ,UACd,GAAI,EAAQ,QAAU,CAAE,QAAS,EAAQ,OAAQ,EAAI,CAAC,EACtD,SAAU,OACZ,CAAC,EACH,CAEA,OAAO,CACT,CAOA,SAAS,gBAAgB,EAAuD,CAC9E,OAAO,OAAO,GAAU,QAC1B,CAQA,SAAS,uBAAuB,EAAwB,CAItD,OAHI,EAAM,OAAS,IAAsB,CAAC,GAAiB,KAAK,CAAK,EAC5D,GAEF,sBAAsB,CAAK,GAAK,GACzC,CAOA,SAAS,sBAAsB,EAAuB,CACpD,IAAM,EAAc,IAAI,IACxB,IAAK,IAAM,KAAQ,EACjB,EAAY,IAAI,GAAO,EAAY,IAAI,CAAI,GAAK,GAAK,CAAC,EAGxD,IAAI,EAAU,EACd,IAAK,IAAM,KAAS,EAAY,OAAO,EAAG,CACxC,IAAM,EAAc,EAAQ,EAAM,OAClC,GAAW,EAAc,KAAK,KAAK,CAAW,CAChD,CACA,OAAO,CACT,CC3RA,SAAgB,wBAA+B,CAC7C,WAME,SAAW,CACX,OAAQ,KAAM,CACZ,YAAY,EAAgC,CAAC,CAC7C,MAAM,SAAyB,CAAC,CAChC,MAAM,KAAqB,CAAC,CAC5B,MAAM,aAAmD,CACvD,MAAO,CAAC,CACV,CACF,CACF,CACF,CCUA,eAAsB,WACpB,EACA,EAA6B,CAAC,EACwB,CACtD,uBAAuB,EACvB,IAAM,EAAY,eAAe,CAAU,EAC3C,GAAI,CAAC,EACH,MAAU,MACR,2FACF,EAEF,IAAM,EAAe,EAAK,QAAQ,QAAQ,IAAI,EAAG,CAAS,EAE1D,GAAI,CAACC,EAAG,WAAW,CAAY,EAC7B,MAAU,MAAM,iCAAiC,GAAY,EAG/D,IAAM,EAAY,GAAc,CAAY,EACtC,EAAc,EAAQ,aAAe,GAAmB,EAC1D,GACF,EAAU,aAAa,IAAI,GAAoB,CAAW,EAE5D,IAAI,EACJ,GAAI,CACF,EAAe,MAAM,OAAO,EAAU,KACxC,OAAS,EAAO,CACd,MAAM,eAAe,EAAO,CAAY,CAC1C,CACA,GACE,OAAO,GAAiB,WACxB,GACA,EAAE,YAAa,IACf,CAAC,EAAa,QAEd,MAAM,aACA,MAAM,wDAAwD,EAClE,CACF,EAGF,IAAM,EAAY,GAAgB,UAAU,EAAa,OAAO,EAChE,GAAI,CAAC,EAAU,QAAS,CACtB,IAAM,EAAS,EAAU,MAAM,OAC5B,IAAK,GAAM,OAAO,EAAE,KAAK,KAAK,GAAG,GAAK,SAAS,IAAI,EAAE,SAAS,CAAC,CAC/D,KAAK;CAAI,EACZ,MAAM,aACA,MAAM,4BAA4B,EAAa,KAAK,GAAQ,EAChE,CACF,CACF,CAEA,IAAM,EAAY,EAAa,QAC/B,GAAI,CACF,MAAM,sBAAsB,CAAE,IAAK,EAAU,IAAK,WAAY,CAAa,CAAC,CAC9E,OAAS,EAAO,CACd,MAAM,aAAiB,MAAQ,aAAa,EAAO,CAAY,EAAI,CACrE,CACA,IAAM,EAAM,EAAU,IAClB,OAAO,YACL,OAAO,QAAQ,EAAU,GAAG,CAAC,CAAC,KAAK,CAAC,EAAK,KAAW,CAAC,EAAK,gBAAgB,CAAK,CAAC,CAAC,CACnF,EACA,IAAA,GAIE,EAAuB,CAAC,EAC9B,IAAK,IAAM,KAAS,GAAiB,CAAY,EAAG,CAClD,IAAM,EAAS,EAAM,IAAK,GAAS,GAAmB,UAAU,CAAI,CAAC,EACjE,EAAO,MAAO,GAAW,EAAO,OAAO,GACzC,EAAW,KAAK,GAAG,EAAO,IAAK,GAAW,EAAO,IAAI,CAAC,CAE1D,CAEA,MAAO,CACL,OAAQ,CACN,GAAG,EACH,GAAI,EAAM,CAAE,KAAI,EAAI,CAAC,EACrB,KAAM,CACR,EACA,QAAS,CACX,CACF,CAQA,SAAS,aAA8B,EAAU,EAAyB,CACxE,OAAO,GAAqB,EAAO,CAAE,SAAU,CAAE,KAAM,CAAa,CAAE,CAAC,CACzE,CAeA,SAAS,mBAAmB,EAA2C,CACrE,GAAI,OAAO,GAAU,WAAY,GAAkB,aAAiB,MAAO,MAAO,GAClF,GAAM,CAAE,OAAM,UAAS,WAAU,aAAc,EAC/C,OACE,IAAS,iBACT,OAAO,GAAY,UACnB,OAAO,GAAa,WACnB,IAAc,IAAA,IAAa,OAAO,GAAc,SAErD,CAaA,SAAgB,eAAe,EAAgB,EAA+B,CAU5E,OATI,mBAAmB,CAAK,EACnB,GAAyB,YAAY,EAAM,QAAS,CAAE,MAAO,CAAM,CAAC,EAAG,CAC5E,SAAU,CACR,KAAM,EAAM,SACZ,GAAI,EAAM,YAAc,IAAA,GAAY,CAAC,EAAI,CAAE,KAAM,EAAM,SAAU,CACnE,CACF,CAAC,EAEG,aAAiB,MAChB,GAAoB,CAAK,CAAC,CAAC,SAAW,EAAQ,aAAa,EAAO,CAAY,EAD/C,CAExC,CCxJA,eAAsB,eAAe,EAA6C,CAKhF,IAAM,EAAc,GAAM,SAAW,QAAQ,IAAI,wBACjD,GAAI,CAAC,EAAa,OAElB,IAAM,GAAU,MADK,mBAAmB,EAAA,CACjB,SAAS,GAC5B,GAAC,GAAW,EAAQ,WAAa,GACrC,MAAM,EAAS,CACb,KAAM,mBACN,QAAS,YAAY,EAAY,iBACjC,QACE,qMACF,WAAY,yFAAyF,EAAY,sBACnH,CAAC,CACH,CC3BA,SAAS,mBAA6B,CAEpC,MAAO,GADU,QAAQ,IAAI,uBAAyB,QAAQ,IAAI,aAEpE,CAQA,eAAsB,QAAQ,EAAiD,CAC7E,IAAM,EAAc,MAAM,gBAAgB,CACxC,QAAS,EAAQ,OACnB,CAAC,EACG,EACJ,GAAI,CACF,EAAiB,MAAM,yBAAyB,CAC9C,QAAS,EAAQ,OACnB,CAAC,CACH,OAAS,EAAO,CACd,GAAI,CAAC,kBAAkB,EAAG,MAAM,CAClC,CAEA,IAAI,EACJ,AAGE,EAHE,EAAQ,SAAS,SAAS,GAAG,EAChB,EAAQ,SAER,6BAA6B,EAAQ,WAGtD,IAAM,EAAM,IAAI,IAAI,EAAc,GAAmB,CAAc,CAAC,EAE9D,EAAW,MAAM,MAAM,EAAI,SAAS,EAAG,CAC3C,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,cAAe,UAAU,IACzB,aAAc,MAAM,GAAU,CAChC,EACA,KAAM,EAAQ,MAAQ,IACxB,CAAC,EAEK,EAAgB,MAAM,EAAS,KAAK,EAE1C,GAAI,CAAC,EAAS,GACZ,MAAM,EAAS,CACb,KAAM,qBACN,QAAS,oBAAoB,EAAS,OAAO,KAAK,KAAK,UAAU,CAAI,IACrE,QAAS,CAAE,OAAQ,EAAS,MAAO,CACrC,CAAC,EAGH,MAAO,CACL,OAAQ,EAAS,OACjB,MACF,CACF,CChEA,eAAsB,6BAA6B,EAA8C,CAC/F,IAAM,EAAc,MAAM,gBAAgB,CAAE,QAAS,EAAQ,OAAQ,CAAC,EAMtE,MAAO,CAAE,OAAA,MALY,EAAmB,CAAW,EAKlC,YAAA,MAJS,gBAAgB,CACxC,QAAS,EAAQ,QACjB,YAAa,EAAQ,WACvB,CAAC,CAC4B,CAC/B,CCXA,SAAgB,WAAqB,CACnC,MAAO,CAAC,IAAQ,QAAQ,MAAM,QAAU,IAAQ,QAAQ,OAAO,QAAU,IAAQ,CAAC,EAAO,QAC3F,CAQA,SAAS,UACP,EACA,EACgC,CAChC,OAAO,KAAO,IAA+B,CAC3C,GAAI,CAAC,UAAU,EAAG,MAAM,IAAI,GAAc,CAAkB,EAC5D,GAAI,CACF,OAAO,MAAM,EAAG,CAAM,CACxB,OAAS,EAAO,CAEd,MADI,aAAiB,IAAiB,QAAQ,KAAK,GAAG,EAChD,CACR,CACF,CACF,CAmDA,MAAa,EAAS,CACpB,QAAS,UACP,GACA,sJACF,EACA,KAAM,UAA8B,EAAK,EACzC,SAAU,UAAkC,EAAQ,EACpD,OAAsB,GACpB,UAAsC,EAAM,CAAC,CAAC,CAAM,CACxD,EC/CA,SAAgB,gBAMd,EAA0C,CAC1C,IAAM,EAAe,CAAC,EAChB,EAAe,CAAC,EAChB,EAAe,CAAC,EAChB,EAAgB,CAAC,EACjB,EAAkB,CAAC,EAEnB,YACJ,EAAQ,SAAW,GAAK,EAAQ,SAAW,GAAK,EAAQ,SAAW,GAAK,EAAS,SAAW,EAE9F,MAAO,CACL,QACA,UACA,UACA,UACA,WACA,YACA,QACA,UAAa,CACX,GAAI,QAAQ,EAAG,MAAO,CAAC,EACvB,IAAM,UAAa,GAAoB,GAAkB,CACvD,KAAK,EAAO,GAAG,EAAK,OACpB,IAAI,EAAK,SAAW,CAAC,EAAA,CAAG,IAAK,GAAM,OAAO,GAAG,CAC/C,EACA,MAAO,CACL,EAAO,KAAK,GAAG,EAAM,EAAE,EACvB,GAAG,EAAQ,QAAQ,UAAU,EAAQ,MAAM,CAAC,EAC5C,GAAG,EAAQ,QAAQ,UAAU,EAAQ,MAAM,CAAC,EAC5C,GAAG,EAAQ,QAAQ,UAAU,EAAQ,MAAM,CAAC,EAC5C,GAAG,EAAS,QAAQ,UAAU,EAAQ,OAAO,CAAC,CAChD,CACF,CACF,CACF,CAOA,SAAgB,oBACd,EAMa,CACb,IAAM,EAAuB,CAAE,OAAQ,EAAG,OAAQ,EAAG,OAAQ,EAAG,QAAS,CAAE,EAE3E,IAAK,IAAM,KAAa,EACtB,EAAQ,QAAU,EAAU,QAAQ,OACpC,EAAQ,QAAU,EAAU,QAAQ,OACpC,EAAQ,QAAU,EAAU,QAAQ,OACpC,EAAQ,SAAW,EAAU,SAAS,OAGxC,OAAO,CACT,CAOA,SAAgB,kBAAkB,EAA8B,CAC9D,IAAM,EAAQ,CACZ,GAAG,EAAQ,OAAO,YAClB,GAAG,EAAQ,OAAO,YAClB,GAAG,EAAQ,OAAO,WACpB,EAMA,OAJI,EAAQ,QAAU,GACpB,EAAM,KAAK,GAAG,EAAQ,QAAQ,YAAY,EAGrC,SAAS,EAAM,KAAK,IAAI,GACjC,CC9GA,SAAgB,sBACd,EACA,EACS,CACT,OAAO,GAAO,EAAQ,GAAO,EAAQ,CAAK,CAAC,CAC7C,CAOA,SAAgBC,kBAAgB,EAAwB,CAatD,OAZI,MAAM,QAAQ,CAAK,EACd,IAAI,EAAM,IAAK,GAAU,IAAS,IAAA,GAAY,OAASA,kBAAgB,CAAI,CAAE,CAAC,CAAC,KAAK,GAAG,EAAE,GAE9F,GAAS,OAAO,GAAU,SAIrB,IAHS,OAAO,QAAQ,CAAgC,CAAC,CAC7D,QAAQ,CAAC,EAAK,KAAgB,IAAQ,aAAe,IAAe,IAAA,EAAS,CAAC,CAC9E,UAAU,CAAC,GAAO,CAAC,KAAW,EAAK,cAAc,CAAK,CACxC,CAAC,CAAC,KAAK,CAAC,EAAK,KAAgB,GAAG,KAAK,UAAU,CAAG,EAAE,GAAGA,kBAAgB,CAAU,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,GAG1G,KAAK,UADV,OAAO,GAAU,SACG,EAAM,SAAS,EAEjB,CAFkB,CAG1C,CAOA,SAAgB,qBAAwB,EAAa,CAInD,OAHI,GAAiC,KAC5B,EAEF,KAAK,MAAMA,kBAAgB,CAAK,CAAC,CAC1C,CAOA,SAAgB,qBAAqB,EAAiD,CACpF,OAAQ,GAAU,CAAC,EAAA,CAAG,SAAS,CACjC,CAQA,SAAgB,mBAAmB,EAAe,EAAyB,CACzE,OACEA,kBAAgB,qBAAqB,CAAI,CAAC,IAAMA,kBAAgB,qBAAqB,CAAK,CAAC,CAE/F,CC9CA,SAAS,UAAU,EAA6B,CAC9C,MAAO,oBAAoB,GAC7B,CA4BA,SAAgB,YAAY,EAAqB,EAAoB,EAAsB,CACzF,MAAO,GAAG,UAAU,CAAW,EAAE,GAAG,EAAK,GAAG,GAC9C,CAeA,SAAS,kBACP,EACA,EACA,EACQ,CACR,MAAO,GAAG,UAAU,CAAW,EAAE,GAAG,EAAO,GAAG,GAAG,EAAO,GAAG,GAAG,EAAM,GAAG,GAAG,EAAM,IAClF,CAYA,SAAgB,gBAAgB,EAAqB,EAAmB,EAA0B,CAChG,OAAO,kBAAkB,EAAa,CAAC,WAAY,CAAS,EAAG,CAAC,OAAQ,CAAQ,CAAC,CACnF,CASA,SAAgB,YAAY,EAAqB,EAAmB,EAA8B,CAChG,OAAO,kBAAkB,EAAa,CAAC,WAAY,CAAS,EAAG,CAAC,WAAY,CAAY,CAAC,CAC3F,CAKA,MAAa,GAAkB,WAClB,GAAqB,cACrB,GAAmB,aAQhC,SAAgB,mBAAmB,EAAuB,CACxD,MAAO,OAAsB,GAC/B,CAQA,SAAgB,sBACd,EACA,EACS,CACT,OAAO,IAAiB,MAAwB,IAAgB,GAClE,CAaA,SAAgB,aACd,EACA,EACA,EACS,CACT,GAAI,CAAC,EAAQ,MAAO,GACpB,IAAM,EAAa,EAAO,IAI1B,OAHI,EACK,IAAU,IAAA,IAAa,IAAe,mBAAmB,CAAK,EAEhE,EAAO,MAAqB,CACrC,CAiBA,SAAS,UAAU,EAAgC,CACjD,OAAO,IAAU,OAAS,2BAA8B,sBAC1D,CAQA,MAAM,GAAoB,iEAQ1B,SAAgB,sBACd,EACA,EAAyB,WACL,CACpB,OAAO,GAAkB,KAAK,CAAK,EAAI,GAAG,UAAU,CAAK,IAAI,IAAU,IAAA,EACzE,CAoBA,SAAgB,qBACd,EACA,EAAyB,WACH,CACtB,GAAI,CAAC,EAAQ,MAAO,CAAC,EACrB,IAAM,EAAS,UAAU,CAAK,EAC9B,OAAO,OAAO,QAAQ,CAAM,CAAC,CAC1B,UAAU,CAAC,GAAI,CAAC,KAAQ,EAAI,EAAI,GAAK,IAAI,EAAU,CAAC,CACpD,SAAS,CAAC,EAAK,KAAY,CAC1B,GAAI,CAAC,EAAI,WAAW,CAAM,EAAG,MAAO,CAAC,EACrC,IAAM,EAAQ,EAAI,MAAM,EAAO,MAAM,EACrC,OAAO,GAAkB,KAAK,CAAK,EAAI,CAAC,CAAE,QAAO,QAAO,CAAC,EAAI,CAAC,CAChE,CAAC,CACL,CAQA,MAAa,EAAiB,CAC5B,cAAe,EAAmB,IAAqB,YAAY,EAAU,QAAQ,IACrF,UAAW,EAAmB,IAC5B,YAAY,EAAU,YAAY,IACpC,IAAM,GAAiB,OAAO,IAC9B,SAAW,GAAiB,YAAY,IAGxC,aAAe,GAAiB,YAAY,EAAK,MACnD,EA6CA,SAAgB,qBACd,EACyD,CACzD,GAAM,CAAE,iBAAgB,gBAAe,YAAW,SAAQ,QAAQ,YAAe,EACjF,GAAI,EACF,MAAO,CACL,OAAQ,CAAC,EACT,OAAQ,qBAAqB,EAAgB,CAAK,CAAC,CAAC,SACjD,CAAE,WAAY,sBAAsB,EAAO,CAAK,GAAK,CAAC,CACzD,CACF,EAEF,IAAM,EAAa,GAAiB,IAAI,IAClC,EAAQ,GAAa,IAAI,IAEzB,EAAiC,CAAC,EACxC,IAAK,GAAM,CAAC,EAAO,KAAW,EAAY,CACxC,IAAM,EAAM,sBAAsB,EAAO,CAAK,EAC9C,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,iBACN,QAAS,mBAAmB,EAAM,sDAClC,WACE,iGACJ,CAAC,EAEH,EAAO,GAAO,CAChB,CAQA,MAAO,CAAE,SAAQ,OANF,qBAAqB,EAAgB,CAAK,CAAC,CAAC,SAAS,CAAE,WAAY,CAChF,GAAI,CAAC,EAAM,IAAI,CAAK,GAAK,EAAW,IAAI,CAAK,EAAG,MAAO,CAAC,EACxD,IAAM,EAAM,sBAAsB,EAAO,CAAK,EAC9C,OAAO,EAAM,CAAC,CAAG,EAAI,CAAC,CACxB,CAEsB,CAAE,CAC1B,CA4BA,eAAsB,iBACpB,EAC6B,CAC7B,GAAM,CAAE,MAAK,UAAS,QAAO,YAAa,EACpC,EAAc,MAAM,GAAgB,EAEpC,EAAa,EAAY,QAC3B,IAAI,EAAY,QAAQ,QAAQ,MAAO,GAAG,IAC1C,UAEJ,MAAO,CACL,MACA,OAAQ,CACN,GAAG,GACF,IAAkB,GAClB,IAAqB,EACtB,GAAI,EAAQ,EAAG,IAAmB,mBAAmB,CAAK,CAAE,EAAI,CAAC,CACnE,EACA,OAAQ,EAAQ,IAAA,GAAY,CAAC,EAAgB,CAC/C,CACF,CA0BA,SAAgB,qBACd,EACA,EACoB,CACpB,GAAM,CAAE,MAAK,gBAAe,YAAW,SAAQ,SAAU,EAKzD,MAJA,GAAM,aAAe,CACnB,GAAI,EAAM,cAAgB,CAAC,EAC3B,CAAE,cAAe,GAAe,IAAI,CAAG,EAAG,YAAW,SAAQ,OAAM,CACrE,EACO,CACT,CAoCA,MAAM,GAAqB,OAAO,oBAAoB,EAQtD,IAAM,mBAAN,KAAyB,CACvB,GACA,GAAwB,IAAI,IAC5B,GAEA,YAAY,EAAiC,CAC3C,KAAK,GAAU,CACjB,CAEA,MAAM,QAAQ,EAA0C,CACtD,GAAI,KAAK,GAAe,CAEtB,MAAM,KAAK,GAAc,UAAY,IAAA,EAAS,EAC9C,MAAM,0BAA0B,KAAK,GAAS,CAAK,EACnD,MACF,CACA,IAAM,EAAS,KAAK,GAAa,IAAI,EAAM,GAAG,GAAK,CAAC,EACpD,EAAO,KAAK,CAAK,EACjB,KAAK,GAAa,IAAI,EAAM,IAAK,CAAM,CACzC,CAEA,OAAuB,CAErB,MADA,MAAK,KAAkB,KAAK,GAAa,EAClC,KAAK,EACd,CAEA,KAAM,IAA8B,CAClC,IAAM,EAAS,CAAC,GAAG,KAAK,EAAY,CAAC,CAAC,UAAU,CAAC,GAAI,CAAC,KAAQ,EAAI,EAAI,GAAK,IAAI,EAAU,EACnF,YAAc,MAAO,CAAC,EAAK,KAAqC,CAEpE,IAAM,GAAgB,MADA,MAAgB,KAAK,GAAQ,YAAY,CAAE,KAAI,CAAC,CAAC,EAAA,EACxC,UAAU,QAAU,CAAC,EAC9C,EAAS,EAAO,OAAO,wBAAyB,CAAa,EACnE,OAAO,cAAc,EAAe,CAAM,EAAI,IAAA,GAAY,CAAE,MAAK,QAAO,CAC1E,EACM,EAAwC,CAAC,EAC3C,EAAS,EAEb,KAAO,EAAS,EAAO,QAAU,EAAW,OAAS,GAAG,CACtD,IAAI,EACF,EAAW,SAAW,EAAI,CAAC,EAAI,IAAA,GACjC,KAAO,EAAS,EAAO,QAAU,EAAW,OAAS,KAAwB,CAEvE,EAAW,OAAS,IAAG,EAAgB,IAAA,IAC3C,IAAM,EAAU,EAAO,MAAM,EAAQ,EAAS,GAAoB,EAClE,GAAU,EAAQ,OAClB,IAAM,EAAU,MAAM,QAAQ,IAC5B,EAAQ,IAAI,KAAO,IAAU,CAC3B,IAAM,EAAU,MAAM,YAAY,CAAK,EACvC,OAAO,EAAU,CAAE,QAAO,SAAQ,EAAI,IAAA,EACxC,CAAC,CACH,EACA,IAAK,IAAM,KAAa,EACjB,IACL,EAAW,KAAK,EAAU,KAAK,EAC/B,GAAe,KAAK,EAAU,OAAO,EAEzC,CAEA,IAAM,EAAe,EAAW,OAAO,EAAG,GAAsB,EAE1D,EACJ,IACC,MAAM,QAAQ,IAAI,EAAa,IAAK,GAAU,YAAY,CAAK,CAAC,CAAC,EAAA,CAAG,OAClE,GAAY,IAAY,IAAA,EAC3B,EACE,EAAe,OAAS,GAC1B,MAAM,KAAK,GAAQ,gBAAgB,CAAE,SAAU,CAAe,CAAC,CAEnE,CACF,CACF,EAEA,SAAS,uBAAuB,EAAoC,CAClE,MAAO,GACL,OAAO,KAAK,EAAM,QAAU,CAAC,CAAC,CAAC,CAAC,QAAU,EAAM,QAAQ,QAAU,EAAM,cAAc,OAE1F,CAEA,SAAS,wBACP,EACA,EACwB,CACxB,GAAM,CAAE,SAAQ,SAAQ,gBAAiB,EACnC,GAAY,GAAgB,CAAC,EAAA,CAAG,IAAK,GACzC,qBAAqB,CAAE,GAAG,EAAS,eAAgB,CAAc,CAAC,CACpE,EACM,EAAiC,CACrC,GAAG,EACH,GAAG,EACH,GAAG,OAAO,OAAO,CAAC,EAAG,GAAG,EAAS,IAAK,GAAY,EAAQ,MAAM,CAAC,CACnE,EACA,IAAK,IAAM,IAAO,CAAC,GAAI,GAAU,CAAC,EAAI,GAAG,EAAS,QAAS,GAAY,EAAQ,MAAM,CAAC,EACpF,OAAO,EAAO,GAEhB,OAAO,CACT,CAEA,SAAS,sBAAsB,EAAqB,EAAqC,CACvF,IAAM,cAAiB,GACrB,GAAW,CAAK,EAAI,GAAyB,EAAM,OAAO,CAAC,EAAI,GAAQ,CAAK,CAAC,CAAC,QAChF,OAAO,GACD,eACF,CAAC,EAAY,CAAU,EACvB,0BAA0B,cAAc,CAAU,EAAE,qCAAqC,cAAc,CAAU,IACjH,CAAE,MAAO,CAAW,CACtB,EACA,CACE,KAAM,kCACN,WACE,sKACF,OAAQ,CAAE,MAAO,EAAY,SAAU,CAAW,CACpD,CACF,CACF,CASA,eAAsB,uBACpB,EACA,EACY,CACZ,IAAM,EAAQ,IAAI,mBAAmB,CAAM,EACrC,EAAc,IAAI,MAAM,EAAQ,CACpC,IAAI,EAAQ,EAAU,EAAU,CAC9B,OAAO,IAAa,GAAqB,EAAQ,QAAQ,IAAI,EAAQ,EAAU,CAAQ,CACzF,CACF,CAAC,EACG,EACJ,GAAI,CACF,EAAS,MAAM,EAAM,CAAW,CAClC,OAAS,EAAY,CACnB,GAAI,CACF,MAAM,EAAM,MAAM,CACpB,OAAS,EAAY,CACnB,MAAM,sBAAsB,EAAY,CAAU,CACpD,CACA,MAAM,CACR,CAEA,OADA,MAAM,EAAM,MAAM,EACX,CACT,CAsBA,eAAsB,oBACpB,EACA,EACe,CACf,GAAI,CAAC,uBAAuB,CAAK,EAAG,OACpC,IAAM,EAAS,EAAoC,IACnD,GAAI,EAAO,CACT,MAAM,EAAM,QAAQ,CAAK,EACzB,MACF,CACA,MAAM,0BAA0B,EAAQ,CAAK,CAC/C,CASA,eAAsB,0BACpB,EACA,EACe,CACf,GAAI,CAAC,uBAAuB,CAAK,EAAG,OACpC,GAAM,CAAE,OAAQ,EAEV,GAAgB,MADA,MAAgB,EAAO,YAAY,CAAE,KAAI,CAAC,CAAC,EAAA,EAClC,UAAU,QAAU,CAAC,EAC9C,EAAS,wBAAwB,EAAe,CAAK,EACvD,cAAc,EAAe,CAAM,GACvC,MAAM,EAAO,YAAY,CAAE,MAAK,OAAQ,CAAO,CAAC,CAClD,CAEA,SAAS,cAAc,EAA2B,EAAoC,CACpF,IAAM,EAAO,OAAO,KAAK,CAAC,EAC1B,OAAO,EAAK,SAAW,OAAO,KAAK,CAAC,CAAC,CAAC,QAAU,EAAK,MAAO,GAAQ,EAAE,KAAS,EAAE,EAAI,CACvF,CC9nBA,eAAsB,iCACpB,EACuB,CACvB,GAAM,CAAE,SAAQ,YAAW,UAAS,UAAW,EACzC,EAAe,MAAM,EAAiB,CAAS,EAC/C,EAAkC,CAAC,EAiBzC,OAhBA,MAAM,QAAQ,IACZ,EAAa,IAAI,KAAO,IAAa,CACnC,IAAM,EAAO,EAAQ,CAAQ,EAC7B,GAAI,CAAC,EACH,OAEF,GAAM,CAAE,YAAa,MAAM,EAAO,YAAY,CAC5C,IAAK,EAAO,CAAI,CAClB,CAAC,EACD,EAAkB,GAAQ,CACxB,WACA,MAAO,GAAU,OAAO,IACxB,UAAW,GAAU,MACvB,CACF,CAAC,CACH,EACO,CACT,CA2BA,SAAgB,8BACd,EACS,CACT,GAAM,CAAE,SAAQ,aAAY,UAAS,QAAO,eAAc,eAAc,YAAW,aACjF,EACI,EAAQ,aAAa,EAAQ,EAAS,CAAK,EAYjD,OAXK,IACE,EAGH,EAAU,KAAK,CACb,eACA,eACA,aAAc,CAChB,CAAC,EAND,EAAU,KAAK,CAAE,eAAc,cAAa,CAAC,GAS1C,CACT,CAqBA,SAAgB,4BAA4B,EAAoD,CAC9F,GAAM,CAAE,SAAQ,aAAY,UAAS,QAAO,kBAAmB,EACzD,EAAQ,aAAa,EAAQ,EAAS,CAAK,EAIjD,OAHI,GAAc,CAAC,GACjB,EAAe,IAAI,CAAU,EAExB,CACT,CCpFA,eAAsB,mBACpB,EACA,EACA,EAAyD,gBACzD,CACA,GAAM,CAAE,YAAW,yBAA0B,EACzC,IAAU,iBAEZ,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,QAAQ,IAAI,KAAO,IAAW,CACzC,MAAM,EAAO,oBAAoB,EAAO,OAAO,EAC/C,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,EACD,GAAG,EAAU,QAAQ,IAAI,KAAO,IAAW,CACzC,MAAM,EAAO,oBAAoB,EAAO,OAAO,EAC/C,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,CACH,CAAC,EAED,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAsB,QAAQ,IAAI,KAAO,IAAQ,CAClD,MAAM,EAAO,gBAAgB,EAAI,OAAO,EACxC,MAAM,oBAAoB,EAAQ,EAAI,WAAW,CACnD,CAAC,EACD,GAAG,EAAsB,QAAQ,IAAK,GAAQ,EAAO,mBAAmB,EAAI,OAAO,CAAC,CACtF,CAAC,GAID,MAAM,QAAQ,IAAI,EAAU,QAAQ,IAAK,GAAQ,EAAO,oBAAoB,EAAI,OAAO,CAAC,CAAC,CAE7F,CAwCA,SAAS,gBAAgB,EAAqB,EAAqB,EAAgB,CACjF,MAAO,oBAAoB,EAAY,iBAAiB,EAAY,iBAAiB,GACvF,CAEA,SAAS,sCACP,EACyB,CACzB,MAAO,CACL,YAAa,EAAM,YACnB,mBAAoB,EAAM,mBAAmB,SAAS,CACxD,CACF,CAEA,SAAS,iCACP,EACyB,CACzB,OAAO,sCAAsC,CAC3C,YAAa,EAAM,aAAe,GAClC,mBAAoB,CAAC,GAAI,EAAM,oBAAsB,CAAC,CAAE,CAC1D,CAAC,CACH,CAEA,SAAS,uBACP,EACA,EACS,CACT,OAAO,mBACL,iCAAiC,CAAQ,EACzC,iCAAiC,CAAO,CAC1C,CACF,CAOA,SAAgB,gCAAgC,EAA2C,CACzF,OACE,EAAQ,iCACR,IAAI,IAAI,EAAQ,YAAY,sBAAsB,IAAK,GAAY,EAAQ,IAAI,CAAC,CAEpF,CAOA,eAAsB,kBAAkB,EAAsB,CAC5D,GAAM,CAAE,SAAQ,cAAa,cAAa,cAAe,EACnD,EAAY,gBAChB,gBACF,EACM,EAAwB,gBAI5B,eAAe,EACX,EAA6B,CAAC,EAC9B,EAAiC,CAAC,EAClC,EAAiB,IAAI,IAErB,EAAmB,MAAM,iCAAiC,CAC9D,SACA,UAAW,MAAO,EAAW,IAAa,CACxC,GAAM,CAAE,iBAAgB,iBAAkB,MAAM,EAAO,mBAAmB,CACxE,cACA,YACA,UACF,CAAC,EACD,MAAO,CAAC,EAAgB,CAAa,CACvC,EACA,QAAU,GAAa,EAAS,KAChC,OAAS,GAAS,YAAY,EAAa,gBAAiB,CAAI,CAClE,CAAC,EAGK,EAAoB,IAAI,IAExB,EAAwB,EAAa,CAAC,EAAI,EAAY,sBAC5D,IAAK,IAAM,KAAkB,EAAuB,CAClD,IAAM,EAAS,EACT,EAAO,EAAe,KACtB,EAAW,EAAiB,GAC5B,EAAc,MAAM,iBAAiB,CACzC,IAAK,YAAY,EAAa,gBAAiB,CAAI,EACnD,QAAS,EAAY,KACrB,MAAO,EAAY,EACrB,CAAC,EACK,EAAU,iCAAiC,CAAM,EACjD,EAAU,CACd,cACA,cAAe,CACb,OACA,YAAa,EAAO,aAAe,GACnC,mBAAoB,EAAO,oBAAsB,CAAC,CACpD,CACF,EAEA,GAAI,EAAU,CACZ,IAAM,EAAQ,8BAA8B,CAC1C,OAAQ,EAAS,UACjB,WAAY,EAAS,MACrB,QAAS,EAAY,KACrB,MAAO,EAAY,GACnB,aAAc,gBACd,aAAc,EACd,YACA,WACF,CAAC,EAGC,GACA,sBAAsB,EAAS,UAAW,EAAY,MAAM,GAC5D,uBAAuB,EAAS,SAAU,CAAO,EAEjD,EAAU,UAAU,KAAK,CAAE,MAAK,CAAC,EAEjC,EAAU,QAAQ,KAAK,CACrB,OACA,UACA,aACF,CAAC,EAGC,GACF,EAAkB,IAAI,CAAI,EAE5B,OAAO,EAAiB,EAC1B,MACE,EAAU,QAAQ,KAAK,CACrB,OACA,UACA,aACF,CAAC,EAED,EAAkB,IAAI,CAAI,CAE9B,CACA,OAAO,QAAQ,CAAgB,CAAC,CAAC,SAAS,CAAC,KAAU,CACnD,IAAM,EAAQ,EAAiB,GACzB,EAAQ,GAAO,MACP,4BAA4B,CACxC,OAAQ,GAAO,UACf,WAAY,EACZ,QAAS,EAAY,KACrB,MAAO,EAAY,GACnB,gBACF,CACQ,GACN,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,MACF,CACF,CAAC,CAEL,CAAC,EAGD,IAAM,EAA0B,IAAI,IACpC,IAAK,IAAM,KAAW,EAChB,EAAQ,gBAAkB,IAAA,IAAa,EAAkB,IAAI,EAAQ,IAAI,GAC3E,EAAwB,IAAI,EAAQ,KAAM,EAAQ,aAAa,EAMnE,IAAM,EAA2B,IAAI,IAC/B,EAAyB,CAAC,GAAG,CAAiB,CAAC,CAAC,OACnD,GAAS,CAAC,EAAU,QAAQ,KAAM,GAAM,EAAE,OAAS,CAAI,CAC1D,EACA,MAAM,QAAQ,IACZ,EAAuB,IAAI,KAAO,IAAS,CACzC,IAAM,EAAoB,MAAM,EAAU,SAAY,CACpD,GAAM,CAAE,iBAAkB,MAAM,EAAO,kBAAkB,CACvD,cACA,kBAAmB,CACrB,CAAC,EACD,OAAO,MAAM,QAAQ,IACnB,EAAc,IAAI,KAAO,IAAM,CAC7B,GAAM,CAAE,YAAa,MAAM,EAAO,YAAY,CAC5C,IAAK,gBAAgB,EAAa,EAAM,EAAE,MAAM,CAClD,CAAC,EACD,MAAO,CACL,OAAQ,EAAE,OACV,UAAW,GAAU,MACvB,CACF,CAAC,CACH,CACF,CAAC,EACG,GACF,EAAyB,IAAI,EAAM,CAAiB,CAExD,CAAC,CACH,EAGA,IAAK,IAAM,KAAQ,EAAmB,CACpC,IAAM,EAAU,IAAI,IAAI,EAAwB,IAAI,CAAI,GAAK,CAAC,CAAC,EACzD,EAAkB,EAAyB,IAAI,CAAI,GAAK,CAAC,EACzD,EAAc,IAAI,IAAI,EAAgB,IAAK,GAAM,EAAE,MAAM,CAAC,EAC1D,EAAkB,IAAI,IAC1B,EACG,OAAQ,GAAM,aAAa,EAAE,UAAW,EAAY,KAAM,EAAY,EAAE,CAAC,CAAC,CAC1E,IAAK,GAAM,EAAE,MAAM,CACxB,EAEA,IAAK,IAAM,KAAU,EACnB,GAAK,EAAY,IAAI,CAAM,EAYzB,EAAsB,UAAU,KAAK,CAAE,KAAM,CAAO,CAAC,MAZzB,CAC5B,IAAM,EAAc,MAAM,iBAAiB,CACzC,IAAK,gBAAgB,EAAa,EAAM,CAAM,EAC9C,QAAS,EAAY,KACrB,MAAO,EAAY,EACrB,CAAC,EACD,EAAsB,QAAQ,KAAK,CACjC,KAAM,EACN,QAAS,CAAE,cAAa,kBAAmB,EAAM,QAAO,EACxD,aACF,CAAC,CACH,CAMF,GAAI,EAAwB,IAAI,CAAI,EAC7B,IAAA,IAAM,KAAU,EACd,EAAQ,IAAI,CAAM,GACrB,EAAsB,QAAQ,KAAK,CACjC,KAAM,EACN,QAAS,CAAE,cAAa,QAAO,CACjC,CAAC,CAIT,CAEA,MAAO,CAAE,YAAW,wBAAuB,YAAW,YAAW,gBAAe,CAClF,CC1TA,eAAsB,eACpB,EACA,EACA,EAAyD,gBACzD,CACA,GAAM,CAAE,aAAc,EAClB,IAAU,gBACZ,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,QAAQ,IAAI,KAAO,IAAW,CACzC,EAAO,QAAQ,KAAO,MAAM,GAC1B,EACA,EAAc,EAAO,QAAQ,YAAa,6BAA6B,EACvE,EAAO,QAAQ,KACf,gBACF,EACA,MAAM,EAAO,gBAAgB,EAAO,OAAO,EAC3C,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,EACD,GAAG,EAAU,QAAQ,IAAI,KAAO,IAAW,CACzC,EAAO,QAAQ,KAAO,MAAM,GAC1B,EACA,EAAc,EAAO,QAAQ,YAAa,6BAA6B,EACvE,EAAO,QAAQ,KACf,gBACF,EACA,MAAM,EAAO,gBAAgB,EAAO,OAAO,EAC3C,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,CACH,CAAC,EAED,MAAM,QAAQ,IAAI,EAAU,QAAQ,IAAK,GAAQ,EAAO,gBAAgB,EAAI,OAAO,CAAC,CAAC,CAEzF,CA6BA,SAAS,kCACP,EACqB,CACrB,MAAO,CACL,cAAe,EAAM,cACrB,KAAM,EAAM,KAAK,SAAS,CAC5B,CACF,CAEA,SAAS,6BAA6B,EAAsD,CAC1F,OAAO,kCAAkC,CACvC,cAAe,EAAM,eAAiB,GACtC,KAAM,CAAC,GAAI,EAAM,MAAQ,CAAC,CAAE,CAC9B,CAAC,CACH,CAEA,SAAS,mBAAmB,EAA0B,EAA4C,CAChG,OAAO,mBACL,6BAA6B,CAAQ,EACrC,6BAA6B,CAAO,CACtC,CACF,CAOA,eAAsB,cAAc,EAAsB,CACxD,GAAM,CAAE,SAAQ,cAAa,cAAa,cAAe,EACnD,EAAY,gBAChB,YACF,EACM,EAA6B,CAAC,EAC9B,EAAiC,CAAC,EAClC,EAAiB,IAAI,IAErB,EAAmB,MAAM,iCAAiC,CAC9D,SACA,UAAW,MAAO,EAAW,IAAa,CACxC,GAAM,CAAE,aAAY,iBAAkB,MAAM,EAAO,eAAe,CAChE,cACA,YACA,UACF,CAAC,EACD,MAAO,CAAC,EAAY,CAAa,CACnC,EACA,QAAU,GAAa,EAAS,KAChC,OAAS,GAAS,YAAY,EAAa,YAAa,CAAI,CAC9D,CAAC,EAEK,EAAoB,EAAa,CAAC,EAAI,EAAY,kBAClD,EAAwB,gCAAgC,CAAO,EACrE,IAAK,IAAM,KAAkB,EAAmB,CAC9C,IAAM,EAAS,EACT,EAAO,EAAe,KACtB,EAAW,EAAiB,GAC5B,EAAc,MAAM,iBAAiB,CACzC,IAAK,YAAY,EAAa,YAAa,CAAI,EAC/C,QAAS,EAAY,KACrB,MAAO,EAAY,EACrB,CAAC,EACK,EAAe,MAAM,GACzB,EACA,EACA,EAAO,KAAO,CAAC,GAAG,EAAO,IAAI,EAAI,CAAC,EAClC,iBACA,CAAE,mBAAoB,CAAsB,CAC9C,EACM,EAAU,6BAA6B,CAAE,GAAG,EAAQ,KAAM,CAAa,CAAC,EACxE,EAAU,CACd,cACA,cAAe,EACf,cAAe,EAAO,cACtB,KAAM,EAAO,KAAO,CAAC,GAAG,EAAO,IAAI,EAAI,CAAC,CAC1C,EAEI,GACY,8BAA8B,CAC1C,OAAQ,EAAS,UACjB,WAAY,EAAS,MACrB,QAAS,EAAY,KACrB,MAAO,EAAY,GACnB,aAAc,YACd,aAAc,EACd,YACA,WACF,CAGM,GACJ,sBAAsB,EAAS,UAAW,EAAY,MAAM,GAC5D,mBAAmB,EAAS,SAAU,CAAO,EAE7C,EAAU,UAAU,KAAK,CAAE,MAAK,CAAC,EAEjC,EAAU,QAAQ,KAAK,CACrB,OACA,UACA,aACF,CAAC,EAEH,OAAO,EAAiB,IAExB,EAAU,QAAQ,KAAK,CACrB,OACA,UACA,aACF,CAAC,CAEL,CAqBA,OApBA,OAAO,QAAQ,CAAgB,CAAC,CAAC,SAAS,CAAC,EAAM,KAAW,CAC1D,IAAM,EAAQ,GAAO,MACP,4BAA4B,CACxC,OAAQ,GAAO,UACf,WAAY,EACZ,QAAS,EAAY,KACrB,MAAO,EAAY,GACnB,gBACF,CACQ,GACN,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,cAAe,CACjB,CACF,CAAC,CAEL,CAAC,EAEM,CAAE,YAAW,YAAW,YAAW,gBAAe,CAC3D,CCnLA,eAAsB,iBACpB,EACA,EACA,EAAyD,gBACzD,CACA,GAAI,IAAU,gBAAiB,CAG7B,IAAM,EAAU,CAAC,GAAG,EAAU,QAAS,GAAG,EAAU,SAAS,EAC7D,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,QAAQ,IAAI,KAAO,IAAW,CACzC,EAAO,QAAQ,KAAO,MAAM,GAC1B,EACA,EAAc,EAAO,QAAQ,YAAa,6BAA6B,EACvE,EAAO,QAAQ,KACf,MACF,EACA,MAAM,EAAO,kBAAkB,EAAO,OAAO,EAC7C,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,EACD,GAAG,EAAQ,IAAI,KAAO,IAAW,CAC/B,EAAO,QAAQ,KAAO,MAAM,GAC1B,EACA,EAAc,EAAO,QAAQ,YAAa,6BAA6B,EACvE,EAAO,QAAQ,KACf,MACF,EACA,MAAM,EAAO,kBAAkB,EAAO,OAAO,EAC7C,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,CACH,CAAC,CACH,MAGE,MAAM,QAAQ,IACZ,EAAU,QAAQ,IAAI,KAAO,IAAQ,CACnC,MAAM,EAAO,kBAAkB,EAAI,OAAO,CAC5C,CAAC,CACH,CAEJ,CA+CA,SAAS,YAAY,EAAiD,CACpE,OAAQ,GAAU,CAAC,EAAA,CAAG,SAAS,CACjC,CAEA,SAAS,mBACP,EACoC,CACpC,MAAO,CAAC,GAAI,GAAa,CAAC,CAAE,CAAC,CAC1B,IAAK,IAAc,CAClB,YAAa,EAAc,EAAS,YAAa,8BAA8B,EAC/E,iBAAkB,EAAS,kBAAoB,EACjD,EAAE,CAAC,CACF,UAAU,EAAM,IACX,EAAK,cAAgB,EAAM,YAGxB,EAAK,iBAAiB,cAAc,EAAM,gBAAgB,EAFxD,EAAK,YAAc,EAAM,WAGnC,CACL,CAEA,SAAS,sBACP,EAWyB,CACzB,MAAO,CAAC,GAAI,GAAgB,CAAC,CAAE,CAAC,CAC7B,IAAK,IAAa,CACjB,KAAM,EAAQ,MAAQ,GACtB,YAAa,EAAQ,aAAe,GACpC,QAAS,YAAY,EAAQ,OAAO,EACpC,YAAa,EAAQ,aAAe,GACpC,aAAc,EAAQ,cAAgB,GAGtC,QAAS,EAAQ,SAAW,GAC5B,SAAU,EAAQ,UAAY,CAChC,EAAE,CAAC,CACF,UAAU,EAAM,IAAU,EAAK,KAAK,cAAc,EAAM,IAAI,CAAC,CAClE,CAEA,SAAS,wBACP,EAWuB,CACvB,MAAO,CACL,cAAe,EAAM,cACrB,kBAAmB,EAAM,kBACzB,KAAM,YAAY,EAAM,IAAI,EAC5B,UAAW,CAAC,GAAG,EAAM,SAAS,EAC9B,mBAAoB,YAAY,EAAM,kBAAkB,EACxD,qBAAsB,EAAM,qBAC5B,SAAU,EAAM,SAChB,aAAc,CAAC,GAAG,EAAM,YAAY,CACtC,CACF,CAEA,SAAS,+BACP,EACA,EACA,EACA,EACA,EACuB,CACvB,OAAO,wBAAwB,CAC7B,cAAe,GAAiB,GAChC,kBAAmB,GAAqB,GACxC,OACA,UAAW,mBAAmB,EAAY,UAAU,IAAK,GAAa,cAAc,CAAQ,CAAC,CAAC,EAC9F,mBAAoB,EAAY,OAAO,oBAAsB,CAAC,EAC9D,qBAAsB,EAAY,OAAO,sBAAwB,GACjE,SAAU,GACV,aAAc,sBAAsB,CAAY,CAClD,CAAC,CACH,CAEA,SAAS,uCAAuC,EAA8C,CAC5F,OAAO,wBAAwB,CAC7B,cAAe,EAAI,cACnB,kBAAmB,EAAI,kBACvB,KAAM,EAAI,KACV,UAAW,mBAAmB,EAAI,SAAS,EAC3C,mBAAoB,EAAI,mBACxB,qBAAsB,EAAI,qBAC1B,SAAU,EAAI,SACd,aAAc,sBAAsB,EAAI,YAAY,CACtD,CAAC,CACH,CAEA,SAAS,qBAAqB,EAA4B,EAAyC,CACjG,OAAO,mBAAmB,uCAAuC,CAAQ,EAAG,CAAO,CACrF,CAQA,eAAsB,gBACpB,EACA,EACA,CACA,GAAM,CAAE,SAAQ,cAAa,cAAa,cAAe,EACnD,EAA6B,CAAC,EAC9B,EAAiC,CAAC,EAClC,EAAiB,IAAI,IACrB,EAAY,gBAMhB,cAAc,EAEV,EAAuB,MAAM,EAAiB,MAAO,EAAW,IAAgB,CACpF,GAAM,CAAE,eAAc,iBAAkB,MAAM,EAAO,iBAAiB,CACpE,cACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAc,CAAa,CACrC,CAAC,EAED,GAAI,EAAY,CAId,IAAM,EAAa,EAAY,GAC3B,EACA,EAAqB,OAAQ,GAAQ,EAAI,OAAS,EAAY,IAAI,EAChE,EAAQ,MAAM,QAAQ,IAC1B,EAAW,IAAI,KAAO,IAAQ,CAC5B,IAAM,EAAS,MAAM,eAAe,EAAQ,EAAa,EAAI,IAAI,EACjE,OAAO,4BAA4B,CACjC,SACA,WAAY,IAAA,YACZ,QAAS,EAAY,KACrB,MAAO,EAAY,GACnB,gBACF,CAAC,EACG,EAAI,KACJ,IACN,CAAC,CACH,EACA,IAAK,IAAM,KAAQ,EACb,GACF,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,gBAAiB,CACnB,CACF,CAAC,EAGL,OAAO,cAAc,EAAW,EAAW,EAAW,CAAc,CACtE,CAIA,GAAI,EAAY,UAAU,SAAW,EACnC,OAAO,cAAc,EAAW,EAAW,EAAW,CAAc,EAGtE,IAAI,EACA,EACJ,GAAI,EAAY,YAAa,CAC3B,EAAgB,EAAY,YAAY,OAAO,KAE/C,IAAM,EAAa,EAAY,YAAY,OAAO,WAC9C,IACF,EAAoB,EAAW,KAEnC,MAAO,GAAI,EAAY,OAAO,KAAM,CAGlC,GADA,EAAgB,EAAY,OAAO,KAAK,KACpC,EAAQ,4BAA4B,IAAI,CAAa,EACvD,EAAoB,EAAQ,2BAA2B,IAAI,CAAa,MACnE,CACL,IAAM,EAAa,MAAM,EAAiB,MAAO,EAAW,IAAgB,CAC1E,GAAM,CAAE,aAAY,iBAAkB,MAAM,EAAO,mBAAmB,CACpE,cACA,cAAe,EACb,EACA,sDACF,EACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAY,CAAa,CACnC,CAAC,EACD,GAAI,EAAW,OAAS,EAAG,CACzB,GAAM,CAAC,GAAe,EAClB,IACF,EAAoB,EAAY,KAEpC,CACF,CACF,CACA,IAAM,EAAc,MAAM,iBAAiB,CACzC,IAAK,YAAY,EAAa,cAAe,EAAY,IAAI,EAC7D,QAAS,EAAY,KACrB,MAAO,EAAY,GACnB,SAAU,EAAY,OAAO,QAC/B,CAAC,EACK,EAAiB,MAAM,eAAe,EAAQ,EAAa,EAAY,IAAI,EACjF,kBAAkB,EAAY,KAAM,EAAgB,CAAW,EAC/D,IAAM,EAAkB,oBAAoB,EAAgB,EAAY,OAAO,QAAQ,EACjF,EAAwB,gCAAgC,CAAO,EAC/D,EAAe,MAAM,GACzB,EACA,EACA,EAAY,OAAO,KACnB,OACA,CAAE,mBAAoB,CAAsB,CAC9C,EACM,EAAe,kBAAkB,EAAa,CAAsB,EACpE,EAAU,+BACd,EACA,EACA,EACA,EACA,CACF,EACM,EAAU,CACd,cACA,gBAAiB,EAAY,KAC7B,gBACA,oBACA,KAAM,EAAY,OAAO,KACzB,UAAW,EAAY,UAAU,IAAK,GAAa,cAAc,CAAQ,CAAC,EAC1E,mBAAoB,EAAY,OAAO,mBACvC,qBAAsB,EAAY,OAAO,qBACzC,cACF,EACM,EAAW,EAAqB,KAAM,GAAQ,EAAI,OAAS,EAAY,IAAI,EAIjF,GAAI,EAAY,GAAI,CAClB,IAAM,EAAY,EAAqB,OAAQ,GAAQ,EAAI,OAAS,EAAY,IAAI,EAC9E,EAAc,MAAM,QAAQ,IAChC,EAAU,IAAI,KAAO,IAEZ,aAAa,MADC,eAAe,EAAQ,EAAa,EAAI,IAAI,EACrC,EAAY,KAAM,EAAY,EAAE,EAAI,EAAI,KAAO,IAC5E,CACH,EACA,IAAK,IAAM,KAAQ,EACb,GACF,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,gBAAiB,CACnB,CACF,CAAC,CAGP,CAEA,GAAI,EAAU,CACZ,IAAM,EAAQ,8BAA8B,CAC1C,OAAQ,EACR,WAAY,IAAiB,IAC7B,QAAS,EAAY,KACrB,MAAO,EAAY,GACnB,aAAc,cACd,aAAc,EAAY,KAC1B,YACA,WACF,CAAC,EACK,EAA4B,CAChC,KAAM,EAAY,KAClB,UACA,aACF,EACA,GACE,GACA,sBAAsB,EAAgB,EAAY,MAAM,GACxD,qBAAqB,EAAU,CAAO,GACtC,EAAgB,SAAW,EAG3B,EAAU,UAAU,KAAK,CAAM,MAC1B,CACL,IAAM,EAAU,CACd,GAAG,uBAAuB,EAAS,aAAc,CAAY,EAC7D,GAAG,CACL,EACI,EAAQ,OAAS,IACnB,EAAO,QAAU,GAEnB,EAAU,QAAQ,KAAK,CAAM,CAC/B,CACF,KAAO,CACL,IAAM,EAAU,CAAC,GAAG,uBAAuB,IAAA,GAAW,CAAY,EAAG,GAAG,CAAe,EACvF,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAY,KAClB,UACA,cACA,QAAS,EAAQ,OAAS,EAAI,EAAU,IAAA,EAC1C,CAAC,CACH,CAEA,OAAO,cAAc,EAAW,EAAW,EAAW,CAAc,CACtE,CAgBA,SAAS,cACP,EACA,EACA,EACA,EACiG,CACjG,OAAO,OAAO,OAAO,EAAW,CAAE,YAAW,YAAW,gBAAe,CAAC,CAC1E,CAEA,eAAe,eACb,EACA,EACA,EAC6C,CAO7C,OAAO,MANgB,EAAU,SAAY,CAC3C,GAAM,CAAE,YAAa,MAAM,EAAO,YAAY,CAC5C,IAAK,YAAY,EAAa,cAAe,CAAO,CACtD,CAAC,EACD,OAAO,CACT,CAAC,EAAA,EACgB,MACnB,CAWA,SAAgB,uBACd,EACA,EACU,CACV,IAAM,EAAiB,IAAI,KAAK,GAAoB,CAAC,EAAA,CAAG,IAAK,GAAM,CAAC,EAAE,MAAQ,GAAI,CAAC,CAAC,CAAC,EAC/E,EAAgB,IAAI,IAAI,EAAgB,IAAK,GAAM,CAAC,EAAE,MAAQ,GAAI,CAAC,CAAC,CAAC,EACrE,EAAmD,CAAC,EAC1D,IAAK,GAAM,CAAC,EAAM,KAAY,EAAe,CAC3C,IAAM,EAAW,EAAe,IAAI,CAAI,EACnC,EAGF,mBAAmB,sBAAsB,CAAC,CAAQ,CAAC,CAAC,CAAC,GAAI,sBAAsB,CAAC,CAAO,CAAC,CAAC,CAAC,EAAE,GAE7F,EAAQ,KAAK,CAAE,OAAM,OAAQ,EAAQ,MAAO,CAAC,EAJ7C,EAAQ,KAAK,CAAE,OAAM,OAAQ,EAAQ,MAAO,CAAC,CAMjD,CACA,IAAK,IAAM,KAAQ,EAAe,KAAK,EAChC,EAAc,IAAI,CAAI,GACzB,EAAQ,KAAK,CAAE,OAAM,OAAQ,EAAQ,MAAO,CAAC,EAGjD,OAAO,EACJ,UAAU,EAAM,IAAU,EAAK,KAAK,cAAc,EAAM,IAAI,CAAC,CAAC,CAC9D,IAAK,GAAU,GAAG,EAAM,OAAO,GAAG,EAAM,KAAK,eAAe,CACjE,CAeA,SAAS,kBACP,EACA,EACA,EACM,CACN,IAAM,EAAS,IAAI,IAAI,CACrB,GAAG,OAAO,KAAK,GAAkB,CAAC,CAAC,EACnC,GAAG,OAAO,KAAK,EAAM,QAAU,CAAC,CAAC,CACnC,CAAC,EACD,IAAK,IAAM,KAAO,EAAM,QAAU,CAAC,EACjC,EAAO,OAAO,CAAG,EAEnB,GAAI,EAAO,MAAA,GAA6B,OACxC,IAAM,EAAQ,IAAI,IAAI,OAAO,KAAK,EAAM,QAAU,CAAC,CAAC,CAAC,EAC/C,EAAW,CAAC,GAAG,CAAM,CAAC,CAAC,OAAQ,GAAQ,CAAC,EAAM,IAAI,CAAG,CAAC,CAAC,CAAC,SAAS,EACvE,MAAM,EAAS,CACb,KAAM,8BACN,QAAS,gBAAgB,EAAQ,gBAAgB,EAAO,KAAK,2CAC7D,QAAS,GAAG,EAAM,KAAK,6BAA6B,EAAS,OAAO,+CAA+C,EAAS,OAAS,KAAK,EAAS,KAAK,IAAI,EAAE,GAAK,GAAG,GACtK,WACE,iGACJ,CAAC,CACH,CASA,SAAS,oBACP,EACA,EACU,CACV,IAAM,EAAW,GAAkB,CAAC,EAC9B,SAAY,GAAgB,OAAO,OAAO,EAAU,CAAG,EAC7D,OAAO,OAAO,QAAQ,GAAY,CAAC,CAAC,CAAC,CAClC,QAAQ,CAAC,EAAK,KAAW,CAAC,SAAS,CAAG,GAAK,EAAS,KAAS,CAAK,CAAC,CACnE,UAAU,CAAC,GAAO,CAAC,KAAW,EAAK,cAAc,CAAK,CAAC,CAAC,CACxD,KAAK,CAAC,KAAS,GAAG,SAAS,CAAG,EAAI,EAAQ,OAAS,EAAQ,OAAO,GAAG,EAAI,YAAY,CAC1F,CAEA,SAAS,kBACP,EACA,EAC8C,CAC9C,IAAM,EAAW,EAAY,oBAAoB,UAAY,CAAC,EAI9D,OAHI,EAAS,SAAW,EACf,CAAC,EAEH,EAAS,IAAK,GAAW,CAC9B,IAAM,EAAc,GAAwB,cAAc,IAAI,EAAO,QAAQ,IAAI,EACjF,GAAI,CAAC,EACH,MAAM,EACJ,iBAAiB,EAAO,QAAQ,KAAK,sDACvC,EAEF,IAAI,EAAe,GACnB,GAAI,EAAO,UAAW,CACpB,IAAM,EAAU,GAAwB,eAAe,IAAI,EAAO,QAAQ,IAAI,EAC9E,GAAI,CAAC,EACH,MAAM,EACJ,iBAAiB,EAAO,QAAQ,KAAK,uEACvC,EAEF,EAAe,CACjB,CACA,MAAO,CACL,KAAM,EAAO,QAAQ,KACrB,YAAa,EAAO,QAAQ,YAC5B,QAAS,EAAO,QAAQ,IAAK,GAAM,GAAa,EAAE,EAClD,cACA,eAGA,QAAS,EAAO,QAAQ,QACxB,SAAU,EAAO,QAAQ,QAC3B,CACF,CAAC,CACH,CAEA,SAAS,cACP,EACyC,CAEzC,IAAI,EACJ,OAAQ,EAAS,KAAjB,CACE,IAAK,WACH,EAAc,GAAqB,SACnC,MACF,IAAK,WACH,EAAc,GAAqB,SACnC,MACF,IAAK,MACH,EAAc,GAAqB,IACnC,MACF,IAAK,OACH,EAAc,GAAqB,KACnC,MACF,QACE,MAAM,EAAc,0BAA0B,EAAS,MAAM,CACjE,CACA,MAAO,CACL,cACA,iBAAkB,EAAS,IAC7B,CACF,CC1nBA,MAAM,GAA0B,EAAE,OAAO,CACvC,KAAM,EAAE,OAAO,EACf,WAAY,EAAE,OAAO,CAAC,CAAC,SAAS,CAClC,CAAC,EAGK,GAAqB,EAAE,OAAO,CAClC,OAAQ,EAAE,OAAO,EAAE,OAAO,EAAG,EAAE,OAAO,EAAE,OAAO,EAAG,EAAuB,CAAC,EAC1E,YAAa,EAAE,OAAO,EAAE,OAAO,EAAG,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CACzD,CAAC,EAGK,GAA8B,EAAE,OAAO,CAC3C,QAAS,EAAE,QAAQ,CAAC,EACpB,YAAa,EAAE,OAAO,EACtB,eAAgB,EAAE,OAAO,EACzB,MAAO,EACT,CAAC,EAgBD,SAAgB,oBAAoB,EAAkC,CACpE,IAAM,EAAY,UAAU,KAAK,UAAU,CAAC,EAAM,YAAa,oBAAoB,CAAK,CAAC,CAAC,CAAC,EAC3F,OAAO,EAAK,KAAK,GAAW,EAAG,gBAAiB,GAAG,EAAU,MAAM,CACrE,CAEA,SAAS,0BAA0B,EAA6D,CAC9F,GAAI,CACF,IAAM,EAAM,GAAa,oBAAoB,CAAK,EAAG,OAAO,EACtD,EAAiB,GAA4B,MAAM,KAAK,MAAM,CAAG,CAAC,EAOxE,OALE,EAAe,cAAgB,EAAM,aACrC,EAAe,iBAAmB,oBAAoB,CAAK,EAE3D,OAEK,CACT,MAAQ,CACN,MACF,CACF,CAEA,SAAS,oBAAoB,EAAkC,CAC7D,GAAI,CAAC,EAAM,cACT,MAAM,EACJ,gBAAgB,EAAM,gBAAgB,qCACxC,EAEF,MAAO,MAAM,EAAM,eACrB,CAOA,SAAgB,iBAAiB,EAAwC,CAIvE,OAHK,EAAM,cAGJ,0BAA0B,CAAK,CAAC,EAAE,OAAS,CAAE,OAAQ,CAAC,CAAE,EAFtD,CAAE,OAAQ,CAAC,CAAE,CAGxB,CAOA,SAAgB,iBAAiB,EAA0B,EAA2B,CACpF,GAAI,CAAC,EAAM,cACT,OAEF,IAAM,EAAW,oBAAoB,CAAK,EACpC,EAAM,EAAK,QAAQ,CAAQ,EACjC,GAAU,EAAK,CAAE,UAAW,EAAK,CAAC,EAElC,IAAM,EAAW,GAAG,EAAS,OAAO,GAAW,IAC/C,GACE,EACA,KAAK,UACH,CACE,QAAS,EACT,YAAa,EAAM,YACnB,eAAgB,oBAAoB,CAAK,EACzC,OACF,EACA,KACA,CACF,EACA,OACF,EACA,GAAW,EAAU,CAAQ,CAC/B,CAOA,SAAgB,UAAU,EAAuB,CAC/C,OAAO,GAAW,QAAQ,CAAC,CAAC,OAAO,CAAK,CAAC,CAAC,OAAO,KAAK,CACxD,CAOA,SAAgB,oBAAoB,EAAuD,CACzF,OAAO,IAAe,IAAA,GAAY,IAAA,GAAY,GAAG,EAAW,QAAQ,GAAG,EAAW,OACpF,CAEA,MAQM,GAAa,IAAI,IAYvB,eAAsB,qBACpB,EACA,EACY,CACZ,GAAI,CAAC,EAAM,cACT,OAAO,EAAG,EAEZ,IAAM,EAAW,GAAG,oBAAoB,CAAK,EAAE,OAC3C,EAAQ,GAAW,IAAI,CAAQ,EAKnC,OAJK,IACH,EAAQ,GAAO,CAAC,EAChB,GAAW,IAAI,EAAU,CAAK,GAEzB,EAAM,SAAY,CACvB,IAAM,EAAQ,MAAM,gBAAgB,CAAQ,EACtC,EAAY,gBAAkB,YAAY,EAAU,CAAK,EAAG,GAA0B,EAC5F,EAAU,MAAM,EAChB,GAAI,CACF,OAAO,MAAM,EAAG,CAClB,QAAU,CACR,cAAc,CAAS,EACvB,gBAAgB,EAAU,CAAK,CACjC,CACF,CAAC,CACH,CAEA,eAAe,gBAAgB,EAAmC,CAChE,GAAU,EAAK,QAAQ,CAAQ,EAAG,CAAE,UAAW,EAAK,CAAC,EACrD,IAAM,EAAQ,GAAW,EACnB,EAAW,KAAK,IAAI,EAAI,IAC9B,OAAS,CACP,IAAI,EAAU,GACd,GAAI,CACF,GAAU,CAAQ,CACpB,OAAS,EAAO,CACd,GAAK,EAAgC,OAAS,SAC5C,MAAM,EAER,EAAU,EACZ,CACA,GAAI,EAAS,CACX,GAAI,CACF,GACE,EAAK,KAAK,EAAU,YAAY,EAChC,KAAK,UAAU,CAAE,IAAK,QAAQ,IAAK,OAAM,CAAC,CAC5C,CACF,OAAS,EAAO,CAEd,MADA,GAAO,EAAU,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,EAC3C,CACR,CACA,OAAO,CACT,CACI,mBAAc,CAAQ,GAAK,UAAU,CAAQ,GAGjD,IAAI,KAAK,IAAI,GAAK,EAChB,MAAM,EAAS,CACb,KAAM,sBACN,QACE,wFACF,WACE,kGACJ,CAAC,EAEH,MAAM,IAAI,QAAS,GAAY,WAAW,EAAS,GAAqB,CAAC,CAFtE,CAGL,CACF,CAEA,SAAS,cAAc,EAA2B,CAChD,GAAI,CACF,OAAO,KAAK,IAAI,EAAI,GAAS,CAAQ,CAAC,CAAC,QAAU,GACnD,MAAQ,CACN,MAAO,EACT,CACF,CAEA,SAAS,cAAc,EAA2B,CAChD,GAAI,CACF,OACE,KAAK,MAAM,GAAa,EAAK,KAAK,EAAU,YAAY,EAAG,OAAO,CAAC,CAAC,CACpE,KACJ,MAAQ,CACN,MACF,CACF,CAEA,SAAS,YAAY,EAAkB,EAAqB,CAC1D,GAAI,cAAc,CAAQ,IAAM,EAC9B,OAEF,IAAM,EAAM,IAAI,KAChB,GAAI,CACF,GAAW,EAAU,EAAK,CAAG,CAC/B,MAAQ,CAER,CACF,CAEA,SAAS,gBAAgB,EAAkB,EAAqB,CAG1D,cAAc,CAAQ,IAAM,GAGhC,GAAO,EAAU,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,CACnD,CAEA,SAAS,UAAU,EAA2B,CAG5C,IAAM,EAAQ,GAAG,EAAS,SAAS,QAAQ,IAAI,GAAG,KAAK,IAAI,IAC3D,GAAI,CACF,GAAW,EAAU,CAAK,CAC5B,MAAQ,CACN,MAAO,EACT,CACA,GAAI,cAAc,CAAK,EAErB,OADA,GAAO,EAAO,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,EACvC,GAIT,GAAI,CACF,GAAW,EAAO,CAAQ,CAC5B,MAAQ,CACN,GAAO,EAAO,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,CAChD,CACA,MAAO,EACT,CC1OA,SAAS,uBACP,EACA,EACA,EAC4D,CAC5D,MAAO,CACL,cACA,WAAY,CACV,OACA,KAAM,GAAoB,OAC1B,OAAQ,CACN,KAAM,SACN,MAAO,CACL,YAAa,EAAO,YACpB,UAAW,EAAO,UAClB,SAAU,EAAO,SACjB,aAAc,EAAO,aACrB,QAAS,EAAO,SAAW,GAC3B,SAAU,EAAO,UAAY,EAC/B,CACF,CACF,CACF,CACF,CAEA,SAAS,gBACP,EACA,EACA,EACqB,CACrB,GAAI,EAAS,OAAO,OAAS,SAAU,CACrC,IAAM,EAAQ,CACZ,OACA,sBACA,oBACA,mBACA,kBACA,kBACF,EAEA,OADI,EAAQ,cAAc,EAAM,KAAK,sBAAsB,EACpD,CAAE,OAAM,CACjB,CAEA,IAAM,EAAkB,CAAC,EACnB,EAAI,EAAS,OAAO,MAO1B,OANI,EAAE,cAAgB,EAAQ,aAAa,EAAM,KAAK,qBAAqB,EACvE,EAAE,YAAc,EAAQ,WAAW,EAAM,KAAK,mBAAmB,EACjE,EAAE,WAAa,EAAQ,UAAU,EAAM,KAAK,kBAAkB,EAC9D,EAAE,WAAa,EAAQ,SAAW,KAAK,EAAM,KAAK,iBAAiB,EACnE,EAAE,YAAc,EAAQ,UAAY,KAAK,EAAM,KAAK,kBAAkB,EACtE,GAAiB,EAAQ,cAAc,EAAM,KAAK,sBAAsB,EACrE,CAAE,OAAM,CACjB,CAWA,eAAsB,oBACpB,EACA,EACA,EACA,EACA,EACA,CACA,IAAM,EAAa,CACjB,cACA,cAAe,EACf,gBAAiB,CACnB,EACM,EAAY,gBAKhB,kBAAkB,EACd,EAA6B,CAAC,EAC9B,EAAiC,CAAC,EAClC,EAAiB,IAAI,IAErB,EAA2D,CAAC,EAClE,IAAK,IAAM,KAAQ,EACjB,IAAK,GAAM,CAAC,EAAM,KAAW,OAAO,QAAQ,EAAK,WAAW,EAC1D,EAAmB,GAAQ,EAC3B,EAAO,eAAe,EAAO,YAAY,EAI7C,IAAM,EAAe,MAAM,EAAiB,MAAO,EAAW,IAAgB,CAC5E,GAAM,CAAE,cAAa,iBAAkB,MAAM,EAAO,oBAAoB,CACtE,cACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAa,CAAa,CACpC,CAAC,EAEK,EAAiD,CAAC,EACxD,MAAM,QAAQ,IACZ,EAAa,IAAI,KAAO,IAAa,CACnC,GAAM,CAAE,YAAa,MAAM,EAAO,YAAY,CAC5C,IAAK,YAAY,EAAa,kBAAmB,EAAS,IAAI,CAChE,CAAC,EACD,EAAoB,EAAS,MAAQ,CACnC,WACA,MAAO,GAAU,OAAO,IACxB,UAAW,GAAU,MACvB,CACF,CAAC,CACH,EAEA,IAAM,EAAQ,iBAAiB,CAAU,EAEzC,IAAK,GAAM,CAAC,EAAM,KAAW,OAAO,QAAQ,CAAkB,EAAG,CAC/D,IAAM,EAAW,EAAoB,GAC/B,EAAc,MAAM,iBAAiB,CACzC,IAAK,YAAY,EAAa,kBAAmB,CAAI,EACrD,UACA,OACF,CAAC,EAED,GAAI,EAAU,CACZ,IAAM,EAAQ,8BAA8B,CAC1C,OAAQ,EAAS,UACjB,WAAY,EAAS,MACrB,UACA,QACA,aAAc,kBACd,aAAc,EACd,YACA,WACF,CAAC,EAIK,EAFc,UAAU,EAAO,YAEL,IADb,EAAM,cAAc,GAEjC,EAAa,gBAAgB,EAAS,SAAU,EAAQ,CAAa,EAEvE,EAAW,MAAM,OAAS,EAC5B,EAAU,SAAS,KAAK,CACtB,OACA,cAAe,CACb,GAAG,uBAAuB,EAAa,EAAM,CAAM,EACnD,YACF,EACA,aACF,CAAC,EACS,EASV,EAAU,UAAU,KAAK,CAAE,MAAK,CAAC,EAFjC,EAAU,QAAQ,KAAK,CAAE,OAAM,aAAY,CAAC,EAI9C,OAAO,EAAoB,EAC7B,MACE,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,uBAAuB,EAAa,EAAM,CAAM,EACzD,aACF,CAAC,CAEL,CAEA,IAAK,GAAM,CAAC,EAAM,KAAU,OAAO,QAAQ,CAAmB,EACvD,GACS,4BAA4B,CACxC,OAAQ,EAAM,UACd,WAAY,EAAM,MAClB,UACA,QACA,gBACF,CAIQ,GACN,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CAAE,cAAa,eAAgB,CAAK,CAC/C,CAAC,EAIL,MAAO,CAAE,YAAW,YAAW,YAAW,iBAAgB,YAAW,CACvE,CAaA,eAAsB,qBACpB,EACA,EACA,EACA,CACA,GAAM,CAAE,YAAW,cAAe,EAE9B,IAAU,kBACR,EAAU,QAAQ,OAAS,GAAK,EAAU,SAAS,OAAS,IAC9D,MAAM,qBAAqB,EAAY,SAAY,CACjD,MAAM,QAAQ,IACZ,EAAU,QAAQ,IAAI,KAAO,IAAW,CACtC,MAAM,EAAO,qBAAqB,EAAO,OAAO,EAChD,MAAM,oBAAoB,EAAQ,EAAO,WAAW,EACpD,EAAO,KACL,eAAe,EAAO,KAAK,8EACmB,EAAO,KAAK,iDAE5D,CACF,CAAC,CACH,EAEA,IAAK,IAAM,KAAW,EAAU,UAE1B,MADe,EAAO,qBAAqB,EAAQ,aAAa,EAAA,CAC3D,YAAY,SAAW,GAAsB,cACpD,EAAO,KACL,eAAe,EAAQ,KAAK,yFACkB,EAAQ,KAAK,iDAE7D,EAEF,MAAM,oBAAoB,EAAQ,EAAQ,WAAW,EAGvD,IAAM,EAAiB,EAAU,SAAS,OAAQ,GAChD,EAAQ,cAAc,YAAY,OAAO,SAAS,sBAAsB,CAC1E,EACA,GAAI,EAAU,QAAQ,OAAS,GAAK,EAAe,OAAS,EAAG,CAC7D,IAAM,EAAQ,iBAAiB,CAAU,EACzC,AACE,EAAM,cAAc,CAAC,EAEvB,IAAK,IAAM,KAAU,EAAU,QAAS,CACtC,IAAM,EAAO,EAAO,QAAQ,WACxB,GAAM,QAAQ,OAAS,WACzB,EAAM,YAAY,EAAO,MAAQ,UAAU,EAAK,OAAO,MAAM,cAAgB,EAAE,EAEnF,CACA,IAAK,IAAM,KAAW,EAAgB,CACpC,IAAM,EAAO,EAAQ,cAAc,WAC/B,GAAM,QAAQ,OAAS,WACzB,EAAM,YAAY,EAAQ,MAAQ,UAAU,EAAK,OAAO,MAAM,cAAgB,EAAE,EAEpF,CACA,iBAAiB,EAAY,CAAK,CACpC,CACF,CAAC,EAKH,MAAM,QAAQ,IACZ,EAAU,QAAQ,IAAI,KAAO,IAAW,CACtC,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,CACH,GACS,EAAU,QAAQ,OAAS,GACpC,MAAM,qBAAqB,EAAY,SAAY,CACjD,MAAM,QAAQ,IACZ,EAAU,QAAQ,IAAI,KAAO,IAAQ,CACnC,MAAM,EAAO,qBAAqB,EAAI,OAAO,CAC/C,CAAC,CACH,EAEA,IAAM,EAAQ,iBAAiB,CAAU,EACzC,GAAI,EAAM,YAAa,CACrB,IAAK,IAAM,KAAO,EAAU,QAC1B,OAAO,EAAM,YAAY,EAAI,MAE/B,iBAAiB,EAAY,CAAK,CACpC,CACF,CAAC,CAEL,CC3TA,MAAMC,GAAa,MA0BnB,SAAS,mBAAmB,EAAyB,CACnD,OAAOC,GAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,EAAS,OAAO,CAAC,CAAC,OAAO,KAAK,CAC1E,CAEA,MAEa,GAAkB,aAS/B,SAAgB,qBAAqB,EAAmB,EAA8B,CACpF,MAAO,aAAqB,EAAU,IAAI,GAC5C,CAOA,SAAgB,qBAAqB,EAA8B,CACjE,MAAO,aAAqB,GAC9B,CAOA,SAAgB,wBAAwB,EAAyB,CAC/D,MAAO,GAAG,KAAkB,GAC9B,CAOA,SAAgB,6BAKd,EAAkC,CASlC,SAAS,UAA6B,EAAqC,CACzE,IAAM,EAAsB,CAC1B,YAAa,CAAC,EACd,SAAU,CAAC,EACX,SAAU,CAAC,EACX,SAAU,CAAC,EACX,MAAO,CAAC,CACV,EACA,IAAK,IAAM,KAAQ,EACb,EAAK,KAAK,WAAA,YAA0B,EAAG,EAAQ,YAAY,KAAK,CAAI,EAC/D,EAAK,KAAK,WAAA,YAA0B,EAAG,EAAQ,SAAS,KAAK,CAAI,EACjE,EAAK,KAAK,WAAA,YAA0B,EAAG,EAAQ,SAAS,KAAK,CAAI,EACjE,EAAK,KAAK,WAAA,aAA2B,EAAG,EAAQ,SAAS,KAAK,CAAI,EACtE,EAAQ,MAAM,KAAK,CAAI,EAE9B,OAAO,CACT,CAEA,IAAM,EAAU,UAAU,EAAU,OAAO,EACrC,EAAU,UAAU,EAAU,OAAO,EACrC,EAAU,UAAU,EAAU,OAAO,EACrC,EAAW,UAAU,EAAU,QAAQ,EACvC,EAAY,UAAU,EAAU,SAAS,EAE/C,SAAS,QAA0C,EAAQ,CACzD,MAAO,CACL,QAAS,EAAQ,GACjB,QAAS,EAAQ,GACjB,QAAS,EAAQ,GACjB,SAAU,EAAS,GACnB,UAAW,EAAU,EACvB,CACF,CAEA,MAAO,CACL,mBAAoB,QAAQ,aAAa,EACzC,wBAAyB,QAAQ,UAAU,EAC3C,wBAAyB,QAAQ,UAAU,EAC3C,wBAAyB,QAAQ,UAAU,EAC3C,aAAc,QAAQ,OAAO,CAC/B,CACF,CAQA,SAAgB,qBAAqB,EAAkB,EAA2B,CAChF,MAAO,cAAc,EAAS,IAAI,GACpC,CASA,SAAgB,uBACd,EACA,EACA,EACiB,CACjB,IAAM,EAA2B,CAAC,EAGlC,IAAK,IAAM,KAAO,EAAY,aAC5B,IAAK,IAAM,KAAY,EAAI,iBACzB,IAAK,IAAM,KAAY,OAAO,OAAO,EAAS,SAAS,EAAG,CACxD,IAAM,EAAU,EAAe,UAAU,IACvC,GAAkB,EAAS,UAAW,EAAS,IAAI,CACrD,EACA,GAAI,CAAC,EAAS,CACZ,EAAO,KACL,wCAAwC,EAAS,UAAU,GAAG,EAAS,MACzE,EACA,QACF,CACA,EAAQ,KAAK,CACX,KAAM,qBAAqB,EAAS,UAAW,EAAS,IAAI,EAC5D,cAAe,EACf,YAAa,mBAAmB,CAAO,EACvC,YAAa,aAAa,EAAS,UAAU,GAAG,EAAS,MAC3D,CAAC,CACH,CAKJ,GAAI,EAAY,gBAAiB,CAC/B,IAAM,EAAY,EAAY,gBAAgB,UAC9C,IAAK,IAAM,KAAY,OAAO,OAAO,CAAS,EAC5C,GAAI,EAAS,UAAU,OAAS,YAAc,EAAS,UAAU,OAAS,cAAe,CACvF,IAAM,EAAU,EAAe,UAAU,IAAI,EAAS,IAAI,EAC1D,GAAI,CAAC,EAAS,CACZ,EAAO,KAAK,wCAAwC,EAAS,MAAM,EACnE,QACF,CACA,EAAQ,KAAK,CACX,KAAM,qBAAqB,EAAS,IAAI,EACxC,cAAe,EACf,YAAa,mBAAmB,CAAO,EACvC,YAAa,aAAa,EAAS,MACrC,CAAC,CACH,CAEJ,CAGA,IAAK,IAAM,KAAO,EAAc,CAC9B,IAAM,EAAU,EAAe,aAAa,IAAI,EAAI,IAAI,EACxD,GAAI,CAAC,EAAS,CACZ,EAAO,KAAK,4CAA4C,EAAI,MAAM,EAClE,QACF,CACA,EAAQ,KAAK,CACX,KAAM,wBAAwB,EAAI,IAAI,EACtC,cAAe,EACf,YAAa,mBAAmB,CAAO,EACvC,YAAa,iBAAiB,EAAI,MACpC,CAAC,CACH,CAGA,IAAK,IAAM,KAAO,EAAY,aAC5B,GAAI,EAAI,aAAa,OAAO,OAAO,YAAa,CAC9C,IAAM,EAAW,EAAI,YAAY,OAAO,KAClC,EAAW,qBAAqB,EAAU,cAAc,EACxD,EAAU,EAAe,UAAU,IAAI,CAAQ,EACrD,GAAI,CAAC,EAAS,CACZ,EAAO,KAAK,yCAAyC,GAAU,EAC/D,QACF,CACA,EAAQ,KAAK,CACX,KAAM,EACN,cAAe,EACf,YAAa,mBAAmB,CAAO,EACvC,YAAa,cAAc,EAAS,cACtC,CAAC,CACH,CAGF,OAAO,CACT,CAQA,SAAgB,0BACd,EACA,EACgB,CAChB,IAAM,EAAO,IAAI,IAAI,CAAY,EACjC,OAAO,EAAK,OAAQ,GAAQ,EAAK,IAAI,EAAI,IAAI,CAAC,CAChD,CAgBA,eAAsB,qBACpB,EACA,EACA,EACA,EACA,EACA,CACA,IAAM,EAAuC,gBAI3C,mBAAmB,EACf,EAA6B,CAAC,EAC9B,EAAiC,CAAC,EAClC,EAAiB,IAAI,IAErB,EAAc,MAAM,iCAAiC,CACzD,SACA,UAAW,MAAO,EAAW,IAAgB,CAC3C,IAAM,EAAW,MAAM,EAAO,uBAAuB,CACnD,cACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CACL,EAAS,UAAU,IAAK,IAAyB,CAC/C,KAAM,EAAE,KACR,YAAa,EAAE,WACjB,EAAE,EACF,EAAS,aACX,CACF,EACA,QAAU,GAAS,EAAK,KACxB,OAAS,GAAS,YAAY,EAAa,oBAAqB,CAAI,CACtE,CAAC,EAGD,IAAK,IAAM,KAAS,EAAS,CAC3B,IAAM,EAAW,EAAY,EAAM,MAC7B,EAAc,MAAM,iBAAiB,CACzC,IAAK,YAAY,EAAa,oBAAqB,EAAM,IAAI,EAC7D,UACA,OACF,CAAC,EAED,GAAI,EAAU,CACZ,IAAM,EAAQ,8BAA8B,CAC1C,OAAQ,EAAS,UACjB,WAAY,EAAS,MACrB,UACA,QACA,aAAc,oBACd,aAAc,EAAM,KACpB,YACA,WACF,CAAC,EAGC,EAAS,SAAS,cAAgB,EAAM,aACxC,GACA,sBAAsB,EAAS,UAAW,EAAY,MAAM,EAE5D,EAAU,UAAU,KAAK,CACvB,KAAM,EAAM,IACd,CAAC,EAED,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAM,KACZ,QACA,aACF,CAAC,EAEH,OAAO,EAAY,EAAM,KAC3B,MACE,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAM,KACZ,QACA,aACF,CAAC,CAEL,CAGA,IAAK,GAAM,CAAC,EAAM,KAAa,OAAO,QAAQ,CAAW,EAClD,GACS,4BAA4B,CACxC,OAAQ,EAAS,UACjB,WAAY,EAAS,MACrB,UACA,QACA,gBACF,CACQ,GACN,EAAU,QAAQ,KAAK,CACrB,OACA,aACF,CAAC,EAIL,GAAM,CACJ,qBACA,0BACA,0BACA,2BACE,6BAA6B,CAAS,EAC1C,MAAO,CACL,YACA,qBACA,0BACA,0BACA,0BACA,YACA,YACA,gBACF,CACF,CASA,eAAe,qBACb,EACA,EACA,EACA,EACA,CACA,IAAM,EAAS,OAAO,KAAK,EAAM,cAAe,OAAO,EAEjD,EAAO,CACX,cACA,KAAM,EAAM,KACZ,YAAa,EAAM,YACnB,UAAW,OAAO,EAAO,MAAM,EAC/B,YAAa,EAAM,WACrB,EAEA,GAAI,EAAU,CAEZ,eAAgB,cAEd,CACA,KAAM,CAAE,QAAS,CAAE,KAAM,OAAiB,MAAO,CAAK,CAAE,EACxD,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,OAAQ,GAAKD,GACtC,KAAM,CACJ,QAAS,CACP,KAAM,QACN,MAAO,EAAO,SAAS,EAAG,KAAK,IAAI,EAAIA,GAAY,EAAO,MAAM,CAAC,CACnE,CACF,CAEJ,CACA,MAAM,EAAO,uBAAuB,aAAa,CAAC,CACpD,KAAO,CAEL,eAAgB,cAEd,CACA,KAAM,CAAE,QAAS,CAAE,KAAM,OAAiB,MAAO,CAAK,CAAE,EACxD,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,OAAQ,GAAKA,GACtC,KAAM,CACJ,QAAS,CACP,KAAM,QACN,MAAO,EAAO,SAAS,EAAG,KAAK,IAAI,EAAIA,GAAY,EAAO,MAAM,CAAC,CACnE,CACF,CAEJ,CACA,MAAM,EAAO,uBAAuB,aAAa,CAAC,CACpD,CACF,CASA,eAAsB,sBACpB,EACA,EACA,EACA,EAAyD,gBACzD,CACA,GAAM,CAAE,aAAc,EACtB,GAAI,IAAU,gBAAiB,CAG7B,IAAM,EAAgB,GAAmB,EAEzC,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,QAAQ,IAAK,GACxB,EAAc,SAAY,CACxB,MAAM,qBAAqB,EAAQ,EAAa,EAAO,MAAO,EAAI,EAClE,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,CACH,EACA,GAAG,EAAU,QAAQ,IAAK,GACxB,EAAc,SAAY,CACxB,MAAM,qBAAqB,EAAQ,EAAa,EAAO,MAAO,EAAK,EACnE,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,CACH,CACF,CAAC,CACH,MACE,MAAM,QAAQ,IACZ,EAAU,QAAQ,IAAK,GACrB,EAAO,uBAAuB,CAC5B,YAAa,EAAI,YACjB,KAAM,EAAI,IACZ,CAAC,CACH,CACF,CAEJ,CCpdA,SAAS,sCACP,EACiC,CACjC,MAAO,CACL,QAAS,IAAI,IAAI,GAAS,QAAQ,IAAK,GAAS,EAAK,IAAI,GAAK,CAAC,CAAC,EAChE,QAAS,IAAI,IAAI,GAAS,QAAQ,IAAK,GAAS,EAAK,IAAI,GAAK,CAAC,CAAC,EAChE,QAAS,IAAI,IAAI,GAAS,QAAQ,IAAK,GAAS,EAAK,IAAI,GAAK,CAAC,CAAC,EAChE,SAAU,IAAI,IAAI,GAAS,SAAS,IAAK,GAAS,EAAK,IAAI,GAAK,CAAC,CAAC,CACpE,CACF,CAEA,MAAa,GAAiB,CAC5B,OAAQ,EAAQ,OAChB,OAAQ,EAAQ,OAChB,OAAQ,EAAQ,OAChB,QAAS,EAAQ,OACnB,EASA,SAAgB,uBACd,EAIA,EAAmB,CAAC,EACpB,EACuB,CACvB,SAAS,QAAQ,EAAuB,EAAoC,CAC1E,MAAO,CACL,SACA,OAAQ,GAAe,GACvB,KAAM,EAAK,KACX,OAAQ,CAAC,GAAG,CAAM,EAClB,UAAW,IAAe,CAAI,CAChC,CACF,CACA,MAAO,CACL,GAAG,EAAU,QAAQ,IAAK,GAAS,QAAQ,SAAU,CAAI,CAAC,EAC1D,GAAG,EAAU,QAAQ,IAAK,GAAS,QAAQ,SAAU,CAAI,CAAC,EAC1D,GAAG,EAAU,QAAQ,IAAK,GAAS,QAAQ,SAAU,CAAI,CAAC,EAC1D,GAAG,EAAU,SAAS,IAAK,GAAS,QAAQ,UAAW,CAAI,CAAC,CAC9D,CACF,CAEA,SAAS,yBAAyB,EAA4B,CAC5D,OAAO,EAAM,OAAO,OAAS,EACzB,GAAG,EAAM,OAAO,GAAG,EAAM,KAAK,IAAI,EAAM,OAAO,KAAK,IAAI,EAAE,GAC1D,GAAG,EAAM,OAAO,GAAG,EAAM,MAC/B,CAEA,SAAS,0BAA0B,EAA2D,CAC5F,GAAI,EAAK,WAAA,YAA0B,EAAG,CACpC,GAAM,EAAG,EAAW,GAAgB,EAAK,MAAM,IAAI,EACnD,GAAI,GAAa,EACf,MAAO,CAAE,YAAa,EAAc,WAAU,CAElD,CAMA,GAJI,EAAK,WAAA,YAA0B,GAI/B,EAAK,WAAA,YAA0B,EACjC,MAAO,CAAE,YAAa,EAAK,MAAM,EAAsB,CAAE,EAG3D,GAAI,EAAK,WAAA,aAA2B,EAAG,CACrC,GAAM,EAAG,EAAW,GAAa,EAAK,MAAM,IAAI,EAChD,GAAI,GAAa,EACf,MAAO,CAAE,YAAa,EAAW,WAAU,CAE/C,CAEA,MAAO,CAAE,YAAa,CAAK,CAC7B,CAQA,SAAS,sCACP,EACA,EAA4C,sCAAsC,EAC3D,CAQvB,MAAO,CANL,CAAC,SAAU,EAAM,QAAS,EAAS,OAAO,EAC1C,CAAC,SAAU,EAAM,QAAS,EAAS,OAAO,EAC1C,CAAC,SAAU,EAAM,QAAS,EAAS,OAAO,EAC1C,CAAC,UAAW,EAAM,SAAU,EAAS,QAAQ,CAGlC,CAAC,CAAC,SAAS,CAAC,EAAQ,EAAS,KACxC,CAAC,GAAG,CAAO,CAAC,CACT,OAAQ,GAAS,CAAC,EAAY,IAAI,CAAI,CAAC,CAAC,CACxC,IAAK,GAAS,CACb,GAAM,CAAE,cAAa,aAAc,0BAA0B,CAAI,EACjE,MAAO,CACL,SACA,OAAQ,GAAe,GACvB,KAAM,EACN,OAAQ,CAAC,UAAU,EACnB,WACF,CACF,CAAC,CACL,CACF,CAsBA,SAAgB,wCAKd,EACA,EAMA,EACA,EACA,EAIuB,CACvB,GAAM,CAAE,eAAc,kBAAmB,GAAW,CAAC,EAC/C,EAAgB,sCAAsC,CAAuB,EAC7E,EAA4C,sCAAsC,EAExF,SAAS,aACP,EACA,EACA,EACA,EACuB,CACvB,OAAO,EAAM,IAAK,GAAS,CACzB,IAAM,EAAQ,EAAyB,EAAM,CAAM,EAC7C,EAAW,EAAM,KAAM,GAAS,EAAU,IAAI,CAAI,CAAC,EACzD,GAAI,EACG,IAAA,IAAM,KAAQ,EACb,EAAU,IAAI,CAAI,GACpB,EAAY,IAAI,CAAI,EAI1B,MAAO,CACL,SACA,OAAQ,GAAe,GACvB,KAAM,IAAiB,CAAI,GAAK,EAAK,KACrC,OAAQ,EAAW,CAAC,EAAe,UAAU,EAAI,CAAC,CAAa,EAC/D,UAAW,IAAe,CAAI,CAChC,CACF,CAAC,CACH,CAEA,MAAO,CACL,GAAG,aAAa,EAAU,QAAS,SAAU,EAAc,QAAS,EAAS,OAAO,EACpF,GAAG,aAAa,EAAU,QAAS,SAAU,EAAc,QAAS,EAAS,OAAO,EACpF,GAAG,aAAa,EAAU,QAAS,SAAU,EAAc,QAAS,EAAS,OAAO,EACpF,GAAG,EAAU,SAAS,IAAK,IAAU,CACnC,OAAQ,UACR,OAAQ,GAAe,QACvB,KAAM,IAAiB,CAAiB,GAAK,EAAK,KAClD,OAAQ,CAAC,CAAa,EACtB,UAAW,IAAe,CAAiB,CAC7C,EAAE,EACF,GAAG,sCAAsC,EAAe,CAAQ,CAClE,CACF,CAYA,SAAgB,sBACd,EAImB,CACnB,MAAO,CACL,GAAG,EAAU,QAAQ,IAAK,IAAU,CAAE,KAAM,EAAK,KAAM,OAAQ,QAAkB,EAAE,EACnF,GAAG,EAAU,QAAQ,IAAK,IAAU,CAAE,KAAM,EAAK,KAAM,OAAQ,QAAkB,EAAE,EACnF,GAAG,EAAU,QAAQ,IAAK,IAAU,CAAE,KAAM,EAAK,KAAM,OAAQ,QAAkB,EAAE,EACnF,GAAG,EAAU,SAAS,IAAK,IAAU,CAAE,KAAM,EAAK,KAAM,OAAQ,SAAmB,EAAE,CACvF,CACF,CAWA,SAAgB,yBACd,EACA,EACA,EACU,CACV,IAAM,EAAa,IAAI,IACvB,GAAI,EACF,IAAK,IAAM,KAAM,EACf,EAAW,IAAI,EAAG,KAAM,EAAG,MAAM,EAIrC,GAAI,EAAQ,SAAW,GAAK,EAAW,OAAS,EAC9C,MAAO,CAAC,EAGV,IAAM,EAAgB,CAAC,EAAO,KAAK,GAAG,EAAM,EAAE,CAAC,EAGzC,EAAyC,CAAC,EAC1C,EAAc,IAAI,IACxB,IAAK,IAAM,KAAS,EAAS,CAC3B,IAAM,EAAK,EAAM,UACZ,EAAY,IAAI,CAAE,IACrB,EAAe,KAAK,CAAE,EACtB,EAAY,IAAI,EAAI,CAAC,CAAC,GAExB,EAAc,EAAY,IAAI,CAAE,EAAG,yBAAyB,CAAC,CAAC,KAAK,CAAK,CAC1E,CAGA,IAAM,EAAkB,IAAI,IAE5B,IAAK,IAAM,KAAM,EAAgB,CAC/B,IAAM,EAAQ,EAAc,EAAY,IAAI,CAAE,EAAG,yBAAyB,EAC1E,GAAI,EAAI,CACN,IAAM,EAAY,EAAW,IAAI,CAAE,EAC7B,EAAS,EAAY,GAAG,GAAe,GAAW,GAAK,GAC7D,EAAI,KAAK,KAAK,IAAS,EAAO,KAAK,GAAG,EAAG,EAAE,GAAG,EAC9C,EAAgB,IAAI,CAAE,EACtB,IAAK,IAAM,KAAS,EAClB,EAAI,KAAK,OAAO,yBAAyB,CAAK,GAAG,CAErD,MACE,IAAK,IAAM,KAAS,EAClB,EAAI,KAAK,KAAK,yBAAyB,CAAK,GAAG,CAGrD,CAGA,IAAK,GAAM,CAAC,EAAM,KAAW,EACtB,EAAgB,IAAI,CAAI,GAC3B,EAAI,KAAK,KAAK,GAAe,GAAQ,GAAG,GAAM,EAIlD,OAAO,CACT,CCzTA,MAAa,GAAmB,CAC9B,aAAe,GAAiB,mBAAmB,EAAK,GACxD,SAAW,GAAiB,aAAa,EAAK,GAC9C,WAAa,GAAiB,gBAAgB,EAAK,GACnD,SAAW,GAAiB,aAAa,EAAK,GAC9C,YAAc,GAAiB,QAAQ,EAAK,GAC5C,aAAe,GAAyB,qBAAqB,EAAa,EAC5E,EAGa,GAAwB,CACnC,aAAe,IAAyC,CACtD,SAAU,GAAiB,aAAa,CAAI,EAC5C,QAAS,QACX,GACA,SAAW,IAAyC,CAClD,SAAU,GAAiB,SAAS,CAAI,EACxC,QAAS,kBACX,GACA,WAAa,IAAyC,CACpD,SAAU,GAAiB,WAAW,CAAI,EAC1C,QAAS,SACX,GACA,SAAW,IAAyC,CAClD,SAAU,GAAiB,SAAS,CAAI,EACxC,QAAS,mBACX,GACA,YAAc,IAAyC,CACrD,SAAU,GAAiB,YAAY,CAAI,EAC3C,QAAS,uBACT,aAAc,yBAChB,EACF,EAQA,SAAS,2BAA2B,EAAyC,CAC3E,GAAM,CAAE,WAAU,UAAS,eAAe,MAAS,EACnD,MACE,GAAG,EAAS,kDAAkD,EAAQ,yBAAyB,EAAa,iFAGhH,CAiBA,SAAgB,mBAAmB,EAA6C,CAC9E,MAAO,CAAC,EAAS,QACnB,CAmBA,SAAgB,8BAA8B,EAA0C,CACtF,GAAM,CAAE,WAAU,aAAY,YAAa,EAC3C,GAAI,IAAa,IAAS,EACxB,MAAU,MAAM,2BAA2B,CAAQ,CAAC,CAExD,CAaA,SAAgB,qBAAqB,EAA6C,CAEhF,OADA,8BAA8B,CAAM,EAC7B,EAAO,UAAY,EAAO,UACnC,CC/GA,KAAM,CAAE,8BAA8B,GAGpC,CACA,IAAK,KACL,KAAM,KACN,GAAI,KACJ,SAAU,KACZ,CAAC,EAOD,SAAgB,6BAA6B,EAAkD,CAC7F,OAAO,GAA0B,CAAU,CAC7C,CAOA,SAAgB,uBAAuB,EAAqD,CAC1F,MAAO,CACL,OAAQ,EAAW,OAAO,IAAK,GAAM,6BAA6B,CAAC,CAAC,EACpE,KAAM,EAAW,KAAK,IAAK,GAAM,6BAA6B,CAAC,CAAC,EAChE,OAAQ,EAAW,OAAO,IAAK,GAAM,6BAA6B,CAAC,CAAC,EACpE,OAAQ,EAAW,OAAO,IAAK,GAAM,6BAA6B,CAAC,CAAC,EACpE,wBAAyB,EAAW,wBAA0B,CAAC,EAAA,CAAG,IAAK,GACrE,6BAA6B,CAAC,CAChC,EACA,aAAc,EAAW,aAAe,CAAC,EAAA,CAAG,IAAK,GAAM,6BAA6B,CAAC,CAAC,CACxF,CACF,CAOA,SAAgB,mBACd,EACmC,CAC9B,KAGL,OAAO,uBAAuB,CAAa,CAC7C,CAQA,SAAgB,uBAAuB,EAAoD,CACzF,GAAI,CAAC,EACH,MAAO,CAAC,EAEV,IAAM,EAAsB,CAAC,EAC7B,IAAK,IAAM,KAAU,OAAO,KAAK,CAAU,EACzC,EAAW,EAAO,EAAE,SAAS,EAAe,IAAkB,CACxD,GAAiB,CAAI,GACvB,EAAU,KAAK,GAAG,OAAO,CAAM,EAAE,GAAG,EAAM,EAAE,CAEhD,CAAC,EAEH,OAAO,CACT,CCfA,eAAe,4BACb,EACA,EACe,CACf,IAAM,EAAS,EAAQ,eACjB,EAAY,GAAQ,qBAC1B,GAAI,CAAC,GAAU,CAAC,GAAW,OACzB,OAEF,IAAM,EAAW,MAAM,GACrB,EACA,EAAc,EAAQ,YAAa,6BAA6B,EAChE,EACA,gBAAgB,EAAQ,eAAiB,GAAG,uBAC9C,EAIA,GAAI,EAAS,SAAW,EAAU,OAChC,MAAM,EAAS,CACb,KAAM,+BACN,QAAS,gBAAgB,EAAQ,eAAiB,GAAG,0BAA0B,EAAU,OAAS,EAAS,OAAO,MAAM,EAAU,OAAO,iCACzI,WAAY,yEACd,CAAC,EAEH,EAAO,qBAAuB,CAChC,CAQA,SAAgB,mBAAmB,EAAuB,EAAoB,CAC5E,MAAO,OAAO,EAAc,GAAG,GACjC,CAQA,SAAgB,oBAAoB,EAAuB,EAAoB,CAC7E,MAAO,iBAAiB,EAAc,GAAG,GAC3C,CASA,eAAsB,SACpB,EACA,EACA,EAAuC,gBACvC,CACA,GAAM,CAAE,aAAc,EAClB,IAAU,iBAGZ,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,QAAQ,QAAQ,IAAI,KAAO,IAAW,CACjD,MAAM,4BAA4B,EAAQ,EAAO,OAAO,EACxD,MAAM,EAAO,iBAAiB,EAAO,OAAO,EAC5C,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,EACD,GAAG,EAAU,QAAQ,QAAQ,IAAI,KAAO,IAAW,CACjD,MAAM,4BAA4B,EAAQ,EAAO,OAAO,EACxD,MAAM,EAAO,iBAAiB,EAAO,OAAO,EAC5C,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,EACD,GAAG,EAAU,QAAQ,UAAU,QAAS,GACtC,EAAM,YAAc,CAAC,oBAAoB,EAAQ,EAAM,WAAW,CAAC,EAAI,CAAC,CAC1E,CACF,CAAC,EAGD,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,OAAO,QAAQ,IAAI,KAAO,IAAW,CAChD,IAAM,EAAO,MAAM,EAAO,gBAAgB,EAAO,OAAO,EACpD,EAAK,QAAQ,cAAc,EAAO,eAAe,EAAK,OAAO,YAAY,EAG7E,IAAM,EAAY,mBAChB,EAAc,EAAO,QAAQ,cAAe,+BAA+B,EAC3E,EAAO,QAAQ,QAAQ,MAAQ,EACjC,EACM,EAAa,oBACjB,EAAc,EAAO,QAAQ,cAAe,+BAA+B,EAC3E,EAAO,QAAQ,QAAQ,MAAQ,EACjC,EACA,MAAM,EAAO,yBAAyB,CACpC,YAAa,EAAO,QAAQ,YAC5B,uBAAwB,CAC1B,CAAC,EACD,MAAM,EAAO,0BAA0B,CACrC,YAAa,EAAO,QAAQ,YAC5B,uBAAwB,EACxB,wBAAyB,EACzB,yBAA0B,EAAK,QAAQ,YACzC,CAAC,CACH,CAAC,EACD,GAAG,EAAU,OAAO,QAAQ,IAAI,KAAO,IAAW,CAEhD,IAAM,EAAY,mBAAmB,EAAO,cAAe,EAAO,IAAI,EAChE,EAAa,oBAAoB,EAAO,cAAe,EAAO,IAAI,EAOpE,MANgB,EAAU,SACrB,MAAM,EAAO,sBAAsB,CACxC,YAAa,EAAO,YACpB,uBAAwB,CAC1B,CAAC,CACF,IAED,MAAM,EAAO,yBAAyB,CACpC,YAAa,EAAO,YACpB,uBAAwB,CAC1B,CAAC,EACD,MAAM,EAAO,0BAA0B,CACrC,YAAa,EAAO,YACpB,uBAAwB,EACxB,wBAAyB,EACzB,yBAA0B,EAAO,YACnC,CAAC,EACH,CAAC,CACH,CAAC,GACQ,IAAU,mBAGnB,MAAM,QAAQ,IACZ,EAAU,OAAO,QAAQ,IAAI,KAAO,IAAQ,CAC1C,MAAM,EAAO,gBAAgB,EAAI,OAAO,EAGxC,IAAM,EAAY,OAAO,EAAI,QAAQ,cAAc,GAAG,EAAI,QAAQ,OAClE,MAAM,EAAO,yBAAyB,CACpC,YAAa,EAAI,QAAQ,YACzB,uBAAwB,CAC1B,CAAC,CACH,CAAC,CACH,EAGA,MAAM,QAAQ,IAAI,EAAU,QAAQ,QAAQ,IAAK,GAAQ,EAAO,iBAAiB,EAAI,OAAO,CAAC,CAAC,CAElG,CAOA,eAAsB,QAAQ,EAAsB,CAClD,GAAM,CACJ,SACA,cACA,cACA,aACA,gBAAgB,GAChB,wBACA,gBACA,aACE,EACE,EAAO,EAAa,CAAC,EAAI,EAAY,YACrC,EAAwB,gCAAgC,CAAO,EAC/D,CACJ,UAAW,EACX,YACA,YACA,kBACE,MAAME,eACR,EACA,EACA,EAAY,KACZ,EAAY,GACZ,EACA,GAAyB,IAAI,IAC7B,EACA,CAAE,gBAAe,WAAU,CAC7B,EAUA,MAAO,CACL,UAAW,CACT,QAAS,EACT,OAAQ,MAXkB,YAC5B,EACA,EACA,EAJsB,EAAiB,QAAQ,IAAK,GAAQ,EAAI,IAKlD,EACd,CACF,CAME,EACA,YACA,YACA,gBACF,CACF,CAsCA,SAAS,kCACP,EACqC,CACrC,MAAO,CACL,sBAAuB,GAAQ,uBAAyB,GACxD,uBAAwB,GAAQ,wBAA0B,GAC1D,yBAA0B,GAAQ,0BAA4B,GAC9D,yBAA0B,GAAQ,0BAA4B,GAC9D,+BAAgC,GAAQ,gCAAkC,GAC1E,uBAAwB,GAAQ,wBAA0B,GAK1D,kBAAmB,GAAQ,mBAAqB,EAChD,kBAAmB,GAAQ,mBAAqB,KAIhD,oBAAqB,CACnB,GAAG,IAAI,KAAK,GAAQ,qBAAuB,CAAC,EAAA,CAAG,IAAK,GAAW,EAAO,YAAY,CAAC,CAAC,CACtF,CAAC,CAAC,SAAS,EACX,iBAAkB,GAAQ,kBAAoB,GAC9C,oBAAqB,GAAQ,qBAAuB,GACpD,oBAAqB,GAAQ,qBAAuB,GACpD,UAAW,GAAQ,WAAa,GAChC,WAAY,GAAQ,YAAc,GAClC,sBAAuB,GAAQ,sBAAwB,CAAC,EAAA,CAAG,SAAS,EACpE,UAAW,GAAQ,WAAa,EAClC,CACF,CAEA,SAAS,wCACP,EACqC,CACrC,MAAO,CACL,OAAQ,GAAO,QAAU,GACzB,OAAQ,GAAO,QAAU,GACzB,OAAQ,GAAO,QAAU,GACzB,KAAM,GAAO,MAAQ,GACrB,uBAAwB,GAAO,wBAA0B,GACzD,sBAAuB,GAAO,uBAAyB,GACvD,YAAa,GAAO,aAAe,EACrC,CACF,CAEA,SAAS,+BACP,EACoC,CACpC,MAAO,CACL,SAAU,GAAO,UAAY,GAC7B,qBAAsB,GAAO,sBAAwB,EACvD,CACF,CAEA,SAAS,8BACP,EAUsB,CACtB,MAAO,CACL,cAAe,EAAM,eAAiB,IAAA,GACtC,KAAM,EAAM,OAAS,GAAQ,YAAc,GAAQ,GAAK,EAAM,KAC9D,eAAgB,EAAM,eACtB,cAAe,EAAM,cACrB,qBAAsB,EAAM,qBAC5B,YAAa,EAAM,YACnB,WAAY,EAAM,UACpB,CACF,CAEA,SAAS,8BACP,EAC+D,CAI/D,GAHI,CAAC,GAIH,EAAW,OAAO,SAAW,GAC7B,EAAW,KAAK,SAAW,GAC3B,EAAW,OAAO,SAAW,GAC7B,EAAW,OAAO,SAAW,GAC7B,EAAW,uBAAuB,SAAW,GAC7C,EAAW,YAAY,SAAW,EAElC,OAEF,IAAM,gBAAmB,IAAgD,CACvE,WAAY,EAAO,WAAW,IAAK,IAAO,CACxC,KAAM,EAAE,KAAO,CAAE,KAAM,EAAE,KAAK,IAAK,EAAI,IAAA,GACvC,SAAU,EAAE,SACZ,MAAO,EAAE,MAAQ,CAAE,KAAM,EAAE,MAAM,IAAK,EAAI,IAAA,EAC5C,EAAE,EACF,OAAQ,EAAO,OAEf,YAAa,EAAO,aAAe,IAAA,EACrC,GACA,MAAO,CACL,OAAQ,EAAW,OAAO,IAAI,eAAe,EAC7C,KAAM,EAAW,KAAK,IAAI,eAAe,EACzC,OAAQ,EAAW,OAAO,IAAI,eAAe,EAC7C,OAAQ,EAAW,OAAO,IAAI,eAAe,EAC7C,uBAAwB,EAAW,uBAAuB,IAAI,eAAe,EAC7E,YAAa,EAAW,YAAY,IAAI,eAAe,CACzD,CACF,CAEA,SAAS,oBAAoB,EAA2B,EAAwC,CAC9F,OAAO,mBACL,8BAA8B,CAC5B,cAAe,EAAS,cACxB,KAAM,EAAS,KACf,eAAgB,kCAAkC,EAAS,cAAc,EACzE,cAAe,EAAS,kBACxB,qBAAsB,wCAAwC,EAAS,oBAAoB,EAC3F,YAAa,+BAA+B,EAAS,WAAW,EAChE,WAAY,8BAA8B,EAAS,UAAU,CAC/D,CAAC,EACD,CACF,CACF,CAEA,eAAeA,eACb,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EAIA,CACA,IAAM,EAAY,gBAMhB,cAAc,EACV,EAA6B,CAAC,EAC9B,EAAiC,CAAC,EAClC,EAAiB,IAAI,IAErB,EAAmB,MAAM,iCAAiC,CAC9D,SACA,UAAW,MAAO,EAAW,IAAgB,CAC3C,GAAM,CAAE,cAAa,iBAAkB,MAAM,EAAO,gBAAgB,CAClE,cACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAa,CAAa,CACpC,EACA,QAAU,GAAa,EAAS,WAAW,KAC3C,OAAS,GAAS,YAAY,EAAa,MAAO,CAAI,CACxD,CAAC,EAED,IAAK,IAAM,KAAO,EAAM,CACtB,IAAM,EAAgB,EAAI,KACpB,EAAW,EAAiB,GAC5B,EAAc,qBAClB,MAAM,iBAAiB,CACrB,IAAK,YAAY,EAAa,MAAO,CAAa,EAClD,UACA,OACF,CAAC,EACD,CACE,IAAK,EAAe,IAAI,CAAa,EACrC,cAAe,EAAQ,cACvB,UAAW,EAAQ,UACnB,OAAQ,EAAI,gBAAkB,IAAA,EAChC,CACF,EACI,EACJ,OAAQ,EAAI,cAAZ,CACE,IAAK,WACH,EAAgB,aAChB,MACF,IAAK,WACH,EAAgB,oCAChB,MACF,KAAK,IAAA,GACH,EAAgB,IAAA,GAChB,MACF,QACE,EAAgB,EAAI,cAAc,GAEtC,CAEA,IAAM,EAAO,YAAY,EAAI,IAAI,EAC3B,EAAiB,EAAI,eACrB,EAAgB,qBAAqB,CACzC,SAAU,EAAI,cACd,WAAY,EAAsB,IAAI,CAAa,EACnD,SAAU,GAAsB,WAAW,CAAa,CAC1D,CAAC,EACK,EAAc,EAAI,YACnB,EAAI,YACP,EAAO,KAAK,gBAAgB,EAAc,gCAAgC,EAE5E,IAAM,EAAyB,uBAAuB,EAAI,UAAU,EAChE,EAAuB,OAAS,GAClC,EAAO,KACL,gBAAgB,EAAc,2BAA2B,EAAuB,KAAK,IAAI,EAAE,gJAC7F,EAEE,GAA2B,CAAc,GAC3C,EAAO,KACL,gBAAgB,EAAc,8PAChC,EAEF,IAAM,EAAmB,mBAAmB,EAAI,UAAU,EACpD,EAAkB,EAAmB,mBAAmB,CAAgB,EAAI,IAAA,GAC5E,EAAwB,MAAM,GAClC,EACA,EACA,GAAgB,qBAAuB,CAAC,GAAG,EAAe,oBAAoB,EAAI,CAAC,EACnF,gBAAgB,EAAc,wBAC9B,CAAE,mBAAoB,CAAsB,CAC9C,EACM,EAA2B,GAC7B,CAAE,GAAG,EAAgB,qBAAsB,CAAsB,EAE/D,GAAU,8BAA8B,CAC5C,gBACA,OACA,eAAgB,kCAAkC,CAAwB,EAC1E,gBACA,qBAAsB,wCACpB,8BAA8B,EAAI,aAAa,CACjD,EACA,YAAa,+BAA+B,CAAW,EACvD,WAAY,CACd,CAAC,EACK,GAAU,CACd,cACA,gBACA,gBACA,OACA,iBACA,kBAAmB,EACnB,qBAAsB,8BAA8B,EAAI,aAAa,EACrE,cACA,WAAY,CACd,EAEI,GACY,8BAA8B,CAC1C,OAAQ,EAAS,UACjB,WAAY,EAAS,MACrB,UACA,QACA,aAAc,cACd,aAAc,EAAI,KAClB,YACA,WACF,CAEM,GACJ,sBAAsB,EAAS,UAAW,EAAY,MAAM,GAC5D,oBAAoB,EAAS,SAAU,EAAO,EAE9C,EAAU,UAAU,KAAK,CAAE,KAAM,EAAe,aAAY,CAAC,EAE7D,EAAU,QAAQ,KAAK,CACrB,KAAM,EACN,WACA,aACF,CAAC,EAEH,OAAO,EAAiB,IAExB,EAAU,QAAQ,KAAK,CACrB,KAAM,EACN,WACA,aACF,CAAC,CAEL,CAqBA,OApBA,OAAO,QAAQ,CAAgB,CAAC,CAAC,SAAS,CAAC,KAAmB,CAC5D,IAAM,EAAQ,EAAiB,GACjB,4BAA4B,CACxC,OAAQ,GAAO,UACf,WAAY,GAAO,MACnB,UACA,QACA,gBACF,CACQ,GACN,EAAU,QAAQ,KAAK,CACrB,KAAM,EACN,QAAS,CACP,cACA,eACF,CACF,CAAC,CAEL,CAAC,EAEM,CAAE,YAAW,YAAW,YAAW,gBAAe,CAC3D,CAmBA,eAAe,YACb,EACA,EACA,EACA,EACA,EAAgB,GAChB,CACA,IAAM,EAAY,gBAA0D,aAAa,EAEnF,aAAgB,GACb,EAAiB,MAAO,EAAW,IAAgB,CACxD,GAAM,CAAE,UAAS,iBAAkB,MAAM,EAAO,eAAe,CAC7D,cACA,gBACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAS,CAAa,CAChC,CAAC,EAGG,EAAe,MAAM,QAAQ,IAAI,EAAK,IAAK,GAAQ,aAAa,EAAI,IAAI,CAAC,CAAC,EAChF,IAAK,GAAM,CAAC,EAAG,KAAQ,EAAK,QAAQ,EAAG,CACrC,IAAM,EAAgB,EAAI,KACpB,EAAkB,EACtB,EAAa,GACb,0CACF,EACM,EAAkB,IAAI,IAC5B,EAAgB,QAAS,GAAW,CAClC,EAAgB,IAAI,EAAO,KAAM,EAAO,YAAY,EACpD,EAAO,eAAe,EAAO,YAAY,CAC3C,CAAC,EACD,IAAK,IAAM,KAAQ,EAAI,QACjB,EAAgB,IAAI,CAAI,GACtB,EACF,EAAU,QAAQ,KAAK,CACrB,OACA,cACA,gBACA,aAAc,EAAgB,IAAI,CAAI,GAAK,EAC7C,CAAC,EAED,EAAU,UAAU,KAAK,CACvB,MACF,CAAC,EAEH,EAAgB,OAAO,CAAI,GAE3B,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,gBACA,OAAQ,CACN,MACF,CACF,CACF,CAAC,EAGL,EAAgB,SAAS,EAAe,IAAS,CAC/C,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,gBACA,MACF,CACF,CAAC,CACH,CAAC,CACH,CAEA,IAAM,EAA0B,MAAM,QAAQ,IAC5C,EAAgB,IAAK,GAAkB,aAAa,CAAa,CAAC,CACpE,EACA,IAAK,GAAM,CAAC,EAAG,KAAkB,EAAgB,QAAQ,EACvD,EACE,EAAwB,GACxB,yDACF,CAAC,CAAC,QAAS,GAAW,CACpB,EAAO,eAAe,EAAO,YAAY,EACzC,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAO,KACb,QAAS,CACP,cACA,gBACA,KAAM,EAAO,IACf,CACF,CAAC,CACH,CAAC,EAEH,OAAO,CACT,CAEA,SAAS,YAAY,EAAyC,CAC5D,OAAQ,EAAR,CACE,IAAK,KACH,OAAO,GAAQ,GACjB,IAAK,KACH,OAAO,GAAQ,GACjB,QACE,OAAO,GAAQ,WACnB,CACF,CAKA,SAAS,8BACP,EACqC,CAChC,KAGL,MAAO,CACL,OAAQ,EAAc,SAAW,GACjC,OAAQ,EAAc,SAAW,GACjC,OAAQ,EAAc,SAAW,GACjC,KAAM,EAAc,OAAS,GAC7B,uBAAwB,EAAc,yBAA2B,GACjE,sBAAuB,EAAc,wBAA0B,GAC/D,YAAa,EAAc,cAAgB,EAC7C,CACF,CAEA,SAAS,mBACP,EACmD,CACnD,MAAO,CACL,OAAQ,EAAW,OAAO,IAAK,GAAM,eAAe,CAAC,CAAC,EACtD,KAAM,EAAW,KAAK,IAAK,GAAM,eAAe,CAAC,CAAC,EAClD,OAAQ,EAAW,OAAO,IAAK,GAAM,eAAe,CAAC,CAAC,EACtD,OAAQ,EAAW,OAAO,IAAK,GAAM,eAAe,CAAC,CAAC,EACtD,uBAAwB,EAAW,uBAAuB,IAAK,GAAM,eAAe,CAAC,CAAC,EACtF,YAAa,EAAW,YAAY,IAAK,GAAM,eAAe,CAAC,CAAC,CAClE,CACF,CAEA,SAAS,eACP,EACyD,CACzD,IAAI,EACJ,OAAQ,EAAO,OAAf,CACE,IAAK,QACH,EAAS,EAAoB,MAC7B,MACF,IAAK,OACH,EAAS,EAAoB,KAC7B,MACF,QACE,MAAM,EAAc,uBAAuB,EAAO,QAAwB,CAC9E,CACA,MAAO,CACL,WAAY,EAAO,WAAW,IAAK,GAAS,kBAAkB,CAAI,CAAC,EACnE,SACA,YAAa,EAAO,WACtB,CACF,CAEA,SAAS,kBACP,EAC4D,CAC5D,GAAM,CAAC,EAAM,EAAU,GAAS,EAE1B,EAAI,gBAAgB,CAAI,EACxB,EAAI,gBAAgB,CAAK,EAC3B,EACJ,OAAQ,EAAR,CACE,IAAK,KACH,EAAK,GAAsB,GAC3B,MACF,IAAK,KACH,EAAK,GAAsB,GAC3B,MACF,IAAK,KACH,EAAK,GAAsB,GAC3B,MACF,IAAK,MACH,EAAK,GAAsB,IAC3B,MACF,QACE,MAAM,EAAc,qBAAqB,GAA0B,CACvE,CACA,MAAO,CACL,KAAM,EACN,SAAU,EACV,MAAO,CACT,CACF,CAEA,SAAS,gBACP,EAC0D,CAC1D,GAAI,OAAO,GAAY,UAAY,CAAC,MAAM,QAAQ,CAAO,EAAG,CAC1D,GAAI,SAAU,EACZ,MAAO,CAAE,KAAM,CAAE,KAAM,YAAa,MAAO,EAAQ,IAAK,CAAE,EACrD,GAAI,YAAa,EACtB,MAAO,CAAE,KAAM,CAAE,KAAM,eAAgB,MAAO,EAAQ,OAAQ,CAAE,EAC3D,GAAI,eAAgB,EACzB,MAAO,CAAE,KAAM,CAAE,KAAM,kBAAmB,MAAO,EAAQ,UAAW,CAAE,EACjE,GAAI,eAAgB,EACzB,MAAO,CAAE,KAAM,CAAE,KAAM,kBAAmB,MAAO,EAAQ,UAAW,CAAE,EAEtE,MAAM,EAAc,oBAAoB,KAAK,UAAU,CAAO,GAAG,CAErE,CAEA,MAAO,CACL,KAAM,CACJ,KAAM,QACN,MAAO,GAAS,GAAa,CAAO,CACtC,CACF,CACF,CC9tBA,eAAsB,UACpB,EACA,EACA,EAAwB,gBACxB,CACA,GAAM,CAAE,aAAc,GAmKlB,IAAU,+BAAiC,IAAU,mBACvD,MAAM,SAnK0B,CAChC,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,QAAQ,QAAQ,IAAI,KAAO,IAAW,CACjD,MAAM,EAAO,kBAAkB,EAAO,OAAO,EAC7C,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,EACD,GAAG,EAAU,QAAQ,QAAQ,IAAI,KAAO,IAAW,CACjD,MAAM,EAAO,kBAAkB,EAAO,OAAO,EAC7C,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,CACH,CAAC,CACH,EAwJQ,CAAc,EACpB,MAAM,SAvJ8B,CACpC,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,YAAY,QAAQ,IAAI,KAAO,IAAW,CACrD,IAAM,EAAU,MAAM,EAAO,sBAAsB,EAAO,OAAO,EAIjE,OAHI,EAAQ,aAAa,cACvB,EAAO,eAAe,EAAQ,YAAY,YAAY,EAEjD,CACT,CAAC,EACD,GAAG,EAAU,YAAY,QAAQ,IAAI,KAAO,IAAW,CACrD,IAAM,EAAU,MAAM,EAAO,sBAAsB,EAAO,OAAO,EAIjE,OAHI,EAAQ,aAAa,cACvB,EAAO,eAAe,EAAQ,YAAY,YAAY,EAEjD,CACT,CAAC,CACH,CAAC,CACH,EAsIQ,CAAkB,IAEtB,IAAU,4BAA8B,IAAU,kBACpD,MAAM,SAjIwC,CAC9C,MAAM,qBACJ,EACA,CACE,UAAW,EAAU,WACrB,WAAY,EAAO,oBACrB,EACA,eACF,EAEA,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,UAAU,QAAQ,IAAI,KAAO,KACpC,EAAO,UAAU,OAAS,eAC5B,EAAc,EAAO,QAAQ,UAAW,2BAA2B,CAAC,CAAC,OACnE,MAAM,sBACJ,EACA,EAAc,EAAO,QAAQ,YAAa,6BAA6B,EACvE,EAAO,SACT,GAEG,EAAO,oBAAoB,EAAO,OAAO,EACjD,EACD,GAAG,EAAU,UAAU,QAAQ,IAAI,KAAO,KACpC,EAAO,UAAU,OAAS,eAC5B,EAAc,EAAO,QAAQ,UAAW,2BAA2B,CAAC,CAAC,OACnE,MAAM,sBACJ,EACA,EAAc,EAAO,QAAQ,YAAa,6BAA6B,EACvE,EAAO,SACT,GAEG,EAAO,oBAAoB,EAAO,OAAO,EACjD,CACH,CAAC,EAED,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,kBAAkB,QAAQ,IAAK,GAC1C,EAAO,wBAAwB,EAAO,OAAO,CAC/C,EACA,GAAG,EAAU,kBAAkB,QAAQ,IAAK,GAC1C,EAAO,wBAAwB,EAAO,OAAO,CAC/C,CACF,CAAC,EAED,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,aAAa,QAAQ,IAAK,GAAW,EAAO,mBAAmB,EAAO,OAAO,CAAC,EAC3F,GAAG,EAAU,aAAa,QAAQ,IAAK,GAAW,EAAO,mBAAmB,EAAO,OAAO,CAAC,CAC7F,CAAC,EAED,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,SAAS,QAAQ,IAAK,GAAW,EAAO,eAAe,EAAO,OAAO,CAAC,EACnF,GAAG,EAAU,SAAS,QAAQ,IAAK,GAAW,EAAO,eAAe,EAAO,OAAO,CAAC,CACrF,CAAC,EAED,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,aAAa,QAAQ,IAAI,KAAO,IAAW,CACtD,IAAM,EAAe,EACnB,EAAO,QAAQ,aACf,8BACF,EACA,EAAa,aAAe,MAAM,GAChC,EACA,EAAc,EAAO,QAAQ,YAAa,6BAA6B,EACvE,EAAa,aACb,sBACF,EACA,IAAM,EAAU,MAAM,EAAO,uBAAuB,EAAO,OAAO,EAIlE,OAHI,EAAQ,cAAc,cACxB,EAAO,eAAe,EAAQ,aAAa,YAAY,EAElD,CACT,CAAC,EACD,GAAG,EAAU,aAAa,QAAQ,IAAI,KAAO,IAAW,CACtD,IAAM,EAAe,EACnB,EAAO,QAAQ,aACf,8BACF,EACA,EAAa,aAAe,MAAM,GAChC,EACA,EAAc,EAAO,QAAQ,YAAa,6BAA6B,EACvE,EAAa,aACb,sBACF,EACA,IAAM,EAAU,MAAM,EAAO,uBAAuB,EAAO,OAAO,EAIlE,OAHI,EAAQ,cAAc,cACxB,EAAO,eAAe,EAAQ,aAAa,YAAY,EAElD,CACT,CAAC,CACH,CAAC,EAED,IAAK,IAAM,KAAW,EAAU,aAAa,SAAU,CACrD,MAAM,EAAO,uBAAuB,EAAQ,aAAa,EACzD,IAAM,EAAsB,EAC1B,EAAQ,cAAc,aACtB,oCACF,EACA,EAAoB,aAAe,MAAM,GACvC,EACA,EAAc,EAAQ,cAAc,YAAa,mCAAmC,EACpF,EAAoB,aACpB,sBACF,EACA,IAAM,EAAW,MAAM,EAAO,uBAAuB,EAAQ,aAAa,EACtE,EAAS,cAAc,cACzB,EAAO,eAAe,EAAS,aAAa,YAAY,CAE5D,CAEA,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,KAAK,QAAQ,IAAK,GAAW,EAAO,qBAAqB,EAAO,OAAO,CAAC,EACrF,GAAG,EAAU,KAAK,QAAQ,IAAK,GAAW,EAAO,qBAAqB,EAAO,OAAO,CAAC,CACvF,CAAC,EAED,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,aAAa,QAAQ,IAAK,GACrC,EAAO,uBAAuB,EAAO,OAAO,CAC9C,EACA,GAAG,EAAU,aAAa,QAAQ,IAAK,GACrC,EAAO,uBAAuB,EAAO,OAAO,CAC9C,CACF,CAAC,CACH,EAOQ,CAA4B,EAEhC,IAAU,oBAGZ,MAAM,QAAQ,IACZ,EAAU,aAAa,QAAQ,IAAK,GAAQ,EAAO,uBAAuB,EAAI,OAAO,CAAC,CACxF,EAGA,MAAM,QAAQ,IACZ,EAAU,KAAK,QAAQ,IAAK,GAAQ,EAAO,qBAAqB,EAAI,OAAO,CAAC,CAC9E,EAGA,MAAM,QAAQ,IACZ,EAAU,aAAa,QAAQ,IAAK,GAAQ,EAAO,uBAAuB,EAAI,OAAO,CAAC,CACxF,EAGA,MAAM,QAAQ,IAAI,EAAU,SAAS,QAAQ,IAAK,GAAQ,EAAO,eAAe,EAAI,OAAO,CAAC,CAAC,EAG7F,MAAM,QAAQ,IACZ,EAAU,YAAY,QAAQ,IAAK,GAAQ,EAAO,sBAAsB,EAAI,OAAO,CAAC,CACtF,EAGA,MAAM,QAAQ,IACZ,EAAU,aAAa,QAAQ,IAAK,GAAQ,EAAO,mBAAmB,EAAI,OAAO,CAAC,CACpF,EAGA,MAAM,SAxKoC,CAC1C,MAAM,QAAQ,IACZ,EAAU,kBAAkB,QAAQ,IAAK,GAAQ,EAAO,wBAAwB,EAAI,OAAO,CAAC,CAC9F,CACF,EAoKQ,CAAwB,EAG9B,MAAM,QAAQ,IACZ,EAAU,UAAU,QAAQ,IAAK,GAAQ,EAAO,oBAAoB,EAAI,OAAO,CAAC,CAClF,EAGA,MAAM,qBACJ,EACA,CACE,UAAW,EAAU,WACrB,WAAY,EAAO,oBACrB,EACA,kBACF,GACS,IAAU,mBAEnB,MAAM,QAAQ,IACZ,EAAU,QAAQ,QAAQ,IAAK,GAAQ,EAAO,kBAAkB,EAAI,OAAO,CAAC,CAC9E,CAEJ,CAOA,eAAsB,SAAS,EAAsB,CACnD,GAAM,CAAE,SAAQ,cAAa,cAAa,aAAY,gBAAgB,IAAU,EAC1E,EAAiC,CAAC,EACpC,CAAC,GAAc,EAAY,cAC7B,MAAM,EAAY,YAAY,kBAAkB,EAChD,EAAM,KAAK,EAAY,WAAW,GAEpC,GAAM,CACJ,UAAW,EACX,YACA,YACA,kBACE,MAAMC,eACR,EACA,EACA,EAAY,KACZ,EAAY,GACZ,EACA,CACF,EACM,EAAkB,EAAiB,QAAQ,IAAK,GAAQ,EAAI,IAAI,EAChE,EAAwB,gCAAgC,CAAO,EAC/D,CACJ,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,GACE,MAAM,QAAQ,IAAI,CACpB,eAAe,EAAQ,EAAa,EAAO,EAAiB,CAAa,EACzE,uBAAuB,EAAQ,EAAa,EAAO,EAAiB,CAAa,EACjF,kBAAkB,EAAQ,EAAa,EAAO,EAAiB,CAAa,EAC5E,iBAAiB,EAAQ,EAAa,EAAO,EAAiB,CAAa,EAC3E,cAAc,EAAQ,EAAa,EAAO,EAAiB,CAAa,EACxE,kBACE,EACA,EACA,EACA,EACA,EACA,CACF,EACA,gBAAgB,EAAQ,EAAa,EAAO,CAAe,EAC3D,kBAAkB,EAAQ,EAAa,EAAO,CAAe,EAC7D,oBAAoB,EAAQ,EAAa,EAAY,KAAM,EAAY,GAAI,CAAK,CAClF,CAAC,EACD,MAAO,CACL,UAAW,CACT,QAAS,EACT,UAAW,EACX,kBAAmB,EACnB,aAAc,EACd,YAAa,EACb,SAAU,EACV,aAAc,EACd,KAAM,EACN,aAAc,EACd,WAAY,EAAiB,SAC/B,EACA,UAAW,CAAC,GAAG,EAAW,GAAG,EAAiB,SAAS,EACvD,UAAW,CAAC,GAAG,EAAW,GAAG,EAAiB,SAAS,EACvD,eAAgB,IAAI,IAAI,CAAC,GAAG,EAAgB,GAAG,EAAiB,cAAc,CAAC,EAC/E,qBAAsB,EAAiB,UACzC,CACF,CAmBA,eAAeA,eACb,EACA,EACA,EACA,EACA,EACA,EAAgB,GAChB,CACA,IAAM,EAAY,gBAA6D,eAAe,EACxF,EAA6B,CAAC,EAC9B,EAAiC,CAAC,EAClC,EAAiB,IAAI,IAErB,EAAmB,MAAM,iCAAiC,CAC9D,SACA,UAAW,MAAO,EAAW,IAAgB,CAC3C,GAAM,CAAE,eAAc,iBAAkB,MAAM,EAAO,iBAAiB,CACpE,cACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAc,CAAa,CACrC,EACA,QAAU,GAAa,EAAS,WAAW,KAC3C,OAAS,GAAS,YAAY,EAAa,OAAQ,CAAI,CACzD,CAAC,EAED,IAAK,IAAM,KAAQ,EAAO,CACxB,GAAM,CAAE,UAAW,EACb,EAAW,EAAiB,EAAO,MACnC,EAAc,MAAM,iBAAiB,CACzC,IAAK,YAAY,EAAa,OAAQ,EAAO,IAAI,EACjD,UACA,OACF,CAAC,EACK,EAAU,CACd,cACA,cAAe,EAAO,KACtB,qBAAsB,EAAO,oBAC/B,EACA,GAAI,EAAU,CACZ,IAAM,EAAQ,8BAA8B,CAC1C,OAAQ,EAAS,UACjB,WAAY,EAAS,MACrB,UACA,QACA,aAAc,eACd,aAAc,EAAO,KACrB,YACA,WACF,CAAC,EAGC,CAAC,GACD,EAAS,SAAS,wBAA0B,EAAO,sBAAwB,KAC3E,EAEA,EAAU,UAAU,KAAK,CAAE,KAAM,EAAO,IAAK,CAAC,EAE9C,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAO,KACb,UACA,aACF,CAAC,EAEH,OAAO,EAAiB,EAAO,KACjC,MACE,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAO,KACb,UACA,aACF,CAAC,CAEL,CAqBA,OApBA,OAAO,QAAQ,CAAgB,CAAC,CAAC,SAAS,CAAC,KAAmB,CAC5D,IAAM,EAAQ,EAAiB,GACjB,4BAA4B,CACxC,OAAQ,GAAO,UACf,WAAY,GAAO,MACnB,UACA,QACA,gBACF,CACQ,GACN,EAAU,QAAQ,KAAK,CACrB,KAAM,EACN,QAAS,CACP,cACA,eACF,CACF,CAAC,CAEL,CAAC,EAEM,CAAE,YAAW,YAAW,YAAW,gBAAe,CAC3D,CAmBA,eAAe,eACb,EACA,EACA,EACA,EACA,EAAgB,GAChB,CACA,IAAM,EAAY,gBAChB,iBACF,EAEM,gBAAmB,GAChB,EAAiB,MAAO,EAAW,IAAgB,CACxD,GAAM,CAAE,aAAY,iBAAkB,MAAM,EAAO,mBAAmB,CACpE,cACA,gBACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAY,CAAa,CACnC,CAAC,EAGH,IAAK,IAAM,KAAe,EAAO,CAC/B,GAAM,CAAE,UAAW,EACb,EAAqB,MAAM,gBAAgB,EAAO,IAAI,EACtD,EAAc,IAAI,IACxB,EAAmB,QAAS,GAAc,CACxC,EAAY,IAAI,EAAU,KAAM,CAAS,CAC3C,CAAC,EACD,IAAM,EAAY,EAAO,WACzB,GAAI,EAAW,CACb,IAAM,EAAU,eAAe,CAAS,EAClC,EAAW,EAAY,IAAI,EAAU,IAAI,EAC/C,GAAI,EAAU,CACZ,IAAM,EAAoB,MAAM,4BAC9B,EACA,EACA,EACA,CACF,EACA,GAAI,CAAC,EAAmB,CACtB,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAU,KAChB,YACA,QAAS,CACP,cACA,cAAe,EAAO,KACtB,UAAW,CACb,CACF,CAAC,EACD,EAAY,OAAO,EAAU,IAAI,EACjC,QACF,CACI,CAAC,GAAiB,uBAAuB,EAAU,CAAiB,EACtE,EAAU,UAAU,KAAK,CAAE,KAAM,EAAU,IAAK,CAAC,EAEjD,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAU,KAChB,YACA,QAAS,CACP,cACA,cAAe,EAAO,KACtB,UAAW,CACb,CACF,CAAC,EAEH,EAAY,OAAO,EAAU,IAAI,CACnC,MACE,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAU,KAChB,YACA,QAAS,CACP,cACA,cAAe,EAAO,KACtB,UAAW,CACb,CACF,CAAC,CAEL,CACA,EAAY,SAAS,EAAG,IAAS,CAC/B,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,cAAe,EAAO,KACtB,MACF,CACF,CAAC,CACH,CAAC,CACH,CAEA,IAAK,IAAM,KAAiB,GAE1B,MADiC,gBAAgB,CAAa,EAAA,CAC3C,QAAS,GAAc,CACxC,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAU,KAChB,QAAS,CACP,cACA,gBACA,KAAM,EAAU,IAClB,CACF,CAAC,CACH,CAAC,EAEH,OAAO,CACT,CAEA,eAAe,4BACb,EACA,EACA,EACA,EACmE,CACnE,GAAI,EAAU,OAAS,aACrB,OAAO,EAGT,IAAM,EAAS,MAAM,yBAAyB,EAAQ,EAAa,CAAS,EAC5E,OAAO,EACH,CACE,KAAM,EAAQ,KACd,SAAU,EAAQ,SAClB,QACF,EACA,IAAA,EACN,CAEA,SAAS,iCAAiC,EAAyD,CACjG,OAAO,sBAAsB,EAAqB,CAAS,CAC7D,CAEA,SAAS,uBACP,EACA,EACA,CACA,OAAO,mBACL,iCAAiC,CAAQ,EACzC,iCAAiC,CAAO,CAC1C,CACF,CAEA,SAAS,eAAe,EAA2E,CACjG,OAAQ,EAAU,KAAlB,CACE,IAAK,UACH,MAAO,CACL,KAAM,EAAU,KAChB,SAAU,EAAuB,SACjC,OAAQ,CACN,OAAQ,CACN,KAAM,UACN,MAAO,CACL,YAAa,EAAU,YACvB,SAAU,EAAU,SACpB,UAAW,EAAU,UACrB,cAAe,EAAU,aAC3B,CACF,CACF,CACF,EACF,IAAK,OACH,MAAO,CACL,KAAM,EAAU,KAChB,SAAU,EAAuB,KACjC,OAAQ,CACN,OAAQ,CACN,KAAM,OACN,MAAO,CACL,GAAI,EAAU,cAAgB,IAAA,GAE1B,CACE,YAAa,EACX,EAAU,YACV,iCACF,CACF,EANA,CAAE,YAAa,EAAU,WAAY,EAOzC,kBAAmB,EAAU,kBAC7B,mBAAoB,EAAU,kBAChC,CACF,CACF,CACF,EACF,IAAK,OACH,MAAO,CACL,KAAM,EAAU,KAChB,SAAU,EAAuB,KACjC,OAAQ,CACN,OAAQ,CACN,KAAM,OACN,MAAO,CACL,YAAa,EAAU,SACvB,gBAAiB,CACf,UAAW,EAAU,aAAa,UAClC,UAAW,EAAU,aAAa,SACpC,EACA,YAAa,EAAU,YACvB,UAAW,EAAU,UACrB,cAAe,EAAU,aAC3B,CACF,CACF,CACF,EACF,IAAK,aACH,MAAO,CACL,KAAM,EAAU,KAChB,SAAU,EAAuB,KAEjC,OAAQ,CAAC,CACX,EACF,QACE,MAAM,EAAc,wBAAwB,GAA2B,CAC3E,CACF,CAEA,eAAe,sBACb,EACA,EACA,EAC8D,CAC9D,IAAM,EAAS,MAAM,yBAAyB,EAAQ,EAAa,CAAgB,EACnF,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,gBACN,QAAS,iBAAiB,EAAiB,UAAU,cACrD,WAAY,0CACd,CAAC,EAEH,OAAO,CACT,CAEA,eAAe,yBACb,EACA,EACA,EAC0E,CAC1E,IAAM,EAAa,MAAM,EAAU,SAC1B,MAAM,EAAO,cAAc,CAChC,cACA,cAAe,EAAiB,SAClC,CAAC,CACF,EACD,GAAI,CAAC,EAAY,OAEjB,IAAM,EAAY,MAAM,EAAU,SACzB,MAAM,EAAO,aAAa,CAC/B,cACA,cAAe,EAAiB,UAChC,KAAM,EAAiB,UACzB,CAAC,CACF,EACD,GAAI,CAAC,EAAW,OAEhB,IAAM,EAAY,mBAAmB,EAAiB,UAAW,EAAiB,UAAU,EACtF,EAAY,oBAAoB,EAAiB,UAAW,EAAiB,UAAU,EAC7F,MAAO,CACL,OAAQ,CACN,KAAM,OACN,MAAO,CACL,YAAa,EAAU,QAAQ,SAC/B,gBAAiB,CACf,YACA,WACF,EACA,YAAa,EAAW,YAAY,YACpC,cAAe,MACjB,CACF,CACF,CACF,CAiBA,eAAe,uBACb,EACA,EACA,EACA,EACA,EAAgB,GAChB,CACA,IAAM,EAAY,gBAIhB,yBAAyB,EAE3B,IAAK,IAAM,KAAQ,EAAO,CACxB,GAAM,CAAE,UAAW,EACb,EAAO,GAAG,EAAO,KAAK,sBACtB,EAAW,MAAM,EAAU,SACxB,MAAM,EAAO,qBAAqB,CACvC,cACA,cAAe,EAAO,IACxB,CAAC,CACF,EACD,GAAI,CAAC,EAAU,CACb,IAAM,EAAuB,EAAK,YAC9B,GACF,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,cAAe,EAAO,KACtB,0BAA2B,uBAAuB,CAAoB,CACxE,CACF,CAAC,EAEH,QACF,CAEA,IAAM,EAAuB,EAAK,YAClC,GAAI,EAAsB,CACxB,IAAM,EAAU,uBAAuB,CAAoB,EAEzD,CAAC,GACD,2BAA2B,EAAS,2BAA6B,CAAC,EAAG,CAAO,EAE5E,EAAU,UAAU,KAAK,CAAE,MAAK,CAAC,EAEjC,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,cAAe,EAAO,KACtB,0BAA2B,CAC7B,CACF,CAAC,CAEL,MACE,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,cAAe,EAAO,IACxB,CACF,CAAC,CAEL,CAEA,IAAK,IAAM,KAAiB,EAOrB,MANkB,EAAU,SACxB,MAAM,EAAO,qBAAqB,CACvC,cACA,eACF,CAAC,CACF,GAED,EAAU,QAAQ,KAAK,CACrB,KAAM,GAAG,EAAc,sBACvB,QAAS,CACP,cACA,eACF,CACF,CAAC,EAEH,OAAO,CACT,CAEA,SAAS,uBACP,EAC0D,CAE1D,IAAM,EAAe,EAAY,WAC7B,OAAO,YAAY,OAAO,KAAK,EAAY,UAAU,CAAC,CAAC,IAAK,GAAQ,CAAC,EAAK,CAAG,CAAC,CAAC,EAC/E,IAAA,GAEJ,MAAO,CACL,aAAc,EAAkD,SAChE,OAAQ,CACN,OAAQ,CACN,KAAM,WACN,MAAO,CACL,UAAW,EAAY,UACvB,KAAM,EAAY,KAAK,KACvB,cAAe,EAAY,cAC3B,cAAe,IAAA,GACf,iBAAkB,EAAY,cAC9B,cACF,CACF,CACF,CACF,CACF,CAiBA,eAAe,kBACb,EACA,EACA,EACA,EACA,EAAgB,GAChB,CACA,IAAM,EAAY,gBAChB,oBACF,EAEA,IAAK,IAAM,KAAQ,EAAO,CACxB,GAAM,CAAE,UAAW,EACb,EAAO,GAAG,EAAO,KAAK,gBACtB,EAAW,MAAM,EAAU,SACxB,MAAM,EAAO,gBAAgB,CAClC,cACA,cAAe,EAAO,IACxB,CAAC,CACF,EACD,GAAI,CAAC,EAAU,CACT,EAAO,gBACT,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,cAAe,EAAO,KACtB,qBAAsB,kBAAkB,EAAO,cAAc,CAC/D,CACF,CAAC,EAEH,QACF,CAEA,GAAI,EAAO,eAAgB,CACzB,IAAM,EAAU,kBAAkB,EAAO,cAAc,EACnD,CAAC,GAAiB,8BAA8B,EAAS,qBAAsB,CAAO,EACxF,EAAU,UAAU,KAAK,CAAE,MAAK,CAAC,EAEjC,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,cAAe,EAAO,KACtB,qBAAsB,CACxB,CACF,CAAC,CAEL,MACE,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,cAAe,EAAO,IACxB,CACF,CAAC,CAEL,CAEA,IAAK,IAAM,KAAiB,EAOrB,MANkB,EAAU,SACxB,MAAM,EAAO,gBAAgB,CAClC,cACA,eACF,CAAC,CACF,GAED,EAAU,QAAQ,KAAK,CACrB,KAAM,GAAG,EAAc,gBACvB,QAAS,CACP,cACA,eACF,CACF,CAAC,EAEH,OAAO,CACT,CAEA,SAAS,kBACP,EACqD,CACrD,MAAO,CACL,aAAc,GAAwC,SACtD,OAAQ,CACN,OAAQ,CACN,KAAM,WACN,MAAO,CACL,UAAW,EAAa,UACxB,KAAM,EAAa,KACnB,eAAgB,EAAa,cAC/B,CACF,CACF,CACF,CACF,CAiBA,eAAe,iBACb,EACA,EACA,EACA,EACA,EAAgB,GAChB,CACA,IAAM,EAAY,gBAChB,mBACF,EAEM,kBAAqB,GAClB,EAAiB,MAAO,EAAW,IAAgB,CACxD,GAAM,CAAE,eAAc,iBAAkB,MAAM,EAAO,qBAAqB,CACxE,cACA,gBACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAc,CAAa,CACrC,CAAC,EAGH,IAAK,IAAM,KAAQ,EAAO,CACxB,GAAM,CAAE,UAAW,EACb,EAAuB,MAAM,kBAAkB,EAAO,IAAI,EAC1D,EAAc,IAAI,IACxB,EAAqB,QAAS,GAAgB,CAC5C,EAAY,IAAI,EAAY,KAAM,CAAW,EAC7C,EAAO,eAAe,EAAY,YAAY,CAChD,CAAC,EACD,IAAK,IAAM,KAAmB,OAAO,KAAK,EAAO,cAAgB,CAAC,CAAC,EAAG,CACpE,IAAM,EAAc,EAAO,eAAe,GAC1C,GAAI,CAAC,EACH,SAEF,IAAM,EAAqB,CACzB,WAAY,EAAY,cACxB,aAAc,EAAY,WACtB,6BAA6B,EAAY,UAAU,EACnD,IAAA,EACN,EACM,EAAW,EAAY,IAAI,CAAe,EAC5C,GACE,CAAC,GAAiB,qBAAqB,EAAU,CAAkB,EACrE,EAAU,UAAU,KAAK,CAAE,KAAM,CAAgB,CAAC,EAElD,EAAU,QAAQ,KAAK,CACrB,KAAM,EACN,QAAS,CACP,cACA,cAAe,EAAO,KACtB,KAAM,EACN,WAAY,EAAY,cACxB,aAAc,EAAmB,YACnC,CACF,CAAC,EAEH,EAAY,OAAO,CAAe,GAElC,EAAU,QAAQ,KAAK,CACrB,KAAM,EACN,QAAS,CACP,cACA,cAAe,EAAO,KACtB,KAAM,EACN,WAAY,EAAY,cACxB,aAAc,EAAmB,YACnC,CACF,CAAC,CAEL,CACA,EAAY,SAAS,EAAG,IAAS,CAC/B,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,cAAe,EAAO,KACtB,MACF,CACF,CAAC,CACH,CAAC,CACH,CAEA,IAAK,IAAM,KAAiB,GAE1B,MADmC,kBAAkB,CAAa,EAAA,CAC7C,QAAS,GAAgB,CAC5C,EAAO,eAAe,EAAY,YAAY,EAC9C,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAY,KAClB,QAAS,CACP,cACA,cAAe,EACf,KAAM,EAAY,IACpB,CACF,CAAC,CACH,CAAC,EAEH,OAAO,CACT,CAEA,SAAS,6BACP,EACsD,CACtD,IAAM,EAA4D,CAAC,EACnE,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAY,EACpD,EAAI,GAAO,GAAS,GAAa,GAAS,IAAI,EAEhD,OAAO,CACT,CAEA,SAAS,qCACP,EACA,CACA,IAAM,EAAmB,EAAO,QAAQ,OAClC,EAAiB,GAAkB,OAAS,WAAa,EAAiB,MAAQ,IAAA,GAExF,OAAO,sBAAsB,GAAiC,CAC5D,aAAc,EAAO,aACrB,OAAQ,EACJ,CACE,OAAQ,CACN,KAAM,WACN,MAAO,CACL,GAAG,EACH,cAAe,EAAe,eAAiB,GAC/C,iBAAkB,qBAAqB,EAAe,gBAAgB,EACtE,aAAc,qBAAqB,EAAe,cAAgB,CAAC,CAAC,CACtE,CACF,CACF,EACA,IAAA,EACN,CAAC,CACH,CAEA,SAAS,2BACP,EACA,EACA,CACA,OAAO,mBACL,qCAAqC,CAAQ,EAC7C,qCAAqC,CAAO,CAC9C,CACF,CAEA,SAAS,wCACP,EACA,CACA,OAAO,sBAAsB,EAA4B,GAAU,CAAC,CAAC,CACvE,CAEA,SAAS,8BACP,EACA,EACA,CACA,OAAO,mBACL,wCAAwC,CAAQ,EAChD,wCAAwC,CAAO,CACjD,CACF,CAEA,SAAS,+BAA+B,EAGrC,CACD,OAAO,qBAAqB,CAC1B,WAAY,qBAAqB,EAAM,UAAU,EACjD,aAAc,qBAAqB,EAAM,cAAgB,CAAC,CAAC,CAC7D,CAAC,CACH,CAEA,SAAS,qBACP,EAIA,EAIA,CACA,OAAO,mBACL,+BAA+B,CAAQ,EACvC,+BAA+B,CAAO,CACxC,CACF,CAEA,SAAS,gCACP,EAYA,CACA,IAAM,EAAsB,wBAAwB,EAAO,mBAAmB,EACxE,EAAuB,wBAAwB,EAAO,oBAAoB,EAEhF,OAAO,qBAAqB,CAC1B,GAAG,EAEH,YAAa,EAAO,aAAe,IAAA,GACnC,aAAc,qBAAqB,EAAO,YAAY,EACtD,YAAa,EAAO,YAAc,CAAC,EAAA,CAAG,UAAU,EAAM,IAAU,EAAO,CAAK,EAC5E,oBAAqB,GAAuB,MAC5C,qBAAsB,GAAwB,OAC9C,YAAa,EAAO,aAAe,EACrC,CAAC,CACH,CAEA,SAAS,wBACP,EAMA,CACA,GAAI,OAAO,GAAa,SACtB,OAAO,EAGT,GAAI,GAAU,SAAW,KACvB,OAAO,OAAO,EAAS,OAAO,CAIlC,CAEA,SAAS,sBACP,EAUA,EAYA,CACA,OAAO,mBACL,gCAAgC,CAAQ,EACxC,gCAAgC,CAAO,CACzC,CACF,CAuBA,eAAe,kBACb,EACA,EACA,EACA,EACA,EACA,EAAgB,GAChB,CACA,IAAM,EAAY,gBAKhB,oBAAoB,EAEhB,mBAAsB,GACnB,EAAiB,MAAO,EAAW,IAAgB,CACxD,GAAM,CAAE,gBAAe,iBAAkB,MAAM,EAAO,sBAAsB,CAC1E,cACA,gBACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAe,CAAa,CACtC,CAAC,EAGH,IAAK,IAAM,KAAQ,EAAO,CACxB,GAAM,CAAE,UAAW,EACb,EAAwB,MAAM,mBAAmB,EAAO,IAAI,EAC5D,EAAqB,IAAI,IAC/B,EAAsB,QAAS,GAAiB,CAC9C,EAAmB,IAAI,EAAa,KAAM,CAAY,EACtD,EAAO,eAAe,EAAa,YAAY,CACjD,CAAC,EACD,IAAK,IAAM,KAAoB,OAAO,KAAK,EAAO,eAAiB,CAAC,CAAC,EAAG,CACtE,IAAM,EAAe,EAAO,gBAAgB,GAC5C,GAAI,CAAC,EACH,SAEF,IAAM,EAAkB,kBAAkB,EAAkB,CAAY,EAClE,EAAuB,MAAM,GACjC,EACA,EACA,EAAgB,cAAgB,CAAC,EACjC,uBACA,CAAE,mBAAoB,CAAsB,CAC9C,EACA,GAAI,EAAmB,IAAI,CAAgB,EAAG,CAC5C,IAAM,EAAiB,EACrB,EAAmB,IAAI,CAAgB,EACvC,uDACF,EACA,GAAI,EAAe,aAAe,EAAgB,WAEhD,EAAU,SAAS,KAAK,CACtB,KAAM,EACN,cAAe,CACb,cACA,cAAe,EAAO,KACtB,KAAM,CACR,EACA,cAAe,CACb,cACA,cAAe,EAAO,KACtB,aAAc,CAChB,CACF,CAAC,MACI,CACL,IAAM,EAAoB,CACxB,GAAG,EACH,aAAc,EACd,oBAAqB,wBAAwB,EAAgB,mBAAmB,EAChF,qBAAsB,wBAAwB,EAAgB,oBAAoB,CACpF,EACM,EAAqB,CACzB,KAAM,EAAe,KACrB,YAAa,EAAe,YAC5B,WAAY,EAAe,WAC3B,aAAc,EAAe,aAC7B,WAAY,EAAe,WAC3B,oBAAqB,wBAAwB,EAAe,mBAAmB,EAC/E,qBAAsB,wBAAwB,EAAe,oBAAoB,EACjF,YAAa,EAAe,WAC9B,EACI,CAAC,GAAiB,sBAAsB,EAAoB,CAAiB,EAC/E,EAAU,UAAU,KAAK,CAAE,KAAM,CAAiB,CAAC,EAEnD,EAAU,QAAQ,KAAK,CACrB,KAAM,EACN,QAAS,CACP,cACA,cAAe,EAAO,KACtB,aAAc,CAChB,CACF,CAAC,CAEL,CACA,EAAmB,OAAO,CAAgB,CAC5C,MACE,EAAU,QAAQ,KAAK,CACrB,KAAM,EACN,QAAS,CACP,cACA,cAAe,EAAO,KACtB,aAAc,CAChB,CACF,CAAC,CAEL,CACA,EAAmB,SAAS,EAAG,IAAS,CACtC,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,cAAe,EAAO,KACtB,MACF,CACF,CAAC,CACH,CAAC,CACH,CAEA,IAAK,IAAM,KAAiB,GAE1B,MADoC,mBAAmB,CAAa,EAAA,CAC9C,QAAS,GAAiB,CAC9C,EAAO,eAAe,EAAa,YAAY,EAC/C,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAa,KACnB,QAAS,CACP,cACA,gBACA,KAAM,EAAa,IACrB,CACF,CAAC,CACH,CAAC,EAGH,OAAO,CACT,CAEA,SAAS,kBACP,EACA,EACiD,CAKjD,MAAO,CACL,KAAM,EACN,YAAa,EAAa,YAC1B,WAAY,EAAa,WAAW,IAAK,GAAc,CACrD,OAAQ,EAAR,CACE,IAAK,qBACH,OAAO,GAA2B,mBACpC,IAAK,gBACH,OAAO,GAA2B,cACpC,QACE,MAAM,EAAc,qCAAqC,GAA2B,CACxF,CACF,CAAC,EACD,aAAc,EAAa,aAC3B,WACE,CACE,aAAc,EAA4B,aAC1C,OAAQ,EAA4B,OACpC,QAAS,EAA4B,OACvC,EACA,EAAa,YAAc,gBAC7B,oBAAqB,EAAa,2BAClC,qBAAsB,EAAa,4BACnC,YAAa,EAAa,WAC5B,CACF,CAiBA,eAAe,gBACb,EACA,EACA,EACA,EACA,CACA,IAAM,EAAY,gBAChB,kBACF,EAEA,IAAK,IAAM,KAAQ,EAAO,CACxB,GAAM,CAAE,UAAW,EACb,EAAO,GAAG,EAAO,KAAK,cAOvB,MANkB,EAAU,SACxB,MAAM,EAAO,kBAAkB,CACpC,cACA,cAAe,EAAO,IACxB,CAAC,CACF,EAYU,EAAO,KAChB,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,cAAe,EAAO,KACtB,WAAY,gBAAgB,EAAO,IAAI,CACzC,CACF,CAAC,EAED,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,cAAe,EAAO,IACxB,CACF,CAAC,EA1BG,EAAO,MACT,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,cAAe,EAAO,KACtB,WAAY,gBAAgB,EAAO,IAAI,CACzC,CACF,CAAC,CAoBP,CAEA,IAAK,IAAM,KAAiB,EAOrB,MANkB,EAAU,SACxB,MAAM,EAAO,kBAAkB,CACpC,cACA,eACF,CAAC,CACF,GAED,EAAU,QAAQ,KAAK,CACrB,KAAM,GAAG,EAAc,cACvB,QAAS,CACP,cACA,eACF,CACF,CAAC,EAEH,OAAO,CACT,CAEA,SAAS,gBAAgB,EAAuE,CAC9F,IAAI,EACJ,OAAQ,EAAW,cAAc,KAAjC,CACE,IAAK,SACH,EAAoB,EAAiC,OACrD,MACF,IAAK,SACH,EAAoB,EAAiC,OACrD,MACF,QACE,MAAM,EACJ,oCAAoC,EAAW,cAAc,MAC/D,CACJ,CAEA,MAAO,CACL,gBAAiB,EAAW,gBAC5B,oBACA,oBAAqB,CACnB,KAAM,eACN,MAAO,CACL,UAAW,EAAW,cAAc,cAAc,UAClD,UAAW,EAAW,cAAc,cAAc,SACpD,CACF,CACF,CACF,CAiBA,eAAe,kBACb,EACA,EACA,EACA,EACA,CACA,IAAM,EAAY,gBAChB,oBACF,EAEM,mBAAqB,KAAO,IAQzB,MAPgB,EAAU,SAAY,CAC3C,GAAM,CAAE,iBAAkB,MAAM,EAAO,qBAAqB,CAC1D,cACA,eACF,CAAC,EACD,OAAO,CACT,CAAC,GACkB,CAAC,EAGtB,IAAK,IAAM,KAAQ,EAAO,CACxB,GAAM,CAAE,UAAW,EACb,EAAwB,MAAM,mBAAmB,EAAO,IAAI,EAC5D,EAAkB,IAAI,IAC5B,EAAsB,QAAS,GAAiB,CAC9C,EAAgB,IAAI,EAAa,IAAI,CACvC,CAAC,EACD,IAAK,IAAM,KAAgB,EAAO,MAAM,WAAa,CAAC,EAChD,EAAgB,IAAI,EAAa,IAAI,GACvC,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAa,KACnB,QAAS,CACP,cACA,cAAe,EAAO,KACtB,aAAc,kBAAkB,CAAY,CAC9C,CACF,CAAC,EACD,EAAgB,OAAO,EAAa,IAAI,GAExC,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAa,KACnB,QAAS,CACP,cACA,cAAe,EAAO,KACtB,aAAc,kBAAkB,CAAY,CAC9C,CACF,CAAC,EAGL,EAAgB,QAAS,GAAS,CAChC,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,cAAe,EAAO,KACtB,MACF,CACF,CAAC,CACH,CAAC,CACH,CAEA,IAAK,IAAM,KAAiB,GAE1B,MADoC,mBAAmB,CAAa,EAAA,CAC9C,QAAS,GAAiB,CAC9C,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAa,KACnB,QAAS,CACP,cACA,gBACA,KAAM,EAAa,IACrB,CACF,CAAC,CACH,CAAC,EAEH,OAAO,CACT,CAEA,SAAS,kBACP,EACiD,CACjD,MAAO,CACL,KAAM,EAAa,KACnB,kBAAmB,EAAa,kBAChC,aAAc,EAAa,aAC3B,WAAY,CACV,KAAM,EAAa,WAAW,KAC9B,WAAY,EAAa,WAAW,WAAW,IAAK,GAAS,mBAAmB,CAAI,CAAC,CACvF,EACA,iBAAkB,EAAa,iBAAiB,IAAK,IAAU,CAC7D,cAAe,EAAK,cACpB,SAAU,EAAK,QACjB,EAAE,CACJ,CACF,CAEA,SAAS,mBAAmB,EAAuE,CACjG,IAAI,EACJ,OAAQ,EAAK,KAAb,CACE,IAAK,SACH,EAAM,EAAuB,OAC7B,MACF,IAAK,SACH,EAAM,EAAuB,OAC7B,MACF,IAAK,UACH,EAAM,EAAuB,QAC7B,MACF,IAAK,WACH,EAAM,EAAuB,SAC7B,MACF,IAAK,UACH,EAAM,EAAuB,QAC7B,MACF,QACE,MAAM,EAAc,gCAAgC,EAAK,MAAsB,CACnF,CACA,IAAI,EACJ,GAAI,EAAK,WACP,OAAQ,EAAK,WAAb,CACE,IAAK,WACH,EAAa,EAA6B,UAC1C,MACF,IAAK,YACH,EAAa,EAA6B,WAC1C,MACF,IAAK,YACH,EAAa,EAA6B,WAC1C,MACF,QACE,MAAM,EACJ,sCAAsC,EAAK,YAC7C,CACJ,CAEF,IAAI,EACJ,GAAI,EAAK,WACP,OAAQ,EAAK,WAAb,CACE,IAAK,OACH,EAAa,GAA6B,KAC1C,MACF,IAAK,SACH,EAAa,GAA6B,OAC1C,MACF,IAAK,SACH,EAAa,GAA6B,OAC1C,MACF,QACE,MAAM,EACJ,sCAAsC,EAAK,YAC7C,CACJ,CAEF,MAAO,CACL,KAAM,EACN,KAAM,EAAK,KACX,YAAa,EAAK,YAClB,aACA,SAAU,EAAK,SACf,YAAa,EAAK,YAClB,aACA,gBAAiB,EAAK,iBAAmB,IAAA,GACzC,cAAe,EAAK,eAAe,IAAK,GAAS,mBAAmB,CAAI,CAAC,CAC3E,CACF,CAiBA,SAAS,kBACP,EAOA,EAOS,CACT,OAAO,mBACL,CACE,UAAW,EAAS,WAAa,GACjC,QAAS,EAAS,QACd,CACE,UAAW,EAAS,QAAQ,WAAa,GACzC,gBAAiB,EAAS,QAAQ,iBAAmB,EACvD,EACA,IAAA,EACN,EACA,CACE,UAAW,EAAQ,WAAa,GAChC,QAAS,EAAQ,QACb,CACE,UAAW,EAAQ,QAAQ,WAAa,GACxC,gBAAiB,EAAQ,QAAQ,iBAAmB,EACtD,EACA,IAAA,EACN,CACF,CACF,CAQA,SAAgB,4BACd,EAIA,EACuB,CACvB,OAAO,wCACL,WACA,EACA,EACC,GAAS,CACR,GAAM,CAAC,EAAW,GAAa,EAAK,KAAK,MAAM,GAAG,EAClD,OAAO,GAAa,EAAY,CAAC,qBAAqB,EAAW,CAAS,CAAC,EAAI,CAAC,CAClF,EACA,CACE,aAAe,GAAS,EAAK,KAAK,MAAM,GAAG,CAAC,CAAC,GAC7C,eAAiB,GAAS,EAAK,KAAK,MAAM,GAAG,CAAC,CAAC,IAAM,EAAK,IAC5D,CACF,CACF,CAEA,eAAe,cACb,EACA,EACA,EACA,EACA,EAAgB,GAChB,CACA,IAAM,EAAY,gBAAgE,YAAY,EAE9F,IAAK,IAAM,KAAQ,EAAO,CACxB,GAAM,CAAE,UAAW,EACb,EAAc,EAAO,OAAO,YAE5B,EAQU,MAAM,EAAU,SAAY,CAC1C,GAAM,CAAE,QAAS,MAAM,EAAO,YAAY,CACxC,cACA,cAAe,EAAO,KACtB,UAAW,EAAc,YAC3B,CAAC,EACD,OAAO,CACT,CAAC,EAED,GAAI,EAAa,CACf,IAAM,EAAc,CAClB,cACA,cAAe,EAAO,KACtB,KAAM,CACJ,UAAW,EAAc,aACzB,UAAW,qBAAqB,EAAO,KAAM,cAAc,EAC3D,QAAS,CACP,UAAW,EAAO,KAClB,gBAAiB,EAAY,OAC/B,CACF,CACF,EAEI,EACE,CAAC,GAAiB,kBAAkB,EAAc,EAAY,IAAI,EACpE,EAAU,UAAU,KAAK,CACvB,KAAM,GAAG,EAAO,KAAK,cACvB,CAAC,EAED,EAAU,QAAQ,KAAK,CACrB,KAAM,GAAG,EAAO,KAAK,eACrB,QAAS,CACX,CAAC,EAGH,EAAU,QAAQ,KAAK,CACrB,KAAM,GAAG,EAAO,KAAK,eACrB,QAAS,CACX,CAAC,CAEL,MAAW,GACT,EAAU,QAAQ,KAAK,CACrB,KAAM,GAAG,EAAO,KAAK,eACrB,QAAS,CACP,cACA,cAAe,EAAO,KACtB,UAAW,EAAc,YAC3B,CACF,CAAC,CAEL,CAEA,IAAK,IAAM,KAAiB,EAQtB,MAP+B,EAAU,SACpC,MAAM,EAAO,YAAY,CAC9B,cACA,gBACA,UAAW,EAAc,YAC3B,CAAC,CACF,GAEC,EAAU,QAAQ,KAAK,CACrB,KAAM,GAAG,EAAc,eACvB,QAAS,CACP,cACA,gBACA,UAAW,EAAc,YAC3B,CACF,CAAC,EAIL,OAAO,CACT,CCj8DA,SAAgB,iBACd,EACA,EACA,EAC4D,CACxD,OAAY,IAAA,GAChB,IAAI,OAAO,GAAY,SAAU,CAC/B,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,wBACN,QAAS,GAAG,EAAQ,2BAA2B,EAAQ,wCACvD,WAAY,iDACd,CAAC,EAEH,MAAO,CAAE,UAAW,EAAe,gBAAiB,CAAQ,CAC9D,CACA,OAAO,CADP,CAEF,CCyBA,eAAsB,cACpB,EACA,EACA,EAAyD,gBACzD,CACA,GAAM,CAAE,aAAc,EAClB,IAAU,gBAEZ,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,QAAQ,IAAI,KAAO,IAAW,CACzC,MAAM,EAAO,uBAAuB,EAAO,OAAO,EAClD,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,EACD,GAAG,EAAU,QAAQ,IAAI,KAAO,IAAW,CACzC,MAAM,EAAO,uBAAuB,EAAO,OAAO,EAClD,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,CACH,CAAC,EAID,MAAM,QAAQ,IAAI,EAAU,QAAQ,IAAK,GAAQ,EAAO,uBAAuB,EAAI,OAAO,CAAC,CAAC,CAEhG,CAwBA,eAAsB,aAAa,EAAsB,CACvD,GAAM,CAAE,SAAQ,cAAa,cAAa,cAAe,EACnD,EAAY,gBAAgE,WAAW,EACvF,EAA6B,CAAC,EAC9B,EAAiC,CAAC,EAClC,EAAiB,IAAI,IAErB,EAAoB,MAAM,iCAAiC,CAC/D,SACA,UAAW,MAAO,EAAW,IAAa,CACxC,GAAM,CAAE,YAAW,iBAAkB,MAAM,EAAO,sBAAsB,CACtE,cACA,YACA,UACF,CAAC,EACD,MAAO,CAAC,EAAW,CAAa,CAClC,EACA,QAAU,GAAa,EAAS,KAChC,OAAS,GAAS,YAAY,EAAa,WAAY,CAAI,CAC7D,CAAC,EAEK,EAAY,EAAa,CAAC,EAAM,MAAM,EAAY,iBAAiB,cAAc,GAAM,CAAC,EAC9F,IAAK,IAAM,KAAY,OAAO,OAAO,CAAS,EAAG,CAC/C,IAAM,EAAW,EAAkB,EAAS,MACtC,EAAc,MAAM,iBAAiB,CACzC,IAAK,YAAY,EAAa,WAAY,EAAS,IAAI,EACvD,QAAS,EAAY,KACrB,MAAO,EAAY,EACrB,CAAC,EACK,EAAkB,cAAc,EAAS,CAAQ,EACnD,GACY,8BAA8B,CAC1C,OAAQ,EAAS,UACjB,WAAY,EAAS,MACrB,QAAS,EAAY,KACrB,MAAO,EAAY,GACnB,aAAc,WACd,aAAc,EAAS,KACvB,YACA,WACF,CAGM,GACJ,sBAAsB,EAAS,UAAW,EAAY,MAAM,GAC5D,kBAAkB,EAAS,SAAU,CAAe,EAEpD,EAAU,UAAU,KAAK,CAAE,KAAM,EAAS,IAAK,CAAC,EAEhD,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAS,KACf,QAAS,CACP,cACA,SAAU,CACZ,EACA,aACF,CAAC,EAEH,OAAO,EAAkB,EAAS,OAElC,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAS,KACf,QAAS,CACP,cACA,SAAU,CACZ,EACA,aACF,CAAC,CAEL,CAsBA,OArBA,OAAO,QAAQ,CAAiB,CAAC,CAAC,SAAS,CAAC,KAAU,CACpD,IAAM,EAAQ,EAAkB,GAC1B,EAAQ,GAAO,MACP,4BAA4B,CACxC,OAAQ,GAAO,UACf,WAAY,EACZ,QAAS,EAAY,KACrB,MAAO,EAAY,GACnB,gBACF,CACQ,GACN,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,MACF,CACF,CAAC,CAEL,CAAC,EAEM,CAAE,YAAW,YAAW,YAAW,gBAAe,CAC3D,CAIA,SAAS,yBACP,EACA,CACA,OACE,GAAU,aAAe,EAAmB,UAC5C,GAAU,aAAe,EAAmB,YAEhD,CAOA,SAAgB,4BACd,EAC6E,CAC7E,OAAO,OAAO,YACZ,CAAC,GAAG,EAAU,QAAS,GAAG,EAAU,OAAO,CAAC,CAAC,IAAK,GAAS,CAAC,EAAK,KAAM,EAAK,QAAQ,QAAQ,CAAC,CAC/F,CACF,CASA,SAAgB,4BACd,EAIA,EACA,EACwB,CACxB,OAAO,wCACL,WACA,EACA,GACC,EAAM,IAAW,CAChB,GAAI,IAAW,SACb,MAAO,CAAC,qBAAqB,EAAK,IAAI,CAAC,EAEzC,IAAM,EAAW,EAAU,EAAK,MAChC,OAAO,GAAY,yBAAyB,CAAQ,EAChD,CAAC,qBAAqB,EAAK,IAAI,CAAC,EAChC,CAAC,CACP,CACF,CACF,CAEA,SAAS,4BAA4B,EAA2D,CAC9F,IAAM,EAAa,qBAAqB,CAAQ,EAC1C,EACJ,EAAW,cAAc,QAAQ,OAAS,WACrC,EAAW,aAAa,OAAO,MAAM,SAAW,CAAC,EAAA,CAAG,UAAU,EAAM,KAClE,EAAK,KAAO,GAAA,CAAI,cAAc,EAAM,KAAO,EAAE,CAChD,EACA,IAAA,GACA,EACJ,EAAW,eAAe,QAAQ,OAAS,kBACvC,CACE,GAAG,EAAW,cACd,OAAQ,CACN,GAAG,EAAW,cAAc,OAC5B,MAAO,CACL,GAAG,EAAW,cAAc,OAAO,MAEnC,OAAQ,IAAA,EACV,CACF,CACF,EACA,EAAW,eAAe,QAAQ,OAAS,QACzC,CACE,GAAG,EAAW,cACd,OAAQ,CACN,GAAG,EAAW,cAAc,OAC5B,MAAO,CACL,GAAG,EAAW,cAAc,OAAO,MAEnC,UAAW,IAAA,EACb,CACF,CACF,EACA,EAAW,cACb,EAAa,qBAAqB,CACtC,KAAM,EAAW,KACjB,YAAa,EAAW,aAAe,GACvC,SAAU,EAAW,UAAY,GACjC,YAAa,EAAW,YACxB,gBACA,WAAY,EAAW,WACvB,aACE,EAAW,cAAc,QAAQ,OAAS,UACtC,CACE,GAAG,EAAW,aACd,OAAQ,CACN,GAAG,EAAW,aAAa,OAC3B,MAAO,CACL,GAAG,EAAW,aAAa,OAAO,MAClC,QAAS,CACX,CACF,CACF,EACA,EAAW,cAAc,QAAQ,OAAS,WACxC,CACE,GAAG,EAAW,aACd,OAAQ,CACN,GAAG,EAAW,aAAa,OAC3B,MAAO,CACL,GAAG,EAAW,aAAa,OAAO,MAClC,OAAQ,IAAA,EACV,CACF,CACF,EACA,EAAW,YACrB,CAAC,EACD,OAAO,sBAAsB,EAAwB,CAAU,CACjE,CAEA,SAAS,kBACP,EACA,EACS,CACT,OAAO,mBACL,4BAA4B,CAAQ,EACpC,4BAA4B,CAAO,CACrC,CACF,CAUA,SAAS,wBACP,EACA,EACA,EACoB,CACpB,GAAI,CAAC,GAAmB,IAAI,CAAY,EACtC,OAEF,IAAM,EAAY,EAAkB,IAAI,CAAY,EACpD,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,sCACN,QACE,GAAG,EAAc,IAAI,EAAa,8HAEtC,CAAC,EAEH,OAAO,CACT,CAQA,SAAS,sBACP,EACA,EACoB,CACpB,OAAO,EAAY,iBAAiB,KAAM,GAAY,OAAO,OAAO,EAAQ,MAAO,CAAS,CAAC,CAAC,EAC1F,SACN,CAQA,SAAgB,sBACd,EACA,EACoB,CACpB,OAAO,EAAY,iBAAiB,KAAM,GACxC,OAAO,OAAO,EAAQ,SAAS,CAAC,CAAC,KAAM,GAAa,EAAS,OAAS,CAAY,CACpF,CAAC,EAAE,SACL,CAEA,SAAS,iBAAiB,EAMf,CACT,GAAM,CAAE,gBAAe,eAAc,kBAAiB,qBAAoB,qBACxE,EACI,EAAiB,EAAmB,EAC1C,GAAI,IAAmB,IAAA,GACrB,OAAO,EAET,IAAM,EAAmB,wBAAwB,EAAmB,EAAc,CAAa,EAC/F,GAAI,IAAqB,IAAA,GACvB,OAAO,EAET,IAAM,EAA6B,EAC/B,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAkB,OAAO,CAAC,CAAC,CAAC,OAAQ,GAAU,IAAU,IAAA,EAAS,CAAC,CAAC,EACnF,CAAC,EACC,EAAsB,CAAC,GAAG,EAAiB,GAAG,CAA0B,EAC9E,MAAM,EAAS,CACb,KAAM,4BACN,QAAS,GAAG,EAAc,IAAI,EAAa,sDAAsD,EAAoB,KAAK,IAAI,GAChI,CAAC,CACH,CAEA,SAAS,yBACP,EACA,EACA,EACQ,CACR,OAAO,iBAAiB,CACtB,cAAe,iBACf,aAAc,EACd,gBAAiB,EAAY,iBAAiB,IAAK,GAAY,EAAQ,SAAS,EAChF,uBAA0B,sBAAsB,EAAa,CAAQ,EACrE,mBACF,CAAC,CACH,CAEA,SAAS,yBACP,EACA,EACA,EACQ,CACR,OAAO,iBAAiB,CACtB,cAAe,WACf,aAAc,EACd,gBAAiB,EAAY,iBAAiB,IAAK,GAAY,EAAQ,SAAS,EAChF,uBAA0B,sBAAsB,EAAa,CAAY,EACzE,mBACF,CAAC,CACH,CAQA,SAAgB,2BACd,EACqB,CACrB,IAAM,EAAQ,IAAI,IAAI,EAAY,YAAY,IAAK,GAAQ,EAAI,IAAI,CAAC,EACpE,IAAK,IAAM,KAAY,EAAY,UAC7B,EAAS,OAAS,OACpB,EAAM,IAAI,EAAS,IAAI,EAG3B,OAAO,CACT,CAEA,SAAS,oBACP,EACA,EACA,EACA,EACQ,CACR,IAAM,EAAgB,2BAA2B,CAAW,EAC5D,GAAI,IAAY,IAAA,GAAW,CACzB,IAAM,EAAiB,GAAmB,EAC1C,GAAI,CAAC,EAAe,IAAI,CAAO,EAAG,CAChC,IAAM,EAAY,CAAC,GAAG,CAAc,CAAC,CAAC,KAAK,IAAI,EAC/C,MAAM,EAAS,CACb,KAAM,yBACN,QACE,aAAa,EAAa,mBAAmB,EAAQ,qFACO,GAChE,CAAC,CACH,CACA,OAAO,CACT,CACA,GAAI,EAAc,OAAS,EACzB,MAAM,EAAS,CACb,KAAM,wBACN,QAAS,aAAa,EAAa,oDACrC,CAAC,EAEH,GAAI,EAAc,KAAO,EAAG,CAC1B,IAAM,EAAY,CAAC,GAAG,CAAa,CAAC,CAAC,KAAK,IAAI,EAC9C,MAAM,EAAS,CACb,KAAM,yBACN,QACE,aAAa,EAAa,mEACtB,EAAU,qEAClB,CAAC,CACH,CACA,OAAO,EAAc,CAAC,GAAG,CAAa,CAAC,CAAC,GAAI,qBAAqB,CACnE,CAEA,SAAS,cACP,EACA,EACiD,CACjD,GAAM,CAAE,eAAgB,EAClB,EAAU,EAAY,KACtB,EAAM,EAAY,IAClB,EAAU,EAAS,QACrB,EACA,EAEE,EAAW,GAAsB,EAAQ,KAAM,CAAG,EAExD,SAAS,kBACP,EACsD,CACtD,MAAO,CAAE,OAAQ,CAAE,KAAM,QAAS,MAAO,CAAE,aAAY,CAAE,CAAE,CAC7D,CAEA,OAAQ,EAAQ,KAAhB,CACE,IAAK,WACH,EAAc,GAAoB,SAClC,EAAgB,CACd,OAAQ,CACN,KAAM,WACN,MAAO,CACL,SAAU,EAAQ,SAClB,UAAW,EAAQ,IACrB,CACF,CACF,EACA,MACF,IAAK,WACH,EAAc,GAAoB,MAClC,EAAgB,kBAAkB,CAChC,KAAM,WACN,MAAO,CACL,WAAY,EAAQ,OACpB,cAAe,yBACb,EACA,EAAQ,UACR,EAAQ,sBACV,EACA,SAAU,EAAQ,UAClB,GAAI,EAAQ,UACR,CAAE,UAAW,CAAE,KAAM,IAAI,GAAkB,EAAQ,SAAS,EAAE,IAAI,EAAS,EAAG,CAAE,EAChF,CAAC,CACP,CACF,CAAC,EACD,MACF,IAAK,mBACH,EAAc,GAAoB,MAClC,EAAgB,kBAAkB,CAChC,KAAM,WACN,MAAO,CACL,WAAY,CAAC,4BAA4B,EACzC,cAAe,yBACb,EACA,EAAQ,aACR,EAAQ,kBACV,EACA,aAAc,EAAQ,aACtB,GAAI,EAAQ,UACR,CAAE,UAAW,CAAE,KAAM,IAAI,GAAkB,EAAQ,SAAS,EAAE,IAAI,EAAS,EAAG,CAAE,EAChF,CAAC,CACP,CACF,CAAC,EACD,MACF,IAAK,kBACH,EAAc,GAAoB,iBAClC,EAAgB,CACd,OAAQ,CACN,KAAM,kBACN,MAAO,EAAQ,SACX,CACE,SAAU,CACR,GAAI,EAAQ,SAAS,KACjB,CACE,KAAM,CACJ,KAAM,IAAI,GAAkB,EAAQ,SAAS,IAAI,EAAE,IAAI,EAAS,EAClE,CACF,EACA,CAAC,EACL,GAAI,EAAQ,SAAS,YAAc,KAE/B,CAAC,EADD,CAAE,WAAY,EAAQ,SAAS,UAAW,CAEhD,CACF,EACA,CAAC,CACP,CACF,EACA,MACF,IAAK,UACH,EAAc,GAAoB,MAClC,EAAgB,kBAAkB,CAChC,KAAM,MACN,MAAO,CACL,WAAY,EAAQ,OACpB,cAAe,oBACb,EACA,EAAS,KACT,EAAQ,IACR,EAAQ,QACV,CACF,CACF,CAAC,EACD,MACF,IAAK,kBACH,EAAc,GAAoB,MAClC,EAAgB,kBAAkB,CAChC,KAAM,OACN,MAAO,CACL,WAAY,EAAQ,OACpB,cAAe,GAAgC,CAAW,CAC5D,CACF,CAAC,EACD,MACF,IAAK,oBACL,IAAK,uBACH,EAAc,GAAoB,MAClC,EAAgB,kBAAkB,CAChC,KAAM,WACN,MAAO,CACL,WAAY,EAAQ,OACpB,aAAc,EAAQ,aACtB,GAAI,EAAQ,UACR,CAAE,UAAW,CAAE,KAAM,IAAI,GAAkB,EAAQ,SAAS,EAAE,IAAI,EAAS,EAAG,CAAE,EAChF,CAAC,CACP,CACF,CAAC,EACD,MACF,QACE,MAAM,EAAc,oBAAoB,GAAyB,CACrE,CAEA,IAAM,EAAS,EAAS,UACpB,EACA,EAEE,EAAgB,GAA4B,CAAW,EACvD,EAAiB,aAAa,EAAS,KAAK,GAElD,OAAQ,EAAO,KAAf,CACE,IAAK,UACH,EAAa,EAAmB,QAChC,EAAe,CACb,OAAQ,CACN,KAAM,UACN,MAAO,CACL,IAAK,CACH,KAAM,IAAI,GAAkB,EAAO,GAAG,EAAE,IAAI,EAAS,EACvD,EACA,QAAS,EAAO,QACZ,OAAO,QAAQ,EAAO,OAAO,CAAC,CAAC,KAAK,CAAC,EAAK,KAAO,CAC/C,IAAI,EAeJ,MAdA,CAME,EANE,OAAO,GAAM,SACP,CACN,KAAM,WACN,MAAO,CACT,EAEQ,CACN,KAAM,cACN,MAAO,CACL,UAAW,EAAE,MACb,UAAW,EAAE,GACf,CACF,EAEK,CAAE,MAAK,OAAM,CACtB,CAAC,EACD,IAAA,GACJ,KAAM,EAAO,YACT,CACE,KAAM,IAAI,GAAkB,EAAO,WAAW,EAAE,IAAI,EAAS,EAC/D,EACA,IAAA,EACN,CACF,CACF,EACA,MAEF,IAAK,UACH,EAAa,EAAmB,eAChC,EAAe,CACb,OAAQ,CACN,KAAM,gBACN,MAAO,CACL,QAAS,EAAO,SAAW,EAC3B,MAAO,EAAO,MACd,UAAW,EAAO,UACd,CACE,KAAM,IAAI,GAAkB,EAAO,SAAS,EAAE,IAAI,EAAS,EAC7D,EACA,IAAA,GACJ,QAAS,iBAAiB,EAAO,QAAS,EAAe,CAAc,CACzE,CACF,CACF,EACA,MAEF,IAAK,WACL,IAAK,cACH,AAGE,EAHE,EAAO,OAAS,WACL,EAAmB,SAEnB,EAAmB,aAGlC,EAAe,CACb,OAAQ,CACN,KAAM,WACN,MAAO,CACL,KAAM,YACN,UAAW,qBAAqB,EAAS,IAAI,EAC7C,UAAW,CACT,KAAM,CACR,EACA,QAAS,iBAAiB,EAAO,QAAS,EAAe,CAAc,CACzE,CACF,CACF,EACA,MAEF,IAAK,WACH,EAAa,EAAmB,SAChC,EAAe,CACb,OAAQ,CACN,KAAM,WACN,MAAO,CACL,aAAc,EAAO,aACrB,UACE,EAAO,OAAS,IAAA,GAIZ,IAAA,GAHA,OAAO,EAAO,MAAS,WACrB,CAAE,KAAM,IAAI,GAAkB,EAAO,IAAI,EAAE,IAAI,EAAS,EAAG,EAC3D,CAAE,KAAM,KAAK,UAAU,EAAO,IAAI,CAAE,EAE5C,QAAS,iBAAiB,EAAO,QAAS,EAAe,CAAc,CACzE,CACF,CACF,EACA,MAEF,QACE,MAAM,EAAc,mBAAmB,GAAwB,CACnE,CAEA,MAAO,CACL,KAAM,EAAS,KACf,YAAa,EAAS,YACtB,SAAU,EAAS,SACnB,cACA,gBACA,aACA,cACF,CACF,CCxrBA,MAAM,GAAkB,CACtB,KAAM,CAAE,KAAM,aAAc,KAAM,IAAK,EACvC,OAAQ,CAAE,KAAM,aAAc,KAAM,QAAS,EAC7C,QAAS,CAAE,KAAM,aAAc,KAAM,KAAM,EAC3C,MAAO,CAAE,KAAM,aAAc,KAAM,OAAQ,EAC3C,QAAS,CAAE,KAAM,mBAAoB,KAAM,SAAU,EACrD,QAAS,CAAE,KAAM,aAAc,KAAM,SAAU,EAC/C,KAAM,CAAE,KAAM,mBAAoB,KAAM,MAAO,EAC/C,SAAU,CAAE,KAAM,mBAAoB,KAAM,UAAW,EACvD,KAAM,CAAE,KAAM,mBAAoB,KAAM,MAAO,CACjD,EAYA,eAAsB,cACpB,EACA,EACA,EAAuC,gBACvC,CACA,GAAM,CAAE,aAAc,EAClB,IAAU,iBAEZ,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,QAAQ,QAAQ,IAAI,KAAO,IAAW,CACjD,MAAM,EAAO,sBAAsB,EAAO,OAAO,EACjD,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,EACD,GAAG,EAAU,QAAQ,QAAQ,IAAI,KAAO,IAAW,CACjD,MAAM,EAAO,sBAAsB,EAAO,OAAO,EACjD,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,CACH,CAAC,EAID,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,SAAS,QAAQ,IAAI,KAAO,IAAW,CAClD,MAAM,EAAO,uBAAuB,EAAO,OAAO,EAClD,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,EACD,GAAG,EAAU,SAAS,QAAQ,IAAI,KAAO,IAAW,CAClD,MAAM,EAAO,uBAAuB,EAAO,OAAO,EAClD,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,EACD,GAAG,EAAU,SAAS,UAAU,QAAS,GACvC,EAAM,YAAc,CAAC,oBAAoB,EAAQ,EAAM,WAAW,CAAC,EAAI,CAAC,CAC1E,CACF,CAAC,GACQ,IAAU,mBAGnB,MAAM,QAAQ,IACZ,EAAU,SAAS,QAAQ,IAAK,GAAQ,EAAO,uBAAuB,EAAI,OAAO,CAAC,CACpF,EAGA,MAAM,QAAQ,IACZ,EAAU,QAAQ,QAAQ,IAAK,GAAQ,EAAO,sBAAsB,EAAI,OAAO,CAAC,CAClF,CAEJ,CAOA,eAAsB,aAAa,EAAsB,CACvD,GAAM,CAAE,SAAQ,cAAa,cAAa,aAAY,gBAAgB,IAAU,EAC1E,EAAyC,CAAC,EAChD,GAAI,CAAC,EACH,IAAK,IAAM,KAAY,EAAY,iBACjC,MAAM,EAAS,cAAc,EAC7B,EAAU,KAAK,CAAQ,EAG3B,IAAM,EAAY,EACd,CAAC,EACD,OAAO,OAAQ,MAAM,EAAY,iBAAiB,cAAc,GAAM,CAAC,CAAC,EAEtE,CACJ,UAAW,EACX,YACA,YACA,kBACE,MAAMC,eAAa,EAAQ,EAAa,EAAY,KAAM,EAAY,GAAI,CAAS,EACjF,EAAkB,EAAiB,QAAQ,IAAK,GAAQ,EAAI,IAAI,EAChE,CAAE,UAAW,GAAsB,MAAM,cAC7C,EACA,EACA,EACA,EACA,EAAQ,uBAAyB,IAAI,IACrC,EACA,EAAY,IACZ,GAA4B,CAAW,EACvC,EACA,CACE,QAAS,EAAY,KACrB,MAAO,EAAY,GACnB,cAAe,EAAQ,cACvB,UAAW,EAAQ,SACrB,CACF,EAEA,MAAO,CACL,UAAW,CACT,QAAS,EACT,SAAU,CACZ,EACA,YACA,YACA,gBACF,CACF,CAmBA,eAAeA,eACb,EACA,EACA,EACA,EACA,EACA,CACA,IAAM,EAAY,gBAChB,mBACF,EACM,EAA6B,CAAC,EAC9B,EAAiC,CAAC,EAClC,EAAiB,IAAI,IAErB,EAAmB,MAAM,iCAAiC,CAC9D,SACA,UAAW,MAAO,EAAW,IAAgB,CAC3C,GAAM,CAAE,mBAAkB,iBAAkB,MAAM,EAAO,qBAAqB,CAC5E,cACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAkB,CAAa,CACzC,EACA,QAAU,GAAa,EAAS,WAAW,KAC3C,OAAS,GAAS,YAAY,EAAa,WAAY,CAAI,CAC7D,CAAC,EAED,IAAK,IAAM,KAAY,EAAW,CAChC,IAAM,EAAW,EAAiB,EAAS,WACrC,EAAc,MAAM,iBAAiB,CACzC,IAAK,YAAY,EAAa,WAAY,EAAS,SAAS,EAC5D,UACA,OACF,CAAC,EACG,GACY,8BAA8B,CAC1C,OAAQ,EAAS,UACjB,WAAY,EAAS,MACrB,UACA,QACA,aAAc,mBACd,aAAc,EAAS,UACvB,YACA,WACF,CAEQ,GAAK,sBAAsB,EAAS,UAAW,EAAY,MAAM,EACvE,EAAU,UAAU,KAAK,CAAE,KAAM,EAAS,SAAU,CAAC,EAErD,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAS,UACf,QAAS,CACP,cACA,cAAe,EAAS,SAC1B,EACA,aACF,CAAC,EAEH,OAAO,EAAiB,EAAS,YAEjC,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAS,UACf,QAAS,CACP,cACA,cAAe,EAAS,SAC1B,EACA,aACF,CAAC,CAEL,CAsBA,OArBA,OAAO,QAAQ,CAAgB,CAAC,CAAC,SAAS,CAAC,KAAmB,CAC5D,IAAM,EAAQ,EAAiB,GACjB,4BAA4B,CACxC,OAAQ,GAAO,UACf,WAAY,GAAO,MACnB,UACA,QACA,gBACF,CAEQ,GACN,EAAU,QAAQ,KAAK,CACrB,KAAM,EACN,QAAS,CACP,cACA,eACF,CACF,CAAC,CAEL,CAAC,EAEM,CAAE,YAAW,YAAW,YAAW,gBAAe,CAC3D,CAoCA,eAAe,cACb,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EAAgB,GAChB,EAAgC,CAAC,EACjC,CACA,IAAM,EAAY,gBAMhB,oBAAoB,EAChB,CAAE,UAAS,QAAO,gBAAe,aAAc,EAS/C,oBAAsB,MAC1B,EACA,IAGO,qBAAqB,MAAM,iBAAiB,CAAE,IADzC,YAAY,EAAa,EAAW,EAAS,IACJ,EAAK,QAAS,GAAW,GAAI,OAAM,CAAC,EAAG,CAC1F,IAAK,EAAe,SAAS,EAAW,EAAS,IAAI,EACrD,gBACA,YACA,OAAQ,EAAS,gBAAkB,IAAA,EACrC,CAAC,EAGG,eAAkB,GACf,EAAiB,MAAO,EAAW,IAAgB,CACxD,GAAM,CAAE,oBAAmB,iBAAkB,MAAM,EAAO,sBAAsB,CAC9E,cACA,gBACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAmB,CAAa,CAC1C,CAAC,EAGG,EAAwB,IAAI,IAAI,CAA4B,EAClE,IAAK,IAAM,KAAY,EAChB,mBAAmB,CAAQ,GAC5B,EAAS,QAAQ,OAAS,oBAC5B,EAAsB,IAAI,EAAS,QAAQ,YAAY,EAK3D,IAAK,IAAM,KAAY,EACrB,IAAK,IAAM,KAAY,OAAO,OAAO,EAAS,SAAS,EACrD,8BAA8B,CAC5B,SAAU,EAAS,cACnB,WAAY,EAAsB,IAAI,EAAS,IAAI,EACnD,SAAU,GAAsB,SAAS,EAAS,IAAI,CACxD,CAAC,EAIL,IAAK,IAAM,KAAY,EAAW,CAChC,IAAM,EAAoB,MAAM,eAAe,EAAS,SAAS,EAC3D,EAAuB,IAAI,IAC/B,EAAkB,IAAK,GAAa,CAAC,EAAS,KAAM,CAAQ,CAAC,CAC/D,EACA,IAAK,IAAM,KAAY,OAAO,OAAO,EAAS,SAAS,EAAG,CACxD,IAAM,EAAkB,gBACtB,EAAS,UACT,EACA,EACA,EACA,CACF,EACM,EAAmB,EAAqB,IAAI,EAAS,IAAI,EACzD,EAAc,MAAM,oBAAoB,EAAS,UAAW,CAAQ,EAC1E,GAAI,EAAkB,CACpB,GAAM,CAAE,iBAAkB,GAA2B,MAAM,EAAO,oBAAoB,CACpF,cACA,cAAe,EAAS,UACxB,aAAc,EAAS,IACzB,CAAC,EAEC,CAAC,GACD,GACA,kBAAkB,EAAwB,CAAe,EAGzD,EAAU,UAAU,KAAK,CAAE,KAAM,EAAS,KAAM,aAAY,CAAC,EAE7D,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAS,KACf,QAAS,CACP,cACA,cAAe,EAAS,UACxB,iBAAkB,CACpB,EACA,aACF,CAAC,EAEH,EAAqB,OAAO,EAAS,IAAI,CAC3C,MACE,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAS,KACf,QAAS,CACP,cACA,cAAe,EAAS,UACxB,iBAAkB,CACpB,EACA,aACF,CAAC,CAEL,CACA,EAAqB,SAAS,EAAW,IAAS,CAChD,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,cAAe,EAAS,UACxB,aAAc,CAChB,CACF,CAAC,CACH,CAAC,CACH,CAEA,IAAK,IAAM,KAAiB,GAE1B,MADgC,eAAe,CAAa,EAAA,CAC1C,QAAS,GAAa,CACtC,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAS,KACf,QAAS,CACP,cACA,gBACA,aAAc,EAAS,IACzB,CACF,CAAC,CACH,CAAC,EAEH,MAAO,CAAE,WAAU,CACrB,CAUA,SAAgB,4BACd,EAIA,EACwB,CACxB,OAAO,wCACL,WACA,EACA,EACC,GAAS,CACR,IAAM,EAAY,EAAK,QAAQ,cAC/B,OAAO,EAAY,CAAC,qBAAqB,EAAW,EAAK,IAAI,CAAC,EAAI,CAAC,CACrE,EACA,CACE,aAAe,GAAS,EAAK,QAAQ,aACvC,CACF,CACF,CAEA,SAAS,4BAA4B,EAA2D,CAC9F,OAAO,sBAAsB,EAAwB,CAAQ,CAC/D,CAEA,SAAS,kBACP,EACA,EACS,CACT,OAAO,mBACL,4BAA4B,CAAQ,EACpC,4BAA4B,CAAO,CACrC,CACF,CAEA,SAAS,gBACP,EACA,EACA,EACA,EACA,EACiD,CACjD,IAAM,EAAwE,CAC5E,CACE,KAAM,OACN,cAAe,OACf,YAAa,GAAG,EAAS,KAAK,gBAC9B,cAAe,EAA+B,SAC9C,mBAAoB,qBAAqB,EAAW,EAAS,IAAI,EACjE,cAAe,CACb,KAAM,GAA+B,CAAG,CAC1C,EACA,WAAY,YACZ,QAAS,iBAAiB,EAAS,QAAS,EAAe,aAAa,EAAS,KAAK,EAAE,CAC1F,CACF,EAEM,EAAe,GAAW,SAAS,EAAS,IAAI,EAGhD,EAAkE,EAAS,MAC7E,YAAY,EAAS,MAAO,GAAG,EAAa,OAAQ,EAAI,EACxD,CAAC,EAGC,EAAkE,EACtE,YAAY,CAAE,GAAI,EAAS,MAAO,EAAG,GAAG,EAAa,QAAS,EAAK,CAAC,CAAC,GACrE,+BACF,EAGM,EAAsB,EAAS,aAAe,GAAG,EAAS,KAAK,WAC/D,EAAoB,EAAS,OAAO,SAAS,YAC7C,EAAsB,EACxB,GAAG,EAAoB,gBAAgB,IACvC,EAEE,EAAyB,qBAAqB,CAClD,SAAU,EAAS,cACnB,WAAY,EAAsB,IAAI,EAAS,IAAI,EACnD,SAAU,GAAsB,SAAS,EAAS,IAAI,CACxD,CAAC,EAED,MAAO,CACL,cAAe,aACf,YAAa,EACb,SACA,KAAM,EAAS,KACf,cAAe,EAAS,UACxB,WACA,YACA,wBACF,CACF,CAEA,SAAS,YACP,EACA,EACA,EACyD,CACzD,OAAO,OAAO,QAAQ,CAAM,CAAC,CAAC,KAAK,CAAC,EAAW,KAAW,CACxD,IAAI,EAEE,EADgB,GAAW,EAAM,SAAS,OAAO,SAAW,IAAA,GACjC,GAAS,EAAM,SAAS,UAAY,GAErE,GAAI,EAAM,OAAS,SAAU,CAC3B,IAAM,EAAW,EAAM,SAAS,UAAY,GAAG,IAAW,GAAW,SAAS,CAAS,IACvF,EAAO,CACL,KAAM,cACN,KAAM,EACN,YAAa,EAAM,SAAS,aAAe,GAC3C,WACA,OAAQ,YAAY,EAAM,OAAQ,EAAU,CAAO,CACrD,CACF,KAAO,CASL,EATS,EAAM,OAAS,OAEjB,CACL,KAAM,WACN,KAHe,EAAM,SAAS,UAAY,GAAG,IAAW,GAAW,SAAS,CAAS,IAIrF,WACA,cAAe,EAAM,SAAS,aAChC,EAEO,CAAE,GAAG,GAAgB,EAAM,MAAO,UAAS,EAGpD,MAAO,CACL,KAAM,EACN,YAAa,EAAM,SAAS,YAC5B,MAAO,EAAM,SAAS,OAAS,GAC/B,WACA,MACF,CACF,CAAC,CACH,CC1iBA,SAAgB,mBACd,EACgE,CAChE,MAAO,CACL,YAAa,EAAO,YACpB,uBAAwB,EAAO,IACjC,CACF,CAOA,SAAgB,oBACd,EACiE,CACjE,MAAO,CACL,YAAa,EAAO,YACpB,uBAAwB,EAAO,UAC/B,wBAAyB,EAAO,WAChC,yBAA0B,EAAO,KACnC,CACF,CAOA,SAAgB,oBACd,EACiE,CACjE,MAAO,CACL,YAAa,EAAO,YACpB,uBAAwB,EAAO,UAC/B,wBAAyB,EAAO,WAChC,yBAA0B,EAAO,KACnC,CACF,CAOA,eAAsB,kBAAkB,EAAsB,CAC5D,GAAM,CAAE,SAAQ,cAAa,cAAa,aAAY,gBAAgB,IAAU,EAC1E,EAAe,EAAa,CAAC,EAAI,EAAY,QAE7C,EAAiB,gBACrB,uBACF,EACM,EAAkB,gBACtB,wBACF,EACM,EAA6B,CAAC,EAC9B,EAAiC,CAAC,EAClC,EAAiB,IAAI,IAGrB,EAAiB,MAAM,iCAAiC,CAC5D,SACA,UAAW,MAAO,EAAW,IAAgB,CAC3C,GAAM,CAAE,SAAQ,iBAAkB,MAAM,EAAO,wBAAwB,CACrE,cACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAQ,CAAa,CAC/B,EACA,QAAU,GAAa,EAAS,KAChC,OAAS,GAAS,YAAY,EAAa,QAAS,CAAI,CAC1D,CAAC,EAEK,EAAa,CACjB,cACA,cAAe,EAAY,GAC3B,gBAAiB,EAAY,IAC/B,EACM,EAAQ,iBAAiB,CAAU,EACnC,EAA2B,CAAC,EAElC,MAAM,QAAQ,IACZ,EAAa,IAAI,KAAO,IAAU,CAChC,IAAM,EAAY,EAAM,UAClB,EAAW,EAAe,GAEhC,GAAI,EAAU,CACZ,IAAM,EAAc,MAAM,iBAAiB,CACzC,IAAK,YAAY,EAAa,QAAS,CAAS,EAChD,QAAS,EAAY,KACrB,MAAO,EAAY,EACrB,CAAC,EACa,8BAA8B,CAC1C,OAAQ,EAAS,UACjB,WAAY,EAAS,MACrB,QAAS,EAAY,KACrB,MAAO,EAAY,GACnB,aAAc,uBACd,aAAc,EACd,YACA,WACF,CACQ,GAAK,sBAAsB,EAAS,UAAW,EAAY,MAAM,EACvE,EAAe,UAAU,KAAK,CAAE,KAAM,CAAU,CAAC,EAEjD,EAAe,QAAQ,KAAK,CAC1B,KAAM,EACN,aACF,CAAC,EAEH,OAAO,EAAe,EACxB,MACE,EAAe,QAAQ,KAAK,CAC1B,KAAM,EACN,aACF,CAAC,EAIH,IAAM,EAAsB,IAAI,IAChC,GAAI,EAAU,CACZ,IAAM,EAAU,MAAM,EAAiB,MAAO,EAAW,IAAgB,CACvE,GAAM,CAAE,UAAS,iBAAkB,MAAM,EAAO,yBAAyB,CACvE,cACA,uBAAwB,EACxB,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAS,CAAa,CAChC,CAAC,EACD,IAAK,IAAM,KAAU,EACnB,EAAoB,IAAI,EAAO,KAAM,oBAAoB,EAAO,UAAU,CAAC,CAE/E,CAEA,IAAM,EAAc,IAAI,IAAI,EAAoB,KAAK,CAAC,EAGtD,IAAK,IAAM,KAAU,EAAM,QAAS,CAClC,GAAI,EAAO,OAAS,KAAM,CAExB,EAAY,OAAO,EAAO,IAAI,EAC9B,EAAe,KAAK,GAAG,EAAU,GAAG,EAAO,MAAM,EACjD,QACF,CAGA,GAFA,EAAO,eAAe,EAAO,KAAK,EAE9B,EAAY,IAAI,EAAO,IAAI,EAAG,CAChC,IAAM,EAAS,EAAM,OAAO,EAAU,GAAG,EAAO,MAC1C,EAAmB,EAAoB,IAAI,EAAO,IAAI,EAGtD,EACJ,IAAW,IAAA,IACX,EAAO,OAAS,UAAU,EAAO,KAAK,GACtC,EAAO,aAAe,IAAA,IACtB,EAAO,aAAe,GACpB,GAAiB,CAAC,IACpB,EAAgB,QAAQ,KAAK,CAC3B,KAAM,GAAG,EAAU,GAAG,EAAO,OAC7B,WAAY,EAAO,KACnB,cACA,YACA,MAAO,EAAO,KAChB,CAAC,EAEH,EAAY,OAAO,EAAO,IAAI,CAChC,MACE,EAAgB,QAAQ,KAAK,CAC3B,KAAM,GAAG,EAAU,GAAG,EAAO,OAC7B,WAAY,EAAO,KACnB,cACA,YACA,MAAO,EAAO,KAChB,CAAC,CAEL,CAGA,IAAK,IAAM,KAAc,EACvB,EAAgB,QAAQ,KAAK,CAC3B,KAAM,GAAG,EAAU,GAAG,IACtB,WAAY,EACZ,cACA,WACF,CAAC,CAEL,CAAC,CACH,EAGA,IAAK,GAAM,CAAC,EAAM,KAAU,OAAO,QAAQ,CAAc,EAClD,MACS,4BAA4B,CACxC,OAAQ,EAAM,UACd,WAAY,EAAM,MAClB,QAAS,EAAY,KACrB,MAAO,EAAY,GACnB,gBACF,CACQ,EAAG,CAET,IAAM,EAAU,MAAM,EAAiB,MAAO,EAAW,IAAgB,CACvE,GAAM,CAAE,UAAS,iBAAkB,MAAM,EAAO,yBAAyB,CACvE,cACA,uBAAwB,EACxB,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAS,CAAa,CAChC,CAAC,EACD,IAAK,IAAM,KAAU,EACnB,EAAgB,QAAQ,KAAK,CAC3B,KAAM,GAAG,EAAK,GAAG,EAAO,OACxB,WAAY,EAAO,KACnB,cACA,UAAW,CACb,CAAC,EAGH,EAAe,QAAQ,KAAK,CAC1B,OACA,aACF,CAAC,CACH,CAGF,MAAO,CACL,iBACA,kBACA,iBACA,YACA,YACA,iBACA,YACF,CACF,CAUA,eAAsB,mBACpB,EACA,EACA,EAAyD,gBACzD,EACA,CACA,GAAM,CAAE,iBAAgB,kBAAiB,cAAe,EAExD,GAAI,IAAU,gBAAiB,CAE7B,MAAM,QAAQ,IACZ,EAAe,QAAQ,IAAI,KAAO,IAAW,CAC3C,MAAM,EAAO,yBAAyB,mBAAmB,CAAM,CAAC,EAC5D,GAMF,MAAM,oBAAoB,EAAQ,MALR,iBAAiB,CACzC,IAAK,YAAY,EAAO,YAAa,QAAS,EAAO,IAAI,EACzD,QAAS,EAAY,KACrB,MAAO,EAAY,EACrB,CAAC,CAC4C,CAEjD,CAAC,CACH,EAGI,GACF,MAAM,QAAQ,IACZ,EAAe,QAAQ,IAAI,KAAO,IAAW,CAM3C,MAAM,oBAAoB,EAAQ,MALR,iBAAiB,CACzC,IAAK,YAAY,EAAO,YAAa,QAAS,EAAO,IAAI,EACzD,QAAS,EAAY,KACrB,MAAO,EAAY,EACrB,CAAC,CAC4C,CAC/C,CAAC,CACH,EAGF,IAAM,EAAoB,CAAC,GAAG,EAAgB,QAAS,GAAG,EAAgB,OAAO,EAC7E,EAAkB,OAAS,GAC7B,MAAM,qBAAqB,EAAY,SAAY,CAGjD,IAAM,EAAqB,IAAI,IAkB/B,GAfA,MAAM,QAAQ,IACZ,EAAgB,QAAQ,IAAI,KAAO,IAAW,CAC5C,IAAM,EAAW,MAAM,EAAO,0BAA0B,oBAAoB,CAAM,CAAC,EACnF,EAAmB,IAAI,EAAO,KAAM,oBAAoB,EAAS,QAAQ,UAAU,CAAC,CACtF,CAAC,CACH,EAGA,MAAM,QAAQ,IACZ,EAAgB,QAAQ,IAAI,KAAO,IAAW,CAC5C,IAAM,EAAW,MAAM,EAAO,0BAA0B,oBAAoB,CAAM,CAAC,EACnF,EAAmB,IAAI,EAAO,KAAM,oBAAoB,EAAS,QAAQ,UAAU,CAAC,CACtF,CAAC,CACH,EAEI,EAAa,CACf,IAAM,EAAQ,iBAAiB,CAAU,EACzC,IAAK,IAAM,KAAU,EAAmB,CACjC,OAAO,OAAO,EAAM,OAAQ,EAAO,SAAS,IAC/C,EAAM,OAAO,EAAO,WAAa,CAAC,GAEpC,IAAM,EAAa,EAAmB,IAAI,EAAO,IAAI,EACrD,EAAc,EAAM,OAAO,EAAO,WAAY,2BAA2B,CAAC,CACxE,EAAO,YACL,CACF,KAAM,UAAU,EAAO,KAAK,EAC5B,GAAI,IAAe,IAAA,GAAY,CAAC,EAAI,CAAE,YAAW,CACnD,CACF,CACA,iBAAiB,EAAY,CAAK,CACpC,CACF,CAAC,CAEL,MAAW,EAAgB,QAAQ,OAAS,GAAK,EAAe,QAAQ,OAAS,IAC/E,MAAM,qBAAqB,EAAY,SAAY,CAEjD,MAAM,QAAQ,IACZ,EAAgB,QAAQ,IAAK,GAC3B,EAAO,0BAA0B,CAC/B,YAAa,EAAI,YACjB,uBAAwB,EAAI,UAC5B,wBAAyB,EAAI,UAC/B,CAAC,CACH,CACF,EAGA,MAAM,QAAQ,IACZ,EAAe,QAAQ,IAAK,GAC1B,EAAO,yBAAyB,CAC9B,YAAa,EAAI,YACjB,uBAAwB,EAAI,IAC9B,CAAC,CACH,CACF,EAGA,IAAM,EAAQ,iBAAiB,CAAU,EACzC,IAAK,IAAM,KAAO,EAAgB,QAC5B,OAAO,OAAO,EAAM,OAAQ,EAAI,SAAS,IAC3C,OAAO,EAAc,EAAM,OAAO,EAAI,WAAY,2BAA2B,CAAC,CAC5E,EAAI,YAGJ,OAAO,KAAK,EAAc,EAAM,OAAO,EAAI,WAAY,2BAA2B,CAAC,CAAC,CACjF,SAAW,GAEd,OAAO,EAAM,OAAO,EAAI,YAI9B,IAAK,IAAM,KAAO,EAAe,QAC/B,OAAO,EAAM,OAAO,EAAI,MAE1B,iBAAiB,EAAY,CAAK,CACpC,CAAC,CAEL,CCrYA,MAAa,GAA+B,CAC1C,QACA,QACA,SACA,aACA,SACA,kBACF,EAqGA,SAAgB,0BACd,EACoC,CAGpC,OAAO,OAAO,GAAY,YAAY,GAAoB,CAAC,MAAM,QAAQ,CAAO,CAClF,CCnJA,SAAgB,gBACd,EACA,EACiC,CACjC,OAAO,EAAK,QACT,EAAS,IACR,GAAS,QAAU,OAAO,OAAO,EAAQ,OAAQ,CAAO,EACpD,EAAQ,OAAO,GACf,IAAA,GACN,CACF,CACF,CAoBA,SAAgB,2BACd,EACA,EACsB,CAEtB,OADI,EAAO,OAAS,EAAM,KACnB,qBAAqB,EAAO,QAAU,CAAC,EAAG,EAAM,QAAU,CAAC,EAAG,CAAC,CAAC,EADhC,CAAC,CAE1C,CAEA,SAAS,qBACP,EACA,EACA,EACsB,CACtB,IAAM,EAAgC,CAAC,EACjC,EAA8B,CAAC,EAC/B,EAA6B,CAAC,EAEpC,IAAK,GAAM,CAAC,EAAM,KAAiB,OAAO,QAAQ,CAAa,EAAG,CAChE,IAAM,EAAO,CAAC,GAAG,EAAY,CAAI,EAC3B,EAAc,OAAO,OAAO,EAAc,CAAI,EAAI,EAAa,GAAQ,IAAA,GAC7E,GAAI,CAAC,EAAa,CAChB,EAAQ,KAAK,CAAE,KAAM,UAAW,OAAM,OAAQ,CAAa,CAAC,EAC5D,QACF,CACI,EAAa,OAAS,EAAY,MACpC,EAAK,KAAK,GAAG,qBAAqB,EAAa,QAAU,CAAC,EAAG,EAAY,QAAU,CAAC,EAAG,CAAI,CAAC,EAE1F,4BAA4B,EAAc,CAAW,GACvD,EAAK,KAAK,CAAE,KAAM,WAAY,OAAM,OAAQ,EAAc,MAAO,CAAY,CAAC,CAElF,CAEA,IAAK,GAAM,CAAC,EAAM,KAAgB,OAAO,QAAQ,CAAY,EACtD,OAAO,OAAO,EAAe,CAAI,GACpC,EAAM,KAAK,CAAE,KAAM,QAAS,KAAM,CAAC,GAAG,EAAY,CAAI,EAAG,MAAO,CAAY,CAAC,EAIjF,MAAO,CAAC,GAAG,EAAS,GAAG,EAAO,GAAG,CAAI,CACvC,CAUA,SAAgB,4BACd,EACA,EACS,CAET,GADI,EAAS,OAAS,EAAS,MAC3B,EAAS,WAAa,EAAS,SAAU,MAAO,GAEpD,IAAK,IAAM,KAAQ,GACjB,IAAK,EAAS,IAAS,OAAY,EAAS,IAAS,IAAQ,MAAO,GAMtE,GAHI,EAAS,iBAAmB,EAAS,gBACrC,EAAS,kBAAoB,EAAS,kBAErC,EAAS,aAAe,OAAS,EAAS,aAAe,IAAK,MAAO,GAE1E,IAAM,EAAa,EAAS,eAAiB,CAAC,EACxC,EAAa,EAAS,eAAiB,CAAC,EAC9C,GAAI,EAAW,SAAW,EAAW,OAAQ,MAAO,GACpD,IAAM,EAAgB,IAAI,IAAI,EAAW,IAAK,GAAM,CAAC,EAAE,MAAO,EAAE,WAAW,CAAC,CAAC,EAC7E,IAAK,IAAM,KAAK,EAEd,GADI,CAAC,EAAc,IAAI,EAAE,KAAK,IACzB,EAAE,aAAe,OAAS,EAAc,IAAI,EAAE,KAAK,GAAK,IAAK,MAAO,GAG3E,IAAM,EAAW,EAAS,MACpB,EAAW,EAAS,MAE1B,GADI,EAAQ,GAAc,EAAQ,GAC9B,GAAY,KACT,EAAS,QAAQ,MAAQ,OAAS,EAAS,QAAQ,MAAQ,MAC3D,EAAS,QAAQ,MAAQ,OAAS,EAAS,QAAQ,MAAQ,KAAK,MAAO,GAG9E,IAAM,EAAc,EAAS,UAAY,CAAC,EACpC,EAAc,EAAS,UAAY,CAAC,EAC1C,GAAI,EAAY,SAAW,EAAY,OAAQ,MAAO,GACtD,IAAK,IAAI,EAAI,EAAG,EAAI,EAAY,OAAQ,IAAK,CAC3C,IAAM,EAAO,EAAc,EAAY,GAAI,6BAA6B,GAAG,EACrE,EAAO,EAAc,EAAY,GAAI,6BAA6B,GAAG,EAE3E,IADK,EAAK,QAAQ,MAAQ,OAAS,EAAK,QAAQ,MAAQ,KACpD,EAAK,eAAiB,EAAK,aAAc,MAAO,EACtD,CAEA,IAAM,EAAY,EAAS,OACrB,EAAY,EAAS,OAe3B,MALA,GATI,EAAQ,GAAe,EAAQ,GAC/B,GAAa,IACX,EAAU,QAAU,EAAU,OAC9B,EAAU,WAAa,EAAU,WAChC,EAAU,QAAU,OAAS,EAAU,QAAU,MAGpD,EAAS,QAAU,EAAS,OAE5B,EAAS,UAAY,EAAS,UAC5B,OAAO,EAAS,SAAY,OAAO,EAAS,SAC5C,KAAK,UAAU,EAAS,OAAO,IAAM,KAAK,UAAU,EAAS,OAAO,GAI5E,CCsNA,SAAgB,WAAW,EAA8B,CACvD,OAAO,EAAK,QAAQ,OAAS,CAC/B,CAOA,SAAgB,oBAAoB,EAA6B,CAC/D,GAAI,EAAK,QAAQ,SAAW,EAC1B,MAAO,kCAGT,IAAM,EAAkB,CAAC,EAGnB,EAAgB,IAAI,IAC1B,IAAK,IAAM,KAAU,EAAK,QAAS,CACjC,IAAM,EAAW,EAAc,IAAI,EAAO,SAAS,GAAK,CAAC,EACzD,EAAS,KAAK,CAAM,EACpB,EAAc,IAAI,EAAO,UAAW,CAAQ,CAC9C,CAEA,IAAK,GAAM,CAAC,EAAW,KAAY,EAAe,CAChD,EAAM,KAAK,GAAG,EAAK,UAAU,GAAG,EAAU,EAAE,EAE5C,IAAK,IAAM,KAAU,EACnB,EAAM,KAAK,iBAAiB,CAAM,CAAC,CAEvC,CAEA,OAAO,EAAM,KAAK;CAAI,CACxB,CAOA,SAAS,iBAAiB,EAA4B,CACpD,OAAQ,EAAO,KAAf,CACE,IAAK,cACH,MAAO,eAAe,EAAO,UAAU,cACzC,IAAK,gBACH,MAAO,eAAe,EAAO,UAAU,YACzC,IAAK,gBACH,MAAO,eAAe,EAAO,kBAAkB,KAAK,EAAO,UAAU,YACvE,IAAK,iBACH,MAAO,eAAe,EAAO,UAAU,IAAI,EAAO,SACpD,IAAK,0BACH,MAAO,wBAAwB,EAAO,UAAU,IAAI,EAAO,QAAU,qBACvE,IAAK,cAAe,CAClB,IAAM,EAAU,gBAAgB,EAAO,KAAK,EAC5C,MAAO,OAAO,EAAO,UAAU,IAAI,GACrC,CACA,IAAK,gBACH,MAAO,OAAO,EAAO,UAAU,IAAI,EAAO,OAAO,OACnD,IAAK,iBACH,MAAO,OAAO,EAAO,UAAU,IAAI,wBAAwB,EAAO,OAAQ,EAAO,MAAO,EAAO,aAAa,IAC9G,IAAK,sBACH,MAAO,OAAO,EAAO,UAAU,IAAI,wBAAwB,EAAO,OAAQ,EAAO,KAAK,IACxF,IAAK,gBACH,MAAO,OAAO,EAAO,kBAAkB,KAAK,EAAO,UAAU,IAAI,gBAAgB,EAAO,KAAK,EAAE,YACjG,IAAK,cACH,MAAO,eAAe,EAAO,YAC/B,IAAK,gBACH,MAAO,eAAe,EAAO,YAC/B,IAAK,iBACH,MAAO,eAAe,EAAO,UAAU,IAAI,EAAO,QAAU,aAC9D,IAAK,aACH,MAAO,cAAc,EAAO,YAC9B,IAAK,eACH,MAAO,cAAc,EAAO,YAC9B,IAAK,gBACH,MAAO,cAAc,EAAO,UAAU,IAAI,EAAO,QAAU,aAC7D,IAAK,qBACH,MAAO,oBAAoB,EAAO,iBAAmB,KAAK,EAAO,iBAAiB,GAAK,GAAG,IAAI,EAAO,mBACvG,IAAK,uBACH,MAAO,oBAAoB,EAAO,iBAAmB,KAAK,EAAO,iBAAiB,GAAK,GAAG,IAAI,EAAO,mBACvG,IAAK,wBACH,MAAO,oBAAoB,EAAO,iBAAmB,KAAK,EAAO,iBAAiB,GAAK,GAAG,IAAI,EAAO,iBAAiB,IAAI,EAAO,QAAU,aAC7I,IAAK,sBACH,MAAO,oBAAoB,EAAO,QAAU,aAC9C,IAAK,yBACH,MAAO,uBAAuB,EAAO,UAAU,IAAI,EAAO,QAAU,uCACtE,QAAS,CAGP,IAAM,EAAU,EAChB,MAAO,OAAO,EAAQ,UAAU,GAAG,EAAQ,WAAa,IAC1D,CACF,CACF,CAOA,SAAS,gBAAgB,EAAoC,CAC3D,IAAI,EAAO,EAAM,KAIjB,OAHI,EAAM,QAAO,GAAQ,MACrB,EAAM,SAAU,GAAQ,cACvB,GAAQ,cACN,CACT,CASA,SAAS,wBACP,EACA,EACA,EAA+C,CAAC,EACxC,CACR,IAAM,EAAoB,CAAC,EAEvB,EAAO,OAAS,EAAM,MACxB,EAAQ,KAAK,SAAS,EAAO,KAAK,KAAK,EAAM,MAAM,EAEjD,EAAO,WAAa,EAAM,UAC5B,EAAQ,KAAK,aAAa,EAAO,SAAS,KAAK,EAAM,UAAU,EAE7D,EAAQ,EAAO,OAAW,EAAQ,EAAM,OAC1C,EAAQ,KAAK,UAAU,EAAO,OAAS,GAAM,KAAK,EAAM,OAAS,IAAO,EAEtE,EAAQ,EAAO,OAAW,EAAQ,EAAM,OAC1C,EAAQ,KAAK,UAAU,EAAO,OAAS,GAAM,KAAK,EAAM,OAAS,IAAO,EAEtE,EAAQ,EAAO,QAAY,EAAQ,EAAM,QAC3C,EAAQ,KAAK,WAAW,EAAO,QAAU,GAAM,KAAK,EAAM,QAAU,IAAO,EAEzE,EAAQ,EAAO,QAAY,EAAQ,EAAM,QAC3C,EAAQ,KAAK,WAAW,EAAO,QAAU,GAAM,KAAK,EAAM,QAAU,IAAO,EAG7E,IAAM,EAAgB,EAAO,eAAiB,CAAC,EACzC,EAAe,EAAM,eAAiB,CAAC,EACvC,EAAW,IAAI,IAAI,EAAa,IAAK,GAAM,EAAE,KAAK,CAAC,EAIzD,GAFE,EAAc,SAAW,EAAa,QACtC,EAAc,KAAM,GAAM,CAAC,EAAS,IAAI,EAAE,KAAK,CAAC,EACtB,CAC1B,IAAM,EAAe,EAAc,IAAK,GAAM,EAAE,KAAK,CAAC,CAAC,KAAK,IAAI,EAC1D,EAAc,EAAa,IAAK,GAAM,EAAE,KAAK,CAAC,CAAC,KAAK,IAAI,EAC9D,EAAQ,KAAK,mBAAmB,EAAa,OAAO,EAAY,EAAE,CACpE,CAEA,IAAM,EAAc,EAAO,MACrB,EAAa,EAAM,QAEtB,GAAa,QAAQ,MAAQ,OAAS,GAAY,QAAQ,MAAQ,MAClE,GAAa,QAAQ,MAAQ,OAAS,GAAY,QAAQ,MAAQ,MAEnE,EAAQ,KAAK,gBAAgB,EAG/B,IAAM,EAAiB,EAAO,UAAY,CAAC,EACrC,EAAgB,EAAM,UAAY,CAAC,EACrC,EAAe,SAAW,EAAc,QAC1C,EAAQ,KAAK,gBAAgB,EAAe,OAAO,KAAK,EAAc,QAAQ,EAG5E,EAAQ,EAAO,QAAY,EAAQ,EAAM,QAC3C,EAAQ,KACN,WAAW,EAAO,OAAS,UAAY,WAAW,KAAK,EAAM,OAAS,UAAY,YACpF,EAGF,IAAM,EAAe,IAAI,IACvB,EAAc,QAAS,GAAW,CAAC,EAAO,aAAa,KAAK,GAAG,EAAG,EAAO,KAAK,KAAK,GAAG,CAAC,CAAC,CAC1F,EACM,EAAU,2BAA2B,EAAQ,CAAK,CAAC,CACtD,OAAQ,GAAM,CAAC,EAAa,IAAI,EAAE,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,CAClD,IAAK,GAAM,GAAG,GAA6B,EAAE,QAAQ,EAAE,KAAK,KAAK,GAAG,GAAG,EAU1E,OATA,EAAQ,KACN,GAAG,EAAc,IACd,GAAW,GAAG,EAAO,aAAa,KAAK,GAAG,EAAE,KAAK,EAAO,KAAK,KAAK,GAAG,EAAE,WAC1E,CACF,EACI,EAAQ,OAAS,GACnB,EAAQ,KAAK,YAAY,EAAQ,KAAK,IAAI,GAAG,EAGxC,EAAQ,OAAS,EAAI,EAAQ,KAAK,IAAI,EAAI,uBACnD,CAEA,MAAM,GAA2E,CAC/E,QAAS,IACT,MAAO,IACP,SAAU,GACZ,EAOA,SAAgB,sBAAsB,EAA+C,CACnF,GAAI,EAAgB,SAAW,EAC7B,MAAO,GAGT,IAAM,EAAkB,CAAC,6BAA8B,EAAE,EAEzD,IAAK,IAAM,KAAM,EAAiB,CAChC,IAAM,EAAW,EAAG,UAAY,GAAG,EAAG,UAAU,GAAG,EAAG,YAAc,EAAG,UACvE,EAAM,KAAK,OAAO,EAAS,IAAI,EAAG,QAAQ,CAC5C,CAEA,OAAO,EAAM,KAAK;CAAI,CACxB,CAOA,SAAgB,eAAe,EAAuC,CACpE,GAAI,EAAS,SAAW,EACtB,MAAO,GAGT,IAAM,EAAkB,CAAC,+BAAgC,EAAE,EAE3D,IAAK,IAAM,KAAK,EAAU,CACxB,IAAM,EAAW,EAAE,UAAY,GAAG,EAAE,UAAU,GAAG,EAAE,YAAc,EAAE,UACnE,EAAM,KAAK,OAAO,EAAS,IAAI,EAAE,QAAQ,CAC3C,CAEA,OAAO,EAAM,KAAK;CAAI,CACxB,CAEA,MAAM,GAAqD,CACzD,YAAa,iBACb,cAAe,mBACf,cAAe,mBACf,eAAgB,oBAChB,wBAAyB,4BACzB,YAAa,iBACb,cAAe,mBACf,eAAgB,oBAChB,cAAe,mBACf,oBAAqB,yBACrB,YAAa,kBACb,cAAe,oBACf,eAAgB,qBAChB,WAAY,sBACZ,aAAc,wBACd,cAAe,yBACf,mBAAoB,wBACpB,qBAAsB,0BACtB,sBAAuB,2BACvB,oBAAqB,yBACrB,uBAAwB,0BAC1B,EAOA,SAAgB,kBAAkB,EAA6B,CAC7D,IAAM,EAAiD,CAAC,EACxD,IAAK,IAAM,KAAU,EAAK,QACxB,EAAM,EAAO,OAAS,EAAM,EAAO,OAAS,GAAK,EAGnD,IAAM,EAAQ,OAAO,KAAK,CAAK,CAAC,CAAC,IAC9B,GAAS,GAAG,EAAM,GAAwB,GAAG,GAAmB,IACnE,EAEA,OAAO,EAAM,OAAS,EAAI,EAAM,KAAK,IAAI,EAAI,YAC/C,CCpoBA,SAAgB,sBAAsB,EAAqB,CACzD,OAAO,EAAI,SAAS,CAAC,CAAC,SAAS,EAAG,GAAG,CACvC,CAWA,SAAgB,wBAAwB,EAA2B,CACjE,GAAI,UAAU,KAAK,CAAS,EAC1B,OAAO,SAAS,EAAW,EAAE,EAE/B,GAAI,iBAAiB,KAAK,CAAS,EAAG,CACpC,IAAM,EAAS,SAAS,EAAW,EAAE,EACrC,GAAI,EAAS,KACX,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,oBAAoB,EAAU,mCACzC,CAAC,EAEH,OAAO,CACT,CACA,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,oCAAoC,EAAU,oEACzD,CAAC,CACH,CClBA,MAAa,GAAqC,qCAElD,SAAgB,oCAAoC,EAAkB,EAAoB,CACxF,GAAI,OAAO,GAAQ,WAAY,GAAgB,EAAE,YAAa,GAAM,OACpE,IAAM,EAAU,EAAI,QAEpB,GADI,OAAO,GAAY,UAErB,OAAO,UAAU,CAAO,GACxB,GAAA,GACA,GAAA,EAEA,OAGF,IACI,EASJ,KARA,CAME,EANE,EAAA,EACS,iEAAiE,EAAQ,GAC3E,EAAA,EAEP,4FAES,oEAEP,EAAS,CACb,KAAM,GACN,QAAS,6CAA6C,EAAQ,MAAM,EAAS,GAC7E,QAAS,wDACT,WAAY,CACd,CAAC,CACH,CAOA,MAAM,GAAsB,IAAI,IAA4B,CAC1D,CAAC,aAAc,aAAa,EAC5B,CAAC,eAAgB,eAAe,EAChC,CAAC,eAAgB,eAAe,EAChC,CAAC,gBAAiB,gBAAgB,EAClC,CAAC,yBAA0B,yBAAyB,EACpD,CAAC,wBAAyB,wBAAwB,CACpD,CAAC,EAQD,SAAgB,2BAA2B,EAAuB,CAChE,GAAI,OAAO,GAAQ,WAAY,GAAgB,EAAE,YAAa,GAAM,OAAO,EAC3E,IAAM,EAAU,EAAI,QACpB,GAAI,CAAC,MAAM,QAAQ,CAAO,EAAG,OAAO,EAEpC,IAAM,EAAa,EAAQ,IAAK,GAAW,CACzC,GAAI,OAAO,GAAW,WAAY,GAAmB,EAAE,SAAU,GAAS,OAAO,EACjF,IAAM,EAAQ,EAA6B,KAC3C,GAAI,OAAO,GAAS,SAAU,OAAO,EACrC,IAAM,EAAc,GAAoB,IAAI,CAAI,EAChD,OAAO,IAAgB,IAAA,GAAY,EAAS,CAAE,GAAG,EAAQ,KAAM,CAAY,CAC7E,CAAC,EAED,MAAO,CAAE,GAAG,EAAK,QAAS,CAAW,CACvC,CAOA,MAAM,GAAsB,IAAI,IAAoB,CAClD,CAAC,WAAY,WAAW,EACxB,CAAC,mBAAoB,mBAAmB,CAC1C,CAAC,EAED,SAAS,wBAAwB,EAAyB,CACxD,GAAI,OAAO,GAAU,WAAY,GAAkB,MAAM,QAAQ,CAAK,EAAG,OAAO,EAChF,IAAM,EAAS,EACT,EAAmC,CAAC,EACtC,EAAU,GACd,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAM,EAAG,CACjD,IAAM,EAAa,GAAoB,IAAI,CAAG,EAC1C,IAAe,IAAA,IAAa,EAAE,KAAc,IAC9C,EAAQ,GAAc,EACtB,EAAU,IAEV,EAAQ,GAAO,CAEnB,CACA,OAAO,EAAU,EAAU,CAC7B,CAGA,MAAM,GAAwB,CAAC,UAAW,kBAAmB,UAAU,EAQvE,SAAgB,yBAAyB,EAAuB,CAC9D,GAAI,OAAO,GAAQ,WAAY,EAAc,OAAO,EACpD,IAAM,EAAS,EACf,GAAI,EAAE,UAAW,IAAW,WAAY,EAAQ,OAAO,EACvD,GAAM,CAAE,QAAO,GAAG,GAAS,EAC3B,MAAO,CAAE,GAAG,EAAM,OAAQ,CAAM,CAClC,CAQA,SAAgB,0BAA0B,EAAuB,CAC/D,GAAI,OAAO,GAAQ,WAAY,EAAc,OAAO,EACpD,IAAM,EAAS,EACT,EAAsC,CAAE,GAAG,CAAO,EACxD,IAAK,IAAM,KAAO,GAAuB,CACvC,IAAM,EAAU,EAAO,GAClB,MAAM,QAAQ,CAAO,IAC1B,EAAW,GAAO,EAAQ,IAAI,uBAAuB,EACvD,CACA,OAAO,CACT,CAEA,SAAgB,sBAA6C,CAC3D,OAAO,OAAO,OAAO,IAAI,CAC3B,CAEA,SAAgB,mBAAsB,EAA0D,CAC9F,IAAM,EAAO,qBAAwB,EACrC,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,GAAU,CAAC,CAAC,EACpD,EAAK,GAAO,EAEd,OAAO,CACT,CAWA,SAAgB,uBAAuB,EAAiD,CACtF,IAAM,EAAS,EAAM,OACjB,OAAO,YACL,OAAO,QAAQ,EAAM,MAAM,CAAC,CAAC,KAAK,CAAC,EAAM,KAAY,CACnD,EACA,uBAAuB,CAAM,CAC/B,CAAC,CACH,EACA,IAAA,GAEJ,MAAO,CACL,GAAG,EACH,GAAI,EAAM,OAAS,WAAa,EAAM,QAAU,IAAA,IAAa,CAAE,MAAA,CAA6B,EAC5F,GAAI,GAAU,CAAE,QAAO,CACzB,CACF,CAaA,SAAgB,sBAAsB,EAAkD,CAGtF,IAAM,EACH,EAAiC,YAAc,GAAW,UAAU,EAAK,IAAI,EAC1E,EAAS,qBAA0C,EACzD,IAAK,GAAM,CAAC,EAAW,KAAU,OAAO,QAAQ,EAAK,MAAM,EACzD,EAAO,GAAa,uBAAuB,CAAK,EAElD,MAAO,CAAE,GAAG,EAAM,aAAY,QAAO,CACvC,CAQA,SAAgB,wBAAwB,EAAoD,CAC1F,IAAM,EAAS,qBAA2C,EAC1D,IAAK,GAAM,CAAC,EAAW,KAAS,OAAO,QAAQ,EAAS,MAAM,EAC5D,EAAO,GAAa,sBAAsB,CAAI,EAEhD,MAAO,CAAE,GAAG,EAAU,QAAO,CAC/B,CCxMA,MAAa,GAA6C,IAAI,IAAI,CAChE,iBACA,gBACA,iBACA,cACA,gBACA,eACA,kBACA,gBACA,iBACA,aACF,CAAC,EAQD,SAAgB,+BACd,EACA,EACS,CAcT,OAbI,EAAO,OAAS,EAAM,MACtB,EAAO,OAAS,EAAM,OACtB,EAAO,OAAS,UAAY,EAAM,OAAS,UAC3C,EAAO,QAAU,EAAM,QACvB,EAAO,QAAU,EAAM,QACvB,EAAO,YAAc,EAAM,YAE3B,CAAC,GAAsB,IAAI,GAAG,EAAO,KAAK,GAAG,EAAM,MAAM,EAAU,GAMhE,EAAE,EAAO,QAAU,KAAU,EAAM,OAAS,WAAa,EAAO,OAAS,OAClF,CAOA,SAAgB,iBAAiB,EAAoC,CACnE,OAAO,EAAM,MAAQ,GAAG,EAAM,KAAK,IAAM,EAAM,IACjD,CAQA,SAAgB,oBACd,EACA,EACS,CACT,OAAO,EAAO,OAAS,EAAM,OAAS,EAAO,OAAS,OAAY,EAAM,OAAS,GACnF,CAWA,SAAgB,2BACd,EACA,EACS,CAET,GADI,EAAO,OAAS,EAAM,MAAQ,EAAO,OAAS,CAAC,EAAM,OAEvD,EAAO,OAAS,YACf,EAAM,OAAA,IAAmC,EAAO,OAAA,GAEjD,MAAO,GAET,IAAM,EAAc,IAAI,KAAK,EAAM,eAAiB,CAAC,EAAA,CAAG,IAAK,GAAM,EAAE,KAAK,CAAC,EAC3E,OAAQ,EAAO,eAAiB,CAAC,EAAA,CAAG,MAAO,GAAM,EAAY,IAAI,EAAE,KAAK,CAAC,CAC3E,CAwBA,SAAgB,wCACd,EACA,EACsC,CAsBtC,OArBK,oBAAoB,EAAQ,CAAK,EAElC,+BAA+B,EAAQ,CAAK,EACvC,CACL,SAAU,GACV,OAAQ,OAAO,EAAO,KAAK,MAAM,EAAM,KAAK,sCAC9C,EAEE,EAAO,QAAU,EAAM,OAAe,CAAE,SAAU,GAAO,OAAQ,qBAAsB,EACvF,EAAO,MAAc,CAAE,SAAU,GAAO,OAAQ,uBAAwB,EACxE,EAAO,OAAS,UAAY,EAAM,OAAS,SACtC,CAAE,SAAU,GAAO,OAAQ,qBAAsB,EAEtD,EAAO,QAAU,EAAM,OAClB,CAAE,SAAU,GAAO,OAAQ,kCAAmC,EAEnE,EAAO,QAAU,EAAM,OAAe,CAAE,SAAU,GAAO,OAAQ,uBAAwB,EACzF,EAAO,YAAc,EAAM,WACtB,CAAE,SAAU,GAAO,OAAQ,4BAA6B,EAG1D,CAAE,SAAU,EAAK,EApBf,CAAE,SAAU,GAAO,OAAQ,+BAAgC,CAqBtE,CCzGA,MAAM,GAAiC,IAAI,IAA8B,CACvE,QACA,SACA,QACF,CAAC,EAYD,SAAgB,mBACd,EACA,EACS,CACT,GAAI,EAAO,OAAS,EAAM,KAAM,MAAO,GACvC,IAAK,IAAM,KAAQ,GACb,OAA+B,IAAI,CAAI,IACtC,EAAO,IAAS,OAAY,EAAM,IAAS,IAAQ,MAAO,GAIjE,IAFK,EAAO,gBAAkB,OAAS,EAAM,gBAAkB,MAC1D,EAAO,iBAAmB,OAAS,EAAM,iBAAmB,KAC7D,EAAO,QAAU,EAAM,OAAQ,MAAO,GAC1C,GAAI,EAAO,OAAS,OAAQ,CAC1B,IAAM,EAAc,IAAI,KAAK,EAAM,eAAiB,CAAC,EAAA,CAAG,IAAK,GAAM,EAAE,KAAK,CAAC,EAC3E,IAAK,EAAO,eAAiB,CAAC,EAAA,CAAG,KAAM,GAAM,CAAC,EAAY,IAAI,EAAE,KAAK,CAAC,EAAG,MAAO,EAClF,CAMA,IAAM,EAAe,EAAO,QAAU,CAAC,EACjC,EAAc,EAAM,QAAU,CAAC,EAC/B,EAAc,OAAO,KAAK,CAAY,EACtC,EAAa,OAAO,KAAK,CAAW,EAC1C,GAAI,EAAY,SAAW,EAAW,OAAQ,MAAO,GACrD,IAAK,IAAM,KAAQ,EAAa,CAC9B,IAAM,EAAe,EAAa,GAC5B,EAAc,EAAY,GAGhC,GAFI,CAAC,GAAgB,CAAC,GAClB,EAAa,WAAa,EAAY,UACtC,CAAC,mBAAmB,EAAc,CAAW,EAAG,MAAO,EAC7D,CACA,MAAO,EACT,CAOA,SAAgB,qBAAqB,EAA6C,CAChF,IAAM,EAAgB,IAAI,IACpB,EAAc,IAAI,IACxB,IAAK,IAAM,KAAU,EAAK,QACxB,GAAI,EAAO,OAAS,gBAAiB,CACnC,IAAM,EAAO,EAAc,IAAI,EAAO,SAAS,GAAK,CAAC,EACrD,EAAK,KAAK,CAAM,EAChB,EAAc,IAAI,EAAO,UAAW,CAAI,CAC1C,MAAO,GAAI,EAAO,OAAS,cAAe,CACxC,IAAM,EAAO,EAAY,IAAI,EAAO,SAAS,GAAK,CAAC,EACnD,EAAK,KAAK,CAAM,EAChB,EAAY,IAAI,EAAO,UAAW,CAAI,CACxC,CAGF,IAAM,EAAqC,CAAC,EAC5C,IAAK,GAAM,CAAC,EAAW,KAAmB,EAAe,CACvD,IAAM,EAAe,EAAY,IAAI,CAAS,EACzC,KACL,IAAK,IAAM,KAAW,EAAgB,CACpC,IAAM,EAAQ,EAAa,OAAQ,GAAM,mBAAmB,EAAQ,OAAQ,EAAE,KAAK,CAAC,EAChF,EAAM,OAAS,GACjB,EAAW,KAAK,CAAE,YAAW,UAAS,OAAM,CAAC,CAEjD,CACF,CACA,OAAO,CACT,CAYA,SAAgB,kBACd,EACA,EACA,EACS,CACT,IAAM,EAAa,EAAiB,OAAO,EAAK,UAAU,EAAE,OACtD,EAAa,EAAgB,OAAO,EAAK,UAAU,EAAE,OAC3D,MAAO,EACL,KAAa,EAAK,oBACjB,IAAa,EAAK,oBACnB,KAAa,EAAK,YACjB,EAAW,EAAK,WAErB,CASA,SAAgB,wBACd,EACA,EACA,EACM,CACN,IAAM,EAAO,IAAI,IACjB,IAAK,IAAM,KAAU,EAAc,CACjC,GAAM,CAAE,YAAW,oBAAmB,aAAc,EAC9C,EAAQ,GAAG,EAAU,GAAG,EAAkB,GAAG,IACnD,IAAK,IAAM,IAAO,CAAC,GAAG,EAAU,GAAG,IAAqB,GAAG,EAAU,GAAG,GAAW,EAAG,CACpF,GAAI,EAAK,IAAI,CAAG,EACd,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,UAAU,EAAI,mCACzB,CAAC,EAEH,EAAK,IAAI,CAAG,CACd,CAEA,IAAM,EAAW,EAAS,OAAO,GAC3B,EAAW,EAAQ,OAAO,GAChC,GAAI,CAAC,GAAY,CAAC,EAChB,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,iBAAiB,EAAM,WAAW,EAAU,0DACvD,CAAC,EAEH,IAAM,EAAY,EAAS,OAAO,GAClC,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,iBAAiB,EAAM,WAAW,EAAkB,yCAC/D,CAAC,EAEH,GAAI,EAAS,OAAO,GAClB,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,iBAAiB,EAAM,WAAW,EAAkB,sCAC/D,CAAC,EAEH,IAAM,EAAY,EAAS,OAAO,GAClC,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,iBAAiB,EAAM,WAAW,EAAU,wCACvD,CAAC,EAEH,GAAI,EAAS,OAAO,GAClB,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,iBAAiB,EAAM,WAAW,EAAU,yCACvD,CAAC,EAEH,GAAI,CAAC,mBAAmB,EAAW,CAAS,EAC1C,MAAM,EAAS,CACb,KAAM,2BACN,QACE,iBAAiB,EAAM,mPAI3B,CAAC,CAEL,CACF,CAEA,MAAM,GAAwB,sCAO9B,SAAgB,kBAAkB,EAAgC,CAEhE,GAAM,EAAG,EAAW,EAAmB,GADzB,EAAM,MAAM,EAC8B,GAAK,CAAC,EAC9D,GAAI,CAAC,GAAa,CAAC,GAAqB,CAAC,EACvC,MAAM,EAAS,CACb,KAAM,gCACN,QAAS,2BAA2B,EAAM,gDAC1C,QAAS,6BACX,CAAC,EAEH,GAAI,IAAsB,EACxB,MAAM,EAAS,CACb,KAAM,gCACN,QAAS,2BAA2B,EAAM,2CAC1C,QAAS,6BACX,CAAC,EAEH,MAAO,CAAE,YAAW,oBAAmB,WAAU,CACnD,CAWA,MAAM,GAAsB,2BAO5B,SAAgB,gBAAgB,EAA8B,CAE5D,GAAM,EAAG,EAAW,GADN,EAAM,MAAM,EACW,GAAK,CAAC,EAC3C,GAAI,CAAC,GAAa,CAAC,EACjB,MAAM,EAAS,CACb,KAAM,8BACN,QAAS,yBAAyB,EAAM,oCACxC,QAAS,6BACX,CAAC,EAEH,MAAO,CAAE,YAAW,WAAU,CAChC,CAUA,SAAgB,gBACd,EACA,EACA,EACS,CACT,IAAM,EAAa,EAAiB,OAAO,EAAK,UAAU,EAAE,OACtD,EAAa,EAAgB,OAAO,EAAK,UAAU,EAAE,OAC3D,MAAO,EAAQ,KAAa,EAAK,YAAe,IAAa,EAAK,WACpE,CAaA,SAAgB,0BAA0B,EAAwC,CAEhF,GAAM,EAAG,EAAW,GADN,EAAM,MAAM,EACW,GAAK,CAAC,EAC3C,GAAI,CAAC,GAAa,CAAC,EACjB,MAAM,EAAS,CACb,KAAM,yCACN,QAAS,oCAAoC,EAAM,oCACnD,QAAS,6BACX,CAAC,EAEH,MAAO,CAAE,YAAW,WAAU,CAChC,CA8CA,SAAgB,+BACd,EACA,EACS,CAET,GADI,EAAO,OAAS,EAAM,MACtB,EAAO,WAAa,EAAM,SAAU,MAAO,GAC/C,IAAK,IAAM,KAAQ,GACb,OAA+B,IAAI,CAAI,IACtC,EAAO,IAAS,OAAY,EAAM,IAAS,IAAQ,MAAO,GAOjE,IALK,EAAO,gBAAkB,OAAS,EAAM,gBAAkB,MAC1D,EAAO,iBAAmB,OAAS,EAAM,iBAAmB,KAC7D,EAAO,QAAU,EAAM,SACtB,EAAO,OAAS,SAAW,EAAM,OAAS,QAC1C,EAAO,OAAO,QAAQ,MAAQ,OAAS,EAAM,OAAO,QAAQ,MAAQ,MACpE,EAAO,OAAO,QAAQ,MAAQ,OAAS,EAAM,OAAO,QAAQ,MAAQ,IAAK,MAAO,GACrF,IAAM,EAAiB,EAAO,UAAY,CAAC,EACrC,EAAgB,EAAM,UAAY,CAAC,EACzC,GAAI,EAAe,SAAW,EAAc,OAAQ,MAAO,GAC3D,IAAK,GAAM,CAAC,EAAO,KAAe,EAAe,QAAQ,EAAG,CAC1D,IAAM,EAAY,EAAc,GAEhC,IADK,EAAW,QAAQ,MAAQ,OAAS,GAAW,QAAQ,MAAQ,KAChE,EAAW,eAAiB,GAAW,aAAc,MAAO,EAClE,CACA,GAAI,EAAO,OAAS,OAAQ,CAC1B,IAAM,EAAc,IAAI,KAAK,EAAM,eAAiB,CAAC,EAAA,CAAG,IAAK,GAAM,EAAE,KAAK,CAAC,EAC3E,IAAK,EAAO,eAAiB,CAAC,EAAA,CAAG,KAAM,GAAM,CAAC,EAAY,IAAI,EAAE,KAAK,CAAC,EAAG,MAAO,EAClF,CACA,IAAM,EAAgB,EAAO,QAAU,CAAC,EAClC,EAAe,EAAM,QAAU,CAAC,EAChC,EAAc,OAAO,KAAK,CAAa,EAC7C,GAAI,EAAY,SAAW,OAAO,KAAK,CAAY,CAAC,CAAC,OAAQ,MAAO,GACpE,IAAK,IAAM,KAAQ,EAAa,CAC9B,IAAM,EAAe,EAAc,GAC7B,EAAc,OAAO,OAAO,EAAc,CAAI,EAAI,EAAa,GAAQ,IAAA,GAE7E,GADI,CAAC,GAAgB,CAAC,GAClB,CAAC,+BAA+B,EAAc,CAAW,EAAG,MAAO,EACzE,CACA,MAAO,EACT,CAQA,SAAgB,eAAe,EAAsB,EAA+B,CAClF,OAAO,EAAE,SAAW,EAAE,QAAU,EAAE,MAAM,EAAG,EAAE,CAAC,CAAC,OAAO,EAAS,IAAU,IAAY,EAAE,EAAM,CAC/F,CAQA,SAAgB,iCACd,EAC+B,CAC/B,IAAM,EAA4C,CAAC,EACnD,IAAK,IAAM,KAAU,EAAK,QAAS,CACjC,GAAI,EAAO,OAAS,iBAAkB,SACtC,IAAM,EAAgB,2BAA2B,EAAO,OAAQ,EAAO,KAAK,EAC5E,IAAK,IAAM,KAAW,EAAe,CACnC,GAAI,EAAQ,OAAS,UAAW,SAChC,IAAM,EAAQ,EACX,OACE,GACC,EAAU,OAAS,SACnB,eAAe,EAAU,KAAM,EAAQ,IAAI,GAC3C,+BAA+B,EAAQ,OAAQ,EAAU,KAAK,CAClE,CAAC,CACA,IAAK,GAAc,EAAU,KAAK,EAAU,KAAK,OAAS,EAAE,CAAC,CAC7D,OAAQ,GAAyB,IAAS,IAAA,EAAS,EAClD,EAAM,OAAS,GACjB,EAAW,KAAK,CACd,UAAW,EAAO,UAClB,UAAW,EAAO,UAClB,aAAc,EAAQ,KACtB,QAAS,EAAQ,OACjB,OACF,CAAC,CAEL,CACF,CACA,OAAO,CACT,CAWA,SAAgB,8BACd,EACA,EACA,EACS,CACT,IAAM,EAAY,EAAiB,OAAO,EAAK,UAAU,EAAE,OAAO,EAAK,WACjE,EAAY,EAAgB,OAAO,EAAK,UAAU,EAAE,OAAO,EAAK,WACtE,MAAO,EACL,iBAAgB,EAAW,EAAK,YAAY,GAC3C,gBAAgB,EAAW,EAAK,YAAY,GAC7C,iBAAgB,EAAW,EAAK,IAAI,GACnC,gBAAgB,EAAW,EAAK,IAAI,EAEzC,CASA,SAAgB,+BACd,EACA,EACA,EACM,CACN,IAAM,EAAO,IAAI,IACjB,IAAK,IAAM,KAAU,EAAS,CAC5B,GAAM,CAAE,YAAW,YAAW,eAAc,QAAS,EAC/C,EAAgB,GAAG,EAAU,GAAG,EAAU,GAAG,EAAa,KAAK,GAAG,IAClE,EAAQ,GAAG,EAAc,GAAG,EAAK,EAAK,OAAS,IAAM,KAC3D,IAAK,IAAM,IAAO,CAAC,EAAe,GAAG,EAAU,GAAG,EAAU,GAAG,EAAK,KAAK,GAAG,GAAG,EAAG,CAChF,GAAI,EAAK,IAAI,CAAG,EACd,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,WAAW,EAAI,mCAC1B,CAAC,EAEH,EAAK,IAAI,CAAG,CACd,CACA,GAAI,EAAa,SAAW,GAAK,CAAC,eAAe,EAAc,CAAI,EACjE,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,iBAAiB,EAAM,8DAA8D,EAAU,GAC1G,CAAC,EAEH,IAAM,EAAY,EAAS,OAAO,EAAU,EAAE,OAAO,GAC/C,EAAY,EAAQ,OAAO,EAAU,EAAE,OAAO,GACpD,GAAI,GAAW,OAAS,UAAY,GAAW,OAAS,SACtD,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,iBAAiB,EAAM,KAAK,EAAU,GAAG,EAAU,sEAC9D,CAAC,EAEH,IAAM,EAAa,gBAAgB,EAAW,CAAY,EAC1D,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,iBAAiB,EAAM,YAAY,EAAa,KAAK,GAAG,EAAE,yCACrE,CAAC,EAEH,GAAI,gBAAgB,EAAW,CAAY,EACzC,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,iBAAiB,EAAM,YAAY,EAAa,KAAK,GAAG,EAAE,sCACrE,CAAC,EAEH,IAAM,EAAa,gBAAgB,EAAW,CAAI,EAClD,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,iBAAiB,EAAM,YAAY,EAAK,KAAK,GAAG,EAAE,wCAC7D,CAAC,EAEH,GAAI,gBAAgB,EAAW,CAAI,EACjC,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,iBAAiB,EAAM,YAAY,EAAK,KAAK,GAAG,EAAE,yCAC7D,CAAC,EAEH,GAAI,CAAC,+BAA+B,EAAY,CAAU,EACxD,MAAM,EAAS,CACb,KAAM,2BACN,QACE,iBAAiB,EAAM,iQAI3B,CAAC,CAEL,CACF,CAEA,MAAM,GAAsC,uDAQ5C,SAAgB,8BAA8B,EAAuC,CAEnF,GAAM,EAAG,EAAW,EAAW,EAAY,GAD7B,EAAM,MAAM,EACgC,GAAK,CAAC,EAChE,GAAI,CAAC,GAAa,CAAC,GAAa,CAAC,GAAc,CAAC,EAC9C,MAAM,EAAS,CACb,KAAM,gCACN,QAAS,2BAA2B,EAAM,mDAC1C,QAAS,6BACX,CAAC,EAEH,IAAM,EAAe,EAAW,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,EAClD,GAAI,EAAa,EAAa,OAAS,KAAO,EAC5C,MAAM,EAAS,CACb,KAAM,gCACN,QAAS,2BAA2B,EAAM,4CAC1C,QAAS,6BACX,CAAC,EAEH,MAAO,CAAE,YAAW,YAAW,eAAc,KAAM,CAAC,GAAG,EAAa,MAAM,EAAG,EAAE,EAAG,CAAO,CAAE,CAC7F,CAYA,MAAM,GAAoC,4CAO1C,SAAgB,4BAA4B,EAAqC,CAE/E,GAAM,EAAG,EAAW,EAAW,GADjB,EAAM,MAAM,EACuB,GAAK,CAAC,EACvD,GAAI,CAAC,GAAa,CAAC,GAAa,CAAC,EAC/B,MAAM,EAAS,CACb,KAAM,8BACN,QAAS,yBAAyB,EAAM,2CACxC,QAAS,6BACX,CAAC,EAEH,MAAO,CAAE,YAAW,YAAW,KAAM,EAAW,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,CAAE,CACtE,CAYA,SAAgB,4BACd,EACA,EACA,EACS,CACT,IAAM,EAAY,EAAiB,OAAO,EAAK,UAAU,EAAE,OAAO,EAAK,WACjE,EAAY,EAAgB,OAAO,EAAK,UAAU,EAAE,OAAO,EAAK,WACtE,MAAO,GACL,gBAAgB,EAAW,EAAK,IAAI,GACpC,CAAC,gBAAgB,EAAW,EAAK,IAAI,GACrC,gBAAgB,EAAW,EAAK,KAAK,MAAM,EAAG,EAAE,CAAC,EAErD,CAkCA,SAAS,uBACP,EACA,EACA,EACqB,CACrB,IAAM,EAAS,EAAM,OACjB,OAAO,YACL,OAAO,QAAQ,EAAM,MAAM,CAAC,CAAC,KAAK,CAAC,EAAM,KAAY,CACnD,EACA,uBAAuB,EAAQ,EAAmB,CAAS,CAC7D,CAAC,CACH,EACA,IAAA,GACJ,MAAO,CACL,GAAG,EACH,GAAI,EAAM,iBAAmB,GAAqB,CAAE,eAAgB,CAAU,EAC9E,GAAI,GAAU,CAAE,OAAQ,CAAO,CACjC,CACF,CAOA,SAAS,gBAAgB,EAAwB,CAW/C,OAVI,MAAM,QAAQ,CAAK,EACd,IAAI,EAAM,IAAI,eAAe,CAAC,CAAC,KAAK,GAAG,EAAE,GAE9C,OAAO,GAAU,UAAY,EAKxB,IAJS,OAAO,QAAQ,CAAgC,CAAC,CAC7D,QAAQ,EAAG,KAAO,IAAM,IAAA,EAAS,CAAC,CAClC,UAAU,CAAC,GAAI,CAAC,KAAO,EAAE,cAAc,CAAC,CAAC,CAAC,CAC1C,KAAK,CAAC,EAAG,KAAO,GAAG,KAAK,UAAU,CAAC,EAAE,GAAG,gBAAgB,CAAC,GAC3C,CAAC,CAAC,KAAK,GAAG,EAAE,GAExB,KAAK,UAAU,CAAK,CAC7B,CAEA,SAAS,4BACP,EACA,EACS,CAIT,GAHI,CAAC,mBAAmB,EAAQ,CAAK,GACjC,EAAO,WAAa,EAAM,WACzB,EAAO,QAAU,OAAY,EAAM,QAAU,MAC7C,EAAO,OAAS,SAAW,EAAM,OAAS,MAAO,MAAO,GAE7D,IAAK,GAAM,CAAC,EAAM,KAAiB,OAAO,QAAQ,EAAO,QAAU,CAAC,CAAC,EAAG,CACtE,IAAM,EAAc,EAAM,SAAS,GACnC,GAAI,CAAC,GAAe,CAAC,4BAA4B,EAAc,CAAW,EAAG,MAAO,EACtF,CACA,MAAO,EACT,CAmBA,SAAgB,uBACd,EACA,EACS,CACT,GAAI,OAAO,KAAK,EAAO,OAAS,CAAC,CAAC,CAAC,CAAC,OAAS,GAAK,OAAO,KAAK,EAAM,OAAS,CAAC,CAAC,CAAC,CAAC,OAAS,EACxF,MAAO,GAGT,IAAM,EAAmB,OAAO,KAAK,EAAO,MAAM,EAC5C,EAAkB,OAAO,KAAK,EAAM,MAAM,EAChD,GAAI,EAAiB,SAAW,EAAgB,OAAQ,MAAO,GAC/D,IAAK,IAAM,KAAa,EAAkB,CACxC,IAAM,EAAc,EAAO,OAAO,GAC5B,EAAa,EAAM,OAAO,GAOhC,GANI,CAAC,GAAe,CAAC,GAIjB,EAAY,iBAAmB,EAAO,MAAQ,EAAY,UAE1D,CAAC,4BADc,uBAAuB,EAAa,EAAO,KAAM,EAAM,IAChC,EAAG,CAAU,EAAG,MAAO,EACnE,CAEA,OAAO,gBAAgB,EAAO,SAAW,CAAC,CAAC,IAAM,gBAAgB,EAAM,SAAW,CAAC,CAAC,CACtF,CAOA,SAAgB,yBAAyB,EAA4C,CACnF,IAAM,EAAiB,EAAK,QAAQ,OACjC,GAAyC,EAAO,OAAS,eAC5D,EACM,EAAe,EAAK,QAAQ,OAC/B,GAAuC,EAAO,OAAS,aAC1D,EAEM,EAAoC,CAAC,EAC3C,IAAK,IAAM,KAAW,EAAgB,CACpC,IAAM,EAAQ,EAAa,OAAQ,GAAM,uBAAuB,EAAQ,OAAQ,EAAE,KAAK,CAAC,EACpF,EAAM,OAAS,GACjB,EAAW,KAAK,CAAE,UAAS,OAAM,CAAC,CAEtC,CACA,OAAO,CACT,CAYA,SAAgB,sBACd,EACA,EACA,EACS,CACT,MAAO,EACL,GAAiB,OAAO,EAAK,oBAC5B,EAAgB,OAAO,EAAK,oBAC7B,GAAgB,OAAO,EAAK,YAC3B,EAAiB,OAAO,EAAK,WAElC,CASA,SAAgB,uBACd,EACA,EACA,EACM,CACN,IAAM,EAAO,IAAI,IACjB,IAAK,IAAM,KAAU,EAAa,CAChC,GAAM,CAAE,oBAAmB,aAAc,EACnC,EAAQ,GAAG,EAAkB,GAAG,IACtC,IAAK,IAAM,IAAO,CAAC,EAAmB,CAAS,EAAG,CAChD,GAAI,EAAK,IAAI,CAAG,EACd,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,UAAU,EAAI,mCACzB,CAAC,EAEH,EAAK,IAAI,CAAG,CACd,CAEA,IAAM,EAAW,EAAS,OAAO,GACjC,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,iBAAiB,EAAM,WAAW,EAAkB,yCAC/D,CAAC,EAEH,GAAI,EAAQ,OAAO,GACjB,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,iBAAiB,EAAM,WAAW,EAAkB,sCAC/D,CAAC,EAEH,IAAM,EAAW,EAAQ,OAAO,GAChC,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,iBAAiB,EAAM,WAAW,EAAU,wCACvD,CAAC,EAEH,GAAI,EAAS,OAAO,GAClB,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,iBAAiB,EAAM,WAAW,EAAU,yCACvD,CAAC,EAEH,GAAI,CAAC,uBAAuB,EAAU,CAAQ,EAC5C,MAAM,EAAS,CACb,KAAM,2BACN,QACE,iBAAiB,EAAM,qTAK3B,CAAC,CAEL,CACF,CAcA,SAAgB,6BACd,EACA,EACA,EACS,CACT,MAAO,EACL,GAAO,gBACP,GAAM,gBACN,EAAO,iBAAmB,EAAM,gBAC/B,GAAmB,IAAI,EAAO,cAAc,IAAM,EAAM,iBACtD,EAAO,iBAAmB,OAAS,EAAM,iBAAmB,IAEnE,CAEA,MAAM,GAA6B,0BAOnC,SAAgB,sBAAsB,EAA+B,CAEnE,GAAM,EAAG,EAAmB,GADd,EAAM,MAAM,EACmB,GAAK,CAAC,EACnD,GAAI,CAAC,GAAqB,CAAC,EACzB,MAAM,EAAS,CACb,KAAM,gCACN,QAAS,2BAA2B,EAAM,uEAC1C,QAAS,6BACX,CAAC,EAEH,GAAI,IAAsB,EACxB,MAAM,EAAS,CACb,KAAM,gCACN,QAAS,2BAA2B,EAAM,2CAC1C,QAAS,6BACX,CAAC,EAEH,MAAO,CAAE,oBAAmB,WAAU,CACxC,CAUA,MAAM,GAA2B,eAOjC,SAAgB,oBAAoB,EAA6B,CAE/D,GAAM,EAAG,GADK,EAAM,MAAM,EACA,GAAK,CAAC,EAChC,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,8BACN,QAAS,yBAAyB,EAAM,+CACxC,QAAS,6BACX,CAAC,EAEH,MAAO,CAAE,WAAU,CACrB,CAUA,SAAgB,oBACd,EACA,EACA,EACS,CACT,MAAO,EACL,GAAiB,OAAO,EAAK,YAAe,EAAgB,OAAO,EAAK,WAE5E,CC39BA,MAAa,GACX,gFACW,GACX,0FAcF,SAAgB,mCACd,EACqB,CACrB,IAAM,EAAU,2BAA2B,EAAO,OAAQ,EAAO,KAAK,EAChE,EAAe,IAAI,KACtB,EAAO,eAAiB,CAAC,EAAA,CAAG,QAAS,GAAW,CAC/C,EAAO,aAAa,KAAK,GAAG,EAC5B,EAAO,KAAK,KAAK,GAAG,CACtB,CAAC,CACH,EACM,EAAgC,CAAC,EACvC,IAAK,IAAM,KAAW,EAAS,CAC7B,GAAI,EAAQ,OAAS,WAAa,EAAa,IAAI,EAAQ,KAAK,KAAK,GAAG,CAAC,EAAG,SAC5E,IAAM,EAAgB,EACnB,OACE,GACC,EAAM,OAAS,SACf,CAAC,EAAa,IAAI,EAAM,KAAK,KAAK,GAAG,CAAC,GACtC,eAAe,EAAM,KAAM,EAAQ,IAAI,GACvC,+BAA+B,EAAQ,OAAQ,EAAM,KAAK,CAC9D,CAAC,CACA,IAAK,GAAU,EAAM,KAAK,GAAG,EAAE,CAAC,EAC7B,EACJ,EAAc,OAAS,EACnB,yBAAyB,EAAc,KAAK,IAAI,EAAE,8BACrC,EAAO,UAAU,GAAG,EAAO,UAAU,GAAG,EAAQ,KAAK,KAAK,GAAG,EAAE,yFAE5E,GACN,EAAS,KAAK,CACZ,UAAW,EAAO,UAClB,UAAW,CAAC,EAAO,UAAW,GAAG,EAAQ,IAAI,CAAC,CAAC,KAAK,GAAG,EACvD,OAAQ,0FAA0C,GACpD,CAAC,CACH,CACA,OAAO,CACT,CAQA,SAAgB,0BAA0B,EAA0C,CAClF,IAAM,EAAgC,CAAC,EACvC,IAAK,IAAM,KAAU,EAAK,QACpB,EAAO,OAAS,gBAClB,EAAS,KAAK,CACZ,UAAW,EAAO,UAClB,UAAW,EAAO,UAClB,OAAQ,EACV,CAAC,EACQ,EAAO,OAAS,gBACzB,EAAS,KAAK,CAAE,UAAW,EAAO,UAAW,OAAQ,EAA6B,CAAC,EAC1E,EAAO,OAAS,kBACzB,EAAS,KAAK,GAAG,mCAAmC,CAAM,CAAC,EAG/D,OAAO,CACT,CCzBA,SAAS,mBAAmB,EAA+B,EAAwC,CACjG,OACE,4BAA4B,EAAU,CAAQ,GAC9C,2BAA2B,EAAU,CAAQ,CAAC,CAAC,OAAS,CAE5D,CAWA,SAAS,wBACP,EACA,EACA,EACA,EACA,EACsB,CACtB,IAAM,EAAwC,CAAC,EAa/C,GAVI,CAAC,GAAY,GAAY,EAAS,UACpC,EAAgB,KAAK,CACnB,YACA,YACA,OAAQ,sBACV,CAAC,EAKC,GAAY,GAAY,EAAS,OAAS,EAAS,KAAM,CAC3D,IAAM,EAAY,+BAA+B,EAAU,CAAQ,EACnE,EAAgB,KAAK,CACnB,YACA,YACA,OAAQ,2BAA2B,EAAS,KAAK,MAAM,EAAS,OAChE,GAAI,CAAC,GAAa,CAAE,YAAa,GAAM,kBAAmB,EAAK,CACjE,CAAC,CACH,CAaA,GAVI,GAAY,GAAY,CAAC,EAAS,UAAY,EAAS,UACzD,EAAgB,KAAK,CACnB,YACA,YACA,OAAQ,yCACV,CAAC,EAKC,GAAY,IAAa,EAAS,OAAS,OAAY,EAAS,OAAS,IAAQ,CACnF,GAAM,CAAC,EAAU,GAAU,EAAS,MAChC,CAAC,QAAS,cAAc,EACxB,CAAC,eAAgB,OAAO,EAC5B,EAAgB,KAAK,CACnB,YACA,YACA,OAAQ,sBAAsB,EAAS,MAAM,IAC7C,YAAa,GACb,kBAAmB,EACrB,CAAC,CACH,CAqCA,GAhCI,GAAY,GAAY,6BAA6B,EAAU,EAAU,CAAiB,GAC5F,EAAgB,KAAK,CACnB,YACA,YACA,OAAQ,wCAAwC,EAAS,eAAe,MAAM,EAAS,gBACzF,CAAC,EAIC,GAAY,GAAY,EAAE,EAAS,QAAU,MAAW,EAAS,QAAU,KAC7E,EAAgB,KAAK,CACnB,YACA,YACA,OAAQ,kCACV,CAAC,EAMD,GAAU,OAAS,WACnB,GAAU,OAAS,WACnB,EAAS,QAAU,EAAS,OAE5B,EAAgB,KAAK,CACnB,YACA,YACA,OAAQ,8BAA8B,EAAS,MAAM,MAAM,EAAS,OACtE,CAAC,EAIC,GAAY,GAAY,EAAS,OAAS,QAAU,EAAS,OAAS,OAAQ,CAChF,IAAM,EAAa,EAAS,eAAiB,CAAC,EACxC,EAAa,EAAS,eAAiB,CAAC,EACxC,EAAY,EAAW,IAAK,GAAM,EAAE,KAAK,EACzC,EAAe,IAAI,IAAI,EAAW,IAAK,GAAM,EAAE,KAAK,CAAC,EACrD,EAAgB,EAAU,OAAQ,GAAM,CAAC,EAAa,IAAI,CAAC,CAAC,EAC9D,EAAc,OAAS,GACzB,EAAgB,KAAK,CACnB,YACA,YACA,OAAQ,wBAAwB,EAAc,KAAK,IAAI,GACzD,CAAC,CAEL,CAEA,OAAO,CACT,CAaA,SAAS,UACP,EACA,EACA,EACA,EACM,CAGN,GAFA,EAAI,QAAQ,KAAK,CAAM,EAEnB,CAAC,EAAO,UAAW,OAGnB,EAAO,OAAS,kBAClB,EAAI,SAAS,KAAK,GAAG,mCAAmC,CAAM,CAAC,EAGjE,IAAM,EAAkB,wBACtB,EAAO,UACP,EAAO,UACP,EACA,EACA,EAAI,iBACN,EACA,GAAI,EAAgB,OAAS,EAAG,CAC9B,EAAI,gBAAgB,KAAK,GAAG,CAAe,EAC3C,MACF,CAKI,EAAO,OAAS,iBAClB,EAAI,SAAS,KAAK,CAChB,UAAW,EAAO,UAClB,UAAW,EAAO,UAClB,OAAQ,EACV,CAAC,CAEL,CAEA,SAAS,kBACP,EACA,EACA,EACA,EACA,EAA2C,CAAC,EAC5C,EAAyD,CAAC,EACpD,CACN,IAAM,EAAiB,IAAI,IAAI,OAAO,KAAK,EAAS,MAAM,CAAC,EACrD,EAAiB,IAAI,IAAI,OAAO,KAAK,EAAS,MAAM,CAAC,EACrD,EAAmB,IAAI,IAAI,EAAa,IAAK,GAAM,EAAE,iBAAiB,CAAC,EACvE,EAAiB,IAAI,IAAI,EAAa,IAAK,GAAM,EAAE,SAAS,CAAC,EAEnE,IAAK,IAAM,KAAU,EAAc,CACjC,IAAM,EAAY,EAChB,EAAS,OAAO,EAAO,mBACvB,kBAAkB,EAAO,kBAAkB,wBAC7C,EACM,EAAY,EAChB,EAAS,OAAO,EAAO,WACvB,kBAAkB,EAAO,UAAU,wBACrC,EACA,EAAI,QAAQ,KAAK,CACf,KAAM,gBACN,YACA,UAAW,EAAO,UAClB,kBAAmB,EAAO,kBAC1B,OAAQ,EACR,MAAO,CACT,CAAC,EACD,EAAI,gBAAgB,KAAK,CACvB,YACA,UAAW,EAAO,UAClB,OAAQ,sBAAsB,EAAO,kBAAkB,MAAM,EAAO,UAAU,0DAChF,CAAC,CACH,CAGA,IAAK,IAAM,KAAa,EAClB,MAAe,IAAI,CAAS,GAC5B,CAAC,EAAe,IAAI,CAAS,EAAG,CAClC,IAAM,EAAY,EAChB,EAAS,OAAO,GAChB,UAAU,EAAU,wBACtB,EACA,UACE,EACA,CACE,KAAM,cACN,YACA,YACA,MAAO,CACT,EACA,IAAA,GACA,CACF,CACF,CAIF,IAAK,IAAM,KAAa,EAClB,MAAiB,IAAI,CAAS,GAC9B,CAAC,EAAe,IAAI,CAAS,EAAG,CAClC,IAAM,EAAY,EAChB,EAAS,OAAO,GAChB,UAAU,EAAU,wBACtB,EACA,UACE,EACA,CACE,KAAM,gBACN,YACA,YACA,OAAQ,CACV,EACA,EACA,IAAA,EACF,CACF,CAIF,IAAK,IAAM,KAAa,EAAgB,CACtC,GAAI,CAAC,EAAe,IAAI,CAAS,EAAG,SAEpC,IAAM,EAAY,EAChB,EAAS,OAAO,GAChB,UAAU,EAAU,wBACtB,EACM,EAAY,EAChB,EAAS,OAAO,GAChB,UAAU,EAAU,wBACtB,EAEA,GAAI,CAAC,mBAAmB,EAAW,CAAS,EAAG,SAE/C,GAAI,EAAU,OAAS,EAAU,KAAM,CACrC,UACE,EACA,CAAE,KAAM,sBAAuB,YAAW,YAAW,OAAQ,EAAW,MAAO,CAAU,EACzF,EACA,CACF,EACA,QACF,CAEA,IAAM,EAAgB,EACnB,OAAQ,GAAW,EAAO,YAAc,CAAS,CAAC,CAClD,KAAK,CAAE,eAAc,WAAY,CAAE,eAAc,MAAK,EAAE,EAC3D,UACE,EACA,CACE,KAAM,iBACN,YACA,YACA,OAAQ,EACR,MAAO,EACP,GAAI,EAAc,OAAS,GAAK,CAAE,eAAc,CAClD,EACA,EACA,CACF,EACA,IAAK,IAAM,KAAU,EACnB,EAAI,gBAAgB,KAAK,CACvB,YACA,UAAW,CAAC,EAAW,GAAG,EAAO,IAAI,CAAC,CAAC,KAAK,GAAG,EAC/C,OACE,8BAA8B,EAAO,aAAa,KAAK,GAAG,EAAE,MAAM,EAAO,KAAK,KAAK,GAAG,EAAE,0DAE5F,CAAC,CAEL,CACF,CAaA,SAAgB,sBACd,EACA,EACA,EACA,EAC2B,CAoB3B,MAnBI,CAAC,GAAY,EAAE,EAAS,QAAU,IAAe,KAGjD,CAAC,GAAY,EAAE,EAAS,QAAU,IAC7B,CACL,YACA,OAAQ,qCAAqC,EAAU,EACzD,EAKE,KAAK,UAAU,EAAS,OAAO,SAAS,CAAC,IAAM,KAAK,UAAU,EAAS,OAAO,SAAS,CAAC,EAOrF,KANE,CACL,YACA,OAAQ,yCAAyC,EAAU,EAC7D,CAIJ,CAUA,SAAS,eACP,EACA,EACA,EACA,EACM,CACN,IAAM,EAAU,IAAI,IAAI,OAAO,KAAK,GAAc,CAAC,CAAC,CAAC,EAC/C,EAAU,IAAI,IAAI,OAAO,KAAK,GAAc,CAAC,CAAC,CAAC,EAGrD,IAAK,GAAM,CAAC,EAAW,KAAgB,OAAO,QAAQ,GAAc,CAAC,CAAC,EACpE,GAAI,CAAC,EAAQ,IAAI,CAAS,EAAG,CAC3B,EAAI,QAAQ,KAAK,CACf,KAAM,cACN,YACA,YACA,MAAO,CACT,CAAC,EACD,IAAM,EAAW,sBAAsB,EAAW,EAAW,IAAA,GAAW,CAAW,EAC/E,GACF,EAAI,gBAAgB,KAAK,CAAQ,CAErC,CAIF,IAAK,GAAM,CAAC,EAAW,KAAgB,OAAO,QAAQ,GAAc,CAAC,CAAC,EAC/D,EAAQ,IAAI,CAAS,GACxB,EAAI,QAAQ,KAAK,CACf,KAAM,gBACN,YACA,YACA,OAAQ,CACV,CAAC,EAKL,IAAK,GAAM,CAAC,EAAW,KAAa,OAAO,QAAQ,GAAc,CAAC,CAAC,EACjE,GAAI,EAAQ,IAAI,CAAS,EAAG,CAC1B,IAAM,EAAW,EACf,EAAc,EAAY,gDAAgD,CAAC,CAAC,GAC5E,UAAU,EAAU,0BACtB,EAEM,EAAe,KAAK,UAAU,EAAS,OAAO,SAAS,CAAC,EACxD,EAAe,KAAK,UAAU,EAAS,OAAO,SAAS,CAAC,EAE9D,GACE,IAAiB,IAChB,EAAS,QAAU,OAAY,EAAS,QAAU,IACnD,CACA,IAAM,EAAoB,CAAC,EACvB,IAAiB,GAAc,EAAQ,KAAK,gBAAgB,GAC3D,EAAS,QAAU,OAAY,EAAS,QAAU,KACrD,EAAQ,KAAK,2BAA2B,EAC1C,EAAI,QAAQ,KAAK,CACf,KAAM,iBACN,YACA,YACA,OAAQ,EAAQ,KAAK,IAAI,EACzB,OAAQ,EACR,MAAO,CACT,CAAC,EACD,IAAM,EAAW,sBAAsB,EAAW,EAAW,EAAU,CAAQ,EAC3E,GACF,EAAI,gBAAgB,KAAK,CAAQ,CAErC,CACF,CAEJ,CAUA,SAAS,aACP,EACA,EACA,EACA,EACM,CACN,IAAM,EAAU,IAAI,IAAI,OAAO,KAAK,GAAY,CAAC,CAAC,CAAC,EAC7C,EAAU,IAAI,IAAI,OAAO,KAAK,GAAY,CAAC,CAAC,CAAC,EAGnD,IAAK,GAAM,CAAC,EAAU,KAAa,OAAO,QAAQ,GAAY,CAAC,CAAC,EACzD,EAAQ,IAAI,CAAQ,GACvB,EAAI,QAAQ,KAAK,CACf,KAAM,aACN,YACA,UAAW,EACX,MAAO,CACT,CAAC,EAKL,IAAK,GAAM,CAAC,EAAU,KAAa,OAAO,QAAQ,GAAY,CAAC,CAAC,EACzD,EAAQ,IAAI,CAAQ,GACvB,EAAI,QAAQ,KAAK,CACf,KAAM,eACN,YACA,UAAW,EACX,OAAQ,CACV,CAAC,EAKL,IAAK,GAAM,CAAC,EAAU,KAAY,OAAO,QAAQ,GAAY,CAAC,CAAC,EAC7D,GAAI,EAAQ,IAAI,CAAQ,EAAG,CACzB,IAAM,EAAU,EACd,EAAc,EAAU,8CAA8C,CAAC,CAAC,GACxE,SAAS,EAAS,wBACpB,EACI,IAAY,GACd,EAAI,QAAQ,KAAK,CACf,KAAM,gBACN,YACA,UAAW,EACX,OAAQ,sBACR,OAAQ,EACR,MAAO,CACT,CAAC,CAEL,CAEJ,CAWA,SAAS,qBACP,EACA,EACA,EACA,EACA,EACM,CACN,IAAM,EAAU,IAAI,IAAI,OAAO,KAAK,GAAoB,CAAC,CAAC,CAAC,EACrD,EAAU,IAAI,IAAI,OAAO,KAAK,GAAoB,CAAC,CAAC,CAAC,EAG3D,IAAK,GAAM,CAAC,EAAS,KAAQ,OAAO,QAAQ,GAAoB,CAAC,CAAC,EAC3D,EAAQ,IAAI,CAAO,GACtB,EAAI,QAAQ,KAAK,CACf,KAAM,qBACN,YACA,iBAAkB,EAClB,mBACA,MAAO,CACT,CAAC,EAKL,IAAK,GAAM,CAAC,EAAS,KAAQ,OAAO,QAAQ,GAAoB,CAAC,CAAC,EAC3D,EAAQ,IAAI,CAAO,GACtB,EAAI,QAAQ,KAAK,CACf,KAAM,uBACN,YACA,iBAAkB,EAClB,mBACA,OAAQ,CACV,CAAC,EAKL,IAAK,GAAM,CAAC,EAAS,KAAW,OAAO,QAAQ,GAAoB,CAAC,CAAC,EACnE,GAAI,EAAQ,IAAI,CAAO,EAAG,CACxB,IAAM,EAAS,EACb,EAAc,EAAkB,sDAAsD,CAAC,CACrF,GAEF,iBAAiB,EAAQ,gCAC3B,EAEM,EAAoB,CAAC,EACvB,EAAO,aAAe,EAAO,YAAY,EAAQ,KAAK,oBAAoB,EAC1E,EAAO,cAAgB,EAAO,aAAa,EAAQ,KAAK,qBAAqB,EAC7E,EAAO,cAAgB,EAAO,aAAa,EAAQ,KAAK,qBAAqB,EAC7E,EAAO,UAAY,EAAO,SAAS,EAAQ,KAAK,iBAAiB,EACjE,EAAO,cAAgB,EAAO,aAChC,EAAQ,KAAK,qBAAqB,EAGhC,EAAQ,OAAS,GACnB,EAAI,QAAQ,KAAK,CACf,KAAM,wBACN,YACA,iBAAkB,EAClB,mBACA,OAAQ,EAAQ,KAAK,IAAI,EACzB,OAAQ,EACR,MAAO,CACT,CAAC,CAEL,CAEJ,CAYA,SAAS,mBACP,EACA,EACA,EACA,EACA,EACA,EACM,CAEN,IAAM,EAA0B,2BAA2B,CAAa,EAClE,EAA0B,2BAA2B,CAAa,EAGlE,EAFe,KAAK,UAAU,GAA2B,IAE1B,IADhB,KAAK,UAAU,GAA2B,IACT,EAGhD,EAAuB,wBAAwB,CAAU,EACzD,EAAuB,wBAAwB,CAAU,EAGzD,EAFY,KAAK,UAAU,GAAwB,IAE1B,IADb,KAAK,UAAU,GAAwB,IACZ,EAE7C,GAAI,GAAqB,EAAgB,CACvC,IAAM,EAAoB,CAAC,EACvB,GAAmB,EAAQ,KAAK,mBAAmB,EACnD,GAAgB,EAAQ,KAAK,gBAAgB,EAEjD,EAAI,QAAQ,KAAK,CACf,KAAM,sBACN,YACA,OAAQ,GAAG,EAAQ,KAAK,OAAO,EAAE,UACjC,OAAQ,CAAE,iBAAkB,EAAyB,cAAe,CAAqB,EACzF,MAAO,CAAE,iBAAkB,EAAyB,cAAe,CAAqB,CAC1F,CAAC,CACH,CACF,CAEA,MAAM,GAAsD,CAC1D,IAAK,EACL,OAAQ,EACR,KAAM,EACN,OAAQ,EACR,OAAQ,EACR,UAAW,EACX,WAAY,CACd,EAKA,SAAS,WAAc,EAA0B,CAC/C,OAAO,EACJ,IAAK,GAAS,CAAC,KAAK,UAAU,CAAI,EAAG,CAAI,CAAU,CAAC,CACpD,UAAU,CAAC,GAAO,CAAC,KAAY,EAAO,EAAQ,GAAK,IAAO,EAAc,CAAC,CACzE,KAAK,EAAG,KAAU,CAAI,CAC3B,CAEA,SAAS,wBACP,EACmC,CACnC,IAAM,EAAW,GAAY,IAAK,IAAY,CAC5C,GAAG,EACH,WAAY,WAAW,EAAO,UAAU,EACxC,QAAS,EAAO,QAAQ,UACrB,EAAM,IAAU,GAAiB,GAAQ,GAAiB,EAC7D,CACF,EAAE,EACF,OAAO,GAAY,EAAS,OAAS,EAAI,WAAW,CAAQ,EAAI,IAAA,EAClE,CAEA,SAAS,2BACP,EACsC,CACjC,MACA,OAAO,OAAO,CAAU,CAAC,CAAC,KAAM,GAAa,EAAS,OAAS,CAAC,EAQrE,MAAO,CALL,OAAQ,WAAW,EAAW,OAAO,IAAI,yBAAyB,CAAC,EACnE,KAAM,WAAW,EAAW,KAAK,IAAI,yBAAyB,CAAC,EAC/D,OAAQ,WAAW,EAAW,OAAO,IAAI,yBAAyB,CAAC,EACnE,OAAQ,WAAW,EAAW,OAAO,IAAI,yBAAyB,CAAC,CAEtD,CACjB,CAEA,SAAS,0BAA0B,EAA4D,CAC7F,MAAO,CAAE,GAAG,EAAQ,WAAY,WAAW,EAAO,UAAU,CAAE,CAChE,CAEA,SAAS,iCACP,EACmC,CAC9B,KAEL,MAAO,CACL,OAAQ,EAAW,QAAU,GAC7B,OAAQ,EAAW,QAAU,GAC7B,OAAQ,EAAW,QAAU,GAC7B,KAAM,EAAW,MAAQ,EAC3B,CACF,CAEA,SAAS,4BACP,EAC8C,CAC9C,IAAM,EAA+B,CAAC,EAElC,GAAU,cAAgB,KAAM,EAAW,YAAc,IACzD,GAAU,aAAe,KAAM,EAAW,WAAa,IACvD,GAAU,gBAAkB,KAAM,EAAW,cAAgB,IAEjE,IAAM,EAAgB,iCAAiC,GAAU,aAAa,EAG9E,OAFI,IAAe,EAAW,cAAgB,GAEvC,OAAO,KAAK,CAAU,CAAC,CAAC,OAAS,EAAI,EAAa,IAAA,EAC3D,CAEA,SAAS,kBACP,EACA,EACA,EAC2B,CAC3B,MAAO,CACL,GAAI,EAAc,CAAE,aAAY,EAAI,CAAC,EACrC,aACA,GAAI,GAAY,CAAE,UAAS,CAC7B,CACF,CAEA,SAAS,uBAAuB,EAAuD,CACrF,OAAO,kBACL,EAAK,YACL,GAAW,SAAS,EAAK,WAAY,EAAI,EACzC,4BAA4B,EAAK,QAAQ,CAC3C,CACF,CAEA,SAAS,0BAA0B,EAAuD,CACxF,OAAO,kBAAkB,EAAK,YAAa,EAAK,WAAY,EAAK,UAAY,CAAC,CAAC,CACjF,CAEA,SAAS,oBACP,EACA,EACA,EACA,EACM,CACN,IAAM,EAAqB,uBAAuB,CAAQ,EACpD,EAAoB,uBAAuB,CAAO,EAEpD,KAAK,UAAU,CAAkB,IAAM,KAAK,UAAU,CAAiB,GAE3E,EAAI,QAAQ,KAAK,CACf,KAAM,0BACN,YACA,OAAQ,mBACR,OAAQ,0BAA0B,CAAQ,EAC1C,MAAO,0BAA0B,CAAO,CAC1C,CAAC,CACH,CAEA,SAAS,iBAAiB,EAA8C,CACtE,MAAO,CACL,GAAI,EAAK,cAAgB,CAAE,aAAc,EAAK,YAAa,EAC3D,GAAI,EAAK,mBAAqB,IAAA,IAAa,CAAE,iBAAkB,EAAK,gBAAiB,CACvF,CACF,CAEA,SAAS,mBACP,EACA,EACA,EACA,EACM,CACN,IAAM,EAAY,iBAAiB,CAAQ,EACrC,EAAY,iBAAiB,CAAO,EAEtC,KAAK,UAAU,CAAS,IAAM,KAAK,UAAU,CAAS,GAE1D,EAAI,QAAQ,KAAK,CACf,KAAM,yBACN,YACA,OAAQ,8BACR,OAAQ,EACR,MAAO,CACT,CAAC,CACH,CAcA,SAAS,wBACP,EACA,EAC0B,CAC1B,IAAM,EAAS,mBAAmB,EAAS,MAAM,EACjD,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAO,EAAO,EAAK,WACnB,EAAW,GAAM,OAAO,EAAK,WACnC,GAAI,CAAC,GAAQ,CAAC,EAAU,SACxB,IAAM,EAAS,mBAAmB,EAAK,MAAM,EAC7C,EAAO,EAAK,WAAa,CAAE,GAAG,EAAU,SAAU,EAAM,EACxD,EAAO,EAAK,WAAa,CAAE,GAAG,EAAM,QAAO,CAC7C,CACA,OAAO,wBAAwB,CAAE,GAAG,EAAU,QAAO,CAAC,CACxD,CAaA,SAAgB,gBACd,EACA,EACA,EACe,CAEf,MAAO,CAAE,GADI,iBAAiB,wBAAwB,EAAU,CAAK,EAAG,CACzD,EAAG,wBAAyB,EAAK,CAClD,CAiBA,SAAgB,0BACd,EACA,EAC0B,CAC1B,IAAM,EAAS,mBAAmB,EAAS,MAAM,EACjD,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAO,EAAO,EAAK,WACzB,GAAI,CAAC,EAAM,SACX,IAAM,EAAS,mBAAmB,EAAK,MAAM,EAIvC,CAAE,MAAO,EAAQ,SAAU,EAAW,GAAG,GAAY,EAAK,MAChE,EAAO,EAAK,eAAiB,CAAE,GAAG,EAAS,SAAU,GAAO,OAAQ,EAAM,EAC1E,OAAO,EAAO,EAAK,WACnB,EAAO,EAAK,WAAa,CAAE,GAAG,EAAM,QAAO,CAC7C,CACA,OAAO,wBAAwB,CAAE,GAAG,EAAU,QAAO,CAAC,CACxD,CAiCA,SAAgB,iBACd,EACA,EACA,EACe,CACf,IAAM,EAAe,GAAS,cAAgB,CAAC,EAC/C,wBAAwB,EAAU,EAAS,CAAY,EACvD,IAAM,EAAgB,IAAI,IAC1B,IAAK,IAAM,KAAU,EAAc,CACjC,IAAM,EAAO,EAAc,IAAI,EAAO,SAAS,GAAK,CAAC,EACrD,EAAK,KAAK,CAAM,EAChB,EAAc,IAAI,EAAO,UAAW,CAAI,CAC1C,CACA,IAAM,EAAsB,GAAS,qBAAuB,CAAC,EAC7D,+BAA+B,EAAU,EAAS,CAAmB,EACrE,IAAM,EAAsB,IAAI,IAChC,IAAK,IAAM,KAAU,EAAqB,CACxC,IAAM,EAAO,EAAoB,IAAI,EAAO,SAAS,GAAK,CAAC,EAC3D,EAAK,KAAK,CAAM,EAChB,EAAoB,IAAI,EAAO,UAAW,CAAI,CAChD,CACA,IAAM,EAAc,GAAS,aAAe,CAAC,EAC7C,uBAAuB,EAAU,EAAS,CAAW,EACrD,IAAM,EAAoB,IAAI,IAAI,EAAY,IAAK,GAAM,CAAC,EAAE,kBAAmB,EAAE,SAAS,CAAC,CAAC,EACtF,EAAqB,IAAI,IAAI,EAAY,IAAK,GAAM,EAAE,SAAS,CAAC,EAEhE,EAAmB,CACvB,QAAS,CAAC,EACV,gBAAiB,CAAC,EAClB,SAAU,CAAC,EACX,mBACF,EAEM,EAAoB,IAAI,IAAI,OAAO,KAAK,EAAS,MAAM,CAAC,EACxD,EAAmB,IAAI,IAAI,OAAO,KAAK,EAAQ,MAAM,CAAC,EAG5D,IAAK,IAAM,KAAU,EAAa,CAChC,IAAM,EAAW,EACf,EAAS,OAAO,EAAO,mBACvB,kBAAkB,EAAO,kBAAkB,iCAC7C,EACM,EAAW,EACf,EAAQ,OAAO,EAAO,WACtB,kBAAkB,EAAO,UAAU,gCACrC,EACA,EAAI,QAAQ,KAAK,CACf,KAAM,gBACN,UAAW,EAAO,UAClB,kBAAmB,EAAO,kBAC1B,OAAQ,EACR,MAAO,CACT,CAAC,EACD,EAAI,gBAAgB,KAAK,CACvB,UAAW,EAAO,UAClB,OAAQ,sBAAsB,EAAO,kBAAkB,MAAM,EAAO,UAAU,2DAChF,CAAC,EACD,EAAI,gBAAgB,KAAK,CACvB,UAAW,EAAO,UAClB,OACE,kCAAkC,EAAO,kBAAkB,GAAG,EAAS,WAAW,aAC/E,EAAO,UAAU,GAAG,EAAS,WAAW,4BAC/C,CAAC,CACH,CAGA,IAAK,GAAM,CAAC,EAAW,KAAS,OAAO,QAAQ,EAAQ,MAAM,EACvD,EAAmB,IAAI,CAAS,GAC/B,EAAkB,IAAI,CAAS,GAClC,EAAI,QAAQ,KAAK,CACf,KAAM,cACN,YACA,MAAO,CACT,CAAC,EAKL,IAAK,GAAM,CAAC,EAAW,KAAS,OAAO,QAAQ,EAAS,MAAM,EACxD,EAAkB,IAAI,CAAS,GAC9B,EAAiB,IAAI,CAAS,IACjC,EAAI,QAAQ,KAAK,CACf,KAAM,gBACN,YACA,OAAQ,CACV,CAAC,EACD,EAAI,SAAS,KAAK,CAChB,YACA,OAAQ,EACV,CAAC,GAKL,IAAK,IAAM,KAAa,EAAkB,CACxC,GAAI,CAAC,EAAkB,IAAI,CAAS,EAAG,SAEvC,IAAM,EAAW,EACf,EAAS,OAAO,GAChB,UAAU,EAAU,iCACtB,EACM,EAAW,EACf,EAAQ,OAAO,GACf,UAAU,EAAU,gCACtB,EAGA,oBAAoB,EAAK,EAAW,EAAU,CAAQ,EAGtD,mBAAmB,EAAK,EAAW,EAAU,CAAQ,EAGrD,kBACE,EACA,EACA,EACA,EACA,EAAc,IAAI,CAAS,EAC3B,EAAoB,IAAI,CAAS,CACnC,EAGA,eAAe,EAAK,EAAW,EAAS,QAAS,EAAS,OAAO,EAGjE,aAAa,EAAK,EAAW,EAAS,MAAO,EAAS,KAAK,EAG3D,qBACE,EACA,EACA,UACA,EAAS,qBACT,EAAS,oBACX,EACA,qBACE,EACA,EACA,WACA,EAAS,sBACT,EAAS,qBACX,EAGA,mBACE,EACA,EACA,EAAS,aAAa,OACtB,EAAS,aAAa,OACtB,EAAS,aAAa,IACtB,EAAS,aAAa,GACxB,CACF,CAEA,MAAO,CACL,QAAA,EACA,UAAW,EAAQ,UACnB,UAAW,IAAI,KAAK,CAAA,CAAE,YAAY,EAClC,QAAS,EAAI,QACb,mBAAoB,EAAI,gBAAgB,OAAS,EACjD,gBAAiB,EAAI,gBACrB,YAAa,EAAI,SAAS,OAAS,EACnC,SAAU,EAAI,SACd,wBAAyB,EAAI,gBAAgB,OAAS,CACxD,CACF,CAaA,SAAgB,8BACd,EACA,EACA,EACe,CACf,IAAM,EAAkC,CACtC,QAAA,EACA,YACA,UAAW,IAAI,KAAK,CAAA,CAAE,YAAY,EAClC,OAAQ,CACV,EACA,OAAO,iBACL,wBAAwB,CAAQ,EAChC,wBAAwB,CAAe,CACzC,CACF,CCllCA,MAKa,GAAsB,gBAGtB,GAA8B,wBAG9B,GAA+B,0BAoD5C,SAAgB,uBAAuB,EAAiC,CAEtE,OADkB,IAAyB,sBAAsB,CAAe,EAAA,CAC/D,MAAM,EAAA,EAAmB,CAC5C,CAOA,SAAgB,0BAA0B,EAA8B,CACtE,GAAI,CAAC,EAAM,WAAW,GAAsB,EAAG,OAAO,KACtD,IAAM,EAAS,EAAM,MAAM,CAA6B,EAIxD,GAAI,CAAC,QAAQ,KAAK,CAAM,EAAG,OAAO,KAClC,IAAM,EAAM,SAAS,EAAQ,EAAE,EAC/B,OAAO,EAAM,KAAO,KAAO,CAC7B,CAOA,SAAgB,wBAAwB,EAA8B,CACpE,OAAO,GAA6B,KAAK,CAAK,EAAI,EAAQ,IAC5D,CAMA,SAAgB,0BAAmC,CACjD,MAAO,IAAI,GAAW,CAAC,CAAC,WAAW,IAAK,EAAE,GAC5C,CAqBA,SAAgB,8BAA8B,EAAgB,EAA2B,CACvF,GACE,aAAiB,GACjB,EAAM,OAAS,EAAK,oBACpB,EAAM,QAAQ,SAAS,oEAAoE,EAC3F,CACA,EAAO,MACL,yFACF,EACA,EAAO,QAAQ,EACf,IAAK,IAAM,KAAW,EACpB,EAAO,KAAK,CAAO,CAEvB,CACA,MAAM,CACR,CC9FA,SAAS,qBAAwB,EAAyD,CACxF,OAAO,EACJ,OACE,GAAU,OAAO,GAAU,YAAY,GAAkB,CAAC,MAAM,QAAQ,CAAK,EAC9E,CAAE,QAAS,iBAAkB,CAC/B,CAAC,CACA,WAAW,EAAO,IAAQ,CACzB,IAAM,EAAS,OAAO,OAAO,IAAI,EACjC,IAAK,IAAM,KAAO,OAAO,KAAK,CAAK,EAAG,CACpC,IAAM,EAAS,EAAY,UAAU,EAAM,EAAI,EAC/C,GAAI,CAAC,EAAO,QAAS,CACnB,IAAK,IAAM,KAAS,EAAO,MAAM,OAC/B,EAAI,SAAS,CAAE,GAAG,EAAO,KAAM,CAAC,EAAK,GAAG,EAAM,IAAI,CAAE,CAAC,EAEvD,QACF,CACA,EAAO,GAAO,EAAO,IACvB,CACA,OAAO,CACT,CAAC,CACL,CAMA,MAAM,GAA8C,EAAE,YAAY,CAChE,KAAM,EAAE,OAAO,CACjB,CAAC,EAEK,GAA0D,EAAE,YAAY,CAC5E,OAAQ,EAAE,YAAY,CAAE,KAAM,EAAE,OAAO,CAAE,CAAC,CAAC,CAAC,SAAS,EACrD,aAAc,EAAE,OAAO,CACzB,CAAC,EAEK,GAAkD,EAAE,YAAY,CACpE,MAAO,EAAE,OAAO,EAChB,SAAU,EAAE,OAAO,CAAC,CAAC,SAAS,EAC9B,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,CAC9B,CAAC,EAEK,GAAwD,EAAE,YAAY,CAC1E,MAAO,EAAE,OAAO,EAChB,YAAa,EAAE,OAAO,CAAC,CAAC,SAAS,CACnC,CAAC,EAIK,GAA4D,EAAE,YAAY,CAC9E,KAAM,EAAE,OAAO,EAEf,SAAU,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAI,EAClC,MAAO,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC5B,MAAO,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC5B,OAAQ,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC7B,cAAe,EAAE,MAAM,EAAuB,CAAC,CAAC,SAAS,EACzD,WAAY,EAAE,QAAQ,CAAC,CAAC,SAAS,EACjC,eAAgB,EAAE,OAAO,CAAC,CAAC,SAAS,EACpC,gBAAiB,EAAE,OAAO,CAAC,CAAC,SAAS,EACrC,YAAa,EAAE,OAAO,CAAC,CAAC,SAAS,EACjC,OAAQ,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC7B,MAAO,EACJ,YAAY,CACX,OAAQ,GAAmB,SAAS,EACpC,OAAQ,GAAmB,SAAS,CACtC,CAAC,CAAC,CACD,SAAS,EACZ,SAAU,EAAE,MAAM,EAAwB,CAAC,CAAC,SAAS,EACrD,OAAQ,GAAqB,SAAS,EACtC,MAAO,EAAE,OAAO,CAAC,CAAC,SAAS,EAC3B,QAAS,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC9B,OAAQ,EAAE,SAAW,qBAAqB,EAAyB,CAAC,CAAC,CAAC,SAAS,CACjF,CAAC,EAEK,GAA4D,EAAE,YAAY,CAC9E,OAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAC1B,OAAQ,EAAE,QAAQ,CAAC,CAAC,SAAS,CAC/B,CAAC,EAEK,GAA8D,EAAE,YAAY,CAChF,WAAY,EAAE,OAAO,EACrB,YAAa,EAAE,OAAO,EACtB,YAAa,EAAE,OAAO,EACtB,QAAS,EAAE,QAAQ,EACnB,YAAa,EAAE,OAAO,CACxB,CAAC,EAOK,GAAiB,CAAC,OAAQ,SAAU,YAAa,WAAW,EAI5D,GAAkC,EAAE,QAAQ,CAAC,CAAC,OAAQ,GAAM,CAChE,GAAI,OAAO,GAAM,WAAY,GAAc,MAAM,QAAQ,CAAC,EAAG,MAAO,GACpE,IAAM,EAAO,OAAO,KAAK,CAAC,EAE1B,OADoB,GAAe,OAAQ,GAAM,EAAK,SAAS,CAAC,CAAC,CAAC,CAAC,OAC9C,CACvB,EAAG,wFAAwF,EAGrF,GAAqC,EACxC,QAAQ,CAAC,CACT,OAAQ,GAAM,CACb,GAAI,OAAO,GAAM,WAAY,GAAc,MAAM,QAAQ,CAAC,EAAG,MAAO,GACpE,IAAM,EAAO,OAAO,KAAK,CAAC,EAE1B,OADoB,GAAe,OAAQ,GAAM,EAAK,SAAS,CAAC,CAAC,CAAC,CAAC,OAC9C,CACvB,EAAG,wFAAwF,CAAC,CAC3F,OAAQ,GAAM,CACb,GAAI,OAAO,GAAM,WAAY,GAAc,MAAM,QAAQ,CAAC,EAAG,MAAO,GACpE,IAAM,EAAO,OAAO,KAAK,CAAC,EAC1B,MAAO,CAAC,CAAC,SAAU,YAAa,WAAW,CAAC,CAAC,KAAM,GAAM,EAAK,SAAS,CAAC,CAAC,CAC3E,EAAG,wDAAwD,EAGvD,GAAmC,EAAE,OAAO,EAG5C,GAAoC,EACvC,MAAM,CACL,GACA,GACA,EACF,CAAC,CAAC,CACD,KAAK,EAAE,QAAQ,CAAC,EAEb,GAAuC,EAC1C,MAAM,CACL,GACA,GACA,EACF,CAAC,CAAC,CACD,KAAK,EAAE,QAAQ,CAAC,EAEb,GAAsE,EAAE,YAAY,CACxF,WAAY,EAAE,MAAM,EAAiC,EACrD,YAAa,EAAE,OAAO,CAAC,CAAC,SAAS,EACjC,OAAQ,EAAE,KAAK,CAAC,QAAS,MAAM,CAAC,CAClC,CAAC,EAEK,GAAsE,EAAE,YAAY,CACxF,OAAQ,EAAE,MAAM,EAA8B,CAAC,CAAC,QAAQ,CAAC,CAAC,EAC1D,KAAM,EAAE,MAAM,EAA8B,CAAC,CAAC,QAAQ,CAAC,CAAC,EACxD,OAAQ,EAAE,MAAM,EAA8B,CAAC,CAAC,QAAQ,CAAC,CAAC,EAC1D,OAAQ,EAAE,MAAM,EAA8B,CAAC,CAAC,QAAQ,CAAC,CAAC,CAC5D,CAAC,EAGK,GAA0B,EAAE,OAAO,EAEnC,GAA4E,EAAE,YAAY,CAC9F,WAAY,EAAE,MAAM,EAAoC,EACxD,QAAS,EAAE,MAAM,EAAuB,EACxC,OAAQ,EAAE,KAAK,CAAC,QAAS,MAAM,CAAC,EAChC,YAAa,EAAE,OAAO,CAAC,CAAC,SAAS,CACnC,CAAC,EAGK,GAAgE,EAAE,MACtE,EACF,EAMM,GAA8D,EAAE,YAAY,CAChF,KAAM,EAAE,OAAO,EAGf,WAAY,EAAE,OAAO,CAAC,CAAC,SAAS,EAChC,YAAa,EAAE,OAAO,CAAC,CAAC,SAAS,EACjC,OAAQ,qBAAqB,EAAyB,EACtD,SAAU,EACP,YAAY,CACX,YAAa,EAAE,QAAQ,CAAC,CAAC,SAAS,EAClC,WAAY,EAAE,QAAQ,CAAC,CAAC,SAAS,EACjC,cAAe,EACZ,YAAY,CACX,OAAQ,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC7B,OAAQ,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC7B,OAAQ,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC7B,KAAM,EAAE,QAAQ,CAAC,CAAC,SAAS,CAC7B,CAAC,CAAC,CACD,SAAS,EACZ,cAAe,EAAE,QAAQ,CAAC,CAAC,SAAS,CACtC,CAAC,CAAC,CACD,SAAS,EACZ,QAAS,qBAAqB,EAAyB,CAAC,CAAC,SAAS,EAClE,MAAO,qBAAqB,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,EACjD,qBAAsB,qBAAqB,EAA0B,CAAC,CAAC,SAAS,EAChF,sBAAuB,qBAAqB,EAA0B,CAAC,CAAC,SAAS,EACjF,YAAa,EACV,YAAY,CACX,OAAQ,GAA+B,SAAS,EAChD,IAAK,GAA4B,SAAS,CAC5C,CAAC,CAAC,CACD,SAAS,CACd,CAAC,EAMK,GAAsD,EAAE,YAAY,CACxE,UAAW,EAAE,OAAO,CAAC,CAAC,MAAM,EAA4B,EACxD,kBAAmB,EAAE,OAAO,CAAC,CAAC,MAAM,EAA4B,CAAC,CAAC,SAAS,EAC3E,wBAAyB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAC3D,CAAC,EAEY,GAAkD,EAAE,YAAY,CAC3E,QAAS,EAAE,OAAO,EAClB,UAAW,EAAE,OAAO,EACpB,UAAW,EAAE,OAAO,EACpB,OAAQ,qBAAqB,EAA0B,EACvD,WAAY,GAAuB,SAAS,CAC9C,CAAC,EAMK,GAAwD,EAAE,YAAY,CAC1E,QAAS,qBAAqB,EAAyB,CAAC,CAAC,SAAS,EAClE,MAAO,qBAAqB,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CACnD,CAAC,EAEK,GAAwE,EAAE,YAAY,CAC1F,YAAa,EAAE,OAAO,CAAC,CAAC,SAAS,EACjC,WAAY,EAAE,OAAO,EACrB,SAAU,EACP,YAAY,CACX,YAAa,EAAE,QAAQ,CAAC,CAAC,SAAS,EAClC,WAAY,EAAE,QAAQ,CAAC,CAAC,SAAS,EACjC,cAAe,EACZ,YAAY,CACX,OAAQ,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC7B,OAAQ,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC7B,OAAQ,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC7B,KAAM,EAAE,QAAQ,CAAC,CAAC,SAAS,CAC7B,CAAC,CAAC,CACD,SAAS,EACZ,cAAe,EAAE,QAAQ,CAAC,CAAC,SAAS,CACtC,CAAC,CAAC,CACD,SAAS,CACd,CAAC,EAEK,GAAoE,EAAE,YAAY,CACtF,iBAAkB,GAA+B,SAAS,EAC1D,cAAe,GAA4B,SAAS,CACtD,CAAC,EAIK,GAAwB,EAAE,YAAY,CAC1C,KAAM,EAAE,QAAQ,aAAa,EAC7B,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,MAAO,EACT,CAAC,EAEK,GAA0B,EAAE,YAAY,CAC5C,KAAM,EAAE,QAAQ,eAAe,EAC/B,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,OAAQ,EACV,CAAC,EAEK,GAA0B,EAAE,YAAY,CAC5C,KAAM,EAAE,QAAQ,eAAe,EAC/B,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,kBAAmB,EAAE,OAAO,EAC5B,OAAQ,GACR,MAAO,EACT,CAAC,EAEK,GAA2B,EAAE,YAAY,CAC7C,KAAM,EAAE,QAAQ,gBAAgB,EAChC,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,OAAQ,GAAwB,SAAS,EACzC,MAAO,GAAwB,SAAS,CAC1C,CAAC,EAEK,GAAmC,EAAE,YAAY,CACrD,KAAM,EAAE,QAAQ,yBAAyB,EACzC,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,OAAQ,GACR,MAAO,EACT,CAAC,EAEK,GAAyB,EAAE,YAAY,CAC3C,KAAM,EAAE,QAAQ,aAAa,EAC7B,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,UAAW,EAAE,OAAO,EACpB,MAAO,EACT,CAAC,EAEK,GAA2B,EAAE,YAAY,CAC7C,KAAM,EAAE,QAAQ,eAAe,EAC/B,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,UAAW,EAAE,OAAO,EACpB,OAAQ,EACV,CAAC,EAEK,GAA4B,EAAE,YAAY,CAC9C,KAAM,EAAE,QAAQ,gBAAgB,EAChC,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,UAAW,EAAE,OAAO,EACpB,OAAQ,GACR,MAAO,GACP,cAAe,EACZ,MACC,EACG,YAAY,CACX,aAAc,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EACvC,KAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CACjC,CAAC,CAAC,CACD,QACE,CAAE,eAAc,UACf,EAAa,SAAW,EAAK,QAC7B,EAAa,MAAM,EAAG,EAAE,CAAC,CAAC,OAAO,EAAS,IAAU,IAAY,EAAK,EAAM,GAC3E,EAAa,GAAG,EAAE,IAAM,EAAK,GAAG,EAAE,EACpC,CAAE,QAAS,8DAA+D,CAC5E,CACJ,CAAC,CACA,SAAS,CACd,CAAC,EAEK,GAA2B,EAAE,YAAY,CAC7C,KAAM,EAAE,QAAQ,eAAe,EAC/B,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,UAAW,EAAE,OAAO,EACpB,kBAAmB,EAAE,OAAO,EAC5B,OAAQ,GACR,MAAO,EACT,CAAC,EAEK,GAAgC,EAAE,YAAY,CAClD,KAAM,EAAE,QAAQ,qBAAqB,EACrC,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,UAAW,EAAE,OAAO,EACpB,OAAQ,GACR,MAAO,EACT,CAAC,EAEK,GAAyB,EAAE,YAAY,CAC3C,KAAM,EAAE,QAAQ,aAAa,EAC7B,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,UAAW,EAAE,OAAO,EACpB,MAAO,EACT,CAAC,EAEK,GAA2B,EAAE,YAAY,CAC7C,KAAM,EAAE,QAAQ,eAAe,EAC/B,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,UAAW,EAAE,OAAO,EACpB,OAAQ,EACV,CAAC,EAEK,GAA4B,EAAE,YAAY,CAC9C,KAAM,EAAE,QAAQ,gBAAgB,EAChC,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,UAAW,EAAE,OAAO,EACpB,OAAQ,GACR,MAAO,EACT,CAAC,EAEK,GAAwB,EAAE,YAAY,CAC1C,KAAM,EAAE,QAAQ,YAAY,EAC5B,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,UAAW,EAAE,OAAO,EACpB,MAAO,EAAE,OAAO,CAClB,CAAC,EAEK,GAA0B,EAAE,YAAY,CAC5C,KAAM,EAAE,QAAQ,cAAc,EAC9B,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CACnB,CAAC,EAEK,GAA2B,EAAE,YAAY,CAC7C,KAAM,EAAE,QAAQ,eAAe,EAC/B,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,EACjB,MAAO,EAAE,OAAO,CAClB,CAAC,EAEK,GAAgC,EAAE,YAAY,CAClD,KAAM,EAAE,QAAQ,oBAAoB,EACpC,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,iBAAkB,EAAE,OAAO,EAC3B,iBAAkB,EAAE,KAAK,CAAC,UAAW,UAAU,CAAC,CAAC,CAAC,SAAS,EAC3D,MAAO,EACT,CAAC,EAEK,GAAkC,EAAE,YAAY,CACpD,KAAM,EAAE,QAAQ,sBAAsB,EACtC,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,iBAAkB,EAAE,OAAO,EAC3B,iBAAkB,EAAE,KAAK,CAAC,UAAW,UAAU,CAAC,CAAC,CAAC,SAAS,EAC3D,OAAQ,EACV,CAAC,EAEK,GAAmC,EAAE,YAAY,CACrD,KAAM,EAAE,QAAQ,uBAAuB,EACvC,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,iBAAkB,EAAE,OAAO,EAC3B,iBAAkB,EAAE,KAAK,CAAC,UAAW,UAAU,CAAC,CAAC,CAAC,SAAS,EAC3D,OAAQ,GACR,MAAO,EACT,CAAC,EAEK,GAAiC,EAAE,YAAY,CACnD,KAAM,EAAE,QAAQ,qBAAqB,EACrC,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,OAAQ,GAA8B,SAAS,EAC/C,MAAO,GAA8B,SAAS,CAChD,CAAC,EAEK,GAAsD,EAAE,YAAY,CACxE,aAAc,EACX,YAAY,CACX,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,CAC9B,CAAC,CAAC,CACD,SAAS,EACZ,iBAAkB,EAAE,OAAO,CAAC,CAAC,SAAS,CACxC,CAAC,EAEK,GAAkC,EAAE,YAAY,CACpD,KAAM,EAAE,QAAQ,wBAAwB,EACxC,UAAW,EAAE,OAAO,EACpB,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,OAAQ,GACR,MAAO,EACT,CAAC,EAIK,GAA0C,EAAE,mBAAmB,OAAQ,CAC3E,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,EACF,CAAC,EAEK,GAA0D,EAAE,YAAY,CAC5E,UAAW,EAAE,OAAO,EACpB,UAAW,EAAE,OAAO,CAAC,CAAC,SAAS,EAC/B,OAAQ,EAAE,OAAO,EACjB,YAAa,EAAE,QAAQ,CAAC,CAAC,SAAS,EAClC,kBAAmB,EAAE,QAAQ,CAAC,CAAC,SAAS,CAC1C,CAAC,EAEK,GAAwD,EAAE,YAAY,CAC1E,UAAW,EAAE,OAAO,EACpB,UAAW,EAAE,OAAO,CAAC,CAAC,SAAS,EAC/B,OAAQ,EAAE,OAAO,CACnB,CAAC,EAEK,GAAwD,EAAE,YAAY,CAC1E,OAAQ,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAC/B,eAAgB,EAAE,OAAO,CAC3B,CAAC,EAKY,GAAgD,EAAE,YAAY,CACzE,QAAS,EAAE,OAAO,EAClB,UAAW,EAAE,OAAO,EACpB,UAAW,EAAE,OAAO,EACpB,YAAa,EAAE,OAAO,CAAC,CAAC,SAAS,EACjC,QAAS,EAAE,MAAM,EAAgB,EACjC,mBAAoB,EAAE,QAAQ,EAC9B,gBAAiB,EAAE,MAAM,EAAwB,EAEjD,YAAa,EAAE,QAAQ,CAAC,CAAC,SAAS,EAClC,SAAU,EAAE,MAAM,EAAuB,CAAC,CAAC,SAAS,EACpD,wBAAyB,EAAE,QAAQ,EACnC,cAAe,GAAwB,SAAS,CAClD,CAAC,ECljBY,GAAwB,EAKxB,GAAmB,cAEnB,GAAiB,YAEjB,GAAoB,aAEpB,GAAyB,kBAEzB,GAAqB,QAErB,GAA6B,eAE7B,GAAgC,yBAMhC,GAA2B,UA0BxC,SAAgB,uBAAuB,EAA4B,CACjE,OAAO,GAAyB,KAAK,CAAS,CAChD,CASA,MAAa,GAA0D,CACrE,OAAQ,GACR,KAAM,GACN,QAAS,GACT,KAAM,GACN,GAAI,GACJ,aAAc,GACd,WAAY,EACd,EAQA,SAAgB,oBAAoB,EAAuB,EAAqB,CAC9E,IAAM,EAAS,sBAAsB,CAAG,EACxC,OAAO,EAAK,KAAK,EAAe,CAAM,CACxC,CASA,SAAgB,qBACd,EACA,EACA,EACQ,CACR,IAAM,EAAe,oBAAoB,EAAe,CAAG,EAC3D,OAAO,EAAK,KAAK,EAAc,GAAqB,EAAK,CAC3D,CAWA,SAAgB,aAAa,EAA4C,CACvE,IAAM,EAAUC,EAAG,aAAa,EAAU,OAAO,EAC7C,EACJ,GAAI,CACF,EAAM,KAAK,MAAM,CAAO,CAC1B,OAAS,EAAO,CACd,MAAM,EAAS,CACb,KAAM,yBACN,QAAS,8BAA8B,EAAS,IAAI,OAAO,CAAK,IAChE,MAAO,CACT,CAAC,CACH,CACA,oCAAoC,EAAU,CAAG,EACjD,IAAM,EAAS,GAAqB,UAAU,yBAAyB,CAAG,CAAC,EAC3E,GAAI,CAAC,EAAO,QACV,MAAM,EAAS,CACb,KAAM,yBACN,QAAS,8BAA8B,EAAS,IAAI,EAAE,cAAc,EAAO,KAAK,IAChF,MAAO,EAAO,KAChB,CAAC,EAEH,IAAM,EAAW,EAAO,KACxB,OAAO,wBAAwB,CAAQ,CACzC,CAOA,SAAgB,SAAS,EAAiC,CACxD,IAAM,EAAUA,EAAG,aAAa,EAAU,OAAO,EAC7C,EACJ,GAAI,CACF,EAAM,KAAK,MAAM,CAAO,CAC1B,OAAS,EAAO,CACd,MAAM,EAAS,CACb,KAAM,yBACN,QAAS,6BAA6B,EAAS,IAAI,OAAO,CAAK,IAC/D,MAAO,CACT,CAAC,CACH,CACA,oCAAoC,EAAU,CAAG,EACjD,IAAM,EAAS,GAAoB,UACjC,0BAA0B,2BAA2B,CAAG,CAAC,CAC3D,EACA,GAAI,CAAC,EAAO,QACV,MAAM,EAAS,CACb,KAAM,yBACN,QAAS,6BAA6B,EAAS,IAAI,EAAE,cAAc,EAAO,KAAK,IAC/E,MAAO,EAAO,KAChB,CAAC,EAEH,IAAM,EAAS,EAAO,KAShB,EAAW,EAAO,UAAY,0BAA0B,CAAM,EACpE,MAAO,CACL,GAAG,EACH,WACA,YAAa,EAAS,OAAS,CACjC,CACF,CAOA,SAAgB,kBACd,EAC6D,CAC7D,GAAI,CAACA,EAAG,WAAW,CAAa,EAC9B,MAAO,CAAC,EAGV,IAAM,EAAUA,EAAG,YAAY,EAAe,CAAE,cAAe,EAAK,CAAC,EAC/D,EAIA,CAAC,EAEP,IAAK,IAAM,KAAS,EAAS,CAG3B,GADI,CAAC,EAAM,YAAY,GACnB,CAAC,uBAAuB,EAAM,IAAI,EAAG,SAEzC,IAAM,EAAM,SAAS,EAAM,KAAM,EAAE,EAC7B,EAAe,EAAK,KAAK,EAAe,EAAM,IAAI,EAGlD,EAAa,EAAK,KAAK,EAAc,EAAgB,EACvDA,EAAG,WAAW,CAAU,GAC1B,EAAW,KAAK,CACd,OAAQ,EACR,KAAM,SACN,KAAM,CACR,CAAC,EAIH,IAAM,EAAW,EAAK,KAAK,EAAc,EAAc,EACnDA,EAAG,WAAW,CAAQ,GACxB,EAAW,KAAK,CACd,OAAQ,EACR,KAAM,OACN,KAAM,CACR,CAAC,CAEL,CAGA,OAAO,EAAW,UAAU,EAAG,IAAM,EAAE,OAAS,EAAE,MAAM,CAC1D,CAQA,SAAgB,uBAAuB,EAA+B,CACpE,IAAM,EAAQ,kBAAkB,CAAa,EAE7C,OADI,EAAM,SAAW,EAAG,EACjB,KAAK,IAAI,GAAG,EAAM,IAAK,GAAM,EAAE,MAAM,CAAC,EAAI,CACnD,CAQA,SAAgB,yBAAyB,EAA+B,CACtE,OAAO,sBAAsB,kBAAkB,CAAa,CAAC,CAC/D,CAEA,SAAS,sBAAsB,EAAqC,CAElE,OADI,EAAM,SAAW,EAAU,EACxB,KAAK,IAAI,GAAG,EAAM,IAAK,GAAM,EAAE,MAAM,CAAC,CAC/C,CAaA,SAAgB,4BACd,EACA,EACQ,CACR,IAAM,EAAQ,kBAAkB,CAAa,EAC7C,GAAI,IAAoB,GAAK,CAAC,EAAM,KAAM,GAAM,EAAE,SAAW,CAAe,EAC1E,MAAM,EAAS,CACb,KAAM,sBACN,QAAS,aAAa,sBAAsB,CAAe,EAAE,6CAA6C,sBAAsB,sBAAsB,CAAK,CAAC,EAAE,GAChK,CAAC,EAEH,OAAO,sBAAsB,CAAK,CACpC,CChSA,SAAgB,oBACd,EACA,EAC0B,CAC1B,IAAM,EAAS,mBAAmB,EAAS,MAAM,EAEjD,IAAK,IAAM,KAAU,EAAK,QACxB,OAAQ,EAAO,KAAf,CACE,IAAK,cACH,EAAO,EAAO,WAAa,EAAO,MAClC,MACF,IAAK,gBACH,OAAO,EAAO,EAAO,WACrB,MACF,IAAK,iBAAkB,CACrB,IAAM,EAAW,EAAO,EAAO,WAC/B,GAAI,GAAY,EAAO,MAAO,CAC5B,IAAM,EAAQ,EAAO,MACrB,EAAO,EAAO,WAAa,CACzB,GAAG,EACH,GAAI,EAAM,UAAY,IAAA,IAAa,CAAE,QAAS,EAAM,OAAQ,EAC5D,GAAI,EAAM,QAAU,IAAA,IAAa,CAAE,MAAO,EAAM,KAAM,CACxD,CACF,CACA,KACF,CACA,IAAK,0BAA2B,CAC9B,IAAM,EAAW,EAAO,EAAO,WAC3B,IACF,EAAO,EAAO,WAAa,CACzB,GAAG,EACH,YAAa,EAAO,MAAM,YAC1B,WAAY,EAAO,MAAM,WACzB,SAAU,EAAO,MAAM,UAAY,CAAC,CACtC,GAEF,KACF,CACA,IAAK,yBAA0B,CAC7B,IAAM,EAAW,EAAO,EAAO,WAC/B,GAAI,EAAU,CACZ,GAAM,CAAE,aAAc,EAAG,iBAAkB,EAAI,GAAG,GAAS,EAC3D,EAAO,EAAO,WAAa,CACzB,GAAG,EACH,GAAI,EAAO,MAAM,cAAgB,CAAE,aAAc,EAAO,MAAM,YAAa,EAC3E,GAAI,EAAO,MAAM,mBAAqB,IAAA,IAAa,CACjD,iBAAkB,EAAO,MAAM,gBACjC,CACF,CACF,CACA,KACF,CACA,IAAK,cACL,IAAK,iBACL,IAAK,sBAAuB,CAC1B,IAAM,EAAW,EAAO,EAAO,WAC/B,GAAI,EAAU,CACZ,IAAM,EAAS,mBAAmB,EAAS,MAAM,EACjD,EAAO,EAAO,WAAa,EAAO,MAClC,EAAO,EAAO,WAAa,CACzB,GAAG,EACH,QACF,CACF,CACA,KACF,CACA,IAAK,gBAAiB,CACpB,IAAM,EAAW,EAAO,EAAO,WAC/B,GAAI,EAAU,CACZ,IAAM,EAAkB,mBAAmB,EAAS,MAAM,EAC1D,OAAO,EAAgB,EAAO,WAC9B,EAAO,EAAO,WAAa,CACzB,GAAG,EACH,OAAQ,CACV,CACF,CACA,KACF,CACA,IAAK,gBAAiB,CACpB,IAAM,EAAW,EAAO,EAAO,WAC/B,GAAI,EAAU,CACZ,IAAM,EAAS,mBAAmB,EAAS,MAAM,EACjD,OAAO,EAAO,EAAO,mBACrB,EAAO,EAAO,WAAa,EAAO,MAClC,EAAO,EAAO,WAAa,CACzB,GAAG,EACH,QACF,CACF,CACA,KACF,CACA,IAAK,gBACH,OAAO,EAAO,EAAO,mBACrB,EAAO,EAAO,WAAa,EAAO,MAClC,MACF,IAAK,cACL,IAAK,iBAAkB,CACrB,IAAM,EAAW,EAAO,EAAO,WAC/B,GAAI,EAAU,CACZ,IAAM,EAAU,mBAAmB,EAAS,OAAO,EACnD,EAAQ,EAAO,WAAa,EAAO,MACnC,EAAO,EAAO,WAAa,CACzB,GAAG,EACH,SACF,CACF,CACA,KACF,CACA,IAAK,gBAAiB,CACpB,IAAM,EAAW,EAAO,EAAO,WAC/B,GAAI,GAAY,EAAS,QAAS,CAChC,IAAM,EAAmB,mBAAmB,EAAS,OAAO,EAC5D,OAAO,EAAiB,EAAO,WAC/B,EAAO,EAAO,WAAa,CACzB,GAAG,EACH,QAAS,OAAO,KAAK,CAAgB,CAAC,CAAC,OAAS,EAAI,EAAmB,IAAA,EACzE,CACF,CACA,KACF,CACA,IAAK,aACL,IAAK,gBAAiB,CACpB,IAAM,EAAW,EAAO,EAAO,WAC/B,GAAI,EAAU,CACZ,IAAM,EAAQ,mBAAmB,EAAS,KAAK,EAC/C,EAAM,EAAO,WAAa,EAAO,MACjC,EAAO,EAAO,WAAa,CACzB,GAAG,EACH,OACF,CACF,CACA,KACF,CACA,IAAK,eAAgB,CACnB,IAAM,EAAW,EAAO,EAAO,WAC/B,GAAI,GAAY,EAAS,MAAO,CAC9B,IAAM,EAAiB,mBAAmB,EAAS,KAAK,EACxD,OAAO,EAAe,EAAO,WAC7B,EAAO,EAAO,WAAa,CACzB,GAAG,EACH,MAAO,OAAO,KAAK,CAAc,CAAC,CAAC,OAAS,EAAI,EAAiB,IAAA,EACnE,CACF,CACA,KACF,CACA,IAAK,qBACL,IAAK,wBAAyB,CAC5B,IAAM,EAAW,EAAO,EAAO,WAC/B,GAAI,EAAU,CACZ,IAAM,EAAM,EAAO,MAUnB,IAPE,EAAO,mBACN,EAAS,uBAAuB,EAAO,kBACpC,UACA,EAAS,wBAAwB,EAAO,kBACtC,WACA,cAEW,UAAW,CAC5B,IAAM,EAAuB,mBAAmB,EAAS,oBAAoB,EAC7E,EAAqB,EAAO,kBAAoB,EAChD,EAAO,EAAO,WAAa,CACzB,GAAG,EACH,sBACF,CACF,KAAO,CACL,IAAM,EAAwB,mBAAmB,EAAS,qBAAqB,EAC/E,EAAsB,EAAO,kBAAoB,EACjD,EAAO,EAAO,WAAa,CACzB,GAAG,EACH,uBACF,CACF,CACF,CACA,KACF,CACA,IAAK,uBAAwB,CAC3B,IAAM,EAAO,EAAO,EAAO,WAC3B,GAAI,EAAM,CAER,IAAM,EACJ,EAAO,mBACN,EAAK,uBAAuB,EAAO,kBAChC,UACA,EAAK,wBAAwB,EAAO,kBAClC,WACA,MAER,GAAI,IAAe,WAAa,EAAK,uBAAuB,EAAO,kBAAmB,CACpF,IAAM,EAAY,mBAAmB,EAAK,oBAAoB,EAC9D,OAAO,EAAU,EAAO,kBACxB,EAAO,EAAO,WAAa,CACzB,GAAG,EACH,qBAAsB,OAAO,KAAK,CAAS,CAAC,CAAC,OAAS,EAAI,EAAY,IAAA,EACxE,CACF,MAAO,GACL,IAAe,YACf,EAAK,wBAAwB,EAAO,kBACpC,CACA,IAAM,EAAY,mBAAmB,EAAK,qBAAqB,EAC/D,OAAO,EAAU,EAAO,kBACxB,EAAO,EAAO,WAAa,CACzB,GAAG,EACH,sBAAuB,OAAO,KAAK,CAAS,CAAC,CAAC,OAAS,EAAI,EAAY,IAAA,EACzE,CACF,CACF,CACA,KACF,CACA,IAAK,sBAAuB,CAC1B,IAAM,EAAW,EAAO,EAAO,WAC/B,GAAI,GAAY,EAAO,MAAO,CAC5B,IAAM,EAAQ,EAAO,MACrB,EAAO,EAAO,WAAa,CACzB,GAAG,EACH,YAAa,CACX,OAAQ,EAAM,iBACd,IAAK,EAAM,aACb,CACF,CACF,CACA,KACF,CACF,CAGF,OAAO,wBAAwB,CAC7B,GAAG,EACH,SACA,UAAW,EAAK,SAClB,CAAC,CACH,CASA,SAAgB,kCACd,EACA,EACiC,CACjC,IAAM,EAAQ,kBAAkB,CAAa,EAC7C,GAAI,EAAM,SAAW,EAAG,OAAO,KAG/B,IAAM,EAAa,EAAM,KAAM,GAAM,EAAE,OAAS,UAAY,EAAE,SAAA,CAAgC,EAC9F,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,+BACN,QAAS,mCAAmC,EAAc,aAAa,sBAAA,CAEvE,EAAE,aACJ,CAAC,EAGH,IAAI,EAAW,aAAa,EAAW,IAAI,EAG3C,IAAK,IAAM,KAAQ,EACjB,GAAI,EAAK,OAAS,QAAU,EAAK,OAAS,EAAW,OAAQ,CAE3D,GAAI,IAAe,IAAA,IAAa,EAAK,OAAS,EAC5C,SAEF,IAAM,EAAO,SAAS,EAAK,IAAI,EAC/B,EAAW,oBAAoB,EAAU,CAAI,CAC/C,CAGF,OAAO,CACT,CA0BA,SAAgB,uBAAuB,EAAmD,CACxF,IAAM,EAAqC,CAAC,EAE5C,GAAI,CAACC,EAAG,WAAW,CAAa,EAE9B,OAAO,EAIT,IAAM,EAAiB,kBAAkB,CAAa,EACtD,GAAI,EAAe,SAAW,EAE5B,OAAO,EAIT,IAAM,EAAwB,CAAC,EACzB,EAAsB,CAAC,EAE7B,IAAK,IAAM,KAAQ,EACb,EAAK,OAAS,SAChB,EAAY,KAAK,EAAK,MAAM,EAE5B,EAAU,KAAK,EAAK,MAAM,EAKzB,EAAY,SAAA,CAA8B,GAC7C,EAAO,KAAK,CACV,KAAM,iBACN,QAAS,4BAA4B,sBAAA,CAErC,EAAE,0BACF,gBAAA,CACF,CAAC,EAIH,IAAK,IAAM,KAAO,EACZ,IAAA,GACF,EAAO,KAAK,CACV,KAAM,wBACN,QAAS,kCAAkC,sBACzC,CACF,EAAE,oCAAoC,sBAAA,CAA2C,IACjF,gBAAiB,CACnB,CAAC,EAKL,IAAM,EAAa,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAa,GAAG,CAAS,CAAC,CAAC,CAAC,CAAC,UAAU,EAAG,IAAM,EAAI,CAAC,EAExF,GAAI,EAAW,SAAW,EACxB,OAAO,EAIT,IAAK,IAAM,KAAO,EACZ,IAAA,GAAiC,EAAU,SAAS,CAAG,GACzD,EAAO,KAAK,CACV,KAAM,YACN,QAAS,aAAa,sBAAsB,CAAG,EAAE,iCACjD,gBAAiB,CACnB,CAAC,EAKL,IAAM,EAAS,KAAK,IAAI,GAAG,CAAU,EACrC,IAAK,IAAI,EAAA,EAA2B,GAAK,EAAQ,IAC1C,EAAW,SAAS,CAAC,GACxB,EAAO,KAAK,CACV,KAAM,MACN,QAAS,aAAa,sBAAsB,CAAC,EAAE,+BAC/C,gBAAiB,CACnB,CAAC,EAKL,IAAK,IAAM,KAAO,EACZ,EAAA,GAA+B,CAAC,EAAU,SAAS,CAAG,GACxD,EAAO,KAAK,CACV,KAAM,eACN,QAAS,aAAa,sBAAsB,CAAG,EAAE,uBACjD,gBAAiB,CACnB,CAAC,EAIL,OAAO,CACT,CAQA,SAAgB,0BAA0B,EAAuB,EAAyB,CACxF,IAAM,EAAS,uBAAuB,CAAa,EACnD,GAAI,EAAO,OAAS,EAAG,CACrB,IAAM,EAAgB,EAAO,IAAK,GAAM,OAAO,EAAE,SAAS,CAAC,CAAC,KAAK;CAAI,EACrE,MAAM,EAAS,CACb,KAAM,0BACN,QAAS,mDAAmD,EAAU,MAAM,GAC9E,CAAC,CACH,CACF,CCvYA,SAAS,4CACP,EACqB,CACrB,IAAM,EAA8B,CAClC,KAAM,EAAY,KAClB,SAAU,EAAY,WAAa,EACrC,EAmDA,GAjDI,EAAY,QAAO,EAAO,MAAQ,IAClC,EAAY,QAAO,EAAO,MAAQ,IAClC,EAAY,SAAQ,EAAO,OAAS,IAEpC,EAAY,eAAiB,EAAY,cAAc,OAAS,IAClE,EAAO,cAAgB,EAAY,cAAc,IAAK,IAAO,CAC3D,MAAO,EAAE,MACT,GAAI,EAAE,aAAe,CAAE,YAAa,EAAE,WAAY,CACpD,EAAE,GAGA,EAAY,aACd,EAAO,WAAa,GAChB,EAAY,iBAAgB,EAAO,eAAiB,EAAY,gBAChE,EAAY,kBAAiB,EAAO,gBAAkB,EAAY,kBAGpE,EAAY,cAAa,EAAO,YAAc,EAAY,aAC1D,EAAY,SAAQ,EAAO,OAAS,IAEpC,EAAY,QACd,EAAO,MAAQ,CAAC,EACZ,EAAY,MAAM,SACpB,EAAO,MAAM,OAAS,CAAE,KAAM,EAAY,MAAM,OAAO,IAAK,GAE1D,EAAY,MAAM,SACpB,EAAO,MAAM,OAAS,CAAE,KAAM,EAAY,MAAM,OAAO,IAAK,IAI5D,EAAY,UAAY,EAAY,SAAS,OAAS,IACxD,EAAO,SAAW,EAAY,SAAS,IAAK,IAAO,CACjD,OAAQ,CAAE,KAAM,EAAE,OAAO,IAAK,EAC9B,aAAc,EAAE,YAClB,EAAE,GAGA,EAAY,SACd,EAAO,OAAS,CACd,MAAO,EAAY,OAAO,MAC1B,GAAI,EAAY,OAAO,WAAa,IAAA,IAAa,CAAE,SAAU,EAAY,OAAO,QAAS,EACzF,GAAI,EAAY,OAAO,QAAU,CAAE,OAAQ,EAAY,OAAO,MAAO,CACvE,GAGE,EAAY,QAAU,IAAA,KAAW,EAAO,MAAQ,EAAY,OAC5D,EAAY,UAAY,IAAA,KAAW,EAAO,QAAU,EAAY,SAGhE,EAAY,QAAU,OAAO,KAAK,EAAY,MAAM,CAAC,CAAC,OAAS,EAAG,CACpE,IAAM,EAAS,qBAA0C,EACzD,IAAK,GAAM,CAAC,EAAY,KAAiB,OAAO,QAAQ,EAAY,MAAM,EACxE,EAAO,GAAc,4CAA4C,CAAY,EAE/E,EAAO,OAAS,CAClB,CAEA,OAAO,uBAAuB,CAAM,CACtC,CAOA,SAAgB,mBAAmB,EAA0C,CAC3E,IAAM,EAAS,qBAA0C,EAEzD,IAAK,GAAM,CAAC,EAAW,KAAU,OAAO,QAAQ,EAAK,MAAM,EACzD,EAAO,GAAa,4CAA4C,EAAM,MAAM,EAG9E,IAAM,EAAqC,CACzC,KAAM,EAAK,KACX,WAAY,EAAK,YAAc,GAAW,UAAU,EAAK,IAAI,EAC7D,QACF,EAUA,GARI,EAAK,cAAa,EAAa,YAAc,EAAK,aACtD,EAAa,SAAW,CAAC,EACrB,EAAK,SAAS,cAAgB,IAAA,KAChC,EAAa,SAAS,YAAc,EAAK,SAAS,aAEhD,EAAK,SAAS,aAAe,IAAA,KAC/B,EAAa,SAAS,WAAa,EAAK,SAAS,YAE/C,EAAK,SAAS,cAAe,CAE/B,IAAM,EAAM,EAAK,SAAS,cAC1B,EAAa,SAAS,cAAgB,CACpC,GAAI,EAAI,SAAW,IAAA,IAAa,CAC9B,OAAQ,EAAI,MACd,EACA,GAAI,EAAI,SAAW,IAAA,IAAa,CAC9B,OAAQ,EAAI,MACd,EACA,GAAI,EAAI,SAAW,IAAA,IAAa,CAC9B,OAAQ,EAAI,MACd,EACA,GAAI,EAAI,OAAS,IAAA,IAAa,CAC5B,KAAM,EAAI,IACZ,CACF,CACF,CAKA,GAJI,EAAK,SAAS,gBAAkB,IAAA,KAClC,EAAa,SAAS,cAAgB,EAAK,SAAS,eAGlD,EAAK,SAAW,OAAO,KAAK,EAAK,OAAO,CAAC,CAAC,OAAS,EAAG,CACxD,IAAM,EAAU,qBAA0C,EAC1D,IAAK,GAAM,CAAC,EAAW,KAAgB,OAAO,QAAQ,EAAK,OAAO,EAChE,EAAQ,GAAa,CACnB,OAAQ,EAAY,OACpB,OAAQ,EAAY,MACtB,EAEF,EAAa,QAAU,CACzB,CAcA,GAZI,EAAK,OAAS,OAAO,KAAK,EAAK,KAAK,CAAC,CAAC,OAAS,IACjD,EAAa,MAAQ,CAAE,GAAG,EAAK,KAAM,GAGnC,EAAK,eACP,EAAa,aAAe,EAAK,cAG/B,EAAK,mBACP,EAAa,iBAAmB,EAAK,kBAGnC,OAAO,KAAK,EAAK,oBAAoB,CAAC,CAAC,OAAS,EAAG,CACrD,IAAM,EAAuB,qBAA2C,EACxE,IAAK,GAAM,CAAC,EAAS,KAAQ,OAAO,QAAQ,EAAK,oBAAoB,EACnE,EAAqB,GAAW,CAC9B,WAAY,EAAI,WAChB,YAAa,EAAI,YACjB,YAAa,EAAI,YACjB,QAAS,EAAI,QACb,YAAa,EAAI,WACnB,EAEF,EAAa,qBAAuB,CACtC,CAEA,GAAI,OAAO,KAAK,EAAK,qBAAqB,CAAC,CAAC,OAAS,EAAG,CACtD,IAAM,EAAwB,qBAA2C,EACzE,IAAK,GAAM,CAAC,EAAS,KAAQ,OAAO,QAAQ,EAAK,qBAAqB,EACpE,EAAsB,GAAW,CAC/B,WAAY,EAAI,WAChB,YAAa,EAAI,YACjB,YAAa,EAAI,YACjB,QAAS,EAAI,QACb,YAAa,EAAI,WACnB,EAEF,EAAa,sBAAwB,CACvC,CAwBA,OAtBI,EAAK,YAAY,QAAU,EAAK,YAAY,OAC9C,EAAa,YAAc,CAAC,EAExB,EAAK,YAAY,SACnB,EAAa,YAAY,OAAS,CAChC,OAAQ,EAAK,YAAY,OAAO,OAAO,IAAI,uBAAuB,EAClE,KAAM,EAAK,YAAY,OAAO,KAAK,IAAI,uBAAuB,EAC9D,OAAQ,EAAK,YAAY,OAAO,OAAO,IAAI,uBAAuB,EAClE,OAAQ,EAAK,YAAY,OAAO,OAAO,IAAI,uBAAuB,CACpE,GAGE,EAAK,YAAY,MACnB,EAAa,YAAY,IAAM,EAAK,YAAY,IAAI,IAAK,IAAY,CACnE,WAAY,EAAO,WACnB,QAAS,EAAO,QAChB,OAAQ,EAAO,OACf,GAAI,EAAO,aAAe,CAAE,YAAa,EAAO,WAAY,CAC9D,EAAE,IAIC,sBAAsB,CAAY,CAC3C,CAOA,SAAS,wBACP,EAC0B,CAC1B,MAAO,CACL,WAAY,EAAW,WACvB,OAAQ,EAAW,OACnB,GAAI,EAAW,aAAe,CAAE,YAAa,EAAW,WAAY,CACtE,CACF,CAQA,SAAgB,6BACd,EACA,EAC0B,CAC1B,IAAM,EAAgB,qBAA2C,EAEjE,IAAK,GAAM,CAAC,EAAW,KAAS,OAAO,QAAQ,CAAK,EAClD,EAAc,GAAa,mBAAmB,CAAI,EAGpD,OAAO,wBAAwB,CAC7B,QAAA,EACA,YACA,UAAW,IAAI,KAAK,CAAA,CAAE,YAAY,EAClC,OAAQ,CACV,CAAC,CACH,CCjQA,MAAM,GAAQ,SAER,GAAa,aAEb,GAAM,OAIN,GAAa,IAAI,IAAI,CAAC,WAAY,OAAQ,MAAM,CAAC,EA6BjD,IAAO,GAAiB,KAAK,UAAU,CAAI,EAEjD,SAAS,0BAA0B,EAAgE,CACjG,IAAM,EAA+B,CAAC,EAEtC,IAAK,GAAM,CAAC,EAAM,KAAW,OAAO,QAAQ,CAAM,CAAC,CAAC,UAAU,CAAC,GAAI,CAAC,KAAO,EAAE,cAAc,CAAC,CAAC,EAAG,CAC9F,IAAM,EAAgC,CAAC,EAcvC,GAZI,EAAO,OAAO,QAAQ,OAAM,EAAK,GAAK,EAAO,MAAM,OAAO,MAC1D,EAAO,OAAO,QAAQ,OAAM,EAAK,GAAK,EAAO,MAAM,OAAO,MAC1D,EAAO,UAAU,KAAM,GAAM,EAAE,QAAQ,IAAI,IAC7C,EAAK,EAAI,EAAO,SACb,OAAQ,GAAM,EAAE,QAAQ,IAAI,CAAC,CAC7B,IAAK,GAAM,CAAC,EAAE,QAAQ,KAAM,EAAE,YAAY,CAAC,GAE5C,EAAO,UAAY,IAAA,KACrB,EAAK,EAAI,EAAO,mBAAmB,KAAO,EAAO,QAAQ,YAAY,EAAI,EAAO,QAChF,EAAK,EAAI,EAAO,MAGd,EAAO,OAAQ,CACjB,IAAM,EAAS,0BAA0B,EAAO,MAAM,EAClD,EAAO,OAAS,IAClB,EAAK,EAAI,EACT,EAAK,EAAI,CAAC,CAAC,EAAO,MAEtB,CAEI,OAAO,KAAK,CAAI,CAAC,CAAC,OAAS,GAC7B,EAAQ,KAAK,CAAC,EAAM,CAAI,CAAC,CAE7B,CAEA,OAAO,CACT,CAEA,SAAgB,wBACd,EACA,EAIoB,CACpB,IAAM,EAAe,0BAA0B,CAAM,EAOrD,GAAI,EALF,EAAa,OAAS,GACtB,GAAS,cAAc,QACvB,GAAS,cAAc,QACvB,GAAS,kBAEU,OAErB,IAAM,EAAqB,CAAC,CAAY,EAKxC,OAJI,GAAS,cAAc,QAAQ,EAAQ,KAAK,CAAC,MAAO,EAAQ,aAAa,MAAM,CAAC,EAChF,GAAS,cAAc,QAAQ,EAAQ,KAAK,CAAC,MAAO,EAAQ,aAAa,MAAM,CAAC,EAChF,GAAS,kBAAkB,EAAQ,KAAK,CAAC,MAAO,EAAQ,gBAAgB,CAAC,EAEtE,GAAW,QAAQ,CAAC,CAAC,OAAO,KAAK,UAAU,CAAO,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,EAAG,EAAE,CACvF,CAEA,SAAgB,wBAAwB,EAAkC,CAExE,OADc,EAAK,MAAM,uCACd,CAAC,GAAG,EACjB,CAEA,MAAM,aAAgB,GACpB,EAAO,OAAS,UAAY,EAAO,SAAW,IAAA,GAEhD,SAAS,iBAAiB,EAAgB,EAA2B,CAGnE,OAFI,IAAU,OAAS,GAAW,IAAI,CAAS,EAAU,GACrD,aAAiB,KAAa,YAAY,KAAK,UAAU,EAAM,YAAY,CAAC,EAAE,GAC3E,KAAK,UAAU,CAAK,CAC7B,CAgBA,SAAS,gBACP,EACA,EACA,EACA,EACA,EAAS,GACT,EAAmB,EACJ,CACf,IAAM,EAAkB,CAAC,EAEzB,IAAK,GAAM,CAAC,EAAM,KAAW,OAAO,QAAQ,CAAM,EAAG,CACnD,IAAM,EAAS,GAAG,EAAW,GAAG,IAAI,CAAI,EAAE,GACpC,EAAY,GAAG,EAAc,KAAK,IAAI,CAAI,EAAE,GAClD,GAAI,aAAa,CAAM,GAAK,EAAO,OAAQ,CACzC,IAAM,EAAe,GAAG,EAAiB,GAAG,IAAI,CAAI,EAAE,GACtD,GAAI,EAAO,MAAO,CAChB,IAAM,EAAQ,gBACZ,EAAO,OACP,IAAc,SAAW,yCAA2C,OACpE,IAAc,SAAW,gDAAkD,YAC3E,EACA,GACA,MACF,EACA,GAAI,IAAU,KAAM,CAClB,IAAM,EAAS,GAAG,EAAa,yCAAyC,EAAM,IAExE,EAAS,IAAc,SAAW,oBAAoB,EAAO,IAAI,EAAO,GAAK,EACnF,EAAM,KAAK,GAAG,IAAI,CAAI,EAAE,IAAI,EAAa,aAAa,EAAa,KAAK,GAAQ,CAClF,CACF,KAAO,CACL,IAAM,EAAQ,gBACZ,EAAO,OACP,IAAI,EAAO,SACX,EACA,EACA,GACA,IAAI,EAAa,QACnB,EACI,IAAU,MACZ,EAAM,KACJ,GAAG,IAAI,CAAI,EAAE,IAAI,EAAa,aAAa,EAAa,uBAAuB,EAAa,IAAI,EAAM,EACxG,CAEJ,CACA,QACF,CAEA,IAAM,EAAO,EAAO,QAAQ,GAC5B,GAAI,GAAU,EAAO,UAAY,IAAA,GAC/B,MAAU,MAAM,oDAAoD,EAAK,EAAE,EAE7E,IAAM,EAAa,IAAc,UAAY,EAAO,UAAY,IAAA,GAE5D,GAAQ,EACV,EAAM,KACJ,GAAG,IAAI,CAAI,EAAE,kBAAkB,EAAK,KAAK,KAAK,EAAO,OAAO,iBAAiB,EAAO,QAAS,EAAO,IAAI,GAC1G,EACS,GAAQ,IAAc,SAC/B,EAAM,KAAK,GAAG,IAAI,CAAI,EAAE,kBAAkB,EAAK,KAAK,KAAK,EAAO,EAAE,EACzD,EACT,EAAM,KACJ,GAAG,IAAI,CAAI,EAAE,6BAA6B,EAAK,KAAK,KAAK,EAAO,IAAI,EAAU,UAChF,EACS,GACT,EAAM,KAAK,GAAG,IAAI,CAAI,EAAE,IAAI,EAAO,MAAM,iBAAiB,EAAO,QAAS,EAAO,IAAI,GAAG,CAE5F,CAGA,OADI,EAAM,SAAW,EAAU,KACxB,KAAK,EAAM,KAAK,IAAI,EAAE,GAC/B,CAYA,SAAS,wBACP,EACA,EACA,EACA,EAAa,EACH,CACV,IAAM,EAAuB,CAAC,EAE9B,IAAK,GAAM,CAAC,EAAM,KAAW,OAAO,QAAQ,CAAM,EAAG,CACnD,IAAM,EAAS,GAAG,EAAW,GAAG,IAAI,CAAI,EAAE,GACpC,EAAY,EAAY,GAAG,EAAU,KAAK,IAAI,IAAI,GAAM,IAAM,IAAI,CAAI,EAEtE,GAAc,EAAO,UAAY,CAAC,EAAA,CAAG,OAAQ,GAAM,EAAE,QAAQ,IAAI,EACvE,GAAI,EAAW,OAAS,EAAG,CACzB,IAAM,EAAS,EACZ,IACE,GACC,kBAAkB,EAAE,QAAQ,KAAK,2CAA2C,EAAU,aAC1F,CAAC,CACA,KAAK;CAAI,EACZ,EAAW,KAAK,oBAAoB,EAAO,KAAK,EAAO,IAAI,CAC7D,CAEA,GAAI,aAAa,CAAM,GAAK,EAAO,OAAQ,CACzC,GAAI,EAAO,MAAO,CAChB,IAAM,EAAW,IAAe,EAAI,QAAU,QAAQ,IAChD,EAAc,GAAG,EAAU,WAAW,EAAS,QAC/C,EAAa,wBACjB,EAAO,OACP,OACA,EACA,EAAa,CACf,EACI,EAAW,OAAS,GACtB,EAAW,KACT,IAAI,EAAO,yBAAyB,EAAS,UAAU,EAAW,KAAK;CAAI,EAAE,MAC/E,CAEJ,KAAO,CACL,IAAM,EAAS,wBAAwB,EAAO,OAAQ,EAAQ,EAAW,CAAU,EAC/E,EAAO,OAAS,GAClB,EAAW,KAAK,OAAO,EAAO,eAAe,EAAO,KAAK;CAAI,EAAE,IAAI,CAEvE,CACF,CACF,CAEA,OAAO,CACT,CAEA,SAAS,0BAA0B,GAAG,EAAuC,CAC3E,OAAO,EAAM,KAAM,GAAS,GAAM,SAAA,YAAsB,CAAC,EACrD,UAAU,GAAc,MAAM,GAAmB,IACjD,EACN,CAEA,SAAS,SAAS,EAA4B,CAC5C,MAAO,0BAA0B,GAAI,gBAAgB,0BAA0B,CAAU,EAAE,UAAU,EAAW,6DAClH,CAEA,SAAS,aAAa,EAAsB,EAAmC,CAC7E,IAAM,EAAW,EAAmB,kDAAoD,GAClF,EAAgB,0BAA0B,EAAkB,GAAG,CAAU,EACzE,EAAmB,EAAmB,IAAI,EAAiB,GAAK,GACtE,MAAO,sCAAsC,IAAW,EAAc,IAAI,EAAW,KAAK;CAAI,IAAI,EAAiB,4EACrH,CAmBA,SAAgB,iBACd,EACA,EACa,CACb,IAAM,EAAsB,CAAC,EACvB,EAAe,GAAS,aACxB,EAAmB,GAAS,iBAE5B,EAAO,wBAAwB,GAAS,cAAgB,EAAQ,CAAO,EACvE,EAAa,EAAO,wBAAyB,IAAS,GAEtD,EAAmD,CAAC,EAC1D,IAAK,IAAM,IAAa,CAAC,SAAU,QAAQ,EAAY,CACrD,IAAM,EAAe,gBACnB,EACA,GACA,GACA,EACA,GACA,IAAc,SAAW,qBAAqB,GAAW,IAAI,GAAM,GAAK,EAC1E,EACM,EAAgB,IAAe,GACjC,EACJ,GAAI,IAAiB,MAAQ,EAAe,CAC1C,IAAM,EAAgB,0BAA0B,EAAc,CAAa,EAC3E,EAAO,0BAA0B,GAAI,gBAAgB,EAAc,gBAAgB,EAAa,qCAAqC,GAAM,OAAO,EAAc,sBAAsB,GAAM,sEAC9L,MAAW,EACT,EAAO,SAAS,CAAa,EACpB,IAAiB,OAC1B,EAAO,SAAS,CAAY,GAG1B,IACF,EAAK,GAAa,CAAE,KAAM,EAAO,CAAW,EAEhD,EACI,EAAK,QAAU,EAAK,UACtB,EAAO,SAAW,GAGpB,IAAM,EAAa,wBAAwB,EAAQ,aAAY,EAAE,EACjE,GAAI,EAAW,OAAS,GAAK,EAAkB,CAC7C,IAAM,EAAO,aAAa,EAAY,CAAgB,EAAI,EAC1D,EAAO,aAAe,CAAE,OAAQ,CAAE,MAAK,EAAG,OAAQ,CAAE,MAAK,CAAE,CAC7D,CAEA,OAAO,CACT,CC9RA,SAAS,6BAA6B,EAAqD,CACzF,IAAM,EAA8B,CAClC,KAAM,EAAY,KAClB,SAAU,EAAY,QACxB,EAEI,EAAY,QAAO,EAAO,MAAQ,IAClC,EAAY,QAAO,EAAO,MAAQ,IAClC,EAAY,SAAQ,EAAO,OAAS,IACpC,EAAY,aACd,EAAO,WAAa,GAChB,EAAY,iBAAgB,EAAO,eAAiB,EAAY,gBAChE,EAAY,kBAAiB,EAAO,gBAAkB,EAAY,kBAExE,IAAM,EAAgB,EAAY,cAC9B,EAAc,OAAS,IACzB,EAAO,cAAgB,EAAc,IAAK,IAAO,CAC/C,MAAO,EAAE,MACT,GAAI,EAAE,aAAe,CAAE,YAAa,EAAE,WAAY,CACpD,EAAE,GAGA,EAAY,cAAa,EAAO,YAAc,EAAY,aAC1D,EAAY,SAAQ,EAAO,OAAS,IAEpC,EAAY,QACd,EAAO,MAAQ,CAAC,EACZ,EAAY,MAAM,QAAQ,OAC5B,EAAO,MAAM,OAAS,CAAE,KAAM,EAAY,MAAM,OAAO,IAAK,GAE1D,EAAY,MAAM,QAAQ,OAC5B,EAAO,MAAM,OAAS,CAAE,KAAM,EAAY,MAAM,OAAO,IAAK,IAIhE,IAAM,EAAW,EAAY,SACzB,EAAS,OAAS,IACpB,EAAO,SAAW,EAAS,IAAK,IAAO,CACrC,OAAQ,CAAE,KAAM,gCAAgC,EAAE,QAAQ,MAAQ,GAAI,EAAE,MAAM,CAAE,EAChF,aAAc,EAAE,cAAgB,EAClC,EAAE,GAGA,EAAY,SACd,EAAO,OAAS,CACd,MAAO,OAAO,EAAY,OAAO,KAAK,EACtC,GAAI,EAAY,OAAO,UAAY,CAAE,SAAU,OAAO,EAAY,OAAO,QAAQ,CAAE,EACnF,GAAI,EAAY,OAAO,QAAU,CAAE,OAAQ,EAAY,OAAO,MAAO,CACvE,GAGE,EAAY,QAAU,IAAA,KAAW,EAAO,MAAQ,EAAY,OAG5D,EAAY,kBAAoB,CAAC,EAAO,OAAO,SACjD,EAAO,iBAAmB,IAG5B,IAAM,EAAe,EAAY,OACjC,GAAI,OAAO,KAAK,CAAY,CAAC,CAAC,OAAS,EAAG,CACxC,EAAO,OAAS,qBAA0C,EAC1D,IAAK,GAAM,CAAC,EAAW,KAAgB,OAAO,QAAQ,CAAY,EAChE,EAAO,OAAO,GAAa,6BAA6B,CAAW,CAEvE,CAEA,OAAO,CACT,CAOA,SAAS,8BACP,EACqC,CACrC,IAAM,EAAS,qBAA0C,EACnD,EAAe,EAAW,QAAQ,QAAU,CAAC,EAEnD,IAAK,GAAM,CAAC,EAAW,KAAgB,OAAO,QAAQ,CAAY,EAChE,EAAO,GAAa,6BAA6B,CAAW,EAG9D,OAAO,CACT,CAEA,SAAS,gCAAgC,EAAc,EAA2C,CAChG,OAAO,IAAW,GAA0B,MAAQ,EAAK,WAAW,GAAG,EAAI,EAAK,MAAM,CAAC,EAAI,CAC7F,CAEA,SAAS,gCACP,EACA,EAC8C,CAC9C,IAAM,EAA6B,CAAC,EAEhC,GAAgB,cAAa,EAAS,YAAc,IACpD,GAAgB,aAAY,EAAS,WAAa,IAClD,GAAgB,sBAAqB,EAAS,cAAgB,IAElE,IAAM,EAAW,GAAgB,qBACjC,GAAI,EAAU,CACZ,IAAM,EACJ,EAAS,QAAU,EAAS,QAAU,EAAS,QAAU,EAAS,MAChE,GAAkB,gBAAkB,IAAA,IAAa,KACnD,EAAS,cAAgB,CACvB,OAAQ,CAAC,EAAS,OAClB,OAAQ,CAAC,EAAS,OAClB,OAAQ,CAAC,EAAS,OAClB,KAAM,CAAC,EAAS,IAClB,EAEJ,CAEA,OAAO,OAAO,KAAK,CAAQ,CAAC,CAAC,OAAS,EAAI,EAAW,IAAA,EACvD,CAEA,SAAS,+BACP,EACiD,CACjD,IAAM,EAAU,qBAA0C,EAC1D,IAAK,GAAM,CAAC,EAAW,KAAgB,OAAO,QAAQ,GAAiB,CAAC,CAAC,EACvE,EAAQ,GAAa,CACnB,OAAQ,EAAY,WACpB,GAAI,EAAY,QAAU,CAAE,OAAQ,EAAK,CAC3C,EAEF,OAAO,OAAO,KAAK,CAAO,CAAC,CAAC,OAAS,EAAI,EAAU,IAAA,EACrD,CAEA,SAAS,6BACP,EACoC,CACpC,IAAM,EAAQ,qBAA6B,EAC3C,IAAK,GAAM,CAAC,EAAU,KAAe,OAAO,QAAQ,GAAe,CAAC,CAAC,EACnE,EAAM,GAAY,EAAW,aAAe,GAE9C,OAAO,OAAO,KAAK,CAAK,CAAC,CAAC,OAAS,EAAI,EAAQ,IAAA,EACjD,CAEA,SAAS,oCACP,EACA,EACsB,CACtB,OAAO,IAAc,UACjB,CACE,WAAY,EAAa,QACzB,YAAa,EAAa,SAC1B,YAAa,EAAa,SAC1B,QAAS,EAAa,MACtB,YAAa,EAAa,aAAe,EAC3C,EACA,CACE,WAAY,EAAa,QACzB,YAAa,EAAa,SAC1B,YAAa,EAAa,SAC1B,QAAS,EAAa,MACtB,YAAa,EAAa,aAAe,EAC3C,CACN,CAEA,SAAS,2CACP,EACA,EACA,EACS,CACT,IAAM,EAAY,oCAAoC,EAAc,CAAS,EAC7E,OACE,EAAU,aAAe,EAAS,YAClC,EAAU,cAAgB,EAAS,aACnC,EAAU,cAAgB,EAAS,aACnC,EAAU,UAAY,EAAS,OAEnC,CAEA,SAAS,iCACP,EACA,EACA,EACwB,CACxB,IAAM,EAAkB,GAAc,uBAAuB,GACvD,EAAmB,GAAc,wBAAwB,GAiB/D,OAfI,GAAmB,CAAC,EAAyB,UAC7C,GAAoB,CAAC,EAAwB,WAE/C,GACA,2CAA2C,EAAc,EAAiB,SAAS,EAE5E,UAGP,GACA,2CAA2C,EAAc,EAAkB,UAAU,GAKhF,EAAa,MAHX,WAGgC,SAC3C,CAEA,SAAS,qCACP,EACA,EAC8E,CAC9E,IAAM,EAAuB,qBAA2C,EAClE,EAAwB,qBAA2C,EAEzE,IAAK,GAAM,CAAC,EAAkB,KAAiB,OAAO,QAAQ,GAAuB,CAAC,CAAC,EAAG,CACxF,IAAM,EAAY,iCAChB,EACA,EACA,CACF,EACI,IAAc,UAChB,EAAqB,GAAoB,oCACvC,EACA,CACF,EAEA,EAAsB,GAAoB,oCACxC,EACA,CACF,CAEJ,CAEA,MAAO,CACL,GAAI,OAAO,KAAK,CAAoB,CAAC,CAAC,OAAS,GAAK,CAAE,sBAAqB,EAC3E,GAAI,OAAO,KAAK,CAAqB,CAAC,CAAC,OAAS,GAAK,CAAE,uBAAsB,CAC/E,CACF,CASA,MAAM,GAA4B,IAAI,IAA8B,CAClE,CAAC,GAA+B,MAAO,OAAO,EAC9C,CAAC,GAA+B,KAAM,MAAM,CAC9C,CAAC,EAGK,GAA8B,IAAI,IAAwC,CAC9E,CAAC,GAAiC,GAAI,IAAI,EAC1C,CAAC,GAAiC,GAAI,IAAI,EAC1C,CAAC,GAAiC,GAAI,IAAI,EAC1C,CAAC,GAAiC,IAAK,KAAK,EAC5C,CAAC,GAAiC,QAAS,QAAQ,EACnD,CAAC,GAAiC,SAAU,SAAS,CACvD,CAAC,EAED,SAAS,oBACP,EACA,EACkB,CAClB,IAAM,EAAY,GAA0B,IAAI,CAAM,EACtD,GAAI,EAAW,OAAO,EACtB,MAAM,EAAc,eAAe,EAAO,sBAAsB,GAAQ,CAC1E,CAEA,SAAS,sBACP,EACA,EAC4B,CAC5B,IAAM,EAAY,GAA4B,IAAI,CAAQ,EAC1D,GAAI,EAAW,OAAO,EACtB,MAAM,EAAc,eAAe,EAAO,wBAAwB,GAAU,CAC9E,CAEA,SAAS,0BACP,EAC2B,CAC3B,OAAQ,GAAS,KAAK,KAAtB,CACE,IAAK,YACH,MAAO,CAAE,KAAM,EAAQ,KAAK,KAAM,EACpC,IAAK,cACH,MAAO,CAAE,OAAQ,EAAQ,KAAK,KAAM,EACtC,IAAK,iBACH,MAAO,CAAE,UAAW,EAAQ,KAAK,KAAM,EACzC,IAAK,iBACH,MAAO,CAAE,UAAW,EAAQ,KAAK,KAAM,EACzC,IAAK,QACH,OAAO,GAAO,GAAa,EAAQ,KAAK,KAAK,EAC/C,QACE,MAAM,EAAc,gCAAgC,CACxD,CACF,CAEA,SAAS,6BACP,EAC6B,CAC7B,MAAO,CACL,0BAA0B,EAAU,IAAI,EACxC,sBAAsB,EAAU,SAAU,QAAQ,EAClD,0BAA0B,EAAU,KAAK,CAC3C,CACF,CAEA,SAAS,0BACP,EAC6B,CAC7B,MAAO,CACL,0BAA0B,EAAU,IAAI,EACxC,sBAAsB,EAAU,SAAU,KAAK,EAC/C,0BAA0B,EAAU,KAAK,CAC3C,CACF,CAEA,SAAS,0BAA0B,EAAsD,CACvF,MAAO,CACL,WAAY,EAAO,WAAW,IAAI,4BAA4B,EAC9D,OAAQ,oBAAoB,EAAO,OAAQ,QAAQ,EACnD,GAAI,EAAO,aAAe,CAAE,YAAa,EAAO,WAAY,CAC9D,CACF,CAEA,SAAS,wCACP,EACsC,CACtC,IAAM,EAA6C,CACjD,OAAQ,GAAY,OAAO,IAAI,yBAAyB,GAAK,CAAC,EAC9D,KAAM,GAAY,KAAK,IAAI,yBAAyB,GAAK,CAAC,EAC1D,OAAQ,GAAY,OAAO,IAAI,yBAAyB,GAAK,CAAC,EAC9D,OAAQ,GAAY,OAAO,IAAI,yBAAyB,GAAK,CAAC,CAChE,EAEA,OAAO,OAAO,OAAO,CAAgB,CAAC,CAAC,KAAM,GAAa,EAAS,OAAS,CAAC,EACzE,EACA,IAAA,EACN,CAEA,SAAS,uBAAuB,EAAyD,CACvF,OAAQ,EAAR,CACE,KAAK,EAA6B,IAChC,MAAO,MACT,KAAK,EAA6B,OAChC,MAAO,SACT,KAAK,EAA6B,KAChC,MAAO,OACT,KAAK,EAA6B,OAChC,MAAO,SACT,KAAK,EAA6B,OAChC,MAAO,SACT,KAAK,EAA6B,UAChC,MAAO,YACT,KAAK,EAA6B,YAChC,MAAO,aACT,QACE,MAAM,EAAc,sCAAsC,GAAQ,CACtE,CACF,CAEA,SAAS,qCACP,EACmC,CACnC,IAAM,EACJ,GAAY,SAAS,IAAK,IAAY,CACpC,WAAY,EAAO,WAAW,IAAI,yBAAyB,EAC3D,QAAS,EAAO,QAAQ,IAAI,sBAAsB,EAClD,OAAQ,oBAAoB,EAAO,OAAQ,KAAK,EAChD,GAAI,EAAO,aAAe,CAAE,YAAa,EAAO,WAAY,CAC9D,EAAE,GAAK,CAAC,EAEV,OAAO,EAAS,OAAS,EAAI,EAAW,IAAA,EAC1C,CAEA,SAAS,4BACP,EACA,EACsB,CACtB,IAAM,EAAW,gCACf,EAAW,QAAQ,SACnB,GAAc,QAChB,EACM,EAAgB,qCACpB,EAAW,QAAQ,cACnB,CACF,EACM,EAAmB,wCAAwC,EAAW,QAAQ,UAAU,EACxF,EAAqC,CACzC,KAAM,EAAW,KACjB,WAAY,EAAW,QAAQ,UAAU,YAAc,GAAW,UAAU,EAAW,IAAI,EAC3F,OAAQ,8BAA8B,CAAU,EAChD,GAAI,GAAY,CAAE,UAAS,EAC3B,GAAG,CACL,EAEI,EAAW,QAAQ,cACrB,EAAa,YAAc,EAAW,OAAO,aAE/C,IAAM,EAAU,+BAA+B,EAAW,QAAQ,OAAO,EACrE,IAAS,EAAa,QAAU,GAEpC,IAAM,EAAQ,6BAA6B,EAAW,QAAQ,KAAK,EAOnE,OANI,IAAO,EAAa,MAAQ,GAE5B,IACF,EAAa,YAAc,CAAE,OAAQ,CAAiB,GAGjD,CACT,CAUA,SAAgB,8BACd,EACA,EACA,EAAuD,CAAC,EACxD,EAC0B,CAC1B,IAAM,EAAS,qBAA2C,EAC1D,IAAK,IAAM,KAAc,EACvB,EAAO,EAAW,MAAQ,4BACxB,EACA,GAAkB,OAAO,EAAW,KACtC,EAGF,IAAK,IAAM,KAAc,EAAsB,CAC7C,GAAM,CAAE,SAAU,GAAc,EAC1B,EAAe,EAAO,GAC5B,GAAI,CAAC,EAAc,SAEnB,IAAM,EAAgB,qCAAqC,EAAW,UAAU,EAC3E,IAEL,EAAa,YAAc,CACzB,GAAG,EAAa,YAChB,IAAK,CACP,EACF,CAEA,OAAO,wBAAwB,CAC7B,QAAA,EACA,YACA,UAAW,IAAI,KAAK,CAAA,CAAE,YAAY,EAClC,QACF,CAAC,CACH,CAEA,SAAS,qBAAqB,EAAwB,CAEpD,OADI,IAAU,IAAA,IAAa,IAAU,GAAW,OACzC,OAAO,CAAK,CACrB,CAEA,SAAS,mBAAmB,EAAgB,EAAqB,CAC/D,OAAO,EAAS,GAAG,EAAO,GAAG,IAAQ,CACvC,CAEA,SAAS,mBACP,EACA,EACA,EACA,EACA,EACM,CACF,IAAgB,GACpB,EAAY,KACV,GAAG,mBAAmB,EAAQ,CAAG,EAAE,WAAW,qBAC5C,CACF,EAAE,aAAa,qBAAqB,CAAa,GACnD,CACF,CAEA,SAAS,0BACP,EACA,EACA,EACA,EACA,EACM,CACN,mBACE,EACA,EACA,EACA,EAAY,IAAQ,GACpB,EAAc,IAAQ,EACxB,CACF,CAEA,SAAS,4BACP,EACA,EACA,EACA,EACM,CACN,IAAM,EAAgB,EAAY,eAAiB,CAAC,EAC9C,EAAkB,EAAc,eAAiB,CAAC,EACxD,GAAI,EAAc,SAAW,EAAgB,OAAQ,CACnD,EAAY,KACV,GAAG,mBAAmB,EAAQ,eAAe,EAAE,iBAAiB,EAAc,OAAO,aAAa,EAAgB,QACpH,EACA,MACF,CAEA,IAAM,EAAwB,IAAI,IAAI,EAAgB,IAAK,GAAM,CAAC,EAAE,MAAO,EAAE,WAAW,CAAC,CAAC,EAC1F,IAAK,IAAM,KAAS,EAAe,CACjC,GAAI,CAAC,EAAsB,IAAI,EAAM,KAAK,EAAG,CAC3C,EAAY,KACV,GAAG,mBAAmB,EAAQ,eAAe,EAAE,gBAAgB,EAAM,MAAM,kBAC7E,EACA,MACF,CACA,IAAM,EAAsB,EAAsB,IAAI,EAAM,KAAK,EACjE,IAAK,EAAM,aAAe,OAAS,GAAuB,IAAK,CAC7D,mBACE,EACA,EACA,iBAAiB,EAAM,MAAM,cAC7B,EAAM,aAAe,GACrB,GAAuB,EACzB,EACA,MACF,CACF,CAEA,IAAM,EAAsB,IAAI,IAAI,EAAc,IAAK,GAAM,EAAE,KAAK,CAAC,EACrE,IAAK,IAAM,KAAS,EAClB,GAAI,CAAC,EAAoB,IAAI,EAAM,KAAK,EAAG,CACzC,EAAY,KACV,GAAG,mBAAmB,EAAQ,eAAe,EAAE,kBAAkB,EAAM,MAAM,gBAC/E,EACA,MACF,CAEJ,CAEA,SAAS,oBACP,EACA,EACA,EACA,EACM,CACN,mBACE,EACA,EACA,eACA,EAAY,OAAO,QAAQ,MAAQ,GACnC,EAAc,OAAO,QAAQ,MAAQ,EACvC,EACA,mBACE,EACA,EACA,eACA,EAAY,OAAO,QAAQ,MAAQ,GACnC,EAAc,OAAO,QAAQ,MAAQ,EACvC,CACF,CAEA,SAAS,yBACP,EACA,EACA,EACA,EACM,CACN,IAAM,EAAiB,EAAY,UAAY,CAAC,EAC1C,EAAmB,EAAc,UAAY,CAAC,EAChD,EAAe,SAAW,EAAiB,QAC7C,EAAY,KACV,GAAG,mBAAmB,EAAQ,UAAU,EAAE,iBAAiB,EAAe,OAAO,aAAa,EAAiB,QACjH,EAGF,IAAM,EAAe,KAAK,IAAI,EAAe,OAAQ,EAAiB,MAAM,EAC5E,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAc,IAAS,CACjD,IAAM,EAAmB,EACvB,EAAe,GACf,gCAAgC,GAClC,EACM,EAAqB,EACzB,EAAiB,GACjB,kCAAkC,GACpC,EACA,mBACE,EACA,EACA,YAAY,EAAM,UAClB,EAAiB,QAAQ,MAAQ,GACjC,EAAmB,QAAQ,MAAQ,EACrC,EACA,mBACE,EACA,EACA,YAAY,EAAM,gBAClB,EAAiB,aACjB,EAAmB,YACrB,CACF,CACF,CAEA,SAAS,qBACP,EACA,EACA,EACA,EACM,CACN,mBACE,EACA,EACA,eACA,EAAY,QAAQ,MACpB,EAAc,QAAQ,KACxB,EACA,mBACE,EACA,EACA,kBACA,EAAY,QAAQ,SACpB,EAAc,QAAQ,QACxB,EACA,mBACE,EACA,EACA,gBACA,EAAY,QAAQ,QAAU,GAC9B,EAAc,QAAQ,QAAU,EAClC,CACF,CAEA,SAAS,0BACP,EACA,EACA,EACA,EACM,CACN,IAAM,EAAe,EAAY,QAAU,CAAC,EACtC,EAAiB,EAAc,QAAU,CAAC,EAC1C,EAAmB,OAAO,KAAK,CAAY,EAC3C,EAAqB,OAAO,KAAK,CAAc,EAEjD,EAAiB,SAAW,EAAmB,QACjD,EAAY,KACV,GAAG,mBAAmB,EAAQ,QAAQ,EAAE,iBAAiB,EAAiB,OAAO,aAAa,EAAmB,QACnH,EAGF,IAAK,IAAM,KAAa,EAAkB,CACxC,IAAM,EAAoB,EAAa,GACjC,EAAsB,EAAe,GACrC,EAAe,mBAAmB,EAAQ,UAAU,GAAW,EACrE,GAAI,CAAC,EAAqB,CACxB,EAAY,KAAK,GAAG,EAAa,oCAAoC,EACrE,QACF,CACA,oBACE,EACA,EACA,EAAc,EAAmB,iBAAiB,EAAU,UAAU,EACtE,CACF,CACF,CAEA,IAAK,IAAM,KAAa,EAClB,EAAa,IACjB,EAAY,KACV,GAAG,mBAAmB,EAAQ,UAAU,GAAW,EAAE,oCACvD,CAEJ,CAEA,SAAS,oBACP,EACA,EACA,EACA,EACM,CACN,mBAAmB,EAAa,EAAQ,OAAQ,EAAY,KAAM,EAAc,IAAI,EACpF,mBAAmB,EAAa,EAAQ,WAAY,EAAY,SAAU,EAAc,QAAQ,EAEhG,IAAK,IAAM,KAAO,GAChB,0BAA0B,EAAa,EAAQ,EAAK,EAAa,CAAa,EAGhF,mBACE,EACA,EACA,iBACA,EAAY,eACZ,EAAc,cAChB,EACA,mBACE,EACA,EACA,kBACA,EAAY,gBACZ,EAAc,eAChB,EACA,mBACE,EACA,EACA,cACA,EAAY,aAAe,GAC3B,EAAc,aAAe,EAC/B,EACA,4BAA4B,EAAa,EAAQ,EAAa,CAAa,EAC3E,oBAAoB,EAAa,EAAQ,EAAa,CAAa,EACnE,yBAAyB,EAAa,EAAQ,EAAa,CAAa,EACxE,qBAAqB,EAAa,EAAQ,EAAa,CAAa,EACpE,mBAAmB,EAAa,EAAQ,QAAS,EAAY,MAAO,EAAc,KAAK,EACvF,0BAA0B,EAAa,EAAQ,EAAa,CAAa,CAC3E,CAUA,SAAS,cACP,EACA,EACA,EACA,EACoB,CACpB,IAAM,EAAwB,CAAC,EAY/B,OAXA,oBAAoB,EAAa,GAAI,EAAa,CAAa,EAE3D,EAAY,OAAS,EAChB,CACL,YACA,KAAM,iBACN,YACA,QAAS,EAAY,KAAK,IAAI,CAChC,EAGK,IACT,CAKA,MAAM,GAAgB,IAAI,IAAI,CAAC,IAAI,CAAC,EASpC,SAAgB,0BACd,EACA,EACA,EAAuD,CAAC,EACzC,CACf,IAAM,EAAmB,oCACvB,+BACE,8BACE,EACA,EAAS,UACT,EACA,CACF,CACF,EACA,+BAA+B,CAAQ,CACzC,EAEM,EAAe,oBAAoB,EAAa,CAAQ,EAE9D,MAAO,CAAC,GAAG,EAAkB,GAAG,CAAY,CAC9C,CAaA,SAAS,6BAA6B,EAAsD,CAC1F,IAAM,EAAQ,CACZ,EAAW,QAAQ,UAAU,QAAQ,KACrC,EAAW,QAAQ,UAAU,QAAQ,KACrC,EAAW,QAAQ,cAAc,QAAQ,KACzC,EAAW,QAAQ,cAAc,QAAQ,IAC3C,EACI,EACJ,IAAK,IAAM,KAAQ,EAAO,CACxB,GAAI,CAAC,EAAM,SACX,IAAM,EAAO,wBAAwB,CAAI,EACpC,KACL,IAAI,GAAS,IAAU,EAAM,MAAO,CAAE,KAAM,aAAc,EAC1D,EAAQ,CADkD,CAE5D,CACA,OAAO,EAAQ,CAAE,KAAM,OAAQ,KAAM,CAAM,EAAI,CAAE,KAAM,QAAS,CAClE,CAEA,SAAS,iBAAiB,EAAwC,CAChE,MAAO,CAAC,EACN,EAAW,QAAQ,UAAU,QAAQ,MACrC,EAAW,QAAQ,UAAU,QAAQ,MACrC,EAAW,QAAQ,cAAc,QAAQ,MACzC,EAAW,QAAQ,cAAc,QAAQ,KAE7C,CAOA,MAAa,GAAoC,+BAEjD,SAAS,oBACP,EACA,EACe,CACf,IAAM,EAAwB,CAAC,EACzB,EAAe,IAAI,IAAI,EAAY,IAAK,GAAM,CAAC,EAAE,KAAM,CAAC,CAAC,CAAC,EAEhE,IAAK,GAAM,CAAC,EAAW,KAAiB,OAAO,QAAQ,EAAS,MAAM,EAAG,CACvE,IAAM,EAAY,wBAAwB,EAAa,OAAQ,CAC7D,aAAc,EAAa,aAC3B,iBAAkB,EAAa,gBACjC,CAAC,EAEK,EAAa,EAAa,IAAI,CAAS,EACxC,KAEL,IAAI,EAAW,CACb,IAAM,EAAc,6BAA6B,CAAU,EAE3D,GAAI,KADe,EAAY,OAAS,OAAS,EAAY,KAAO,IAAA,IACtC,CAC5B,IAAM,EACJ,EAAY,OAAS,OACjB,UAAU,EAAU,8CACpB,EAAY,OAAS,cACnB,UAAU,EAAU,2CACpB,iBAAiB,CAAU,EACzB,UAAU,EAAU,IAAI,KACxB,UAAU,EAAU,6CAC9B,EAAO,KAAK,CAAE,YAAW,KAAM,kBAAmB,SAAQ,CAAC,CAC7D,CACF,MAAW,iBAAiB,CAAU,GACpC,EAAO,KAAK,CACV,YACA,KAAM,kBACN,QAAS,UAAU,EAAU,4CAC/B,CAAC,CAAA,CAEL,CAEA,OAAO,CACT,CAEA,SAAS,sBAAsB,EAAiD,CAC9E,GAAM,CACJ,MAAO,EACP,SAAU,EACV,QAAS,EACT,iBAAkB,EAClB,GAAG,GACD,EACJ,GAAI,EAAK,OAAQ,CACf,IAAM,EAAS,qBAA0C,EACzD,IAAK,GAAM,CAAC,EAAM,KAAM,OAAO,QAAQ,EAAK,MAAM,EAChD,EAAO,GAAQ,sBAAsB,CAAC,EAExC,MAAO,CAAE,GAAG,EAAM,OAAQ,CAAO,CACnC,CACA,OAAO,CACT,CAUA,SAAgB,+BAA+B,EAAoD,CACjG,IAAM,EAAS,qBAA2C,EAE1D,IAAK,GAAM,CAAC,EAAW,KAAS,OAAO,QAAQ,EAAS,MAAM,EAAG,CAC/D,IAAM,EAAS,qBAA0C,EACzD,IAAK,GAAM,CAAC,EAAW,KAAU,OAAO,QAAQ,EAAK,MAAM,EACrD,GAAc,IAAI,CAAS,IAC/B,EAAO,GAAa,sBAAsB,CAAK,GAEjD,GAAM,CAAE,aAAc,EAAG,iBAAkB,EAAI,GAAG,GAAa,EAC/D,EAAO,GAAa,CAAE,GAAG,EAAU,QAAO,CAC5C,CAEA,OAAO,wBAAwB,CAC7B,GAAG,EACH,QACF,CAAC,CACH,CAEA,SAAS,qBACP,EACa,CACb,OACE,cAAc,EAAO,UAAW,EAAO,UAAW,EAAO,OAAQ,EAAO,KAAK,GAAK,CAChF,UAAW,EAAO,UAClB,KAAM,iBACN,UAAW,EAAO,UAClB,QAAS,UAAU,EAAO,UAAU,sCACtC,CAEJ,CAEA,SAAS,0BAA0B,EAAiC,CAClE,OAAQ,EAAO,KAAf,CACE,IAAK,cACH,MAAO,CACL,UAAW,EAAO,UAClB,KAAM,sBACN,QAAS,UAAU,EAAO,UAAU,uCACtC,EACF,IAAK,gBACH,MAAO,CACL,UAAW,EAAO,UAClB,KAAM,qBACN,QAAS,UAAU,EAAO,UAAU,uCACtC,EAGF,IAAK,gBACH,MAAO,CACL,UAAW,EAAO,UAClB,KAAM,yBACN,QAAS,UAAU,EAAO,kBAAkB,oBAAoB,EAAO,UAAU,EACnF,EACF,IAAK,0BACL,IAAK,iBACH,MAAO,CACL,UAAW,EAAO,UAClB,KAAM,yBACN,QAAS,EAAO,QAAU,mDAC5B,EACF,IAAK,cACH,MAAO,CACL,UAAW,EAAO,UAClB,KAAM,uBACN,UAAW,EAAO,UAClB,QAAS,UAAU,EAAO,UAAU,uCACtC,EACF,IAAK,gBACH,MAAO,CACL,UAAW,EAAO,UAClB,KAAM,sBACN,UAAW,EAAO,UAClB,QAAS,UAAU,EAAO,UAAU,uCACtC,EACF,IAAK,iBACL,IAAK,sBACH,OAAO,qBAAqB,CAAM,EAGpC,IAAK,gBACH,MAAO,CACL,UAAW,EAAO,UAClB,KAAM,iBACN,UAAW,EAAO,UAClB,QAAS,UAAU,EAAO,kBAAkB,oBAAoB,EAAO,UAAU,EACnF,EACF,IAAK,cACH,MAAO,CACL,UAAW,EAAO,UAClB,KAAM,uBACN,UAAW,EAAO,UAClB,QAAS,UAAU,EAAO,UAAU,uCACtC,EACF,IAAK,gBACH,MAAO,CACL,UAAW,EAAO,UAClB,KAAM,sBACN,UAAW,EAAO,UAClB,QAAS,UAAU,EAAO,UAAU,uCACtC,EACF,IAAK,iBACH,MAAO,CACL,UAAW,EAAO,UAClB,KAAM,iBACN,UAAW,EAAO,UAClB,QAAS,EAAO,QAAU,UAAU,EAAO,UAAU,sCACvD,EACF,IAAK,aACH,MAAO,CACL,UAAW,EAAO,UAClB,KAAM,sBACN,SAAU,EAAO,UACjB,QAAS,SAAS,EAAO,UAAU,uCACrC,EACF,IAAK,eACH,MAAO,CACL,UAAW,EAAO,UAClB,KAAM,qBACN,SAAU,EAAO,UACjB,QAAS,SAAS,EAAO,UAAU,uCACrC,EACF,IAAK,gBACH,MAAO,CACL,UAAW,EAAO,UAClB,KAAM,gBACN,SAAU,EAAO,UACjB,QAAS,EAAO,QAAU,SAAS,EAAO,UAAU,sCACtD,EACF,IAAK,qBACH,MAAO,CACL,UAAW,EAAO,UAClB,KAAM,8BACN,iBAAkB,EAAO,iBACzB,iBAAkB,EAAO,iBACzB,QAAS,iBAAiB,EAAO,iBAAiB,uCACpD,EACF,IAAK,uBACH,MAAO,CACL,UAAW,EAAO,UAClB,KAAM,6BACN,iBAAkB,EAAO,iBACzB,iBAAkB,EAAO,iBACzB,QAAS,iBAAiB,EAAO,iBAAiB,uCACpD,EACF,IAAK,wBACH,MAAO,CACL,UAAW,EAAO,UAClB,KAAM,wBACN,iBAAkB,EAAO,iBACzB,iBAAkB,EAAO,iBACzB,QACE,EAAO,QACP,iBAAiB,EAAO,iBAAiB,sCAC7C,EACF,IAAK,sBACH,MAAO,CACL,UAAW,EAAO,UAClB,KAAM,sBACN,QAAS,EAAO,QAAU,gDAC5B,EACF,IAAK,yBACH,MAAO,CACL,UAAW,EAAO,UAClB,KAAM,kBACN,QAAS,EAAO,QAAU,wDAC5B,EACF,QAEE,MAAM,EAAc,yBAAyB,CAEjD,CACF,CAEA,SAAS,oCACP,EACA,EACe,CACf,OAAO,iBAAiB,EAAgB,CAAQ,CAAC,CAAC,QAAQ,IAAI,yBAAyB,CACzF,CAOA,SAAgB,mBAAmB,EAA+B,CAChE,GAAI,EAAO,SAAW,EACpB,MAAO,6BAGT,IAAM,EAAkB,CAAC,EAGnB,EAAe,IAAI,IACzB,IAAK,IAAM,KAAS,EAAQ,CAC1B,IAAM,EAAW,EAAa,IAAI,EAAM,SAAS,GAAK,CAAC,EACvD,EAAS,KAAK,CAAK,EACnB,EAAa,IAAI,EAAM,UAAW,CAAQ,CAC5C,CAEA,IAAK,GAAM,CAAC,EAAW,KAAe,EAAc,CAClD,EAAM,KAAK,YAAY,EAAU,GAAG,EACpC,IAAK,IAAM,KAAS,EAClB,GAAI,EAAM,UACR,EAAM,KAAK,gBAAgB,EAAM,UAAU,KAAK,EAAM,SAAS,OAC1D,GAAI,EAAM,UACf,EAAM,KAAK,gBAAgB,EAAM,UAAU,KAAK,EAAM,SAAS,OAC1D,GAAI,EAAM,SACf,EAAM,KAAK,eAAe,EAAM,SAAS,KAAK,EAAM,SAAS,OACxD,GAAI,EAAM,iBAAkB,CACjC,IAAM,EAAmB,EAAM,iBAAmB,KAAK,EAAM,iBAAiB,GAAK,GACnF,EAAM,KACJ,qBAAqB,EAAiB,IAAI,EAAM,iBAAiB,KAAK,EAAM,SAC9E,CACF,MACE,EAAM,KAAK,SAAS,EAAM,SAAS,CAGzC,CAEA,OAAO,EAAM,KAAK;CAAI,CACxB,CCtoCA,MAAM,GAAuB,OAAO,KAAK,EAAoB,EAE7D,SAAS,4BAA4B,EAAiC,CAGpE,OAFKC,EAAG,WAAW,CAAa,EAEzBA,EACJ,YAAY,EAAe,CAAE,cAAe,EAAK,CAAC,CAAC,CACnD,OAAQ,GAAU,EAAM,YAAY,GAAK,GAAyB,KAAK,EAAM,IAAI,CAAC,CAAC,CACnF,IAAK,GAAU,OAAO,SAAS,EAAM,KAAM,EAAE,CAAC,CAAC,CAC/C,OAAQ,GACP,GAAqB,KAAM,GACzBA,EAAG,WAAW,qBAAqB,EAAe,EAAiB,CAAI,CAAC,CAC1E,CACF,CAAC,CACA,UAAU,EAAG,IAAM,EAAI,CAAC,EAXe,CAAC,CAY7C,CAEA,SAAS,wBACP,EACA,EACA,EAAS,GACT,EAAoB,IAAI,IAClB,CACN,IAAM,EAAoBA,EAAG,aAAa,CAAa,EACvD,GAAI,EAAkB,IAAI,CAAiB,EAAG,CAC5C,EAAK,OAAO,oBAAoB,EAAO,IAAI,EAAkB,GAAG,EAChE,MACF,CACA,EAAkB,IAAI,CAAiB,EACvC,IAAM,EAAUA,EACb,YAAY,EAAe,CAAE,cAAe,EAAK,CAAC,CAAC,CACnD,UAAU,EAAG,IAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC,EAElD,GAAI,CACF,IAAK,IAAM,KAAS,EAAS,CAC3B,IAAM,EAAe,EAAS,GAAG,EAAO,GAAG,EAAM,OAAS,EAAM,KAC1D,EAAY,EAAK,KAAK,EAAe,EAAM,IAAI,EACrD,GAAI,EAAM,YAAY,EACpB,EAAK,OAAO,cAAc,EAAa,GAAG,EAC1C,wBAAwB,EAAM,EAAW,EAAc,CAAiB,OACnE,GAAI,EAAM,OAAO,EACtB,EAAK,OAAO,SAAS,EAAa,GAAG,EACrC,EAAK,OAAOA,EAAG,aAAa,CAAS,CAAC,EACtC,EAAK,OAAO,IAAI,OACX,GAAI,EAAM,eAAe,EAAG,CACjC,EAAK,OAAO,YAAY,EAAa,IAAIA,EAAG,aAAa,CAAS,EAAE,GAAG,EACvE,GAAI,CACF,IAAM,EAASA,EAAG,SAAS,CAAS,EAChC,EAAO,YAAY,GACrB,EAAK,OAAO,oBAAoB,EAChC,wBAAwB,EAAM,EAAW,GAAG,EAAa,SAAU,CAAiB,GAC3E,EAAO,OAAO,GACvB,EAAK,OAAO,eAAe,EAC3B,EAAK,OAAOA,EAAG,aAAa,CAAS,CAAC,EACtC,EAAK,OAAO,IAAI,GAEhB,EAAK,OAAO,gBAAgB,CAEhC,OAAS,EAAO,CACd,GAAK,EAAgC,OAAS,SAAU,MAAM,EAC9D,EAAK,OAAO,kBAAkB,CAChC,CACF,MACE,EAAK,OAAO,UAAU,EAAa,GAAG,CAE1C,CACF,QAAU,CACR,EAAkB,OAAO,CAAiB,CAC5C,CACF,CAOA,SAAgB,iBAAiB,EAA0C,CACzE,IAAM,EAAO,GAAW,QAAQ,EAChC,IAAK,IAAM,IAAY,CAAC,GAAG,IAAI,IAAI,CAAS,CAAC,CAAC,CAAC,SAAS,EACtD,EAAK,OAAO,CAAQ,EACpB,EAAK,OAAO,IAAI,EACZA,EAAG,WAAW,CAAQ,EACxB,EAAK,OAAOA,EAAG,aAAa,CAAQ,CAAC,EAErC,EAAK,OAAO,WAAW,EAEzB,EAAK,OAAO,IAAI,EAElB,OAAO,EAAK,OAAO,KAAK,CAC1B,CAOA,SAAgB,0BACd,EACwB,CACxB,IAAM,EAAQ,OAAO,OAAO,IAAI,EAChC,IAAK,GAAM,CAAE,YAAW,mBAAmB,EAAyB,UAAU,EAAG,IAC/E,EAAE,UAAU,cAAc,EAAE,SAAS,CACvC,EAAG,CACD,IAAM,EAAO,GAAW,QAAQ,EAC1B,EAAmB,4BAA4B,CAAa,EAClE,IAAK,IAAM,KAAmB,EAAkB,CAC9C,IAAM,EAAyB,sBAAsB,CAAe,EACpE,EAAK,OAAO,cAAc,EAAuB,GAAG,EACpD,wBAAwB,EAAM,EAAK,KAAK,EAAe,CAAsB,CAAC,CAChF,CACA,EAAM,GAAa,EAAK,OAAO,KAAK,CACtC,CACA,OAAO,CACT,CCpGA,SAAS,mBAAmB,EAAqE,CAE/F,GADI,OAAO,GAAa,WAAY,GAChC,EAAE,cAAe,GAAW,MAAO,GAEvC,IAAM,EAAY,EAAS,UAI3B,OAHI,OAAO,GAAc,WAAY,GACjC,EAAE,cAAe,GAAmB,GAEjC,OAAO,EAAU,WAAc,QACxC,CAQA,SAAgB,4BACd,EACA,EAC2B,CAC3B,IAAM,EAAoC,CAAC,EAE3C,IAAK,IAAM,KAAa,OAAO,KAAK,EAAO,IAAM,CAAC,CAAC,EAAG,CACpD,IAAM,EAAW,EAAO,KAAK,GAC7B,GAAI,CAAC,mBAAmB,CAAQ,EAAG,SAEnC,IAAM,EAAgB,EAAK,QAAQ,EAAW,EAAS,UAAU,SAAS,EAC1E,EAAO,KAAK,CAAE,YAAW,eAAc,CAAC,CAC1C,CAEA,OAAO,CACT,CAQA,SAAgB,sBACd,EACA,EACyB,CACzB,GAAI,EAAyB,SAAW,EACtC,MAAM,6BAA6B,EAErC,GAAI,EAAW,CACb,IAAM,EAAQ,EAAyB,KAAM,GAAO,EAAG,YAAc,CAAS,EAC9E,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,+BACN,QAAS,cAAc,EAAU,mDACnC,CAAC,EAEH,OAAO,CACT,CACA,GAAI,EAAyB,OAAS,EACpC,MAAM,EAAS,CACb,KAAM,+BACN,QAAS,qFAAqF,EAC3F,IAAK,GAAO,EAAG,SAAS,CAAC,CACzB,KAAK,IAAI,GACd,CAAC,EAEH,OAAO,EAAc,EAAyB,GAAI,mCAAmC,CACvF,CAMA,SAAgB,8BAAyC,CACvD,OAAO,EAAS,CACd,KAAM,6BACN,QAAS,2DACT,WAAY,oEACd,CAAC,CACH,CClFA,eAAsB,0BACpB,EACA,EAC+B,CAC/B,IAAM,EAAW,MAAM,EAAU,SAAY,CAC3C,GAAM,CAAE,YAAa,MAAM,EAAO,YAAY,CAAE,KAAI,CAAC,EACrD,OAAO,CACT,CAAC,EACD,GAAI,CAAC,EACH,MAAO,CACL,eAAgB,GAChB,OAAQ,KACR,UAAW,KACX,iBAAkB,EACpB,EAGF,IAAM,EAAiB,EAAS,OAAO,IACjC,EAAe,EAAS,OAAO,IAC/B,EAAY,EAAe,wBAAwB,CAAY,EAAI,KACzE,MAAO,CACL,eAAgB,GAChB,OAAQ,EAAiB,0BAA0B,CAAc,EAAI,KACrE,YACA,iBAAkB,IAAiB,IAAA,IAAa,IAAc,IAChE,CACF,CAaA,eAAsB,2BACpB,EACA,EACwB,CACxB,OAAQ,MAAM,0BAA0B,EAAQ,CAAG,EAAA,CAAG,MACxD,CCzDA,SAAS,eAAe,EAAuB,CAC7C,OACE,EAAK,SAAS,OAAO,GACrB,GAAwB,IAAI,EAAK,MAAO,CAAE,yBAA0B,EAAK,CAAC,CAAC,CAAC,IAAI,OAAO,CAE3F,CAEA,SAAS,qBACP,EACA,EACsB,CACtB,IAAM,EAAmC,CAAC,EACtC,EACA,EAAmB,CAAC,EAExB,SAAS,aAAoB,CACtB,GAAa,SAClB,EAAW,KAAK,CACd,GAAG,EACH,OAAQ,CACN,GAAG,EAAY,OACf,KAAM,GACJ,iBAAiB,EAAO,KAAK;CAAI,EAAE,MAAM,EAAW,GACpD,4BACF,CACF,CACF,CAAC,EACD,EAAc,IAAA,GACd,EAAS,CAAC,EACZ,CAGA,IAAK,IAAM,KAAc,EACnB,EAAW,QAAU,eAAe,EAAW,OAAO,IAAI,GAC5D,IAAgB,EAChB,EAAO,KACL,SAAS,EAAW,OAAO,KAAK,cAAc,KAAK,UAAU,EAAW,YAAY,EAAE,EACxF,IAEA,YAAY,EACZ,EAAW,KAAK,CAAU,GAI9B,OADA,YAAY,EACL,CACT,CAEA,SAAS,eACP,EACA,EACA,EACA,EACA,EACqB,CACrB,IAAM,EAAa,CAAE,GAAG,CAAM,EAC9B,GAAI,EAAM,OAAQ,CAEhB,IAAM,EAAc,EAAM,MAAQ,OAAS,GAAG,EAAY,KAAK,KAAK,UAAU,CAAS,EAAE,GACnF,EAAe,EAAM,MAAQ,OAAS,GAAG,EAAa,KAAK,KAAK,UAAU,CAAS,EAAE,GACrF,EAAiB,EAAM,MACzB,OACA,GAAG,EAAe,KAAK,KAAK,UAAU,CAAS,EAAE,GACrD,EAAW,OAAS,OAAO,YACzB,OAAO,QAAQ,EAAM,MAAM,CAAC,CAAC,KAAK,CAAC,EAAM,KAAY,CACnD,EACA,eAAe,EAAQ,EAAa,EAAc,EAAgB,CAAI,CACxE,CAAC,CACH,CACF,CACA,GAAI,EAAM,MAAO,CACf,EAAW,MAAQ,CAAE,GAAG,EAAM,KAAM,EACpC,IAAK,IAAM,IAAa,CAAC,SAAU,QAAQ,EAAY,CACrD,IAAM,EAAO,EAAM,MAAM,GACzB,GAAI,GAAQ,eAAe,EAAK,IAAI,EAAG,CACrC,IAAM,EAAW,IAAc,SAAW,EAAe,EACzD,EAAW,MAAM,GAAa,CAC5B,GAAG,EACH,KAAM,GACJ,gBAAgB,EAAK,KAAK,OAAO,EAAS,GAC1C,uBACF,CACF,CACF,CACF,CACF,CAIA,OAHI,EAAM,WACR,EAAW,SAAW,qBAAqB,EAAM,SAAU,CAAc,GAEpE,CACT,CAOA,SAAgB,kCACd,EACsB,CACtB,MAAO,CACL,GAAG,EACH,OAAQ,OAAO,YACb,OAAO,QAAQ,EAAM,MAAM,CAAC,CAAC,KAAK,CAAC,EAAM,KAAW,CAClD,EACA,eACE,EACA,SACA,wCACA,aACA,CACF,CACF,CAAC,CACH,CACF,CACF,CCtCA,SAAS,sBAAsB,EAAoC,EAA8B,CAC/F,OAAO,qBAAqB,CAC1B,SAAU,EAAa,UAAU,cACjC,aACA,SAAU,GAAsB,aAAa,EAAa,IAAI,CAChE,CAAC,CACH,CAQA,SAAgB,yCACd,EACA,EAAmC,CAAC,EACS,CAC7C,IAAM,EAAa,GAAW,SAAS,EAAa,WAAY,EAAI,EAG9D,EAcF,CACF,YAAa,EAAa,UAAU,aAAe,GACnD,WACE,EAAQ,wBAA0B,GAAO,GAAS,EAAa,UAAU,YAAc,GACzF,MAAO,GACP,sBAAuB,KACvB,kBAAmB,MACnB,aACA,oBACE,EAAQ,uBAAyB,IAE7B,sBAAsB,EAAc,EAAQ,YAAc,EAAK,CACvE,EAGM,EAAM,EAAa,UAAU,eAAiB,EAAQ,wBACxD,GAAO,EAAQ,wBAA0B,MAC3C,EAAgB,qBAAuB,CACrC,OAAQ,EAAQ,wBAA0B,IAAQ,GAAK,SAAW,GAClE,OAAQ,EAAQ,wBAA0B,IAAQ,GAAK,SAAW,GAClE,OAAQ,EAAQ,wBAA0B,IAAQ,GAAK,SAAW,GAClE,KAAM,EAAQ,wBAA0B,IAAQ,GAAK,OAAS,EAChE,GAIF,IAAM,EAGF,OAAO,YACT,OAAO,QAAQ,EAAa,MAAM,CAAC,CAChC,QAAQ,CAAC,KAAe,IAAc,IAAI,CAAC,CAC3C,KAAK,CAAC,EAAW,KAAiB,CAAC,EAAW,0BAA0B,CAAW,CAAC,CAAC,CAC1F,EAGM,EAAgB,IAAI,IAK1B,GAAI,EAAa,qBACf,IAAK,GAAM,CAAC,EAAc,KAAQ,OAAO,QAAQ,EAAa,oBAAoB,EAChF,EAAc,IAAI,EAAc,2BAA2B,EAAK,SAAS,CAAC,EAI9E,GAAI,EAAa,sBACf,IAAK,GAAM,CAAC,EAAc,KAAQ,OAAO,QAAQ,EAAa,qBAAqB,EACjF,EAAc,IAAI,EAAc,2BAA2B,EAAK,UAAU,CAAC,EAK/E,IAAM,EAAU,IAAI,IACpB,GAAI,EAAa,QACf,IAAK,GAAM,CAAC,EAAW,KAAgB,OAAO,QAAQ,EAAa,OAAO,EACxE,EAAQ,IAAI,EAAW,oBAAoB,CAAW,CAAC,EAK3D,IAAM,EAAQ,IAAI,IAClB,GAAI,EAAa,MACf,IAAK,GAAM,CAAC,EAAU,KAAgB,OAAO,QAAQ,EAAa,KAAK,EACrE,EAAM,IAAI,EAAU,CAAE,YAAa,GAAe,EAAG,CAAC,EAW1D,IAAM,EAAa,EAAa,aAAa,OACzC,+BAA+B,EAAa,YAAY,MAAM,EAC9D,CAPF,OAAQ,CAAC,EACT,KAAM,CAAC,EACP,OAAQ,CAAC,EACT,OAAQ,CAAC,CAIS,EAKd,CAAE,WAAU,gBAAiB,iBADf,kCAAkC,CACF,CAAA,CAAY,OAAQ,CACtE,aAAc,EAAa,OAC3B,aAAc,EAAa,aAC3B,iBAAkB,EAAa,gBACjC,CAAC,EAED,MAAO,CACL,KAAM,EAAa,KACnB,OAAQ,CACN,YAAa,EAAa,aAAe,GACzC,SACA,cAAe,OAAO,YAAY,CAAa,EAC/C,SAAU,EACV,QAAS,GACT,WAAY,CAAC,EACb,QAAS,OAAO,YAAY,CAAO,EACnC,MAAO,OAAO,YAAY,CAAK,EAC/B,aACA,GAAI,GAAY,CAAE,UAAS,EAC3B,GAAI,GAAgB,CAAE,cAAa,CACrC,CACF,CACF,CAEA,SAAS,iBACP,EACmF,CACnF,OAAO,EAAO,OAAO,QAAU,EAAO,UAAY,IAAA,GAAY,CAAE,iBAAkB,EAAK,EAAI,CAAC,CAC9F,CAOA,SAAgB,0BACd,EACyD,CACzD,IAAM,EAAsE,CAC1E,KAAM,EAAO,KACb,cACE,EAAO,OAAS,OACX,EAAO,eAAe,IAAK,IAA0B,CAAE,GAAG,CAAE,EAAE,GAAK,CAAC,EACrE,CAAC,EACP,YAAa,EAAO,aAAe,GACnC,MAAO,EAAO,OAAS,GACvB,MAAO,EAAO,OAAS,GACvB,OAAQ,EAAO,QAAU,GACzB,WAAY,EAAO,YAAc,GACjC,eAAgB,EAAO,eACvB,gBAAiB,EAAO,gBACxB,SAAU,EAAO,SACjB,OAAQ,EAAO,QAAU,GACzB,GAAG,iBAAiB,CAAM,EAC1B,GAAI,EAAO,QAAU,CACnB,OAAQ,CACN,MAAO,OAAO,EAAO,OAAO,KAAK,EACjC,GAAI,EAAO,OAAO,WAAa,IAAA,IAAa,CAC1C,SAAU,OAAO,EAAO,OAAO,QAAQ,CACzC,EACA,GAAI,EAAO,OAAO,QAAU,CAC1B,OAAQ,EAAO,OAAO,MACxB,CACF,CACF,EACA,GAAI,EAAO,QAAU,IAAA,IAAa,CAAE,MAAO,EAAO,KAAM,CAC1D,EAOA,OAJI,EAAO,OAAS,UAAY,EAAO,SACrC,EAAW,OAAS,gCAAgC,EAAO,MAAM,GAG5D,CACT,CAOA,SAAgB,gCACd,EACyE,CACzE,IAAM,EAAe,IAAI,IAEzB,IAAK,GAAM,CAAC,EAAW,KAAgB,OAAO,QAAQ,CAAM,EAC1D,GAAI,EAAY,OAAS,UAAY,EAAY,OAAQ,CACvD,IAAM,EAAmB,gCAAgC,EAAY,MAAM,EAC3E,EAAa,IAAI,EAAW,CAC1B,KAAM,SACN,cAAe,EAAY,eAAe,IAAK,IAA0B,CAAE,GAAG,CAAE,EAAE,GAAK,CAAC,EACxF,YAAa,EAAY,aAAe,GACxC,SAAU,EAAY,SACtB,MAAO,EAAY,OAAS,GAC5B,MAAO,GACP,OAAQ,GACR,WAAY,GACZ,OAAQ,GACR,OAAQ,EACR,GAAI,EAAY,QAAU,IAAA,IAAa,CAAE,MAAO,EAAY,KAAM,CACpE,CAAC,CACH,MACE,EAAa,IAAI,EAAW,CAC1B,KAAM,EAAY,KAClB,cACE,EAAY,OAAS,OAChB,EAAY,eAAe,IAAK,IAA0B,CAAE,GAAG,CAAE,EAAE,GAAK,CAAC,EAC1E,CAAC,EACP,YAAa,EAAY,aAAe,GACxC,SAAU,EAAY,SACtB,MAAO,EAAY,OAAS,GAC5B,MAAO,GACP,OAAQ,GACR,WAAY,GACZ,OAAQ,GACR,GAAG,iBAAiB,CAAW,EAC/B,GAAI,EAAY,QAAU,CACxB,OAAQ,CACN,MAAO,OAAO,EAAY,OAAO,KAAK,EACtC,GAAI,EAAY,OAAO,WAAa,IAAA,IAAa,CAC/C,SAAU,OAAO,EAAY,OAAO,QAAQ,CAC9C,EACA,GAAI,EAAY,OAAO,QAAU,CAC/B,OAAQ,EAAY,OAAO,MAC7B,CACF,CACF,EACA,GAAI,EAAY,QAAU,IAAA,IAAa,CAAE,MAAO,EAAY,KAAM,CACpE,CAAC,EAIL,OAAO,OAAO,YAAY,CAAY,CACxC,CAQA,SAAS,2BACP,EACA,EACgE,CAWhE,OAVI,IAAc,UACT,CACL,QAAS,EAAI,WACb,SAAU,EAAI,YACd,SAAU,EAAI,YACd,MAAO,EAAI,QACX,YAAa,EAAI,WACnB,EAGK,CACL,QAAS,EAAI,WACb,SAAU,EAAI,YACd,SAAU,EAAI,YACd,MAAO,EAAI,QACX,YAAa,EAAI,WACnB,CACF,CAOA,SAAgB,oBACd,EACmD,CACnD,MAAO,CACL,WAAY,EAAY,OACxB,OAAQ,EAAY,QAAU,EAChC,CACF,CAOA,SAAS,+BACP,EACwD,CACxD,MAAO,CACL,OAAQ,EAAW,OAAO,IAAI,8BAA8B,EAC5D,KAAM,EAAW,KAAK,IAAI,8BAA8B,EACxD,OAAQ,EAAW,OAAO,IAAI,8BAA8B,EAC5D,OAAQ,EAAW,OAAO,IAAI,8BAA8B,CAC9D,CACF,CAOA,SAAS,+BACP,EAC+D,CAC/D,IAAI,EACJ,OAAQ,EAAO,OAAf,CACE,IAAK,QACH,EAAS,GAA+B,MACxC,MACF,IAAK,OACH,EAAS,GAA+B,KACxC,MACF,QACE,MAAM,EAAc,uBAAuB,EAAO,QAAwB,CAC9E,CAEA,MAAO,CACL,WAAY,EAAO,WAAW,IAAI,uBAAuB,EACzD,SACA,YAAa,EAAO,WACtB,CACF,CAOA,SAAS,wBACP,EACkE,CAClE,GAAM,CAAC,EAAM,EAAU,GAAS,EAE1B,EAAI,sBAAsB,CAAI,EAC9B,EAAI,sBAAsB,CAAK,EAEjC,EACJ,OAAQ,EAAR,CACE,IAAK,KACH,EAAK,GAAiC,GACtC,MACF,IAAK,KACH,EAAK,GAAiC,GACtC,MACF,IAAK,KACH,EAAK,GAAiC,GACtC,MACF,IAAK,MACH,EAAK,GAAiC,IACtC,MACF,IAAK,SACH,EAAK,GAAiC,QACtC,MACF,IAAK,UACH,EAAK,GAAiC,SACtC,MACF,QACE,MAAM,EAAc,qBAAqB,GAA0B,CACvE,CAEA,MAAO,CACL,KAAM,EACN,SAAU,EACV,MAAO,CACT,CACF,CAOA,SAAS,sBACP,EACgE,CAChE,GAAI,0BAA0B,CAAO,EAAG,CACtC,GAAI,SAAU,EACZ,MAAO,CAAE,KAAM,CAAE,KAAM,YAAa,MAAO,EAAQ,IAAK,CAAE,EAE5D,GAAI,WAAY,EACd,MAAO,CAAE,KAAM,CAAE,KAAM,cAAe,MAAO,EAAQ,MAAO,CAAE,EAEhE,GAAI,cAAe,EACjB,MAAO,CAAE,KAAM,CAAE,KAAM,iBAAkB,MAAO,EAAQ,SAAU,CAAE,EAEtE,GAAI,cAAe,EACjB,MAAO,CAAE,KAAM,CAAE,KAAM,iBAAkB,MAAO,EAAQ,SAAU,CAAE,EAGtE,MAAM,EAAc,oCAAoC,KAAK,UAAU,CAAO,GAAG,CACnF,CAEA,MAAO,CACL,KAAM,CAAE,KAAM,QAAS,MAAO,GAAS,GAAa,CAAO,CAAE,CAC/D,CACF,CAgBA,SAAgB,qCACd,EACA,EAAuC,CAAC,EACkB,CAC1D,IAAM,EAAY,IAAI,IAChB,CAAE,qBAAoB,GAAG,GAAgB,EAE/C,IAAK,GAAM,CAAC,EAAW,KAAiB,OAAO,QAAQ,EAAS,MAAM,EAAG,CACvE,IAAM,EAAuC,CAC3C,GAAG,EACH,WAAY,GAAoB,IAAI,CAAS,GAAK,EACpD,EACA,EAAU,IAAI,EAAW,yCAAyC,EAAc,CAAW,CAAC,CAC9F,CAEA,OAAO,CACT,CAoBA,SAAgB,0BACd,EACA,EACwB,CACxB,IAAM,EAAqB,IAAI,IAAI,OAAO,KAAK,EAAS,MAAM,CAAC,EAEzD,EAAoB,CAAC,EACrB,EAAoB,CAAC,EACrB,EAAoB,CAAC,EAG3B,IAAK,IAAM,KAAa,EAClB,EAAmB,IAAI,CAAS,EAClC,EAAQ,KAAK,CAAS,EAEtB,EAAQ,KAAK,CAAS,EAK1B,IAAK,IAAM,KAAa,EACjB,EAAmB,IAAI,CAAS,GACnC,EAAQ,KAAK,CAAS,EAI1B,MAAO,CAAE,UAAS,UAAS,SAAQ,CACrC,CAOA,SAAgB,mBACd,EACsD,CACtD,MAAO,CACL,SAAU,EAAW,IAAK,GAAW,eAAe,CAAM,CAAC,CAC7D,CACF,CAEA,SAAS,eACP,EAC6D,CAC7D,IAAM,EAA0C,CAAC,EACjD,IAAK,IAAM,KAAU,EAAO,QAC1B,OAAQ,EAAR,CACE,IAAK,MACH,EAAQ,KAAK,EAA6B,GAAG,EAC7C,MACF,IAAK,SACH,EAAQ,KAAK,EAA6B,MAAM,EAChD,MACF,IAAK,OACH,EAAQ,KAAK,EAA6B,IAAI,EAC9C,MACF,IAAK,SACH,EAAQ,KAAK,EAA6B,MAAM,EAChD,MACF,IAAK,SACH,EAAQ,KAAK,EAA6B,MAAM,EAChD,MACF,IAAK,YACH,EAAQ,KAAK,EAA6B,SAAS,EACnD,MACF,IAAK,aACH,EAAQ,KAAK,EAA6B,WAAW,EACrD,MACF,QACE,MAAM,EAAc,mBAAmB,GAAwB,CACnE,CAEF,IAAI,EACJ,OAAQ,EAAO,OAAf,CACE,IAAK,QACH,EAAS,GAA6B,MACtC,MACF,IAAK,OACH,EAAS,GAA6B,KACtC,MACF,QACE,MAAM,EAAc,uBAAuB,EAAO,QAAwB,CAC9E,CACA,MAAO,CACL,WAAY,EAAO,WAAW,IAAK,GAAS,kBAAkB,CAAI,CAAC,EACnE,UACA,SACA,YAAa,EAAO,WACtB,CACF,CAEA,SAAS,kBACP,EACgE,CAChE,GAAM,CAAC,EAAM,EAAU,GAAS,EAE1B,EAAI,gBAAgB,CAAI,EACxB,EAAI,gBAAgB,CAAK,EAC3B,EACJ,OAAQ,EAAR,CACE,IAAK,KACH,EAAK,GAA+B,GACpC,MACF,IAAK,KACH,EAAK,GAA+B,GACpC,MACF,IAAK,KACH,EAAK,GAA+B,GACpC,MACF,IAAK,MACH,EAAK,GAA+B,IACpC,MACF,IAAK,SACH,EAAK,GAA+B,QACpC,MACF,IAAK,UACH,EAAK,GAA+B,SACpC,MACF,QACE,MAAM,EAAc,qBAAqB,GAA0B,CACvE,CACA,MAAO,CACL,KAAM,EACN,SAAU,EACV,MAAO,CACT,CACF,CAEA,SAAS,gBACP,EAC8D,CAC9D,GAAI,0BAA0B,CAAO,EAAG,CACtC,GAAI,SAAU,EACZ,MAAO,CAAE,KAAM,CAAE,KAAM,YAAa,MAAO,EAAQ,IAAK,CAAE,EAE5D,MAAM,EAAS,CACb,KAAM,0CACN,QAAS,oDAAoD,KAAK,UAAU,CAAO,EAAE,GACrF,WAAY,yDACd,CAAC,CACH,CAEA,MAAO,CACL,KAAM,CAAE,KAAM,QAAS,MAAO,GAAS,GAAa,CAAO,CAAE,CAC/D,CACF,CChpBA,eAAsB,sBACpB,EACA,EACA,EACA,EAAiD,CAAC,EAClD,EACgC,CAEhC,IAAM,EAAY,EAAK,QAAQ,GAAW,EAAG,YAAY,EACzD,EAAG,UAAU,EAAW,CAAE,UAAW,EAAK,CAAC,EAG3C,IAAM,EAAY,EAAK,KAAK,EAAW,aAAa,EAAU,GAAG,EAAgB,UAAU,EAErF,EAAqB,EAAK,QAAQ,CAAU,CAAC,CAAC,QAAQ,MAAO,GAAG,EAIhE,EAAe,CAAY;8CACW,EAAmB;;;;;;;;;;;oBAW7C,KAAK,UAAU,CAAG,EAAE;0BACd,EAAU;;;;;;IAOlC,EAAG,cAAc,EAAW,CAAY,EAExC,IAAM,EAAa,GAAW,EAAK,QAAQ,CAAkB,EACvD,EAAW,MAAM,GAA4B,CAAU,EAGvD,EAAY,GAAgB,CAAE,UAAS,CAAC,EACxC,EAAS,MAAM,GAAS,MAAM,CAClC,QAAS,CACP,GAAmC,EAAW,CAAU,EACxD,GAA0B,EAC1B,EACF,EACA,MAAO,EACP,MAAO,GACP,OAAQ,CACN,OAAQ,MACR,UAAW,GACX,OAAQ,GACR,cAAe,GACf,QAAS,CACP,SAAU,UACZ,CACF,EACA,SAAU,CAAC,UAAU,EACrB,QAAS,CACP,eAAgB,CAAC,OAAQ,QAAQ,CACnC,EACA,WACA,UAAW,CACT,kBAAmB,GACnB,YAAa,GACb,yBAA0B,EAC5B,EACA,GAAG,EAAU,OACf,CAA0B,EAO1B,OANA,EAAU,kBAAkB,EAMrB,CACL,YACA,kBACA,YAPkB,EAAO,OAAO,EAAE,CAAC,IAQrC,CACF,CCpGA,SAAgB,6BAA6B,EAAgD,CAC3F,GAAM,CAAE,kBAAiB,YAAW,aAAY,YAAa,EACvD,EAAO,CACX,SACA,WACA,YACA,SACA,sBAAsB,CAAe,EACrC,cACA,CACF,EACM,EAAY,gBAAgB,CAAU,EAO5C,OANI,IAAc,IAAA,IAChB,EAAK,KAAK,CAAS,EAEjB,GACF,EAAK,KAAK,cAAe,WAAY,UAAU,EAE1C,GAAsB,CAAI,CACnC,CCtCA,MAAM,GAAS,CAAC,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAG,EAI1D,GAAc,YACd,GAAa,UASb,GAAU,2BAEhB,SAAS,cAAc,EAAmB,CACxC,OAAO,EAAE,QAAQ,GAAS,EAAE,CAAC,CAAC,MAChC,CAOA,MAAM,GAAiB,IAAI,IAC3B,IAAI,GAAoB,GACpB,GAAsB,GAE1B,SAAS,iBAAwB,CAC3B,KACJ,GAAoB,GAGpB,QAAQ,GAAG,WAAc,CACvB,IAAK,IAAM,KAAK,GACd,EAAE,cAAc,CAEpB,CAAC,EACH,CAEA,SAAS,mBAA0B,CACjC,GAAI,GAAqB,OACzB,GAAsB,GAatB,IAAM,YAAsB,CAC1B,IAAK,IAAM,KAAK,GAAgB,EAAE,KAAK,CACzC,EACA,QAAQ,gBAAgB,SAAU,OAAO,EACzC,QAAQ,gBAAgB,UAAW,OAAO,CAC5C,CAEA,IAAa,QAAb,KAAqB,CACnB,KACA,GACA,GACA,GACA,GAAS,EACT,GACA,GAAc,EACd,GAAW,GAEX,YAAY,EAA0B,CAAC,EAAG,CACxC,KAAK,KAAO,GACZ,KAAK,GAAU,EAAQ,QAAU,EACjC,KAAK,GAAU,EAAQ,QAAU,QAAQ,OACzC,KAAK,GAAa,EAAQ,KAAK,GAAQ,KACzC,CAEA,MAAM,EAAqB,CAqBzB,OApBI,IAAS,IAAA,KAAW,KAAK,KAAO,GAE/B,KAAK,GAKN,KAAK,GAEA,MAGT,gBAAgB,EAChB,kBAAkB,EAClB,GAAe,IAAI,IAAI,EACvB,KAAK,GAAW,GAChB,KAAK,GAAQ,MAAM,WAAW,EAC9B,KAAK,GAAa,EAClB,KAAK,GAAS,gBAAkB,KAAK,GAAa,EAAG,EAAiB,EAClE,OAAO,KAAK,GAAO,OAAU,YAAY,KAAK,GAAO,MAAM,EACxD,OAjBL,KAAK,GAAW,KAAK,KAAK,MAAM,EACzB,KAiBX,CAEA,MAAa,CAYX,OAXK,KAAK,IACV,KAAK,GAAW,GAChB,AAEE,KAAK,MADL,cAAc,KAAK,EAAM,EACX,IAAA,IAEZ,KAAK,KACP,KAAK,GAAY,EACjB,KAAK,GAAQ,MAAM,EAAW,GAEhC,GAAe,OAAO,IAAI,EACnB,MAXoB,IAY7B,CAEA,QAAQ,EAAqB,CAC3B,OAAO,KAAK,GAAgB,EAAQ,QAAS,CAAI,CACnD,CAEA,KAAK,EAAqB,CACxB,OAAO,KAAK,GAAgB,EAAQ,MAAO,CAAI,CACjD,CAEA,KAAK,EAAqB,CACxB,OAAO,KAAK,GAAgB,EAAQ,QAAS,CAAI,CACnD,CAMA,eAAsB,CACpB,AAEE,KAAK,MADL,cAAc,KAAK,EAAM,EACX,IAAA,IAEZ,KAAK,IACP,KAAK,GAAQ,MAAM,EAAW,CAElC,CAEA,GAAgB,EAAgB,EAAqB,CAenD,OAdI,IAAS,IAAA,KAAW,KAAK,KAAO,GAChC,KAAK,KACP,KAAK,GAAW,GAChB,AAEE,KAAK,MADL,cAAc,KAAK,EAAM,EACX,IAAA,IAEZ,KAAK,KACP,KAAK,GAAY,EACjB,KAAK,GAAQ,MAAM,EAAW,GAEhC,GAAe,OAAO,IAAI,GAE5B,KAAK,GAAW,GAAG,EAAO,GAAG,KAAK,MAAM,EACjC,IACT,CAEA,IAAqB,CACnB,KAAK,GAAQ,MAAM,aAAU,EAC7B,KAAK,GAAY,EACjB,IAAM,EAAQ,EAAO,KACnB,GAAO,KAAK,KAAW,EAAc,GAAO,GAAI,sBAAsB,CACxE,EACA,KAAK,IAAU,KAAK,GAAS,GAAK,GAAO,OAEzC,IAAM,EAAO,GADE,IAAI,OAAO,KAAK,EACV,IAAI,EAAM,GAAG,KAAK,OACvC,KAAK,GAAQ,MAAM,GAAU,KAAK,GAAS,CAAI,CAAC,EAChD,KAAK,GAAQ,MAAM,aAAQ,EAC3B,IAAM,EAAO,KAAK,GAAQ,SAAW,GACrC,KAAK,GAAc,KAAK,IAAI,EAAG,KAAK,KAAK,cAAc,CAAI,EAAI,CAAI,CAAC,CACtE,CAEA,IAAoB,CACd,QAAK,KAAgB,EAEzB,CADA,KAAK,GAAQ,MAAM,IAAe,EAClC,KAAK,GAAQ,MAAM,EAAU,EAC7B,IAAK,IAAI,EAAI,EAAG,EAAI,KAAK,GAAa,IACpC,KAAK,GAAQ,MAAM,SAAS,EAC5B,KAAK,GAAQ,MAAM,EAAU,EAE/B,KAAK,GAAc,CALU,CAM/B,CAEA,GAAW,EAAuB,CAChC,IAAM,EAAS,IAAI,OAAO,KAAK,EAAO,EACtC,KAAK,GAAQ,MAAM,GAAU,KAAK,GAAS,GAAG,IAAS,EAAQ,GAAG,CAAC,CACrE,CACF,EAQA,SAAgB,QAAQ,EAAmC,CACzD,OAAO,IAAI,QAAQ,CAAO,CAC5B,CCnLA,MAAMC,GAAa,MAgCnB,SAAgB,8BAA8B,EAAmB,EAAiC,CAChG,MAAO,uBAAuB,EAAU,IAAI,sBAAsB,CAAe,GACnF,CAWA,eAAe,wBACb,EACA,EACA,EACA,EACA,EACA,EACe,CACf,IAAM,EAAS,OAAO,KAAK,EAAM,OAAO,EAClC,EAAO,CACX,cACA,OACA,YAAa,8CACb,UAAW,OAAO,EAAO,MAAM,EAC/B,YAAaC,GAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,EAAM,OAAO,CAAC,CAAC,OAAO,KAAK,CAC7E,EAGA,eAAgB,QAEd,CACA,KAAM,CAAE,QAAS,CAAE,KAAM,OAAiB,MAAO,CAAK,CAAE,EACxD,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,OAAQ,GAAKD,GACtC,KAAM,CACJ,QAAS,CACP,KAAM,QACN,MAAO,EAAO,SAAS,EAAG,KAAK,IAAI,EAAIA,GAAY,EAAO,MAAM,CAAC,CACnE,CACF,CAEJ,CAEA,MAAM,EAAO,uBAAuB,OAAO,CAAC,EAC5C,MAAM,0BACJ,EACA,MAAM,iBAAiB,CACrB,IAAK,YAAY,EAAa,oBAAqB,CAAI,EACvD,UACA,OACF,CAAC,CACH,CACF,CAaA,eAAe,SACb,EACA,EACA,EACA,EACe,CACf,IAAM,EAA4C,CAChD,GAAI,EACC,CAAC,CAAC,eAAkB,EAAO,eAAe,CAAE,cAAa,YAAW,CAAC,CAAC,CAAC,EAIxE,CAAC,EACL,CACE,mBACM,EAAO,0BAA0B,CAAE,cAAa,gBAAiB,CAAK,CAAC,CAC/E,EACA,CAAC,eAAkB,EAAO,uBAAuB,CAAE,cAAa,MAAK,CAAC,CAAC,CACzE,EAEA,IAAK,GAAM,CAAC,EAAO,KAAQ,EACzB,GAAI,CACF,MAAM,EAAI,CACZ,OAAS,EAAO,CAGd,GAAI,GAAgB,CAAK,EAAG,SAC5B,EAAO,KACL,4CAA4C,EAAM,IAAI,EAAK,KACtD,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAAE,2EAE9D,CACF,CAEJ,CAYA,eAAe,iBACb,EACA,EACA,EACe,CAEf,MAAM,SAAS,EAAQ,EAAa,EAAM,MADjB,wBAAwB,EAAQ,EAAa,CAAI,CACtB,CACtD,CASA,eAAe,wBACb,EACA,EACA,EAC6B,CAC7B,GAAI,CACF,GAAM,CAAE,YAAa,MAAM,EAAO,kBAAkB,CAAE,cAAa,aAAc,CAAK,CAAC,EACvF,OAAO,GAAU,EACnB,OAAS,EAAO,CACd,GAAI,GAAgB,CAAK,EAAG,OAC5B,MAAM,CACR,CACF,CAUA,eAAsB,2BACpB,EACqC,CACrC,GAAM,CAAE,SAAQ,cAAa,OAAM,YAAW,kBAAiB,UAAS,UAAS,SAC/E,EACI,EAAO,8BAA8B,EAAW,CAAe,EAC/D,EAAe,EAAQ,gBAAkB,IAE3C,EACJ,GAAI,CACF,MAAM,iBAAiB,EAAQ,EAAa,CAAI,EAChD,MAAM,wBAAwB,EAAQ,EAAa,EAAM,EAAM,EAAS,CAAK,EAE7E,GAAM,CAAE,eAAgB,MAAM,EAAO,0BAA0B,CAC7D,cACA,gBAAiB,EACjB,UAAW,EACX,uBAAwB,EAC1B,CAAC,EACD,MAAM,0BACJ,EACA,MAAM,iBAAiB,CACrB,IAAK,YAAY,EAAa,wBAAyB,CAAI,EAC3D,UACA,OACF,CAAC,CACH,EAEA,IAAM,EAAU,GAAa,QAC7B,GAAI,IAAY,IAAA,GACd,MAAM,EACJ,qCAAqC,EAAK,iCAC5C,EAGF,GAAM,CAAE,YAAa,MAAM,EAAO,eAAe,CAC/C,cACA,aAAc,EACd,oBAAqB,EACrB,aAAc,EAAG,GAAO,CAAQ,CAClC,CAAC,EAED,GADA,EAAa,GAAU,GACnB,CAAC,EACH,MAAM,EAAc,iCAAiC,EAAK,6BAA6B,EAEzF,MAAM,0BACJ,EACA,MAAM,iBAAiB,CACrB,IAAK,YAAY,EAAa,WAAY,CAAI,EAC9C,UACA,OACF,CAAC,CACH,EAEA,GAAM,CAAE,eAAgB,MAAM,EAAO,cAAc,CACjD,cACA,aACA,YAAa,CACf,CAAC,EAED,OAAO,MAAM,yBAAyB,EAAQ,EAAa,EAAa,CAAY,CACtF,QAAU,CACR,MAAM,SAAS,EAAQ,EAAa,EAAM,CAAU,CACtD,CACF,CAUA,eAAe,yBACb,EACA,EACA,EACA,EACqC,CAGrC,OAAa,CACX,GAAM,CAAE,aAAc,MAAM,EAAO,qBAAqB,CACtD,cACA,aACF,CAAC,EACD,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,+BACN,QAAS,iCAAiC,EAAY,aACxD,CAAC,EAGH,GAAI,EAAU,SAAW,EAAyB,QAAS,CACzD,GAAM,CAAE,QAAS,MAAM,mBAAmB,EAAQ,EAAa,CAAS,EACxE,MAAO,CAAE,QAAS,GAAM,MAAK,CAC/B,CACA,GAAI,EAAU,SAAW,EAAyB,OAAQ,CACxD,IAAM,EAAW,MAAM,mBAAmB,EAAQ,EAAa,CAAS,EACxE,MAAO,CACL,QAAS,GACT,KAAM,EAAS,KACf,MAAO,sBAAsB,CAAQ,CACvC,CACF,CAEA,MAAM,IAAI,QAAS,GAAY,WAAW,EAAS,CAAY,CAAC,CAClE,CACF,CAYA,eAAe,mBACb,EACA,EACA,EAC+C,CAC/C,IAAM,EAAW,MAAM,QAAQ,IAC7B,EAAU,cAAc,IAAI,KAAO,IAAQ,CACpC,KAAI,YACT,GAAI,CACF,GAAM,CAAE,UAAW,GAAsB,MAAM,EAAO,qBAAqB,CACzE,cACA,YAAa,EAAI,WACnB,CAAC,EACD,GAAI,CAAC,EAAmB,OAGxB,IAAM,EACJ,EAAkB,OAAO,QAAQ,KAAK,GAAK,EAAkB,OAAO,KAAK,GAAK,GAChF,MAAO,CAAE,KAAM,EAAkB,KAAM,SAAQ,CACjD,MAAQ,CACN,MACF,CACF,CAAC,CACH,EAEA,MAAO,CACL,KAAM,EACH,IAAK,GAAY,GAAS,IAAI,CAAC,CAC/B,OAAO,OAAO,CAAC,CACf,KAAK;CAAI,EACZ,SAAU,EACP,IAAK,GAAY,GAAS,OAAO,CAAC,CAClC,OAAQ,GAA+B,CAAC,CAAC,CAAO,CACrD,CACF,CAQA,SAAS,sBAAsB,EAAwD,CAQrF,OAPgB,EAAS,SAAS,GAAG,EACjC,GAEkB,EAAS,KAC5B,MAAM;CAAI,CAAC,CACX,OAAQ,GAAS,SAAS,KAAK,CAAI,CAAC,CAAC,CACrC,GAAG,EACa,CAAC,EAAE,KAAK,GAAK,sCAClC,CCvSA,eAAe,0BACb,EACA,EACA,EACiB,CACjB,GAAI,CACF,IAAM,EAAM,YAAY,EAAa,WAAY,CAAS,EAEpD,CAAE,YAAa,MAAM,EAAO,YAAY,CAAE,KAAI,CAAC,EAE/C,EAAQ,GAAU,OAAO,IAM/B,OAJK,EAGO,0BAA0B,CAC7B,GAAK,EAHL,CAIX,OAAS,EAAO,CACd,GAAI,GAAgB,CAAK,EACvB,MAAO,GAET,MAAM,CACR,CACF,CAWA,eAAsB,wBACpB,EACA,EACA,EACA,EACA,EAC6B,CAC7B,IAAM,EAAwC,CAAC,EAE/C,IAAK,GAAM,CAAE,YAAW,mBAAmB,EAA0B,CAEnE,IAAM,EACJ,GAA2B,IAAI,CAAS,GACvC,MAAM,0BAA0B,EAAQ,EAAa,CAAS,EAG3D,EAAiB,kBAAkB,CAAa,EAGtD,IAAK,IAAM,KAAQ,EAAgB,CACjC,GAAI,EAAK,QAAU,EACjB,SAIF,IAAM,EAAW,qBAAqB,EAAe,EAAK,OAAQ,MAAM,EACxE,GAAI,CAACE,EAAG,WAAW,CAAQ,EACzB,SAIF,IAAM,EAAO,SAAS,CAAQ,EAMxB,EAAa,qBAAqB,EAAe,EAAK,OAAQ,SAAS,EACvE,EAAYA,EAAG,WAAW,CAAU,EAC1C,GAAI,EAAK,yBAA2B,CAAC,GAAa,CAAC,EAAK,cAAe,CACrE,IAAM,EAAiB,CAAE,gBAAiB,EAAK,OAAQ,YAAW,YAAW,EAC7E,MAAM,EAAS,CACb,KAAM,4BACN,QAAS,aAAa,EAAU,GAAG,sBAAsB,EAAK,MAAM,EAAE,4DACtE,WAAY,iBAAiB,6BAA6B,CAAc,EAAE,wCAAwC,6BAA6B,CAAE,GAAG,EAAgB,SAAU,EAAK,CAAC,GACtL,CAAC,CACH,CACA,GAAI,EAAK,cAAe,CACtB,IAAM,EAAiB,GAAG,EAAU,GAAG,sBAAsB,EAAK,MAAM,IACxE,GAAI,EACF,MAAM,EAAS,CACb,KAAM,iCACN,QAAS,aAAa,EAAe,6DACrC,WAAY,uDAAuD,6BAA6B,CAAE,gBAAiB,EAAK,OAAQ,YAAW,YAAW,CAAC,EAAE,sCAC3J,CAAC,EAEH,EAAO,KACL,aAAa,EAAe,+CAA+C,EAAK,cAAc,eAAe,IAAI,EAAK,cAAc,OAAO,EAC7I,CACF,CAEA,EAAkB,KAAK,CACrB,OAAQ,EAAK,OACb,aACA,YACA,WACA,YACA,gBACA,MACF,CAAC,CACH,CACF,CAGA,OAAO,EAAkB,UAAU,EAAG,IAChC,EAAE,YAAc,EAAE,UAGf,EAAE,OAAS,EAAE,OAFX,EAAE,UAAU,cAAc,EAAE,SAAS,CAG/C,CACH,CAYA,eAAe,uBACb,EACA,EAC0B,CAC1B,GAAM,CAAE,SAAQ,cAAa,UAAS,MAAK,YAAW,UAAS,SAAU,EAWnE,EAAS,MAAM,2BAA2B,CAC9C,SACA,cACA,MAAM,MAXmB,sBACzB,EAAU,WACV,EAAU,UACV,EAAU,OACV,EACA,CACF,EAKQ,CAAa,YACnB,UAAW,EAAU,UACrB,gBAAiB,EAAU,OAC3B,UACA,UACA,OACF,CAAC,EAED,MAAO,CACL,UAAW,EAAU,UACrB,gBAAiB,EAAU,OAC3B,QAAS,EAAO,QAChB,KAAM,EAAO,KACb,MAAO,EAAO,KAChB,CACF,CAWA,eAAsB,qBACpB,EACA,EACA,EACA,EACA,EACe,CAGf,MAAM,0BAA0B,EAAQ,CACtC,IAHU,YAAY,EAAa,WAAY,CAG/C,EACA,OAAQ,EACL,IAAsB,uBAAuB,CAAe,EAC7D,GAAI,EAAY,EAAG,IAA8B,CAAU,EAAI,CAAC,CAClE,EACA,OAAQ,EAAY,IAAA,GAAY,CAAC,EAA2B,CAC9D,CAAC,CACH,CAQA,eAAsB,kBACpB,EACA,EACe,CAGf,IAAM,EAAwB,EAAW,OAAQ,GAAM,EAAE,SAAS,EAElE,GAAI,EAAsB,SAAW,EACnC,OAIF,IAAM,EAAwB,2BAA2B,CAAqB,EAG9E,IAAK,GAAM,CAAC,EAAW,KAAwB,EAAuB,CAEpE,IAAM,EADW,EAAQ,SAAS,EACF,EAAE,UAG5B,EAAkB,wBAAwB,EAAiB,EAAQ,YAAY,EACrF,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,wBACN,QAAS,mEAAmE,EAAU,IACtF,WACE,+FACJ,CAAC,EAGH,IAAM,EAAU,GAAO,GAAmB,CACxC,UAAW,EAAQ,cACnB,iBACF,CAAC,EAEK,EAAqC,CACzC,OAAQ,EAAQ,OAChB,YAAa,EAAQ,YACrB,UACA,IAAK,EAAQ,IACb,UAAW,EAAQ,UACnB,QAAS,EAAQ,QACjB,MAAO,EAAQ,KACjB,EAEA,EAAO,KAAK,uBAAuB,EAAO,KAAK,CAAe,EAAE,kBAAkB,EAAU,EAAE,EAE9F,IAAK,IAAM,KAAa,EAAqB,CAC3C,IAAM,EAAiB,GAAG,EAAU,UAAU,GAAG,sBAAsB,EAAU,MAAM,IACjF,EAAK,QAAQ,CAAC,CAAC,MACnB,uBAAuB,EAAe,4BACxC,EAEM,EAAS,MAAM,uBAAuB,EAAS,CAAS,EAE9D,GAAI,EAAO,QACT,EAAG,QAAQ,aAAa,EAAe,wBAAwB,EAG3D,EAAO,MAAQ,EAAO,KAAK,KAAK,GAClC,EAAO,IAAI,UAAU,EAAO,MAAM,OAOpC,MAJA,EAAG,KAAK,aAAa,EAAe,QAAQ,EACxC,EAAO,MACT,EAAO,MAAM,UAAU,EAAO,MAAM,EAEhC,EAAS,CAAE,KAAM,mBAAoB,QAAS,EAAO,OAAS,kBAAmB,CAAC,CAE5F,CACF,CACF,CAYA,SAAgB,wBACd,EACA,EACoB,CAEpB,GAAI,GAAiB,YACnB,OAAO,EAAgB,YAIzB,GAAI,GAAgB,EAAa,OAAS,EACxC,OAAO,EAAa,EAIxB,CAOA,SAAgB,2BACd,EACiC,CACjC,IAAM,EAAU,IAAI,IACpB,IAAK,IAAM,KAAa,EAAY,CAClC,IAAM,EAAW,EAAQ,IAAI,EAAU,SAAS,GAAK,CAAC,EACtD,EAAS,KAAK,CAAS,EACvB,EAAQ,IAAI,EAAU,UAAW,CAAQ,CAC3C,CACA,OAAO,CACT,CC9UA,SAAS,kBAAqB,EAA2B,EAAa,EAAgB,CACpF,OAAO,eAAe,EAAQ,EAAK,CACjC,QACA,WAAY,GACZ,SAAU,GACV,aAAc,EAChB,CAAC,CACH,CAKA,MAAM,GAA4B,IAAI,IAAwB,CAC5D,cACA,iBACA,sBACA,gBACA,eACF,CAAC,EAQD,SAAS,0BAA0B,EAA+C,CAChF,OAAO,GAA0B,IAAI,EAAO,IAAI,CAClD,CAwBA,SAAgB,+BACd,EACA,EACA,EACsB,CACtB,IAAM,EAAS,gBAAgB,EAAa,MAAM,EAC9C,EAAqB,GAEzB,IAAK,GAAM,CAAC,EAAW,KAAW,EAC5B,EAAO,OAAS,wBACpB,EAAqB,GACrB,kBAAkB,EAAQ,EAAW,gBAAgB,EAAO,MAAM,CAAC,GAGrE,IAAM,EAAkB,CAAE,GAAG,EAAc,QAAO,EAClD,GAAI,CAAC,GAAsB,CAAC,EAAmB,OAAO,EAEtD,GAAM,CACJ,aAAc,EACd,iBAAkB,EAClB,GAAG,GACD,EACJ,MAAO,CACL,GAAG,EACH,GAAI,EAAkB,OAAO,cAAgB,CAC3C,aAAc,gBAAgB,EAAkB,OAAO,YAAY,CACrE,EACA,GAAI,EAAkB,OAAO,mBAAqB,IAAA,IAAa,CAC7D,iBAAkB,EAAkB,OAAO,gBAC7C,CACF,CACF,CAOA,SAAgB,4BACd,EACwB,CACxB,OAAO,qCAAqC,EAAkB,IAAK,GAAM,EAAE,IAAI,CAAC,CAClF,CAOA,SAAgB,qCACd,EACwB,CACxB,IAAM,EAA8B,IAAI,IACxC,IAAK,IAAM,KAAQ,EACjB,IAAK,IAAM,KAAU,EAAK,QAAS,CAEjC,GADI,CAAC,0BAA0B,CAAM,GACjC,CAAC,EAAO,UAAW,SACvB,IAAM,EAAU,EAAI,IAAI,EAAO,SAAS,GAAK,IAAI,IACjD,EAAQ,IAAI,EAAO,UAAW,CAAM,EACpC,EAAI,IAAI,EAAO,UAAW,CAAO,CACnC,CAEF,OAAO,CACT,CAiBA,SAAgB,kCACd,EACA,EACM,CACN,2BAA2B,EAAQ,EAAa,CAC9C,QAAS,0BACT,qBAAsB,EAAO,IAAW,CACtC,4BAA4B,EAAO,EAAO,OAAQ,EAAO,KAAK,EAC9D,0BAA0B,EAAO,EAAO,eAAiB,CAAC,CAAC,CAC7D,CACF,CAAC,CACH,CAUA,SAAgB,4CACd,EACA,EACM,CACN,2BAA2B,EAAQ,EAAa,CAC9C,QAAU,GAAW,gBAAgB,CAAM,CAC7C,CAAC,CACH,CAgBA,SAAS,2BACP,EACA,EACA,EACM,CACN,IAAK,GAAM,CAAC,EAAW,KAAW,EAAa,CAC7C,GAAI,EAAO,OAAS,gBAAiB,CACnC,kBAAkB,EAAQ,EAAW,EAAS,QAAQ,EAAO,MAAM,CAAC,EACpE,QACF,CAEA,GAAI,EAAO,OAAS,gBAAiB,CAOnC,kBAAkB,EAAQ,EAAO,kBAAmB,EAAS,QAAQ,EAAO,MAAM,CAAC,EACnF,IAAM,EAA0C,EAAO,GACnD,IACE,EAAO,MAAM,WAAU,EAAS,SAAW,KAC3C,EAAO,MAAM,QAAU,MAAO,EAAS,OAAS,KAEtD,QACF,CAEA,IAAM,EAAQ,EAAO,GACrB,GAAI,CAAC,EAAO,SAEZ,IAAM,EAA6B,EAEnC,GAAI,EAAO,OAAS,cAAe,CAC7B,EAAO,MAAM,WACf,EAAQ,SAAW,IAErB,QACF,CAEA,GAAI,EAAO,OAAS,sBAAuB,CACzC,kBAAkB,EAAQ,EAAW,EAAS,QAAQ,EAAO,MAAM,CAAC,EACpE,QACF,CAEA,GAAM,CAAE,SAAQ,SAAU,EAE1B,EAAS,sBAAsB,EAAO,CAAM,EAExC,CAAC,EAAO,UAAY,EAAM,WAC5B,EAAQ,SAAW,IAGjB,EAAE,EAAO,QAAU,MAAW,EAAM,QAAU,MAChD,EAAQ,OAAS,IAInB,IAAM,EAAgB,EAAO,eAAiB,CAAC,EACzC,EAAe,EAAM,eAAiB,CAAC,EACvC,EAAc,IAAI,IAAI,EAAa,IAAK,GAAM,EAAE,KAAK,CAAC,EAE5D,GADsB,EAAc,OAAQ,GAAM,CAAC,EAAY,IAAI,EAAE,KAAK,CAC1D,CAAC,CAAC,OAAS,EAAG,CAC5B,IAAM,EAAW,IAAI,IACrB,IAAK,IAAM,KAAK,EACd,EAAS,IAAI,EAAE,MAAO,EAAE,aAAe,EAAE,EAE3C,IAAK,IAAM,KAAK,EACT,EAAS,IAAI,EAAE,KAAK,GACvB,EAAS,IAAI,EAAE,MAAO,EAAE,aAAe,EAAE,EAG7C,EAAQ,cAAgB,MAAM,KAAK,EAAS,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,EAAO,MAAkB,CACpF,QACA,aACF,EAAE,CACJ,CACF,CACF,CAUA,SAAS,qBACP,EACA,EAC8B,CAC9B,OAAO,EAAK,QACT,EAAS,IAAY,GAAS,SAAS,GACxC,CACF,CACF,CASA,SAAS,4BACP,EACA,EACA,EACM,CACN,IAAK,IAAM,KAAU,2BAA2B,EAAQ,CAAK,EAAG,CAC9D,GAAI,EAAO,OAAS,UAAW,SAC/B,IAAM,EAAa,EAAO,KAAK,KAAK,GAAG,EACjC,EAAgB,EACpB,qBAAqB,EAAO,EAAO,KAAK,MAAM,EAAG,EAAE,CAAC,CAAC,EAAE,OACvD,oCAAoC,EAAW,mCACjD,EACM,EAAa,EAAc,EAAO,KAAK,GAAG,EAAE,EAAG,qCAAqC,EACpF,EAAW,gCAAgC,EAAG,GAAa,EAAO,MAAO,CAAC,EAChF,kBACE,EACA,EACA,EAAc,EAAS,GAAa,2BAA2B,EAAW,UAAU,CACtF,CACF,CACF,CAUA,SAAS,0BACP,EACA,EACM,CACN,IAAK,IAAM,KAAU,EAAe,CAClC,IAAM,EAAS,qBAAqB,EAAO,EAAO,IAAI,EAClD,GAAQ,WAAU,EAAO,SAAW,IACpC,GAAQ,SAAQ,EAAO,OAAS,GACtC,CACF,CAcA,SAAgB,iCACd,EAC6B,CAC7B,OAAO,0CAA0C,EAAkB,IAAK,GAAM,EAAE,IAAI,CAAC,CACvF,CAOA,SAAgB,0CACd,EAC6B,CAC7B,IAAM,EAAmC,IAAI,IAC7C,IAAK,IAAM,KAAQ,EACjB,IAAK,IAAM,KAAU,EAAK,QAAS,CACjC,GAAI,EAAO,OAAS,eAAiB,EAAO,OAAS,iBAAkB,SACvE,IAAM,EAAS,EAAO,OAAS,iBAAmB,EAAO,OAAS,IAAA,GAClE,GAAI,CAAC,sBAAsB,EAAO,UAAW,EAAO,UAAW,EAAQ,EAAO,KAAK,EACjF,SAEF,IAAM,EAAU,EAAI,IAAI,EAAO,SAAS,GAAK,IAAI,IACjD,EAAQ,IAAI,EAAO,UAAW,CAAM,EACpC,EAAI,IAAI,EAAO,UAAW,CAAO,CACnC,CAEF,OAAO,CACT,CAcA,SAAgB,kCACd,EACA,EACM,CACN,4BAA4B,EAAS,EAAkB,mBAAmB,CAC5E,CAOA,SAAgB,4CACd,EACA,EACM,CACN,4BAA4B,EAAS,EAAmB,GAAU,gBAAgB,CAAK,CAAC,CAC1F,CAEA,SAAS,4BACP,EACA,EACA,EACM,CACN,IAAK,GAAM,CAAC,EAAW,KAAW,EAAkB,CAClD,GAAI,EAAO,OAAS,cAAe,CACjC,OAAO,EAAQ,GACf,QACF,CACI,EAAO,OAAS,kBAClB,kBAAkB,EAAS,EAAW,EAAQ,EAAO,MAAM,CAAC,CAEhE,CACF,CCxaA,eAAsB,iCACpB,EACA,EACA,EACoC,CACpC,IAAM,EAAmC,IAAI,IAC7C,IAAK,IAAM,KAAiB,EAAgB,CAC1C,IAAM,EAAQ,MAAM,EAAiB,MAAO,EAAW,IAAgB,CACrE,GAAM,CAAE,gBAAe,iBAAkB,MAAM,EAAO,kBAAkB,CACtE,cACA,gBACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAe,CAAa,CACtC,CAAC,EACK,EAAkB,IAAI,IAC5B,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAW,EAAK,QAAQ,SACzB,EAAK,MACV,EAAgB,IAAI,EAAK,KAAM,CAC7B,WAAY,GAAU,YAAc,GACpC,oBAAqB,GAAU,qBAAuB,GAMtD,GAAI,GAAU,sBAAwB,CACpC,qBAAsB,CACpB,OAAQ,EAAS,qBAAqB,QAAU,GAChD,OAAQ,EAAS,qBAAqB,QAAU,GAChD,OAAQ,EAAS,qBAAqB,QAAU,GAChD,KAAM,EAAS,qBAAqB,MAAQ,EAC9C,CACF,EAEA,aAAc,gBAAgB,CAAI,CACpC,CAAC,CACH,CACA,EAAM,IAAI,EAAe,CAAe,CAC1C,CACA,OAAO,CACT,CAOA,SAAS,sBAAsB,EAA0C,CACvE,IAAM,EAAa,IAAI,IACvB,IAAK,IAAM,KAAU,EAAU,KAAK,QAClC,EAAW,IAAI,EAAO,SAAS,EAEjC,OAAO,CACT,CASA,SAAgB,qBAAqB,EAA0C,CAC7E,IAAM,EAAa,IAAI,IACvB,IAAK,IAAM,KAAU,EAAU,KAAK,QAC9B,EAAO,OAAS,gBAClB,EAAW,IAAI,EAAO,SAAS,EACtB,EAAO,OAAS,iBACzB,EAAW,IAAI,EAAO,iBAAiB,EAG3C,OAAO,CACT,CAKA,MAAa,GAAkB,CAC7B,QAAS,IAAI,IACb,QAAS,IAAI,IACb,wBAAyB,IAAI,IAC7B,OAAQ,CACN,KAAK,QAAQ,MAAM,EACnB,KAAK,QAAQ,MAAM,EACnB,KAAK,wBAAwB,MAAM,CACrC,CACF,EAUa,GAAyB,CACpC,MAAO,IAAI,IACX,OAAQ,CACN,KAAK,MAAM,MAAM,CACnB,EACA,KAAK,EAA6C,CAChD,IAAM,EAAM,GAAG,EAAU,UAAU,GAAG,EAAU,SAC5C,EAAW,KAAK,MAAM,IAAI,CAAG,EACjC,GAAI,CAAC,EAAU,CACb,IAAM,EAAgB,kCACpB,EAAU,cACV,EAAU,MACZ,EACA,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,4BACN,QAAS,mCAAmC,EAAU,UAAU,aAAa,EAAU,OAAO,2BAA2B,EAAU,eACrI,CAAC,EAEH,EAAW,EACX,KAAK,MAAM,IAAI,EAAK,CAAQ,CAC9B,CACA,OAAO,CACT,CACF,EAEA,SAAS,0BACP,EACA,EACA,EACA,EACyD,CAEzD,IAAM,EADW,GAAuB,KAAK,CACjB,CAAC,CAAC,OAAO,GACrC,GAAI,CAAC,EAAc,OACnB,IAAM,EAAQ,EAAe,KAAM,GAAM,EAAE,YAAc,EAAU,SAAS,EACtE,EAAoB,EAAU,KAAK,QAAQ,KAC9C,GACC,EAAO,OAAS,0BAA4B,EAAO,YAAc,CACrE,EAIA,OAAO,yCAHsB,EACzB,+BAA+B,EAAc,EAAa,CAAiB,EAC3E,EACkE,CAKpE,qBAAsB,GACtB,sBAAuB,GACvB,uBAAwB,GAAO,OAAO,aACxC,CAAC,CACH,CASA,eAAe,uBACb,EACe,CAIf,IAAM,GAAW,MAHK,QAAQ,WAC5B,EAAS,OAAQ,GAAyC,IAAY,IAAA,EAAS,CACjF,EAAA,CACyB,KAAM,GAAkC,EAAE,SAAW,UAAU,EACxF,GAAI,EACF,MAAM,EAAS,MAEnB,CAWA,eAAsB,+BACpB,EACA,EACA,EACA,EACA,EACe,CAKf,IAAM,EAAsB,4BAA4B,CAAC,CAAS,CAAC,EAC7D,EAA2B,iCAAiC,CAAC,CAAS,CAAC,EACvE,EAAiB,sBAAsB,CAAS,EAChD,EAAyB,IAAI,IAAI,GAAgB,OAAO,EAE9D,IAAK,IAAM,KAAU,EAAU,KAAK,QAAS,CAC3C,IAAM,EAAY,EAAO,QAAQ,cAAc,KAC/C,GAAI,CAAC,GAAa,CAAC,EAAe,IAAI,CAAS,GAAK,EAAuB,IAAI,CAAS,EACtF,SAEF,IAAM,EAAc,EAAoB,IAAI,CAAS,EAC/C,EAAe,0BACnB,EACA,EACA,EACA,CACF,EACA,GAAI,CAAC,EAAc,SAEnB,IAAM,EAAgB,gBAAgB,EAAO,OAAO,EACpD,EAAc,aAAe,EAEzB,GAAe,EAAY,KAAO,GAAK,EAAc,aAAa,QAAQ,QAC5E,kCAAkC,EAAc,aAAa,OAAO,OAAQ,CAAW,EAEzF,IAAM,EAAe,EAAyB,IAAI,CAAS,EACvD,GAAgB,EAAa,KAAO,GAAK,EAAc,aAAa,QAAQ,SAC9E,kCAAkC,EAAc,aAAa,OAAO,QAAS,CAAY,EAG3F,GAAgB,QAAQ,IAAI,CAAS,EACrC,EAAgB,IAAI,CAAS,EAC7B,MAAM,EAAO,mBAAmB,CAAa,CAC/C,CAEA,IAAK,IAAM,KAAU,EAAU,KAAK,QAAS,CAC3C,IAAM,EAAY,EAAO,QAAQ,cAAc,KAC/C,GAAI,CAAC,GAAa,CAAC,EAAe,IAAI,CAAS,GAAK,CAAC,EAAuB,IAAI,CAAS,EACvF,SAEF,IAAM,EAAc,EAAoB,IAAI,CAAS,EAC/C,EAAe,0BACnB,EACA,EACA,EACA,CACF,EACA,GAAI,CAAC,EAAc,SAEnB,IAAM,EAAoB,gBAAgB,CAAY,EAClD,GAAe,EAAY,KAAO,GAAK,EAAkB,QAAQ,QACnE,kCAAkC,EAAkB,OAAO,OAAQ,CAAW,EAEhF,IAAM,EAAe,EAAyB,IAAI,CAAS,EACvD,GAAgB,EAAa,KAAO,GAAK,EAAkB,QAAQ,SACrE,kCAAkC,EAAkB,OAAO,QAAS,CAAY,EAGlF,GAAgB,QAAQ,IAAI,CAAS,EACrC,EAAgB,IAAI,CAAS,EAC7B,MAAM,EAAO,mBAAmB,CAC9B,YAAa,EAAO,QAAQ,YAC5B,cAAe,EAAO,QAAQ,cAC9B,aAAc,CAChB,CAAC,CACH,CAEA,IAAK,IAAM,KAAU,EAAU,KAAK,QAAS,CAC3C,IAAM,EAAY,EAAO,QAAQ,cAAc,KAC/C,GAAI,CAAC,GAAa,CAAC,EAAe,IAAI,CAAS,EAAG,SAClD,IAAM,EAAc,EAAoB,IAAI,CAAS,EAC/C,EAAe,0BACnB,EACA,EACA,EACA,CACF,EACA,GAAI,CAAC,EAAc,SAEnB,IAAM,EAAgB,gBAAgB,EAAO,OAAO,EACpD,EAAc,aAAe,EAEzB,GAAe,EAAY,KAAO,GAAK,EAAc,aAAa,QAAQ,QAC5E,kCAAkC,EAAc,aAAa,OAAO,OAAQ,CAAW,EAEzF,IAAM,EAAe,EAAyB,IAAI,CAAS,EACvD,GAAgB,EAAa,KAAO,GAAK,EAAc,aAAa,QAAQ,SAC9E,kCAAkC,EAAc,aAAa,OAAO,QAAS,CAAY,EAG3F,GAAgB,QAAQ,IAAI,CAAS,EACrC,EAAgB,IAAI,CAAS,EAC7B,MAAM,EAAO,mBAAmB,CAAa,CAC/C,CAEA,IAAM,EAAoB,IAAI,IAAI,OAAO,KAAK,GAAuB,KAAK,CAAS,CAAC,CAAC,MAAM,CAAC,EACtF,cAAiB,GAAsB,GAAG,EAAU,UAAU,GAAG,IACjE,EAAmC,EAAU,cAAc,QAAQ,OACtE,GACC,EAAO,QAAQ,gBAAkB,EAAU,WAC3C,EAAkB,IAAI,EAAO,IAAI,GACjC,CAAC,GAAgB,wBAAwB,IAAI,cAAc,EAAO,IAAI,CAAC,CAC3E,EACM,EAAmC,EAAU,cAAc,QAAQ,OACtE,GACC,EAAO,QAAQ,gBAAkB,EAAU,WAC3C,EAAkB,IAAI,EAAO,IAAI,GACjC,CAAC,GAAgB,wBAAwB,IAAI,cAAc,EAAO,IAAI,CAAC,CAC3E,EACA,GAAI,EAAiC,OAAS,EAAiC,OAAS,EAAG,CACzF,IAAM,EAAyB,IAAI,IACjC,EAAiC,IAAK,GAAW,EAAO,IAAI,CAC9D,EACM,EAAqB,EAAU,KAAK,QAAQ,OAAQ,GAAW,CACnE,IAAM,EAAY,EAAO,QAAQ,cAAc,KAE/C,OADsB,EAAO,QAAQ,gBAEjB,EAAU,WAC5B,GACA,EAAuB,IAAI,CAAS,GACpC,CAAC,GAAgB,QAAQ,IAAI,CAAS,CAE1C,CAAC,EACD,GAAI,EAAmB,OAAS,EAC9B,IAAK,IAAM,KAAU,EAAoB,CACvC,IAAM,EAAY,EAAO,QAAQ,cAAc,KAC/C,GAAI,CAAC,EAAW,SAChB,IAAM,EAAe,0BAA0B,EAAW,EAAW,CAAc,EACnF,GAAI,CAAC,EAAc,SACnB,GAAgB,QAAQ,IAAI,CAAS,EACrC,EAAgB,IAAI,CAAS,EAC7B,IAAM,EAAgB,gBAAgB,EAAO,OAAO,EACpD,EAAc,aAAe,EAC7B,MAAM,EAAO,mBAAmB,CAAa,CAC/C,CAEF,MAAM,uBAAuB,CAC3B,GAAG,EAAiC,IAAK,GACvC,EAAO,4BAA4B,EAAO,OAAO,CACnD,EACA,GAAG,EAAiC,IAAK,GACvC,EAAO,4BAA4B,EAAO,OAAO,CACnD,CACF,CAAC,EACD,IAAK,IAAM,IAAY,CACrB,GAAG,EAAiC,IAAK,GAAW,EAAO,IAAI,EAC/D,GAAG,EAAiC,IAAK,GAAW,EAAO,IAAI,CACjE,EACE,GAAgB,wBAAwB,IAAI,cAAc,CAAQ,CAAC,CAEvE,CACF,CAKA,MAAa,GAAmB,CAC9B,MAAO,IAAI,IACX,eAAgB,IAAI,IACpB,OAAQ,CACN,KAAK,MAAM,MAAM,EACjB,KAAK,eAAe,MAAM,CAC5B,CACF,EAEA,eAAsB,oCACpB,EACA,EACA,EACA,EACA,EACe,CACf,GAAI,CACF,MAAM,gCACJ,EACA,EACA,EACA,EACA,CACF,CACF,OAAS,EAAe,CACtB,EAAO,KACL,iCAAiC,EAAU,UAAU,GAAG,sBAAsB,EAAU,MAAM,EAAE,IAC3F,aAAyB,MAAQ,EAAc,QAAU,OAAO,CAAa,GACpF,CACF,CACF,CAWA,eAAsB,gCACpB,EACA,EACA,EACA,EACA,EACe,CAGf,IAAM,EAAsB,4BAA4B,CAAC,CAAS,CAAC,EAC7D,EAA2B,iCAAiC,CAAC,CAAS,CAAC,EACvE,EAAgB,IAAI,IAAI,CAC5B,GAAG,EAAoB,KAAK,EAC5B,GAAG,EAAyB,KAAK,CACnC,CAAC,EACK,EAAiB,sBAAsB,CAAS,EAMtD,GAAI,CAEF,IAAK,IAAM,KAAU,EAAU,KAAK,QAAS,CAC3C,IAAM,EAAY,EAAO,QAAQ,cAAc,KAC/C,GAAI,CAAC,GAAa,CAAC,EAAe,IAAI,CAAS,GAAK,CAAC,EAAc,IAAI,CAAS,EAC9E,SAEF,IAAM,EAAe,0BAA0B,EAAW,EAAW,CAAc,EAC9E,IACL,EAAgB,IAAI,CAAS,EAC7B,MAAM,EAAO,mBAAmB,CAC9B,YAAa,EAAO,QAAQ,YAC5B,cAAe,EAAO,QAAQ,cAC9B,aAAc,CAChB,CAAC,EACH,CAGA,IAAK,IAAM,KAAU,EAAU,KAAK,QAAS,CAC3C,IAAM,EAAY,EAAO,QAAQ,cAAc,KAC/C,GAAI,CAAC,GAAa,CAAC,EAAe,IAAI,CAAS,GAAK,CAAC,EAAc,IAAI,CAAS,EAC9E,SAEF,IAAM,EAAe,0BAA0B,EAAW,EAAW,CAAc,EAC9E,IACL,EAAgB,IAAI,CAAS,EAC7B,MAAM,EAAO,mBAAmB,CAC9B,YAAa,EAAO,QAAQ,YAC5B,cAAe,EAAO,QAAQ,cAC9B,aAAc,CAChB,CAAC,EACH,CACF,OAAS,EAAO,CACd,8BAA8B,EAAO,CACnC,uFACA,+EACF,CAAC,CACH,CACF,CAuBA,SAAS,uBAAuB,EAA2C,CACzE,IAAM,EAAa,EAAS,qBAC5B,OACE,EAAS,qBACT,EAAS,YACT,GAAY,SAAW,IACvB,EAAW,SAAW,IACtB,EAAW,SAAW,EAE1B,CAEA,eAAe,wBACb,EACA,EACe,CACf,GAAM,CACJ,cACA,gBACA,WACA,QACA,qBACA,gBACA,aACA,kBAAkB,IAChB,EACA,EACE,EAAa,IAAI,IAAI,CAAC,GAAG,OAAO,KAAK,EAAS,MAAM,EAAG,GAAI,GAAe,KAAK,GAAK,CAAC,CAAE,CAAC,EAC9F,IAAK,IAAM,KAAa,EACtB,GAAI,CACF,IAAM,EAAe,EAAS,OAAO,GAC/B,EAAiB,GAAe,IAAI,CAAS,EAEnD,GADI,GAAiB,CAAC,GAClB,IAAe,CAAC,GAAkB,CAAC,uBAAuB,CAAc,GAAI,SAChF,IAAM,EAAe,EACjB,EACE,yCAAyC,EAAc,CACrD,qBAAsB,GACtB,sBAAuB,GACvB,uBAAwB,EAAM,OAAO,aACvC,CAAC,EACD,yCAAyC,EAAc,CACrD,WAAY,EAAmB,IAAI,CAAS,EAC5C,uBAAwB,EAAM,OAAO,aACvC,CAAC,EACH,GAAgB,aACd,gBAAgB,EAAe,YAAY,EAC3C,IAAA,GACN,GAAI,CAAC,GAAc,OAAQ,SAC3B,EAAa,OAAO,WAAa,CAAC,EAClC,IAAM,EAAW,EAAa,OAAO,SACjC,IACF,EAAS,WAAa,GACtB,EAAS,oBAAsB,GAC/B,EAAS,qBAAuB,CAC9B,OAAQ,GACR,OAAQ,GACR,OAAQ,GACR,KAAM,EACR,GAEE,CAAC,GAAc,IACjB,EAAS,WAAa,EAAe,WACrC,EAAS,oBAAsB,EAAe,oBAC9C,EAAS,qBAAuB,EAAe,qBAC3C,CAAE,GAAG,EAAe,oBAAqB,EACzC,IAAA,IAEN,MAAM,EAAO,mBAAmB,CAAE,cAAa,gBAAe,cAAa,CAAC,CAC9E,OAAS,EAAO,CACd,GAAI,CAAC,EAAiB,MAAM,EAC5B,IAAe,aAAiB,MAAQ,EAAQ,GAAQ,CAAK,CAC/D,CAEF,GAAI,IAAe,IAAA,GAAW,MAAM,CACtC,CAcA,SAAgB,iCACd,EACA,EACA,EACqC,CACrC,IAAM,EAAkB,IAAI,IAC5B,IAAK,GAAM,CAAC,EAAW,KAAiB,OAAO,QAAQ,EAAS,MAAM,EAAG,CACvE,IAAM,EAAW,yCAAyC,EAAc,CACtE,WAAY,GACZ,uBAAwB,EAAM,OAAO,aACvC,CAAC,CAAC,CAAC,QAAQ,SACN,GACL,EAAgB,IAAI,EAAW,CAC7B,WAAY,EAAS,YAAc,GACnC,oBACE,EAAa,UAAU,eAAiB,EAAmB,IAAI,CAAS,EAC1E,GAAI,EAAS,sBAAwB,CACnC,qBAAsB,CACpB,OAAQ,EAAS,qBAAqB,QAAU,GAChD,OAAQ,EAAS,qBAAqB,QAAU,GAChD,OAAQ,EAAS,qBAAqB,QAAU,GAChD,KAAM,EAAS,qBAAqB,MAAQ,EAC9C,CACF,CACF,CAAC,CACH,CACA,OAAO,CACT,CAgBA,eAAsB,2BACpB,EACA,EACA,EACA,EACA,EACA,EACe,CACf,IAAK,GAAM,CAAC,EAAe,KAAa,EAAW,CACjD,IAAM,EAAQ,EAAe,KAAM,GAAU,EAAM,YAAc,CAAa,EACzE,GACL,MAAM,wBAAwB,EAAQ,CACpC,cACA,gBACA,WACA,QACA,qBACA,cAAe,EAAiB,IAAI,CAAa,GAAK,IAAI,IAC1D,WAAY,EACd,CAAC,CACH,CACF,CAiBA,eAAsB,6BACpB,EACA,EACA,EACA,EACA,EACA,EACe,CACf,IAAI,EACJ,IAAK,GAAM,CAAC,EAAe,KAAa,EAAW,CACjD,IAAM,EAAQ,EAAe,KAAM,GAAU,EAAM,YAAc,CAAa,EACzE,KACL,GAAI,CACF,MAAM,wBAAwB,EAAQ,CACpC,cACA,gBACA,WACA,QACA,qBACA,cAAe,GAAmB,IAAI,CAAa,EACnD,WAAY,GACZ,gBAAiB,EACnB,CAAC,CACH,OAAS,EAAO,CACd,IAAe,aAAiB,MAAQ,EAAQ,GAAQ,CAAK,CAC/D,CACF,CACA,GAAI,IAAe,IAAA,GAAW,MAAM,CACtC,CAEA,eAAsB,yCACpB,EACA,EACA,EACe,CACf,IAAM,EAAoB,qBAAqB,CAAS,EACxD,GAAI,EAAkB,KAAO,EAAG,CAC9B,IAAM,EAAyB,EAAU,cAAc,QAAQ,OAAQ,GAAQ,CAC7E,IAAM,EAAU,GAAG,EAAI,QAAQ,cAAc,GAAG,EAAI,OACpD,GAAI,GAAiB,eAAe,IAAI,CAAO,EAAG,MAAO,GACzD,IAAM,EAAY,EAAI,KACtB,OAAO,EAAkB,IAAI,CAAS,CACxC,CAAC,EACD,IAAK,IAAM,KAAO,EAChB,MAAM,EAAO,4BAA4B,EAAI,OAAO,EACpD,GAAiB,eAAe,IAAI,GAAG,EAAI,QAAQ,cAAc,GAAG,EAAI,MAAM,EAGhF,IAAM,EAAgB,EAAU,KAAK,QAAQ,OAAQ,GAAQ,CAC3D,IAAM,EAAY,EAAI,KAEtB,MADI,CAAC,GAAa,GAAiB,MAAM,IAAI,CAAS,EAAU,GACzD,EAAkB,IAAI,CAAS,CACxC,CAAC,EACD,IAAK,IAAM,KAAO,EAChB,MAAM,EAAO,mBAAmB,EAAI,OAAO,EAC3C,GAAiB,MAAM,IAAI,EAAI,IAAI,CAEvC,CACF,CAWA,eAAe,gCACb,EACA,EACA,EACA,EACA,EACe,CAGf,GADI,EAAU,QAAA,GACV,EAAgB,OAAS,EAAG,OAEhC,IAAM,EAAgB,kCACpB,EAAU,cACV,EAAU,OAAS,CACrB,EAGA,GAAI,CAAC,EAAe,CAClB,EAAO,KACL,8BAA8B,EAAU,UAAU,GAAG,sBAAsB,EAAU,MAAM,EAAE,8BAC9D,sBAAsB,EAAU,OAAS,CAAC,EAAE,mFAE7E,EACA,MACF,CACA,IAAM,EAAQ,EAAe,KAAM,GAAM,EAAE,YAAc,EAAU,SAAS,EAE5E,EAAO,KACL,aAAa,EAAU,UAAU,GAAG,sBAAsB,EAAU,MAAM,EAAE,wDAE9E,EAKA,IAAM,EAAiB,CAAC,GAAG,CAAe,CAAC,CAAC,QAAS,GAAc,CACjE,IAAM,EAAa,EAAc,OAAO,GACxC,OAAO,EAAa,CAAC,CAAE,YAAW,YAAW,CAAC,EAAI,CAAC,CACrD,CAAC,EACK,EAAY,CAAC,GAAG,CAAe,CAAC,CAAC,OAAQ,GAAc,CAAC,EAAc,OAAO,EAAU,EAE7F,IAAK,GAAM,CAAE,YAAW,gBAAgB,EACtC,GAAI,CACF,IAAM,EAAW,yCAAyC,EAAY,CACpE,qBAAsB,GACtB,sBAAuB,GACvB,uBAAwB,GAAO,OAAO,aACxC,CAAC,EACD,MAAM,EAAO,mBAAmB,CAC9B,cACA,cAAe,EAAU,UACzB,aAAc,CAChB,CAAC,CACH,OAAS,EAAe,CACtB,EAAO,KACL,8BAA8B,EAAU,kBAAkB,EAAU,UAAU,KACzE,aAAyB,MAAQ,EAAc,QAAU,OAAO,CAAa,GACpF,CACF,CAGF,IAAK,IAAM,KAAa,EACtB,GAAI,CAGF,MAAM,EACH,4BAA4B,CAC3B,cACA,cAAe,EAAU,UACzB,SAAU,CACZ,CAAC,CAAC,CACD,UAAY,IAAA,EAAS,EACxB,MAAM,EAAO,mBAAmB,CAC9B,cACA,cAAe,EAAU,UACzB,iBAAkB,CACpB,CAAC,CACH,OAAS,EAAe,CACtB,EAAO,KACL,8BAA8B,EAAU,kBAAkB,EAAU,UAAU,KACzE,aAAyB,MAAQ,EAAc,QAAU,OAAO,CAAa,GACpF,CACF,CAEJ,CCzwBA,SAAgB,sBAAsB,EAA+C,CACnF,IAAM,EAA8C,CAAC,EACrD,IAAK,GAAM,CAAC,EAAW,KAAS,OAAO,QAAQ,EAAQ,KAAK,EAC1D,EAAM,GAAa,mBAAmB,CAAI,EAE5C,MAAO,CACL,UAAW,EAAQ,UACnB,OAAQ,EAAQ,OAChB,OACF,CACF,CAaA,eAAe,iBACb,EACA,EACA,EAC8B,CAC9B,OAAO,EAAiB,MAAO,EAAW,IAAgB,CACxD,GAAM,CAAE,gBAAe,iBAAkB,MAAM,EAAO,kBAAkB,CACtE,cACA,cAAe,EACf,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAe,CAAa,CACtC,CAAC,CACH,CAEA,eAAe,0BACb,EACA,EACA,EACgC,CAChC,OAAO,EAAiB,MAAO,EAAW,IAAgB,CACxD,GAAM,CAAE,cAAa,iBAAkB,MAAM,EAAO,2BAA2B,CAC7E,cACA,cAAe,EACf,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAa,CAAa,CACpC,CAAC,CACH,CASA,eAAsB,0BACpB,EACA,EACA,EACmC,CACnC,GAAM,CAAC,EAAa,GAAwB,MAAM,QAAQ,IAAI,CAC5D,iBAAiB,EAAQ,EAAa,CAAS,EAC/C,0BAA0B,EAAQ,EAAa,CAAS,CAC1D,CAAC,EACD,OAAO,8BAA8B,EAAa,EAAW,CAAoB,CACnF,CAKA,SAAS,oBAAsC,EAAyB,CACtE,OAAO,OAAO,KAAK,CAAK,CAAC,CAAC,OAAS,EAAI,EAAQ,IAAA,EACjD,CAEA,SAAS,gBACP,EACA,EACA,EACmC,CAEnC,OADoB,EAAe,KAAM,GAAU,EAAM,YAAc,CAAS,CAAC,EAAE,QAC5D,EAAO,KAAK,EACrC,CAEA,SAAS,uBACP,EACA,EACA,EACqB,CACrB,OAAO,gBAAgB,EAAQ,EAAgB,CAAS,CAAC,EAAE,aAC7D,CAEA,MAAM,GAAqB,CAAC,SAAU,SAAU,SAAU,MAAM,EAEhE,SAAS,gCACP,EACmC,CACnC,GAAI,CAAC,EAAY,OACjB,GAAI,IAAe,QACjB,MAAO,CAAE,OAAQ,GAAO,OAAQ,GAAO,OAAQ,EAAM,EAGvD,IAAM,EAAkC,CAAC,EACzC,IAAK,IAAM,KAAO,GACZ,EAAW,KAAS,KAAO,EAAS,GAAO,IAGjD,OAAO,oBAAoB,CAAQ,CACrC,CAEA,SAAS,uCACP,EACA,EACmC,CACnC,GAAI,CAAC,GAAkB,CAAC,EAAoB,OAE5C,IAAM,EAAkC,CAAC,EACzC,IAAK,IAAM,KAAO,GACZ,EAAmB,KAAS,IAAS,EAAe,KAAM,EAAS,GAAO,IAGhF,OAAO,oBAAoB,CAAQ,CACrC,CAEA,SAAS,yBACP,EACA,EACA,EACgB,CAChB,IAAM,EAAqB,IAAI,IAAI,EAAY,IAAK,GAAS,CAAC,EAAK,KAAM,CAAI,CAAC,CAAC,EACzE,EAAqB,gCAAgC,CAAa,EAClE,EAA+C,CAAC,EAEtD,IAAK,GAAM,CAAC,EAAW,KAAS,OAAO,QAAQ,EAAS,MAAM,EAAG,CAC/D,IAAM,EAA6B,CAAE,GAAG,EAAK,QAAS,EAChD,EAAiB,EAAmB,IAAI,CAAS,CAAC,EAAE,QAAQ,SAMlE,GAJI,EAAK,UAAU,gBAAkB,IAAA,IAAa,GAAgB,sBAChE,EAAS,cAAgB,IAGvB,EAAK,UAAU,gBAAkB,IAAA,GAAW,CAC9C,IAAM,EAAW,uCACf,GAAgB,qBAChB,CACF,EACI,IAAU,EAAS,cAAgB,EACzC,CAEA,IAAM,EAAiB,CAAE,GAAG,CAAK,EAC3B,EAAqB,oBAAoB,CAAQ,EACnD,EACF,EAAe,SAAW,EAE1B,OAAO,EAAe,SAExB,EAAO,GAAa,CACtB,CAEA,MAAO,CAAE,GAAG,EAAU,QAAO,CAC/B,CAWA,eAAsB,mBACpB,EACA,EACA,EACA,EACA,EAC2C,CAC3C,IAAM,EAA4C,CAAC,EAEnD,IAAK,GAAM,CAAE,YAAW,mBAAmB,EAA0B,CAEnE,IAAM,EAAc,MAAM,0BACxB,EACA,YAAY,EAAa,WAAY,CAAS,CAChD,EACM,CAAE,iBAAgB,OAAQ,GAA0B,EAE1D,GACE,EAAY,kBACX,IAA0B,MAAQ,EAAY,YAAc,KAC7D,CACA,EAAQ,KAAK,CACX,YACA,sBAAuB,GAAyB,EAChD,OAAQ,CAAC,EACT,SAAU,GACV,uBAAwB,EAC1B,CAAC,EACD,QACF,CAIA,GAAI,IAA0B,KAAM,CAClC,EAAQ,KAAK,CACX,YACA,sBAAuB,EACvB,OAAQ,CAAC,EACT,SAAU,GACV,QAAS,EAAiB,qBAAuB,cACnD,CAAC,EACD,QACF,CAEA,IAAM,EAAwB,yBAAyB,CAAa,EAE9D,EADmB,kCAAkC,EAAe,CACxC,CAAC,EAAE,WAC/B,EAAwB,EAC1B,EAAY,YAAc,EAAW,UACrC,EAAY,YAAc,KACxB,EAAyB,EAC3B,EAAY,YAAc,EAAW,kBACrC,GACE,EACJ,GACA,GACA,IAA0B,EAAW,wBAChC,CACC,KAAM,EACN,GAAI,EACJ,cAAe,EAAY,UAC3B,YAAa,EAAW,SAC1B,EACA,IAAA,GAIN,GAFG,CAAC,GAAyB,CAAC,GAC3B,EAAwB,GAAyB,CAAC,EACzB,CAC1B,IAAM,EACJ,GACA,GACA,EAAwB,EAAW,wBAC/B,CAAE,wBAAyB,EAAW,uBAAwB,EAC9D,IAAA,GACN,EAAQ,KAAK,CACX,YACA,wBACA,OAAQ,CAAC,EACT,SAAU,GACV,uBAAwB,GACxB,GAAI,EAAoB,CAAE,mBAAkB,EAAI,CAAC,CACnD,CAAC,EACD,QACF,CAIA,IAAM,EAAmB,kCACvB,EAJ8B,GAAkB,IAAM,CAMxD,EACA,GAAI,CAAC,EAAkB,CAErB,EAAQ,KAAK,CACX,YACA,wBACA,OAAQ,CAAC,EACT,SAAU,GACV,QAAS,aACX,CAAC,EACD,QACF,CAGA,GAAM,CAAC,EAAa,GAAwB,MAAM,QAAQ,IAAI,CAC5D,iBAAiB,EAAQ,EAAa,CAAS,EAC/C,0BAA0B,EAAQ,EAAa,CAAS,CAC1D,CAAC,EAQK,EAAS,0BACb,EAR6B,yBAC7B,EACA,EACA,uBAAuB,EAAQ,EAAgB,CAAS,CAMxD,EACA,CACF,EAEA,EAAQ,KAAK,CACX,YACA,wBACA,SACA,SAAU,EAAO,OAAS,EAC1B,GAAI,GAAoB,EAAO,SAAW,EAAI,CAAE,kBAAiB,EAAI,CAAC,CACxE,CAAC,CACH,CAEA,OAAO,CACT,CAYA,SAAS,+BAA+B,EAA6B,CACnE,OACE,EAAM,OAAS,mBAAqB,EAAM,QAAQ,SAAA,8BAA0C,CAEhG,CASA,SAAS,6BAA6B,EAAsD,CAC1F,IAAM,EAAY,EAAa,OAAQ,GAAW,EAAO,QAAQ,EACjE,OACE,EAAU,OAAS,GACnB,EAAU,MACP,GAAW,EAAO,OAAO,OAAS,GAAK,EAAO,OAAO,MAAM,8BAA8B,CAC5F,CAEJ,CAOA,SAAgB,uBAAuB,EAAoD,CACzF,EAAO,KAAK,oBAAoB,EAChC,EAAO,KAAK,qDAAsD,CAAE,KAAM,OAAQ,CAAC,EACnF,EAAO,KAAK,+CAAgD,CAAE,KAAM,OAAQ,CAAC,EAC7E,EAAO,KAAK,uCAAwC,CAAE,KAAM,OAAQ,CAAC,EACrE,EAAO,QAAQ,EACf,EAAO,KAAK,aAAa,EACzB,EAAO,KAAK,yEAA0E,CACpF,KAAM,OACR,CAAC,EACD,EAAO,KAAK,8EAA+E,CACzF,KAAM,OACR,CAAC,EACD,EAAO,KACL,2FACA,CAAE,KAAM,OAAQ,CAClB,EACA,EAAO,KAAK,6DAA8D,CAAE,KAAM,OAAQ,CAAC,EACvF,GAAgB,6BAA6B,CAAY,IAC3D,EAAO,QAAQ,EACf,EAAO,KACL,0BAA0B,GAAkC,6DAC9D,EAEJ,CAgBA,SAAS,qBACP,EAC0C,CAC1C,OAAO,EAAO,oBAAsB,IAAA,EACtC,CASA,SAAgB,6BACd,EACM,CACN,IAAM,EAAU,EAAQ,OAAO,oBAAoB,EACnD,GAAI,EAAQ,OAAS,EAAG,CACtB,IAAK,IAAM,KAAU,EAAS,CAC5B,IAAM,EAAS,sBAAsB,EAAO,kBAAkB,uBAAuB,EAC/E,EAAU,sBAAsB,EAAO,qBAAqB,EAClE,EAAO,KACL,GAAG,EAAO,UAAU,4GAA4G,EAAO,qDAAqD,EAAQ,EACtM,CACF,CACA,EAAO,QAAQ,EACf,EAAO,KAAK,aAAa,EACzB,EAAO,KACL,qKACA,CAAE,KAAM,OAAQ,CAClB,EACA,EAAO,KACL,oKACA,CAAE,KAAM,OAAQ,CAClB,EACA,EAAO,KACL,sIACA,CAAE,KAAM,OAAQ,CAClB,CACF,CACI,EAAQ,OAAS,EAAQ,SACvB,EAAQ,OAAS,GAAG,EAAO,QAAQ,EACvC,EAAO,KACL,wFACF,EAEJ,CAOA,SAAgB,gCAAgC,EAAmD,CACjG,IAAM,EAAkB,CAAC,EAEzB,IAAK,IAAM,KAAU,EACd,EAAO,WAEZ,EAAM,KAAK,cAAc,EAAO,WAAW,EAC3C,EAAM,KAAK,uBAAuB,sBAAsB,EAAO,qBAAqB,GAAG,EACvF,EAAM,KAAK,gBAAgB,EAC3B,EAAM,KAAK,mBAAmB,EAAO,MAAM,CAAC,EAC5C,EAAM,KAAK,EAAE,GAGf,OAAO,EAAM,KAAK;CAAI,CACxB,CAmBA,eAAsB,oBACpB,EACA,EACiC,CACjC,IAAM,EAAkC,CAAC,EAEzC,IAAK,GAAM,CAAE,YAAW,mBAAmB,EAA0B,CACnE,IAAM,EAAa,EAAiB,IAAI,CAAS,EACjD,GAAI,CAAC,EACH,SAKF,IAAM,EAAmB,kCAAkC,CAAa,EAExE,GAAI,CAAC,EAAkB,CAErB,EAAQ,KAAK,CACX,YACA,gBACA,QAAS,GACT,KAAM,IAAA,EACR,CAAC,EACD,QACF,CAGA,IAAM,EAAO,8BAA8B,EAAkB,EAAY,CAAS,EAElF,EAAQ,KAAK,CACX,YACA,gBACA,QAAS,WAAW,CAAI,EACxB,KAAM,WAAW,CAAI,EAAI,EAAO,IAAA,EAClC,CAAC,CACH,CAEA,OAAO,CACT,CAOA,SAAgB,4BAA4B,EAAyC,CACnF,IAAM,EAAkB,CAAC,EAEzB,IAAK,IAAM,KAAU,EACd,EAAO,UAIZ,EAAM,KAAK,cAAc,EAAO,WAAW,EAEtC,EAAO,MAGV,EAAM,KAAK,KAAK,kBAAkB,EAAO,IAAI,GAAG,EAChD,EAAM,KAAK,EAAE,EACb,EAAM,KAAK,oBAAoB,EAAO,IAAI,CAAC,GAJ3C,EAAM,KAAK,gFAAgF,EAM7F,EAAM,KAAK,EAAE,GAGf,OAAO,EAAM,KAAK;CAAI,CACxB,CCvjBA,SAAgB,yBACd,EACA,EACS,CACT,IAAM,EAAoB,OAAO,KAAK,CAAO,CAAC,CAAC,SAAS,EAClD,EAAoB,OAAO,KAAK,CAAO,CAAC,CAAC,SAAS,EACxD,OACE,EAAkB,SAAW,EAAkB,QAC/C,EAAkB,OACf,EAAW,IACV,IAAc,EAAkB,IAAU,EAAQ,KAAe,EAAQ,EAC7E,CAEJ,CAYA,eAAsB,4BACpB,EACA,EACA,EACA,EACA,EACA,EACkC,CAElC,IAAM,EAA2B,4BAA4B,EAD3C,EAAK,QAAQ,EAAO,IAC+B,CAAS,EAC1E,EAAwC,CAAC,EACzC,EAAiD,CAAC,EAChD,EAAsB,OAAO,OAAO,IAAI,EAE9C,GAAI,EAAyB,OAAS,EAAG,CAEvC,IAAK,GAAM,CAAE,YAAW,mBAAmB,EACzC,0BAA0B,EAAe,CAAS,EAClD,EAAoB,GAClB,kCAAkC,CAAa,CAAC,EAAE,YAAY,WAAa,KAI/E,GAAI,CAAC,EAAe,CAElB,IAAM,EAAmB,MAAM,oBAC7B,EACA,CACF,EAGA,GAFiB,EAAiB,KAAM,GAAM,EAAE,OAErC,EAMT,MALA,EAAO,MAAM,0DAA0D,EACvE,EAAO,IAAI,4BAA4B,CAAgB,CAAC,EACxD,EAAO,QAAQ,EACf,EAAO,KAAK,qEAAqE,EACjF,EAAO,KAAK,gDAAgD,EACtD,EAAS,CACb,KAAM,gCACN,QAAS,gCACT,WACE,kHACJ,CAAC,EAIH,IAAM,EAA4B,MAAM,mBACtC,EACA,EACA,EACA,EACA,CACF,EACA,EAAoB,EAA0B,QAAS,GACrD,EAAO,iBACH,CAAC,CAAE,UAAW,EAAO,UAAW,GAAG,EAAO,gBAAiB,CAAC,EAC5D,CAAC,CACP,EACA,IAAM,EAA2B,EAA0B,OACxD,GAAW,EAAO,sBACrB,EACA,GAAI,EAAyB,OAAS,EAAG,CACvC,EAAO,MAAM,oEAAoE,EACjF,IAAK,IAAM,KAAU,EACnB,EAAO,IACL,KAAK,EAAO,UAAU,IAAI,sBAAsB,EAAO,qBAAqB,GAC9E,EAIF,MAFA,EAAO,QAAQ,EACf,6BAA6B,CAAwB,EAC/C,EAAS,CACb,KAAM,+BACN,QAAS,iDACX,CAAC,CACH,CAGA,GAFuB,EAA0B,KAAM,GAAM,EAAE,QAE9C,EAOf,MANA,EAAO,MAAM,+BAA+B,EAC5C,EAAO,IAAI,gCAAgC,CAAyB,CAAC,EACrE,EAAO,QAAQ,EACf,uBAAuB,CAAyB,EAChD,EAAO,QAAQ,EACf,EAAO,KAAK,+DAA+D,EACrE,EAAS,CACb,KAAM,yBACN,QAAS,mCACX,CAAC,EAEH,IAAK,IAAM,KAAU,EACnB,EAAO,KACL,mCAAmC,EAAO,UAAU,6CAA6C,sBAAsB,EAAO,IAAI,EAAE,gEACtI,CAEJ,CAGA,IAAM,EAA4B,IAAI,IACpC,EAAkB,IAAK,GAAW,CAAC,EAAO,UAAW,EAAO,EAAE,CAAC,CACjE,EASA,GARA,EAAoB,MAAM,wBACxB,EACA,EACA,EACA,EAAO,KACP,CACF,EAEI,EAAkB,OAAS,EAAG,CAChC,EAAO,QAAQ,EAGf,IAAM,EAAc,EAAkB,OAAQ,GAAM,EAAE,SAAS,EACzD,EAAiB,EAAkB,OAAQ,GAAM,CAAC,EAAE,SAAS,EAEnE,EAAO,KAAK,GAAG,EAAkB,OAAO,uCAAuC,EAC3E,EAAe,OAAS,GAC1B,EAAO,KACL,OAAO,EAAe,OAAO,kEAC7B,CAAE,KAAM,OAAQ,CAClB,EAEE,EAAY,OAAS,GACvB,EAAO,KACL,OAAO,EAAY,OAAO,0DAC1B,CAAE,KAAM,OAAQ,CAClB,CAEJ,CACF,CAEA,MAAO,CACL,oBACA,oBACA,2BACA,mBAAoB,0BAA0B,CAAwB,EACtE,qBACF,CACF,CC9IA,eAAe,yBACb,EACA,EACA,EACA,EACe,CACf,IAAK,GAAM,CAAE,YAAW,mBAAmB,EAA0B,CACnE,GAAI,kBAAkB,CAAa,CAAC,CAAC,SAAW,EAC9C,SAEF,IAAM,EAAgB,yBAAyB,CAAa,EACtD,EAAY,EAAoB,IAAc,KAC9C,EAAc,MAAM,0BACxB,EACA,YAAY,EAAa,WAAY,CAAS,CAChD,CAAC,CAAC,UAAY,IAAI,EACZ,EAAiB,GAAa,QAAU,KAC1C,GAAe,IAAmB,GAAiB,EAAY,YAAc,IAGjF,MAAM,qBACJ,EACA,EACA,EACA,EACA,GAAa,IAAA,EACf,EACI,EACF,EAAO,KACL,iCAAiC,EAAU,eAAe,4BAA4B,CAAc,EAAE,KAAK,sBAAsB,CAAa,EAAE,EAClJ,EAEA,EAAO,KACL,iCAAiC,EAAU,iBAAiB,sBAAsB,CAAa,EAAE,EACnG,EAEJ,CACF,CASA,SAAS,gCACP,EACA,EACA,EACkB,CAClB,IAAM,EAAc,EAAiB,YAAY,YACjD,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,uBACN,QAAS,8DACX,CAAC,EAGH,IAAM,EAAiE,CAAC,EACxE,IAAK,IAAM,KAAa,EAChB,EAAU,aAAa,IAC3B,EAAY,EAAU,WAAa,EAAiB,OAAO,KAAK,EAAU,YAM9E,MAAO,CACL,SACA,YAAa,EAAiB,YAC9B,cAAe,EAAY,OAAO,KAClC,aAAc,EAAY,OAAO,aAC7B,OAAO,KAAK,EAAY,OAAO,YAAY,EAC3C,IAAA,GACJ,SAAU,EACV,IAAK,EAAiB,OAAO,KAAO,CAAC,EACrC,UAAW,EAAK,QAAQ,EAAiB,OAAO,IAAI,EACpD,QAAS,EAAiB,YAAY,KACtC,MAAO,EAAiB,YAAY,EACtC,CACF,CAEA,eAAe,+BACb,EACA,EACkC,CAClC,GAAM,CAAE,WAAY,EACpB,GAAI,EAAQ,uBAAwB,CAClC,IAAM,EAA4B,0BAChC,4BAA4B,EAAQ,OAAQ,EAAK,QAAQ,EAAQ,OAAO,IAAI,CAAC,CAC/E,EACA,GAAI,CAAC,yBAAyB,EAAQ,mBAAoB,CAAyB,EACjF,MAAM,EAAS,CACb,KAAM,oBACN,QAAS,qDACT,WAAY,sDACd,CAAC,EAEH,MAAO,CACL,kBAAmB,CAAC,EACpB,kBAAmB,CAAC,EACpB,yBAA0B,CAAC,EAC3B,mBAAoB,EACpB,oBAAqB,CAAC,CACxB,CACF,CACA,IAAM,EAAmB,IAAI,IAC7B,IAAK,IAAM,KAAY,EAAQ,eAC7B,EAAiB,IAAI,EAAS,UAAW,EAAS,KAAK,EAGzD,IAAM,EAAa,MAAM,4BACvB,EACA,EAAQ,YACR,EACA,EAAQ,OACR,EAAQ,cACR,EAAQ,cACV,EACM,EAAkB,EAAQ,kBAahC,GAXE,EAAgB,SAAW,EAAW,kBAAkB,QACxD,EAAW,kBAAkB,KAC1B,GACC,CAAC,EAAgB,KACd,GACC,EAAS,YAAc,EAAO,WAC9B,EAAS,OAAS,EAAO,MACzB,EAAS,gBAAkB,EAAO,eAClC,EAAS,cAAgB,EAAO,WACpC,CACJ,EAEA,MAAM,EAAS,CACb,KAAM,oBACN,QAAS,wEACT,WAAY,wDACd,CAAC,EAEH,GAAI,CAAC,yBAAyB,EAAQ,mBAAoB,EAAW,kBAAkB,EACrF,MAAM,EAAS,CACb,KAAM,oBACN,QAAS,qDACT,WAAY,kDACd,CAAC,EAEH,OAAO,CACT,CAOA,eAAsB,kBACpB,EACA,EACe,CACf,MAAM,+BAA+B,EAAQ,CAAM,CACrD,CAEA,SAAS,uBACP,EACA,EACA,EACgB,CAChB,IAAM,EAAkB,CAAC,GAAG,qBAAqB,CAAS,CAAC,CAAC,CAAC,QAAS,GAAc,CAClF,IAAM,EAAQ,GAAkB,OAAO,GACvC,OAAO,EAAQ,CAAC,CAAC,EAAW,CAAK,CAAU,EAAI,CAAC,CAClD,CAAC,EACD,MAAO,CACL,GAAG,EACH,OAAQ,CACN,GAAG,EAAS,OACZ,GAAG,OAAO,YAAY,CAAe,CACvC,CACF,CACF,CAEA,SAAS,4BAA4B,EAA2C,CAC9E,OAAO,GAAU,KAAO,UAAY,sBAAsB,CAAM,CAClE,CAQA,eAAsB,cACpB,EACA,EACA,EAAuC,gBACxB,CACf,GAAM,CAAE,YAAW,QAAS,GAAqB,EAEjD,GAAI,IAAU,gBAAiB,CAI7B,GAAM,CAAE,oBAAmB,oBAAmB,2BAA0B,uBACtE,MAAM,+BAA+B,EAAQ,CAAM,EAErD,IAAK,IAAM,KAAU,EACnB,MAAM,qBACJ,EACA,EAAiB,YACjB,EAAO,UACP,EAAO,GACP,EAAO,WACT,EACA,EAAO,KACL,sCAAsC,EAAO,UAAU,UAAU,sBAAsB,EAAO,IAAI,EAAE,SACtG,EAGF,GAAI,EAAkB,OAAS,EAAG,CAKhC,GAAgB,MAAM,EACtB,GAAiB,MAAM,EACvB,GAAuB,MAAM,EAE7B,IAAM,EAAsB,IAAI,IAAI,EAAkB,IAAK,GAAM,EAAE,SAAS,CAAC,EACvE,EAAmB,MAAM,iCAC7B,EACA,EAAiB,YACjB,CACF,EAGA,MAAM,wBAAwB,EAAQ,CAAS,EAiB/C,IAAM,oBAAuB,GAC3B,IAAkB,IAAA,IAAa,CAAC,EAAoB,IAAI,CAAa,EACjE,EAA0B,IAAI,IAC9B,EAAuB,IAAI,IAC3B,EAA2B,IAAI,IACrC,IAAK,IAAM,KAAa,EAAmB,CACzC,IAAM,EAAQ,EAAwB,IAAI,EAAU,SAAS,GACzD,CAAC,GAAS,EAAU,OAAS,EAAM,SACrC,EAAwB,IAAI,EAAU,UAAW,CAAS,EAE5D,IAAM,EAAU,EAAqB,IAAI,EAAU,SAAS,GAAK,IAAI,IACrE,IAAK,IAAM,KAAa,qBAAqB,CAAS,EAAG,EAAQ,IAAI,CAAS,EAC9E,EAAqB,IAAI,EAAU,UAAW,CAAO,EACrD,IAAK,IAAM,KAAa,OAAO,KAAK,GAAuB,KAAK,CAAS,CAAC,CAAC,MAAM,EAC/E,EAAyB,IAAI,GAAG,EAAU,UAAU,GAAG,GAAW,CAEtE,CACA,IAAM,EAAwB,IAAI,IAClC,IAAK,GAAM,CAAC,EAAW,KAAU,EAAyB,CACxD,IAAM,EAAW,kCAAkC,EAAM,cAAe,EAAM,OAAS,CAAC,EACxF,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,4BACN,QAAS,wDAAwD,sBAAsB,EAAM,MAAM,EAAE,kBAAkB,EAAU,EACnI,CAAC,EAEH,EAAsB,IAAI,EAAW,CAAQ,CAC/C,CAEA,IAAM,EAAmB,IAAI,IACvB,EAA4B,IAAI,IACpC,CAAC,GAAG,EAAU,cAAc,QAAS,GAAG,EAAU,cAAc,OAAO,CAAC,CACrE,OAAQ,GAAe,CACtB,IAAM,EAAgB,EAAW,QAAQ,cACzC,OACE,EAAiB,eACjB,IAAkB,IAAA,IAClB,EAAoB,IAAI,CAAa,GACrC,CAAC,EAAyB,IAAI,GAAG,EAAc,GAAG,EAAW,MAAM,CAEvE,CAAC,CAAC,CACD,IAAK,GAAe,GAAG,EAAW,QAAQ,cAAc,GAAG,EAAW,MAAM,CACjF,EAEA,GAAI,CACF,IAAK,IAAM,KAAU,EAAU,KAAK,QAAS,CAC3C,IAAM,EAAgB,EAAO,QAAQ,cACrC,GAAI,oBAAoB,CAAa,EAAG,CACtC,MAAM,EAAO,mBAAmB,EAAO,OAAO,EAC9C,QACF,CACA,IAAM,EAAY,EAAO,QAAQ,cAAc,KAC/C,GAAI,CAAC,GAAiB,CAAC,EAAW,SAClC,IAAM,EAAa,EAAsB,IAAI,CAAa,CAAC,EAAE,OAAO,GACpE,GAAI,CAAC,EAAY,CAEb,EAAiB,eACjB,CAAC,EAAyB,IAAI,GAAG,EAAc,GAAG,GAAW,GAE7D,EAAiB,IAAI,GAAG,EAAc,GAAG,GAAW,EAEtD,QACF,CAKA,GAAI,EAAqB,IAAI,CAAa,CAAC,EAAE,IAAI,CAAS,EAAG,SAC7D,IAAM,EAAQ,EAAiB,eAAe,KAAM,GAAM,EAAE,YAAc,CAAa,EAGvF,GAAgB,QAAQ,IAAI,CAAS,EACrC,MAAM,EAAO,mBAAmB,CAC9B,YAAa,EAAO,QAAQ,YAC5B,gBACA,aAAc,yCAAyC,EAAY,CACjE,qBAAsB,GACtB,sBAAuB,GACvB,uBAAwB,GAAO,OAAO,aACxC,CAAC,CACH,CAAC,CACH,CACA,IAAK,IAAM,KAAU,EAAU,KAAK,QAC7B,oBAAoB,EAAO,QAAQ,aAAa,GACrD,MAAM,EAAO,mBAAmB,EAAO,OAAO,CAElD,OAAS,EAAO,CACd,8BAA8B,EAAO,CACnC,sEACA,wFACF,CAAC,CACH,CACA,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,cAAc,QACxB,OAAQ,GAAW,oBAAoB,EAAO,QAAQ,aAAa,CAAC,CAAC,CACrE,IAAK,GAAW,EAAO,4BAA4B,EAAO,OAAO,CAAC,EACrE,GAAG,EAAU,cAAc,QACxB,OAAQ,GAAW,oBAAoB,EAAO,QAAQ,aAAa,CAAC,CAAC,CACrE,IAAK,GAAW,EAAO,4BAA4B,EAAO,OAAO,CAAC,CACvE,CAAC,EAED,IAAM,EAA6B,EAAkB,OAAQ,GAAM,EAAE,SAAS,EAGxE,EACJ,EAA2B,OAAS,EAChC,gCAAgC,EAAQ,EAAkB,CAA0B,EACpF,IAAA,GAGF,EAA2B,OAAS,IACtC,EAAO,KAAK,aAAa,EAA2B,OAAO,sBAAsB,EACjF,EAAO,QAAQ,GAGjB,IAAM,EAAuB,IAAI,IAAI,CAAqB,EACpD,EAAsB,IAAI,IAAI,CAAgB,EAC9C,EAAyB,IAAI,IAIjC,CAAC,GAAG,CAAuB,CAAC,CAAC,KAAK,CAAC,EAAe,KAAoB,CACpE,EACA,CACE,OAAQ,EAAe,OAAS,EAAI,EAAe,OAAS,EAAI,KAChE,UAAW,EAAoB,IAAkB,IACnD,CACF,CAAC,CACH,EACI,EACJ,GAAI,CAEF,MAAM,2BACJ,EACA,EACA,EACA,EAAiB,eACjB,EAAiB,mBACjB,EAAiB,WACnB,EACA,IAAK,IAAM,KAAa,EAAmB,CACzC,IAAM,EAAkB,IAAI,IAC5B,GAAI,CAEF,MAAM,EAAS,wCACb,+BACE,EACA,EACA,EACA,EAAiB,eACjB,CACF,CACF,EAGI,EAAU,WAAa,GACzB,MAAM,EAAS,sCACb,kBAAkB,EAAc,CAAC,CAAS,CAAC,CAC7C,CAEJ,OAAS,EAAO,CAQd,MAPA,MAAM,oCACJ,EACA,EACA,EAAiB,YACjB,EAAiB,eACjB,CACF,EACM,CACR,CAEA,GAAI,CACF,MAAM,EAAS,yCACb,gCACE,EACA,EACA,EACA,EAAiB,eACjB,CACF,CACF,CACF,OAAS,EAAO,CAQd,MAPA,MAAM,oCACJ,EACA,EACA,EAAiB,YACjB,EAAiB,eACjB,CACF,EACM,CACR,CAEA,IAAM,EAA8B,EAAqB,IAAI,EAAU,SAAS,EAC1E,EAA8B,EAAoB,IAAI,EAAU,SAAS,EACzE,EAAwB,GAAuB,KAAK,CAAS,EACnE,EAAqB,IAAI,EAAU,UAAW,CAAqB,EACnE,IAAM,EAAoB,EAAoB,EAAU,YAAc,KAEtE,GAAI,CACF,MAAM,qBACJ,EACA,EAAiB,YACjB,EAAU,UACV,EAAU,OACV,GAAqB,IAAA,EACvB,CACF,OAAS,EAAO,CACd,IAAI,EACJ,GAAI,CACF,EAAc,MAAM,0BAClB,EACA,YAAY,EAAiB,YAAa,WAAY,EAAU,SAAS,CAC3E,CACF,OAAS,EAAe,CAMtB,MALA,EAAO,KACL,yCAAyC,EAAU,UAAU,GAAG,sBAAsB,EAAU,MAAM,EAAE,4BACnG,aAAyB,MAAQ,EAAc,QAAU,OAAO,CAAa,EAAE,4FAEtF,EACM,CACR,CAEA,IAAM,EAAwB,EAAY,QAAU,IAAA,GAG9C,EADJ,EAAY,kBAAoB,EAAY,YAAc,EAExD,GAAG,4BAA4B,EAAY,MAAM,EAAE,mCACnD,IAA0B,IAAA,IAAa,EAAwB,EAAU,OACvE,sBAAsB,CAAqB,EAC3C,IAAA,GACN,GAAI,IAAyB,IAAA,GAE3B,MADA,EAAqB,OAAO,EAAU,SAAS,EACzC,EAAS,CACb,KAAM,gCACN,QACE,wBAAwB,EAAU,UAAU,GAAG,sBAAsB,EAAU,MAAM,EAAE,4BAA4B,EAAqB,6EAE1I,MAAO,CACT,CAAC,EAGH,GAAI,IAA0B,EAAU,OAatC,MAZA,EAAqB,IACnB,EAAU,UACV,uBACE,EACA,EACA,CACF,CACF,EACA,EAAO,KACL,wBAAwB,EAAU,UAAU,GAAG,sBAAsB,EAAU,MAAM,EAAE,qEAAqE,4BAA4B,CAAqB,EAAE,oIAEjN,EACM,CAEV,CAEA,EAAuB,IAAI,EAAU,UAAW,CAC9C,OAAQ,EAAU,OAClB,UAAW,CACb,CAAC,EAED,IAAM,EAAQ,EAAiB,eAAe,KAC3C,GAAU,EAAM,YAAc,EAAU,SAC3C,EACA,GAAI,EAAO,CACT,IAAM,EAAoB,iCACxB,EACA,EACA,EAAiB,kBACnB,EACA,IAAK,GAAM,CAAC,EAAW,KAAa,GAA+B,CAAC,EAC7D,GAA6B,OAAO,IACvC,EAAkB,IAAI,EAAW,CAAQ,EAG7C,EAAoB,IAAI,EAAU,UAAW,CAAiB,CAChE,CAEA,GAAI,CACF,MAAM,yCAAyC,EAAQ,EAAW,CAAS,CAC7E,OAAS,EAAO,CAKd,MAJA,EAAO,KACL,wBAAwB,EAAU,UAAU,GAAG,sBAAsB,EAAU,MAAM,EAAE,mMAEzF,EACM,CACR,CACF,CAEI,EAA2B,OAAS,IACtC,EAAO,QAAQ,EACf,EAAO,QAAQ,6CAA6C,EAEhE,OAAS,EAAO,CACd,EAAmB,CAAE,OAAM,CAC7B,CAEA,IAAK,GAAM,CAAC,EAAe,KAAuB,EAChD,GAAI,CACF,IAAM,EAAc,MAAM,0BACxB,EACA,YAAY,EAAiB,YAAa,WAAY,CAAa,CACrE,EAKA,GAHE,EAAY,SAAW,EAAmB,QAC1C,CAAC,EAAY,kBACb,EAAY,YAAc,EAAmB,UACrB,SAE1B,EAAqB,OAAO,CAAa,EACzC,IAAM,EAAmB,EAAS,CAChC,KAAM,gCACN,QACE,wBAAwB,EAAc,GAAG,4BAA4B,EAAmB,MAAM,EAAE,4BAA4B,4BAA4B,EAAY,MAAM,EAAE,wEAEhL,CAAC,EACG,EACF,EAAO,KACL,GAAG,EAAiB,QAAQ,iDAC9B,EAEA,EAAmB,CAAE,MAAO,CAAiB,CAEjD,OAAS,EAAqB,CAC5B,EAAqB,OAAO,CAAa,EACzC,IAAM,EAAiB,EAAS,CAC9B,KAAM,kCACN,QACE,sDAAsD,EAAc,GAAG,4BAA4B,EAAmB,MAAM,EAAE,oCAC3H,aAA+B,MAAQ,EAAoB,QAAU,OAAO,CAAmB,EAAE,wEAExG,CAAC,EACG,EACF,EAAO,KACL,GAAG,EAAe,QAAQ,iDAC5B,EAEA,EAAmB,CAAE,MAAO,CAAe,CAE/C,CAGF,GAAI,CACF,MAAM,6BACJ,EACA,EACA,EACA,EAAiB,eACjB,EAAiB,mBACjB,EAAiB,WACnB,CACF,OAAS,EAAkB,CACzB,GAAI,CAAC,EAAkB,MAAM,EAC7B,EAAO,KACL,sEACE,aAA4B,MAAQ,EAAiB,QAAU,OAAO,CAAgB,EACvF,kDACH,CACF,CACA,GAAI,EAAkB,MAAM,EAAiB,MAE7C,IAAK,IAAM,KAAU,EAAU,KAAK,QAAS,CAC3C,IAAM,EAAgB,EAAO,QAAQ,cAC/B,EAAY,EAAO,QAAQ,cAAc,KAC1C,GAAkB,GAClB,EAAiB,IAAI,GAAG,EAAc,GAAG,GAAW,GACzD,MAAM,EAAO,mBAAmB,EAAO,OAAO,CAChD,CACA,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,cAAc,QACxB,OAAQ,GACP,EAA0B,IAAI,GAAG,EAAO,QAAQ,cAAc,GAAG,EAAO,MAAM,CAChF,CAAC,CACA,IAAK,GAAW,EAAO,4BAA4B,EAAO,OAAO,CAAC,EACrE,GAAG,EAAU,cAAc,QACxB,OAAQ,GACP,EAA0B,IAAI,GAAG,EAAO,QAAQ,cAAc,GAAG,EAAO,MAAM,CAChF,CAAC,CACA,IAAK,GAAW,EAAO,4BAA4B,EAAO,OAAO,CAAC,CACvE,CAAC,EAGD,IAAM,EAAgC,EAAU,cAAc,QAAQ,OAAQ,GAAQ,CACpF,IAAM,EAAU,GAAG,EAAI,QAAQ,cAAc,GAAG,EAAI,OACpD,MAAO,CAAC,GAAiB,eAAe,IAAI,CAAO,CACrD,CAAC,EACG,EAA8B,OAAS,GACzC,MAAM,QAAQ,IACZ,EAA8B,IAAK,GACjC,EAAO,4BAA4B,EAAI,OAAO,CAChD,CACF,EAKF,MAAM,QAAQ,IACZ,EAAU,KAAK,QACZ,OACE,GACC,oBAAoB,EAAI,QAAQ,aAAa,GAC7C,CAAC,GAAiB,MAAM,IAAI,EAAI,IAAI,CACxC,CAAC,CACA,IAAK,GAAQ,EAAO,mBAAmB,EAAI,OAAO,CAAC,CACxD,EAQA,MAAM,QAAQ,IACZ,CAAC,GAAG,EAAU,KAAK,QAAS,GAAG,EAAU,KAAK,QAAS,GAAG,EAAU,KAAK,SAAS,CAAC,CAChF,OAAQ,GAAU,EAAM,aAAe,CAAC,GAAiB,MAAM,IAAI,EAAM,IAAI,CAAC,CAAC,CAC/E,QAAS,GACR,EAAM,YAAc,CAAC,oBAAoB,EAAQ,EAAM,WAAW,CAAC,EAAI,CAAC,CAC1E,CACJ,CACF,KAAO,CAGL,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,QAAQ,QAAQ,IAAI,KAAO,IAAW,CACjD,MAAM,EAAO,sBAAsB,EAAO,OAAO,EACjD,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,EACD,GAAG,EAAU,QAAQ,QAAQ,IAAK,GAChC,oBAAoB,EAAQ,EAAO,WAAW,CAChD,CACF,CAAC,EAID,GAAI,CACF,IAAK,IAAM,KAAU,EAAU,KAAK,QAClC,MAAM,EAAO,mBAAmB,EAAO,OAAO,EAC9C,MAAM,oBAAoB,EAAQ,EAAO,WAAW,EAEtD,IAAK,IAAM,KAAU,EAAU,KAAK,QAClC,MAAM,EAAO,mBAAmB,EAAO,OAAO,EAC9C,MAAM,oBAAoB,EAAQ,EAAO,WAAW,EAEtD,MAAM,QAAQ,IACZ,EAAU,KAAK,UAAU,QAAS,GAChC,EAAM,YAAc,CAAC,oBAAoB,EAAQ,EAAM,WAAW,CAAC,EAAI,CAAC,CAC1E,CACF,CACF,OAAS,EAAO,CACd,8BAA8B,EAAO,CACnC,sEACA,wFACF,CAAC,CACH,CAGA,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,cAAc,QAAQ,IAAK,GACtC,EAAO,4BAA4B,EAAO,OAAO,CACnD,EACA,GAAG,EAAU,cAAc,QAAQ,IAAK,GACtC,EAAO,4BAA4B,EAAO,OAAO,CACnD,CACF,CAAC,EAID,MAAM,QAAQ,IACZ,EAAU,cAAc,QAAQ,IAAK,GACnC,EAAO,4BAA4B,EAAI,OAAO,CAChD,CACF,EACA,MAAM,QAAQ,IACZ,EAAU,KAAK,QAAQ,IAAK,GAAQ,EAAO,mBAAmB,EAAI,OAAO,CAAC,CAC5E,CACF,CAME,EAAyB,OAAS,IACjC,EAAiB,eAAiB,EAAkB,SAAW,IAEhE,MAAM,yBACJ,EACA,EAAiB,YACjB,EACA,CACF,CAEJ,MAAW,IAAU,oBAEnB,MAAM,QAAQ,IACZ,EAAU,cAAc,QAAQ,IAAK,GAAQ,EAAO,4BAA4B,EAAI,OAAO,CAAC,CAC9F,EACA,MAAM,QAAQ,IAAI,EAAU,KAAK,QAAQ,IAAK,GAAQ,EAAO,mBAAmB,EAAI,OAAO,CAAC,CAAC,GAG7F,MAAM,QAAQ,IACZ,EAAU,QAAQ,QAAQ,IAAK,GAAQ,EAAO,sBAAsB,EAAI,OAAO,CAAC,CAClF,CAEJ,CAQA,eAAe,wBACb,EACA,EACe,CACf,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,QAAQ,QAAQ,IAAI,KAAO,IAAW,CACjD,MAAM,EAAO,sBAAsB,EAAO,OAAO,EACjD,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,EACD,GAAG,EAAU,QAAQ,QAAQ,IAAK,GAAW,oBAAoB,EAAQ,EAAO,WAAW,CAAC,CAC9F,CAAC,CACH,CC5zBA,SAAS,QAAQ,EAA8B,CAC7C,MAAO,GAAG,EAAK,SAAS,eAAiB,GAAG,GAAG,EAAK,MACtD,CAEA,SAAS,8BACP,EACA,EACA,EACwB,CACxB,IAAM,EAAW,IAAI,IAAI,EAAU,IAAI,OAAO,CAAC,EACzC,EAAoB,IAAI,IAAI,EAAmB,IAAI,OAAO,CAAC,EAC3D,EAAc,EAAU,IAAK,IAAU,CAC3C,SACA,OAAQ,GAAe,GACvB,KAAM,EAAK,KACX,OAAQ,EAAkB,IAAI,QAAQ,CAAI,CAAC,EAAI,CAAC,QAAS,eAAe,EAAI,CAAC,OAAO,EACpF,UAAW,EAAK,SAAS,aAC3B,EAAE,EACI,EAA2B,EAC9B,OAAQ,GAAS,CAAC,EAAS,IAAI,QAAQ,CAAI,CAAC,CAAC,CAAC,CAC9C,IAAK,IAAU,CACd,SACA,OAAQ,GAAe,GACvB,KAAM,EAAK,KACX,OAAQ,CAAC,eAAe,EACxB,UAAW,EAAK,SAAS,aAC3B,EAAE,EAEJ,MAAO,CAAC,GAAG,EAAa,GAAG,CAAwB,CACrD,CAQA,SAAgB,oCACd,EAIA,EAIwB,CACxB,MAAO,CACL,GAAG,8BACD,SACA,EAAc,QACd,EAAuB,OACzB,EACA,GAAG,8BACD,SACA,EAAc,QACd,EAAuB,OACzB,EACA,GAAG,8BACD,SACA,EAAc,QACd,EAAuB,OACzB,EACA,GAAG,8BACD,UACA,EAAc,SACd,EAAuB,QACzB,CACF,CACF,CCvEA,SAAS,mCAAmC,EAGzC,CACD,OAAO,qBAAqB,CAC1B,UAAW,EAAQ,UACnB,gBAAiB,EAAQ,iBAAmB,KAC9C,CAAC,CACH,CAEA,SAAgB,yBACd,EAIA,EACS,CACT,OAAO,mBACL,mCAAmC,CACjC,UAAW,EAAS,WAAW,KAC/B,gBAAiB,EAAS,eAC5B,CAAC,EACD,mCAAmC,CACjC,UAAW,EAAQ,UACnB,gBAAiB,KACnB,CAAC,CACH,CACF,CAEA,SAASC,gBAAc,EAAkD,CACvE,OAAO,OAAO,GAAU,YAAY,GAAkB,CAAC,MAAM,QAAQ,CAAK,CAC5E,CAEA,MAAM,GAA+B,CAKnC,qBAAsB,CACpB,OAAQ,GACR,OAAQ,GACR,OAAQ,GACR,KAAM,EACR,EAKA,gBAAiB,GAKjB,mBAAoB,IAAI,IAAI,CAC1B,+BACA,kCACA,wCACA,mCACF,CAAC,CACH,EAEA,SAAgB,gCAAgC,EAAmD,CAEjG,IAAM,EAAa,qBADD,sBAAsB,GAAoB,CACpB,CAAS,EAcjD,OAAO,8BACL,CACE,KAAM,GAAY,MAAQ,GAC1B,OAAQ,CACN,YAAa,GAAY,QAAQ,aAAe,GAChD,OAAQ,GAAY,QAAQ,QAAU,CAAC,EACvC,cAAe,GAAY,QAAQ,eAAiB,CAAC,EACrD,SAAU,GAAY,QAAQ,UAAY,CAAC,EAC3C,QAAS,GAAY,QAAQ,SAAW,CAAC,EACzC,MAAO,GAAY,QAAQ,OAAS,CAAC,EACrC,WAAY,GAAY,QAAQ,YAAc,CAAC,EAG/C,SAAU,GAAY,QAAQ,UAAY,CAAC,EAC3C,aAAc,GAAY,QAAQ,cAAgB,CAAC,CACrD,CACF,EACA,CAAC,CACH,CACF,CAEA,SAAS,4BAA4B,EAA6C,CAChF,OACE,EAAK,SAAW,GAChB,EAAK,KAAO,UACZ,EAAK,KAAO,eACX,EAAK,KAAO,UAAY,EAAK,KAAO,QAAU,EAAK,KAAO,UAAY,EAAK,KAAO,SAEvF,CAEA,SAAS,8BACP,EACA,EACS,CACT,GAAI,GAAiC,KACnC,OAAO,EAGT,GAAI,OAAO,GAAU,UAInB,OAHI,EAAK,GAAG,EAAE,IAAM,oBAAsB,IAAU,GAClD,OAEK,EAGT,GAAI,OAAO,GAAU,UAAY,OAAO,GAAU,UAAY,OAAO,GAAU,SAU7E,OATI,yBAAyB,CAAI,GAAK,mBAAmB,CAAK,EACrD,OAAO,CAAK,GAGlB,EAAK,GAAG,EAAE,IAAM,QAAU,EAAK,GAAG,EAAE,IAAM,gBAC3C,IAAU,GAA6B,gBAEvC,OAEK,EAGT,GAAI,MAAM,QAAQ,CAAK,EAAG,CACxB,IAAM,EAAQ,EACX,KAAK,EAAM,IAAU,8BAA8B,EAAM,CAAC,GAAG,EAAM,CAAK,CAAC,CAAC,CAAC,CAC3E,OAAQ,GAAS,IAAS,IAAA,EAAS,EActC,OAVI,EAAM,SAAW,GAAK,EAAK,GAAG,EAAE,IAAM,WACxC,OAME,4BAA4B,CAAI,EAC3B,EAAM,UAAU,EAAG,IAAO,KAAK,UAAU,CAAC,EAAI,KAAK,UAAU,CAAC,EAAI,GAAK,CAAE,EAE3E,CACT,CAEA,GAAI,CAACA,gBAAc,CAAK,EACtB,OAAO,EAGT,IAAM,EAAoB,OAAO,QAAQ,CAAK,CAAC,CAC5C,KACE,CAAC,EAAK,KACL,CAAC,EAAK,8BAA8B,EAAY,CAAC,GAAG,EAAM,CAAG,CAAC,CAAC,CACnE,CAAC,CACA,QAAQ,EAAG,KAAgB,IAAe,IAAA,EAAS,EAEhD,EAAmB,OAAO,YAAY,CAAiB,EAEzD,MAAK,GAAG,EAAE,IAAM,UAAY,OAAO,KAAK,CAAgB,CAAC,CAAC,SAAW,KAKvE,EAAK,GAAG,EAAE,IAAM,wBACf,OAAO,KAAK,CAAgB,CAAC,CAAC,SAAW,GACxC,oBAAmB,EAAkB,GAA6B,oBAAoB,GAK1F,OAAO,CACT,CAEA,SAAS,yBAAyB,EAA6C,CAC7E,IAAM,EAAU,EAAK,IAAK,GAAY,OAAO,CAAO,CAAC,CAAC,CAAC,KAAK,GAAG,EAC/D,MAAO,CAAC,GAAG,GAA6B,kBAAkB,CAAC,CAAC,KAAM,GAAY,CAC5E,IAAM,EAAe,EAAQ,MAAM,GAAG,EAChC,EAAY,EAAQ,MAAM,GAAG,EAInC,OAHI,EAAa,SAAW,EAAU,QAG/B,EAAa,OAAO,EAAM,IAAU,IAAS,KAAO,IAAS,EAAU,EAAM,CACtF,CAAC,CACH,CAEA,SAAS,mBAAmB,EAA0C,CACpE,OAAO,OAAO,GAAU,UAAY,OAAO,GAAU,UAAY,UAAU,KAAK,CAAK,CACvF,CAEA,SAAgB,iCAAiC,EAAqB,CASpE,MAAO,CACL,UATiB,qBAAqB,CASlB,CAAC,EAAE,UAAY,CAAC,EAAA,CAAG,IAAK,IAAY,CACtD,GAAG,EACH,SAAU,EAAO,SAAW,CAAC,EAAA,CAAG,UAAU,EAAM,IAAU,EAAO,CAAK,CACxE,EAAE,CACJ,CACF,CCzJA,eAAsB,aAAa,EAAsB,CACvD,GAAM,CACJ,SACA,cACA,cACA,aACA,SACA,gBACA,gBAAgB,IACd,EACE,EAAmC,CAAC,EACpC,EACJ,EAAQ,yBACP,EAAQ,uBACL,IAAI,IACF,CAAC,GAAG,EAAQ,sBAAsB,CAAC,CAAC,KAAK,CAAC,EAAW,KAAc,CACjE,EACA,EAAS,QACX,CAAC,CACH,EACA,IAAA,IACN,GAAI,CAAC,EACH,IAAK,IAAM,KAAY,EAAY,iBAAkB,CACnD,MAAM,EAAS,UAAU,EACzB,IAAM,EAAQ,sBAAsB,CAAQ,EACtC,EAAW,GAAwB,IAAI,EAAS,SAAS,EAC/D,EAAU,KAAK,EAAW,CAAE,GAAG,EAAO,MAAO,EAAS,MAAO,EAAI,CAAK,CACxE,CAEF,IAAM,EAAY,EACd,CAAC,EACD,OAAO,OAAQ,MAAM,EAAY,iBAAiB,cAAc,GAAM,CAAC,CAAC,EACtE,EAAqB,IAAI,IAAI,EAAQ,4BAA8B,CAAC,CAAC,EAC3E,IAAK,IAAM,KAAY,EAChB,mBAAmB,CAAQ,GAC5B,EAAS,QAAQ,OAAS,YAC5B,EAAmB,IAAI,EAAS,QAAQ,SAAS,EAMrD,IAAM,EAAmB,IAAI,IAC7B,IAAK,IAAM,KAAY,EACrB,EAAiB,IAAI,EAAS,UAAW,EAAS,KAAK,EAEzD,IAAM,EAAyB,EAAQ,uBACvC,GAAI,EAAwB,CAC1B,IAAK,IAAM,KAAa,EAAuB,KAAK,EAClD,GAAI,CAAC,EAAU,KAAM,GAAa,EAAS,YAAc,CAAS,EAChE,MAAM,EAAS,CACb,KAAM,kCACN,QAAS,+DAA+D,EAAU,GACpF,CAAC,EAGL,IAAM,EAAkB,IAAI,IAC5B,IAAK,IAAM,KAAY,EACrB,IAAK,IAAM,KAAa,OAAO,KAAK,EAAS,KAAK,EAAG,CACnD,IAAM,EAAoB,EAAgB,IAAI,CAAS,EACvD,GAAI,EACF,MAAM,EAAS,CACb,KAAM,kCACN,QAAS,8DAA8D,EAAU,mBAAmB,EAAkB,SAAS,EAAS,UAAU,GACpJ,CAAC,EAEH,EAAgB,IAAI,EAAW,EAAS,SAAS,CACnD,CAEJ,CACA,IAAM,EAAkB,4BAA4B,EAAQ,EAAK,QAAQ,EAAO,IAAI,CAAC,EAC/E,CAAE,2BAA0B,qBAAoB,qBAAsB,EACxE,CAAE,yBAA0B,CAAC,EAAG,mBAAoB,CAAC,EAAG,kBAAmB,CAAC,CAAE,EAC9E,EACE,CACE,yBAA0B,EAC1B,mBAAoB,0BAA0B,CAAe,EAC7D,kBAAmB,CAAC,CACtB,EACA,MAAM,4BACJ,EACA,EACA,EACA,EACA,GAAiB,GACjB,CACF,EAEA,CACJ,UAAW,EACX,YACA,YACA,kBACE,MAAM,aAAa,EAAQ,EAAa,EAAY,KAAM,EAAY,GAAI,CAAS,EACjF,EAAkB,EAAiB,QAAQ,IAAK,GAAQ,EAAI,IAAI,EAChE,CAAC,EAAe,GAA0B,MAAM,QAAQ,IAAI,CAChE,UACE,EACA,EACA,EACA,EACA,EACA,IAAA,GACA,EACA,CACE,QAAS,EAAY,KACrB,MAAO,EAAY,GACnB,cAAe,EAAQ,cACvB,UAAW,EAAQ,SACrB,CACF,EACA,mBAAmB,EAAQ,EAAa,EAAW,EAAiB,CAAa,CACnF,CAAC,EAQD,OAJA,EAAc,QAAQ,KAAK,EAAM,EACjC,EAAc,QAAQ,KAAK,EAAM,EACjC,EAAc,QAAQ,KAAK,EAAM,EAE1B,CACL,UAAW,CACT,QAAS,EACT,KAAM,EACN,cAAe,CACjB,EACA,YACA,YACA,iBACA,QAAS,CACP,cACA,cACA,eAAgB,EAChB,qBACA,SACA,cAAe,GAAiB,GAChC,GAAI,EAAyB,CAAE,wBAAuB,EAAI,CAAC,EAC3D,2BACA,qBACA,mBACF,CACF,CACF,CAkBA,eAAe,aACb,EACA,EACA,EACA,EACA,EACA,CACA,IAAM,EAAY,gBAChB,mBACF,EACM,EAA6B,CAAC,EAC9B,EAAiC,CAAC,EAClC,EAAiB,IAAI,IAErB,EAAmB,MAAM,iCAAiC,CAC9D,SACA,UAAW,MAAO,EAAW,IAAgB,CAC3C,GAAM,CAAE,mBAAkB,iBAAkB,MAAM,EAAO,qBAAqB,CAC5E,cACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAkB,CAAa,CACzC,EACA,QAAU,GAAa,EAAS,WAAW,KAC3C,OAAS,GAAS,YAAY,EAAa,WAAY,CAAI,CAC7D,CAAC,EAED,IAAK,IAAM,KAAY,EAAW,CAChC,IAAM,EAAW,EAAiB,EAAS,WACrC,EAAc,MAAM,iBAAiB,CACzC,IAAK,YAAY,EAAa,WAAY,EAAS,SAAS,EAC5D,UACA,OACF,CAAC,EACG,GACY,8BAA8B,CAC1C,OAAQ,EAAS,UACjB,WAAY,EAAS,MACrB,UACA,QACA,aAAc,mBACd,aAAc,EAAS,UACvB,YACA,WACF,CAGM,GACJ,sBAAsB,EAAS,UAAW,EAAY,MAAM,GAC5D,yBAAyB,EAAS,SAAU,CAAQ,EAEpD,EAAU,UAAU,KAAK,CAAE,KAAM,EAAS,SAAU,CAAC,EAErD,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAS,UACf,aACF,CAAC,EAEH,OAAO,EAAiB,EAAS,YAEjC,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAS,UACf,QAAS,CACP,cACA,cAAe,EAAS,UAExB,gBAAiB,KACnB,EACA,aACF,CAAC,CAEL,CAqBA,OApBA,OAAO,QAAQ,CAAgB,CAAC,CAAC,SAAS,CAAC,KAAmB,CAC5D,IAAM,EAAQ,EAAiB,GACjB,4BAA4B,CACxC,OAAQ,GAAO,UACf,WAAY,GAAO,MACnB,UACA,QACA,gBACF,CACQ,GACN,EAAU,QAAQ,KAAK,CACrB,KAAM,EACN,QAAS,CACP,cACA,eACF,CACF,CAAC,CAEL,CAAC,EAEM,CAAE,YAAW,YAAW,YAAW,gBAAe,CAC3D,CAoCA,eAAe,UACb,EACA,EACA,EACA,EACA,EACA,EACA,EAAgB,GAChB,EAA4B,CAAC,EAC7B,CACA,IAAM,EAAY,gBAChB,iBACF,EACM,CAAE,UAAS,QAAO,gBAAe,aAAc,EAU/C,gBAAkB,MACtB,EACA,EACA,IAGO,qBAAqB,MAAM,iBAAiB,CAAE,IADzC,gBAAgB,EAAa,EAAW,CACC,EAAK,QAAS,GAAW,GAAI,OAAM,CAAC,EAAG,CAC1F,IAAK,EAAe,aAAa,EAAW,CAAS,EACrD,gBACA,YACA,OAAQ,IAA0B,IAAA,EACpC,CAAC,EAGG,WAAc,GACX,EAAiB,MAAO,EAAW,IAAgB,CACxD,GAAM,CAAE,gBAAe,iBAAkB,MAAM,EAAO,kBAAkB,CACtE,cACA,gBACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAe,CAAa,CACtC,CAAC,EAIH,IAAK,IAAM,KAAY,EAAW,CAChC,IAAM,EAAQ,GAA0B,IAAI,EAAS,SAAS,GAAK,EAAS,MAC5E,IAAK,GAAM,CAAC,EAAW,KAAS,OAAO,QAAQ,CAAK,EAClD,8BAA8B,CAC5B,SAAU,EAAK,UAAU,cACzB,WAAY,EAAmB,IAAI,CAAS,EAC5C,SAAU,GAAsB,aAAa,CAAS,CACxD,CAAC,CAEL,CAEA,IAAK,IAAM,KAAY,EAAW,CAChC,IAAM,EAAgB,MAAM,WAAW,EAAS,SAAS,EACnD,EAAmB,IAAI,IAAI,EAAc,IAAK,GAAS,CAAC,EAAK,KAAM,CAAI,CAAC,CAAC,EAGzE,EAAQ,GAA0B,IAAI,EAAS,SAAS,GAAK,EAAS,MACtE,SAAY,GAChB,gBAAgB,EAAS,UAAW,EAAW,EAAM,EAAU,EAAE,UAAU,aAAa,EAE1F,IAAK,GAAM,CAAC,EAAW,KAAyB,OAAO,QAAQ,CAAK,EAAG,CACrE,IAAM,EAAe,yCAAyC,EAAsB,CAClF,WAAY,EAAmB,IAAI,CAAS,EAC5C,uBAAwB,EAAS,OAAO,aAC1C,CAAC,EACK,EAAe,EAAiB,IAAI,CAAS,EAC/C,GAEA,CAAC,GACD,mBACE,gCAAgC,CAAY,EAC5C,gCAAgC,CAAY,CAC9C,EAGA,EAAU,UAAU,KAAK,CAAE,KAAM,EAAW,YAAa,MAAM,SAAS,CAAS,CAAE,CAAC,EAEpF,EAAU,QAAQ,KAAK,CACrB,KAAM,EACN,QAAS,CACP,cACA,cAAe,EAAS,UACxB,cACF,EACA,YAAa,MAAM,SAAS,CAAS,CACvC,CAAC,EAEH,EAAiB,OAAO,CAAS,GAEjC,EAAU,QAAQ,KAAK,CACrB,KAAM,EACN,QAAS,CACP,cACA,cAAe,EAAS,UACxB,cACF,EACA,YAAa,MAAM,SAAS,CAAS,CACvC,CAAC,CAEL,CACA,EAAiB,SAAS,EAAO,IAAS,CACxC,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,cAAe,EAAS,UACxB,iBAAkB,CACpB,CACF,CAAC,CACH,CAAC,CACH,CACA,IAAK,IAAM,KAAiB,GAE1B,MAD4B,WAAW,CAAa,EAAA,CACtC,QAAS,GAAQ,CAC7B,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAI,KACV,QAAS,CACP,cACA,gBACA,iBAAkB,EAAI,IACxB,CACF,CAAC,CACH,CAAC,EAEH,OAAO,CACT,CAiBA,eAAe,mBACb,EACA,EACA,EACA,EACA,EAAgB,GAChB,CACA,IAAM,EAAY,gBAChB,yBACF,EAEM,oBAAuB,GACpB,EAAiB,MAAO,EAAW,IAAgB,CACxD,GAAM,CAAE,cAAa,iBAAkB,MAAM,EAAO,2BAA2B,CAC7E,cACA,gBACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAa,CAAa,CACpC,CAAC,EAGH,IAAK,IAAM,KAAY,EAAW,CAChC,IAAM,EAAyB,MAAM,oBAAoB,EAAS,SAAS,EACrE,EAAkB,IAAI,IAC5B,EAAuB,QAAS,GAAkB,CAChD,EAAgB,IAAI,EAAc,QAAQ,CAC5C,CAAC,EAED,IAAM,EAAQ,EAAS,MACvB,IAAK,GAAM,CAAC,EAAW,KAAc,OAAO,QAAQ,CAAK,EAAG,CAC1D,IAAM,EAAgB,EAAU,aAAa,IAC7C,GAAI,CAAC,EACH,SAEF,IAAM,EAAoB,mBAAmB,CAAa,EACpD,EAAqB,EAAuB,KAC/C,GAAU,EAAM,WAAa,CAChC,EACI,EAAgB,IAAI,CAAS,GAE7B,CAAC,GACD,GACA,mBACE,iCAAiC,EAAmB,UAAU,EAC9D,iCAAiC,CAAiB,CACpD,EAEA,EAAU,UAAU,KAAK,CAAE,KAAM,CAAU,CAAC,EAE5C,EAAU,QAAQ,KAAK,CACrB,KAAM,EACN,QAAS,CACP,cACA,cAAe,EAAS,UACxB,SAAU,EACV,WAAY,CACd,CACF,CAAC,EAEH,EAAgB,OAAO,CAAS,GAEhC,EAAU,QAAQ,KAAK,CACrB,KAAM,EACN,QAAS,CACP,cACA,cAAe,EAAS,UACxB,SAAU,EACV,WAAY,CACd,CACF,CAAC,CAEL,CACA,EAAgB,QAAS,GAAS,CAChC,EAAU,QAAQ,KAAK,CACrB,OACA,QAAS,CACP,cACA,cAAe,EAAS,UACxB,SAAU,CACZ,CACF,CAAC,CACH,CAAC,CACH,CACA,IAAK,IAAM,KAAiB,GAE1B,MADqC,oBAAoB,CAAa,EAAA,CAC/C,QAAS,GAAkB,CAChD,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAc,SACpB,QAAS,CACP,cACA,gBACA,SAAU,EAAc,QAC1B,CACF,CAAC,CACH,CAAC,EAEH,OAAO,CACT,CC9iBA,eAAsB,cACpB,EACA,EACA,EAAyD,gBACzD,CACA,GAAM,CAAE,YAAW,UAAS,SAAU,EACtC,GAAI,IAAU,gBAAiB,CAE7B,IAAM,EAAsB,MAAM,qBAChC,EACA,EACA,EACA,EACA,EAAO,0BACP,EAAO,wBACT,EAIA,MAAM,QAAQ,IAAI,CAChB,GAAG,EAAU,QAAQ,IAAI,KAAO,IAAW,CACzC,IAAM,EAAmB,0BACvB,EACA,EAAO,YACT,EACM,EAAQ,6BAA6B,EAAO,YAAa,EAAO,QAAQ,EAC9E,MAAM,EAAO,eAAe,CAC1B,YAAa,EAAM,YACnB,aAAc,EAAM,aACpB,oBAAqB,EAAM,oBAC3B,YAAa,EAAM,YACnB,kBAAmB,EAAM,kBACzB,aAAc,EACd,uBAAwB,EAAM,sBAChC,CAAC,EACD,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,EACD,GAAG,EAAU,QAAQ,IAAI,KAAO,IAAW,CACzC,IAAM,EAAmB,0BACvB,EACA,EAAO,YACT,EACM,EAAQ,6BAA6B,EAAO,YAAa,EAAO,QAAQ,EAC9E,MAAM,EAAO,eAAe,CAC1B,YAAa,EAAM,YACnB,aAAc,EAAM,aACpB,oBAAqB,EAAM,oBAC3B,YAAa,EAAM,YACnB,kBAAmB,EAAM,kBACzB,aAAc,EACd,uBAAwB,EAAM,sBAChC,CAAC,EACD,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,EAGD,GAAG,EAAU,UAAU,QAAS,GAC9B,EAAM,YAAc,CAAC,oBAAoB,EAAQ,EAAM,WAAW,CAAC,EAAI,CAAC,CAC1E,CACF,CAAC,CACH,MACE,MAAM,iBACJ,EAAU,QAAQ,IAAK,IAAS,CAC9B,aAAc,WACd,aAAc,EAAI,KAClB,QACE,EAAO,eAAe,CACpB,YAAa,EAAI,YACjB,WAAY,EAAI,UAClB,CAAC,CACL,EAAE,CACJ,EAEA,MAAM,iBACJ,EAAO,mBAAmB,IAAK,IAAS,CACtC,aAAc,wBACd,aAAc,EAAI,gBAClB,QACE,EAAO,0BAA0B,CAC/B,YAAa,EAAI,YACjB,gBAAiB,EAAI,eACvB,CAAC,CACL,EAAE,CACJ,CAEJ,CAQA,eAAe,iBAAiB,EAAwC,CACtE,IAAM,EAAU,MAAM,QAAQ,WAAW,EAAW,IAAK,GAAc,EAAU,IAAI,CAAC,CAAC,EACjF,EAAkB,CAAC,EACzB,EAAQ,SAAS,EAAQ,IAAU,CACjC,GAAI,EAAO,SAAW,YACpB,OAEF,IAAM,EAAY,EAAc,EAAW,GAAQ,4BAA4B,EACzE,EAAQ,EAAO,OACjB,kBAAiB,GAAgB,EAAM,OAAS,EAAK,UAGzD,IAAI,aAAiB,GAAgB,EAAM,OAAS,EAAK,mBAAoB,CAC3E,EAAO,KACL,oBAAoB,EAAU,aAAa,IAAI,EAAU,aAAa,kCACxE,EACA,MACF,CACA,EAAO,KAAK,GAAQ,CAAK,CAAC,CAD1B,CAEF,CAAC,EACD,IAAM,EAAa,EAAO,GAC1B,GAAI,EACF,MAAM,CAEV,CAQA,SAAS,0BACP,EACA,EAC2B,CAC3B,IAAM,EAAsC,CAAC,EAC7C,IAAK,IAAM,KAAW,EAChB,EAAY,KAAa,IAAA,KAC3B,EAAS,GAAW,EAAY,IAGpC,OAAO,CACT,CAeA,eAAe,qBACb,EACA,EACA,EACA,EACA,EAAiD,IAAI,IACrD,EAAyD,IAAI,IACzB,CACpC,IAAM,EAAiD,CAAC,EAGlD,EAAgB,EAAU,QAAQ,IAAM,EAAU,QAAQ,IAAM,EAAU,QAAQ,GACxF,GAAI,CAAC,EACH,OAAO,EAGT,GAAM,CAAE,eAAgB,EAGlB,EAAkB,IAAI,IAC5B,EAA0B,QAAS,GAAY,EAAgB,IAAI,CAAO,CAAC,EAC3E,IAAK,IAAM,IAAQ,CAAC,GAAG,EAAU,QAAS,GAAG,EAAU,OAAO,EAC5D,IAAK,IAAM,KAAW,EAAK,aACzB,EAAgB,IAAI,CAAO,EAI/B,IAAM,EAAuB,MAAM,GAAS,MAAO,EAAW,IAAgB,CAC5E,IAAM,EAAW,MAAM,EAAO,yBAAyB,CACrD,cACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAS,aAAa,IAAK,GAAM,EAAE,IAAI,EAAG,EAAS,aAAa,CAC1E,CAAC,EACK,EAAsB,IAAI,IAAI,CAAoB,EAExD,GAAI,EAAU,QAAQ,OAAS,GAAK,EAAU,QAAQ,OAAS,EAAG,CAGhE,IAAM,EAAU,MAAM,QAAQ,IAC5B,MAAM,KAAK,CAAe,CAAC,CAAC,IAAI,KAAO,IAAY,CACjD,IAAM,EAAa,EAAoB,IAAI,CAAO,EAC5C,EAAU,CACd,cACA,gBAAiB,EACjB,UAAW,wBAAwB,CAAO,EAC1C,uBAAwB,EAAyB,IAAI,CAAO,GAAK,EACnE,EACM,EAAW,EACb,MAAM,EAAO,0BAA0B,CAAO,EAC9C,MAAM,EAAO,0BAA0B,CAAO,EAYlD,OATA,MAAM,oBACJ,EACA,MAAM,iBAAiB,CACrB,IAAK,YAAY,EAAa,wBAAyB,CAAO,EAC9D,UACA,OACF,CAAC,CACH,EAEO,CAAE,UAAS,QAAS,EAAS,aAAa,OAAQ,CAC3D,CAAC,CACH,EAEA,IAAK,GAAM,CAAE,UAAS,aAAa,EAC7B,IACF,EAAoB,GAAW,EAGrC,CAEA,OAAO,CACT,CA+BA,SAAS,qBAAqB,EAAsD,CAClF,IAAM,EAAK,cAAc,CAAQ,EAC3B,EAAU,KAAK,MAAM,EAAK,GAAI,EAC9B,EAAS,EAAK,IAAQ,IAC5B,MAAO,CAAE,QAAS,OAAO,CAAO,EAAG,OAAM,CAC3C,CAEA,SAAS,cAAc,EAAiE,CACtF,MAAO,CACL,WAAY,EAAO,WACnB,eAAgB,qBAAqB,EAAO,cAAc,EAC1D,WAAY,qBAAqB,EAAO,UAAU,EAClD,kBAAmB,EAAO,iBAC5B,CACF,CAEA,SAAS,oBACP,EACkD,CAClD,MAAO,CACL,wBAAyB,EAAO,uBAClC,CACF,CAcA,SAAgB,6BACd,EACA,EACyB,CACzB,MAAO,CACL,cACA,aAAc,EAAS,KACvB,oBAAqB,EAAS,QAAQ,KACtC,GAAI,EAAS,aAAe,CAAE,YAAa,cAAc,EAAS,WAAW,CAAE,EAC/E,GAAI,EAAS,mBAAqB,CAChC,kBAAmB,oBAAoB,EAAS,iBAAiB,CACnE,EACA,uBAAwB,EAAS,eAAiB,EACpD,CACF,CA+BA,MAAM,GAAiD,CACrD,cAAe,IAAI,GACrB,EAEA,SAAS,aAAa,EAAuC,EAA+B,CAC1F,OAAO,EAAY,cAAc,IAAI,CAAY,CACnD,CAwBA,SAAgB,2BAA2B,EAInB,CACtB,GAAM,CAAE,YAAW,cAAa,gBAAiB,EAC3C,EAAW,IAAI,IACrB,IAAK,IAAM,KAAY,EAChB,KAAa,EAAS,IAAI,EAE/B,IAAK,IAAM,KAAW,EAAY,EAAS,QAAQ,OAAS,CAAC,EAC3D,EAAS,IAAI,CAAO,EAGxB,OAAO,CACT,CAUA,SAAS,wBAAwB,EAA6D,CAC5F,GAAM,CAAE,YAAW,cAAa,cAAa,YAAa,EACpD,EAAe,IAAI,IACzB,IAAK,IAAM,KAAY,OAAO,OAAO,CAAS,EAE5C,IAAK,IAAM,KAAW,EAAY,EAAS,QAAQ,OAAS,CAAC,EAC3D,EAAa,IAAI,CAAO,EAG5B,IAAM,EAAqB,2BAA2B,CACpD,UAAW,OAAO,OAAO,CAAS,EAClC,cACA,aAAe,GAAiB,aAAa,EAAa,CAAY,CACxE,CAAC,EAEK,EAAW,IAAI,IACrB,IAAK,IAAM,KAAW,EACpB,EAAS,IACP,EACA,qBAAqB,CACnB,SAAU,EAAS,IAAI,CAAO,EAC9B,WAAY,EAAmB,IAAI,CAAO,EAC1C,SAAU,GAAsB,YAAY,CAAO,CACrD,CAAC,CACH,EAEF,OAAO,CACT,CAQA,SAAS,6BACP,EACA,EACa,CACb,IAAM,EAAQ,IAAI,IAClB,IAAK,GAAM,CAAC,EAAS,KAAkB,EAAU,CAC/C,IAAM,EAAS,EAAS,IAAI,CAAO,EAC/B,GAAU,EAAO,yBAA2B,GAC9C,EAAM,IAAI,CAAO,CAErB,CACA,OAAO,CACT,CAcA,eAAsB,aACpB,EACA,EACA,EACA,EACA,EACA,EACA,EAA6C,IAAI,IACjD,EAA2C,CAAC,EAC5C,CACA,IAAM,EAAY,gBAMhB,WAAW,EACP,EAA6B,CAAC,EAC9B,EAAiC,CAAC,EAClC,EAAiB,IAAI,IACrB,EAA4B,IAAI,IAChC,EAA2B,IAAI,IAE/B,EAAuB,EAAgB,WAAa,GACpD,CAAE,gBAAe,aAAc,EAK/B,8BAAiC,GAAkC,CACvE,IAAM,EAAW,EAAY,EAAU,EAAa,EAAE,QAAQ,MAAQ,KAAO,CAAC,EACxE,EAAW,EAAgB,kBAAoB,IAAI,IACzD,OAAO,EAAS,OAAS,GAAK,EAAS,MAAO,GAAY,EAAS,IAAI,CAAO,CAAC,CACjF,EACM,EAAuB,MAAM,0BAA0B,EAAQ,CAAW,EAC1E,EAA2B,wBAAwB,CACvD,YACA,cACA,YAAa,EAAgB,cAAgB,GAC7C,SAAU,EAAgB,kBAAoB,IAAI,GACpD,CAAC,EACK,EAAwB,6BAC5B,EACA,CACF,EAEM,EAAoB,MAAM,iCAAiC,CAC/D,SACA,UAAW,MAAO,EAAW,IAAa,CACxC,IAAM,EAAW,MAAM,EAAO,cAAc,CAC1C,cACA,YACA,UACF,CAAC,EACD,MAAO,CAAC,EAAS,UAAW,EAAS,aAAa,CACpD,EACA,QAAU,GAAa,EAAS,KAChC,OAAS,GAAS,YAAY,EAAa,WAAY,CAAI,CAC7D,CAAC,EAED,IAAK,IAAM,KAAY,OAAO,OAAO,CAAS,EAAG,CAC/C,IAAM,EAAW,EAAkB,EAAS,MACtC,EAAc,qBAClB,MAAM,iBAAiB,CACrB,IAAK,YAAY,EAAa,WAAY,EAAS,IAAI,EACvD,UACA,OACF,CAAC,EACD,CACE,IAAK,EAAe,SAAS,EAAS,IAAI,EAC1C,gBACA,YACA,OAAQ,EAAS,gBAAkB,IAAA,EACrC,CACF,EAGA,qBAAqB,EAAa,CAChC,IAAK,EAAe,aAAa,EAAS,IAAI,EAC9C,gBACA,YACA,OAAQ,8BAA8B,EAAS,IAAI,EACnD,MAAO,MACT,CAAC,EAED,IAAM,EAAe,EAAY,EAAS,QAAQ,MAClD,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,8BACN,QAAS,QAAQ,EAAS,QAAQ,KAAK,0BAA0B,EAAS,KAAK,mBAC/E,QACE;;+EACF,WAAY,gCAAgC,EAAS,QAAQ,KAAK,gCAAgC,EAAS,QAAQ,KAAK,UAC1H,CAAC,EAEH,EAAa,QAAS,GAAY,EAAyB,IAAI,CAAO,CAAC,EAEvE,IAAM,EAA4B,CAChC,GAAG,EACH,cAAe,qBAAqB,CAClC,SAAU,EAAS,cACnB,WAAY,aAAa,EAAsB,EAAS,IAAI,EAC5D,SAAU,GAAsB,SAAS,EAAS,IAAI,CACxD,CAAC,CACH,EAEA,GAAI,EAAU,CAYZ,GAXc,8BAA8B,CAC1C,OAAQ,EAAS,UACjB,WAAY,EAAS,MACrB,UACA,QACA,aAAc,WACd,aAAc,EAAS,KACvB,YACA,WACF,CAGM,GACJ,sBAAsB,EAAS,UAAW,EAAY,MAAM,GAC5D,4BAA4B,CAC1B,SAAU,EAAS,SACnB,SAAU,EACV,eACA,wBACA,uBACF,CAAC,EACD,CAEA,EAAU,UAAU,KAAK,CAAE,KAAM,EAAS,KAAM,aAAY,CAAC,EAC7D,IAAK,IAAM,KAAW,EACpB,EAA0B,IAAI,CAAO,CAEzC,MACE,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAS,KACf,cACA,SAAU,EACV,eACA,aACF,CAAC,EAEH,OAAO,EAAkB,EAAS,KACpC,MACE,EAAU,QAAQ,KAAK,CACrB,KAAM,EAAS,KACf,cACA,SAAU,EACV,eACA,aACF,CAAC,CAEL,CAEA,IAAM,EAAoC,CAAC,EAC3C,OAAO,OAAO,CAAiB,CAAC,CAAC,QAAS,GAAa,CACrD,GAAI,CAAC,EACH,OAEF,IAAM,EAAQ,4BAA4B,CACxC,OAAQ,EAAS,UACjB,WAAY,EAAS,MACrB,UACA,QACA,gBACF,CAAC,EACK,EAAe,4BAA4B,EAAS,QAAQ,EAC9D,EACF,EAAgB,KAAK,CACnB,KAAM,EAAS,SAAS,KACxB,cACA,WAAY,EAAS,SAAS,GAC9B,eACA,kBAAmB,CAAC,CACtB,CAAC,EAED,EAAa,QAAS,GAAY,EAAyB,IAAI,CAAO,CAAC,CAE3E,CAAC,EAED,IAAM,EAAqB,MAAM,+BAA+B,CAC9D,SACA,cACA,UACA,QACA,yBAA0B,CAAC,GAAG,EAAqB,KAAK,CAAC,EACzD,2BACA,gBACF,CAAC,EACK,EAAoB,IAAI,IAAI,EAAmB,IAAK,GAAQ,EAAI,eAAe,CAAC,EAEtF,IAAK,IAAM,KAAO,EAChB,EAAU,QAAQ,KAAK,CACrB,GAAG,EACH,kBAAmB,EAAI,aAAa,OACjC,GAAY,CAAC,EAAyB,IAAI,CAAO,GAAK,EAAkB,IAAI,CAAO,CACtF,CACF,CAAC,EAGH,MAAO,CACL,YACA,YACA,YACA,iBACA,UACA,QACA,4BACA,qBACA,0BACF,CACF,CAKA,eAAe,0BACb,EACA,EACmD,CACnD,IAAM,EAAe,MAAM,GAAS,MAAO,EAAW,IAAgB,CACpE,IAAM,EAAW,MAAM,EAAO,yBAAyB,CACrD,cACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAS,aAAc,EAAS,aAAa,CACvD,CAAC,EACD,OAAO,IAAI,IAAI,EAAa,IAAK,GAAgB,CAAC,EAAY,KAAM,CAAW,CAAC,CAAC,CACnF,CAYA,eAAe,+BACb,EACsC,CACtC,GAAM,CACJ,SACA,cACA,UACA,QACA,2BACA,2BACA,kBACE,EACE,EAAa,EAAyB,OACzC,GAAY,CAAC,EAAyB,IAAI,CAAO,CACpD,EAmBA,OAAO,MAlBa,QAAQ,IAC1B,EAAW,IAAI,KAAO,IAAoB,CACxC,GAAM,CAAE,YAAa,MAAM,EAAO,YAAY,CAC5C,IAAK,YAAY,EAAa,wBAAyB,CAAe,CACxE,CAAC,EAGD,OAAO,4BAA4B,CACjC,OAAQ,GAAU,OAClB,WAAY,GAAU,OAAA,YACtB,UACA,QACA,gBACF,CAAC,EACG,CAAE,cAAa,iBAAgB,EAC/B,IAAA,EACN,CAAC,CACH,EAAA,CACa,OAAQ,GAA4C,IAAS,IAAA,EAAS,CACrF,CAUA,SAAgB,4BACd,EAIA,EACwB,CACxB,OAAO,wCACL,WACA,EACA,EACC,GACC,iBAAkB,EACd,EAAK,aAAa,IAAK,GAAY,wBAAwB,CAAO,CAAC,EACnE,CAAC,CACT,CACF,CAyBA,SAAS,4BAA4B,EAA2C,CAC9E,GAAM,CAAE,WAAU,WAAU,eAAc,wBAAuB,yBAA0B,EAQ3F,MAPI,CAAC,EAAa,MAAO,GAAY,EAAsB,IAAI,CAAO,CAAC,GAInE,EAAa,KAAM,GAAY,EAAsB,IAAI,CAAO,CAAC,EAC5D,GAEF,kBAAkB,EAAU,EAAU,CAAY,CAC3D,CAEA,SAAS,kBACP,EACA,EACA,EACA,CACA,OACE,EAAS,sBAAwB,EAAS,QAAQ,OACjD,EAAS,wBAA0B,OAAY,EAAS,eAAiB,KAC1E,mBACE,+CAA+C,EAAS,WAAW,EACnE,uCAAuC,EAAS,WAAW,CAC7D,GACA,mBACE,qCAAqC,EAAS,iBAAiB,EAC/D,qCAAqC,EAAS,iBAAiB,CACjE,GACA,mBACE,oCAAoC,EAAS,YAAY,EACzD,oCAAoC,CAAY,CAClD,CAEJ,CAEA,SAAS,+CACP,EAQA,CACK,KAIL,OAAO,+BAA+B,CACpC,WAAY,EAAO,YAAc,EACjC,kBAAmB,EAAO,mBAAqB,EAC/C,eAAgB,CACd,QAAS,EAAO,gBAAgB,SAAW,GAC3C,MAAO,EAAO,gBAAgB,OAAS,CACzC,EACA,WAAY,CACV,QAAS,EAAO,YAAY,SAAW,GACvC,MAAO,EAAO,YAAY,OAAS,CACrC,CACF,CAAC,CACH,CAEA,SAAS,uCAAuC,EAAiC,CAC1E,KAIL,OAAO,+BAA+B,CACpC,WAAY,EAAO,WACnB,kBAAmB,EAAO,kBAC1B,eAAgB,qBAAqB,EAAO,cAAc,EAC1D,WAAY,qBAAqB,EAAO,UAAU,CACpD,CAAC,CACH,CAEA,SAAS,qCACP,EACA,CACI,GAAC,GAAW,EAAO,wBAGvB,MAAO,CAAE,wBAAyB,EAAO,uBAAwB,CACnE,CAEA,SAAS,oCACP,EACA,CACA,OAAO,MAAM,QAAQ,CAAY,EAC7B,EAAa,SAAS,EACtB,OAAO,KAAK,GAAgB,CAAC,CAAC,CAAC,CAAC,SAAS,CAC/C,CAEA,SAAS,4BAA4B,EAGlC,CACD,IAAM,EAAW,IAAI,IAAI,OAAO,KAAK,EAAS,cAAgB,CAAC,CAAC,CAAC,EAIjE,OAHI,EAAS,qBACX,EAAS,IAAI,EAAS,mBAAmB,EAEpC,CAAC,GAAG,CAAQ,CAAC,CAAC,SAAS,CAChC,CAEA,SAAS,+BAA+B,EAKrC,CACD,MAAO,CACL,WAAY,EAAO,WACnB,kBAAmB,EAAO,kBAC1B,eAAgB,CACd,QAAS,OAAO,EAAO,eAAe,OAAO,EAC7C,MAAO,EAAO,eAAe,KAC/B,EACA,WAAY,CACV,QAAS,OAAO,EAAO,WAAW,OAAO,EACzC,MAAO,EAAO,WAAW,KAC3B,CACF,CACF,CCn4BA,SAAS,wBACP,EAC8D,CACzD,KACL,MAAO,CAAE,wBAAyB,EAAO,uBAAwB,CACnE,CAEA,SAAS,+BACP,EACiD,CAC7C,GAAC,GAAW,EAAO,wBACvB,MAAO,CAAE,wBAAyB,EAAO,uBAAwB,CACnE,CAUA,SAAS,YAAY,EAAyC,CAC5D,GAAI,EAAO,YAAc,QAAS,OAAO,EAAO,IAChD,IAAM,EAAO,EAAuC,IACpD,GAAI,OAAO,GAAQ,SACjB,MAAM,EAAS,CACb,KAAM,oCACN,QAAS,sCAAsC,EAAO,KAAK,4IAC7D,CAAC,EAEH,OAAO,CACT,CAQA,SAAgB,6BAA6B,EAAyC,CACpF,OAAOC,GAAc,YAAY,CAAM,EAAG,EAAO,SAAS,CAC5D,CAQA,SAAS,eAAe,EAAuC,CAC7D,GAAI,YAAY,CAAM,CAAC,CAAC,SAAS,GAAG,EAClC,MAAM,EAAS,CACb,KAAM,oCACN,QAAS,sCAAsC,EAAO,KAAK,KAAK,IAClE,CAAC,EAEH,IAAM,EAAS,GAAyC,UAAU,CAChE,KAAM,EAAO,KACb,IAAK,6BAA6B,CAAM,EACxC,kBAAmB,EAAO,iBAC5B,CAAC,EACD,GAAI,CAAC,EAAO,QACV,MAAM,EAAS,CACb,KAAM,oCACN,QAAS,sCAAsC,EAAO,KAAK,KAAK,EAAO,MAAM,OAAO,IAAK,GAAU,EAAM,OAAO,CAAC,CAAC,KAAK,IAAI,GAC7H,CAAC,CAEL,CAYA,eAAsB,uCACpB,EACA,EACA,EACA,EACA,EACA,CACA,IAAM,EAAY,gBAChB,6BACF,EACM,EAA6B,CAAC,EAC9B,EAAiC,CAAC,EAClC,EAAiB,IAAI,IAErB,EAAe,OAAO,OAAO,CAAQ,EAC3C,IAAK,IAAM,KAAU,EACnB,eAAe,CAAM,EAGvB,IAAM,EAAW,MAAM,iCAAiC,CACtD,SACA,UAAW,MAAO,EAAW,IAAa,CACxC,IAAM,EAAW,MAAM,EAAO,yCAAyC,CACrE,cACA,YACA,UACF,CAAC,EACD,MAAO,CAAC,EAAS,SAAU,EAAS,aAAa,CACnD,EACA,QAAU,GAAa,EAAS,KAChC,OAAS,GAAS,YAAY,EAAa,yCAA0C,CAAI,CAC3F,CAAC,EAEK,EAAY,IAAI,IACtB,IAAK,IAAM,KAAU,EAAc,CACjC,GAAI,EAAU,IAAI,EAAO,IAAI,EAC3B,MAAM,EAAS,CACb,KAAM,sCACN,QAAS,6CAA6C,EAAO,KAAK,6DACpE,CAAC,EAEH,EAAU,IAAI,EAAO,IAAI,EAOzB,IAAM,EAAc,MAAM,iBAAiB,CAAE,IAL1B,YACjB,EACA,yCACA,EAAO,IAEyC,EAAY,UAAS,OAAM,CAAC,EACxE,EAAQ,EAAS,EAAO,MAE9B,GAAI,EAAO,CACT,IAAM,EAAQ,8BAA8B,CAC1C,OAAQ,EAAM,UACd,WAAY,EAAM,MAClB,UACA,QACA,aAAc,4BACd,aAAc,EAAO,KACrB,YACA,WACF,CAAC,EAEK,EAAY,EAAM,SAAS,mBAC3B,EAAa,6BAA6B,CAAM,EAChD,EAAoB,+BAA+B,EAAM,SAAS,iBAAiB,EACnF,EAAqB,+BAA+B,EAAO,iBAAiB,EAEhF,GACA,sBAAsB,EAAM,UAAW,EAAY,MAAM,GACzD,IAAc,GACd,mBAAmB,EAAmB,CAAkB,EAGxD,EAAU,UAAU,KAAK,CAAE,KAAM,EAAO,IAAK,CAAC,EACrC,IAAc,EAMvB,EAAU,QAAQ,KAAK,CAAE,KAAM,EAAO,KAAM,cAAa,SAAQ,aAAY,CAAC,EAF9E,EAAU,SAAS,KAAK,CAAE,KAAM,EAAO,KAAM,cAAa,SAAQ,aAAY,CAAC,EAIjF,OAAO,EAAS,EAAO,KACzB,MACE,EAAU,QAAQ,KAAK,CAAE,KAAM,EAAO,KAAM,cAAa,SAAQ,aAAY,CAAC,CAElF,CAEA,IAAK,GAAM,CAAC,EAAM,KAAc,OAAO,QAAQ,CAAQ,EAChD,GACS,4BAA4B,CACxC,OAAQ,EAAU,UAClB,WAAY,EAAU,MACtB,UACA,QACA,gBACF,CACQ,GACN,EAAU,QAAQ,KAAK,CAAE,OAAM,aAAY,CAAC,EAIhD,MAAO,CAAE,YAAW,YAAW,YAAW,gBAAe,CAC3D,CASA,eAAsB,wCACpB,EACA,EACA,EAAyD,gBAC1C,CACf,GAAM,CAAE,aAAc,EAClB,IAAU,gBACZ,MAAM,QAAQ,IAAI,CAIhB,GAAG,EAAU,SAAS,IAAI,KAAO,IAAY,CAC3C,MAAM,EAAO,yCAAyC,CACpD,YAAa,EAAQ,YACrB,oBAAqB,EAAQ,IAC/B,CAAC,EACD,MAAM,EAAO,yCAAyC,CACpD,YAAa,EAAQ,YACrB,oBAAqB,EAAQ,OAAO,KACpC,mBAAoB,6BAA6B,EAAQ,MAAM,EAC/D,kBAAmB,wBAAwB,EAAQ,OAAO,iBAAiB,CAC7E,CAAC,EACD,MAAM,oBAAoB,EAAQ,EAAQ,WAAW,CACvD,CAAC,EACD,GAAG,EAAU,QAAQ,IAAI,KAAO,IAAW,CACzC,MAAM,EAAO,yCAAyC,CACpD,YAAa,EAAO,YACpB,oBAAqB,EAAO,OAAO,KACnC,mBAAoB,6BAA6B,EAAO,MAAM,EAC9D,kBAAmB,wBAAwB,EAAO,OAAO,iBAAiB,CAC5E,CAAC,EACD,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,EACD,GAAG,EAAU,QAAQ,IAAI,KAAO,IAAW,CACzC,MAAM,EAAO,yCAAyC,CACpD,YAAa,EAAO,YACpB,oBAAqB,EAAO,OAAO,KACnC,kBAAmB,wBAAwB,EAAO,OAAO,iBAAiB,CAC5E,CAAC,EACD,MAAM,oBAAoB,EAAQ,EAAO,WAAW,CACtD,CAAC,CACH,CAAC,EAED,MAAM,QAAQ,IACZ,EAAU,QAAQ,IAAK,GACrB,EAAO,yCAAyC,CAC9C,YAAa,EAAI,YACjB,oBAAqB,EAAI,IAC3B,CAAC,CACH,CACF,CAEJ,CClQA,SAAgB,sBAAsB,EAA4C,CAChF,GAAM,CAAE,YAAa,EAAc,GAAG,GAAY,EAClD,OAAO,CACT,CAQA,eAAsB,qBACpB,EACA,EACA,EACe,CACf,IAAM,kBAAoB,KACxB,IACkB,CAClB,IAAK,IAAM,KAAc,EACvB,MAAM,EAAM,CAAU,CAE1B,EAEM,MACJ,EACA,IACkB,EAAS,MAAY,kBAAkB,CAAK,CAAC,EAEjE,MAAM,EAAS,kBAAmB,SAAY,CAC5C,MAAM,kBAAmB,GAAM,kBAAkB,EAAQ,EAAE,QAAQ,CAAC,CACtE,CAAC,EAED,MAAM,uBAAuB,EAAQ,KAAO,IAAgB,CAC1D,MAAM,EAAS,6BAA8B,SAAY,CACvD,MAAM,KAAK,mCAAqC,GAC9C,mBAAmB,EAAa,EAAE,cAAe,gBAAiB,EAAE,WAAW,CACjF,EACA,MAAM,KAAK,sCAAwC,GACjD,sBAAsB,EAAa,EAAa,EAAE,iBAAkB,eAAe,CACrF,EACA,MAAM,KAAK,mCAAqC,GAC9C,mBAAmB,EAAa,EAAE,cAAe,eAAe,CAClE,EACA,MAAM,KAAK,+BAAiC,GAC1C,eAAe,EAAa,EAAE,UAAW,eAAe,CAC1D,EACA,MAAM,KAAK,yBAA2B,GAAM,SAAS,EAAa,EAAE,IAAK,eAAe,CAAC,EACzF,MAAM,KAAK,uCAAyC,GAClD,UAAU,EAAa,EAAE,KAAM,6BAA6B,CAC9D,EACA,MAAM,KAAK,8BAAgC,GACzC,cAAc,EAAa,EAAE,SAAU,eAAe,CACxD,EACA,MAAM,KAAK,oCAAsC,GAC/C,UAAU,EAAa,EAAE,KAAM,0BAA0B,CAC3D,EACA,MAAM,KAAK,8BAAgC,GACzC,cAAc,EAAa,EAAE,SAAU,eAAe,CACxD,CACF,CAAC,EAED,MAAM,EAAS,gCAAiC,SAAY,CAC1D,MAAM,kBAAmB,GAAM,cAAc,EAAa,EAAE,SAAU,kBAAkB,CAAC,EACzF,MAAM,kBAAmB,GAAM,UAAU,EAAa,EAAE,KAAM,kBAAkB,CAAC,EACjF,MAAM,kBAAmB,GAAM,SAAS,EAAa,EAAE,IAAK,kBAAkB,CAAC,CACjF,CAAC,EAED,MAAM,EAAS,gCAAiC,SAAY,CAC1D,MAAM,kBAAmB,GAAM,iBAAiB,EAAa,EAAE,IAAK,eAAe,CAAC,CACtF,CAAC,EAED,MAAM,EAAS,sCAAuC,SAAY,CAChE,MAAM,KAAK,8BAAgC,GACzC,cAAc,EAAa,EAAE,SAAU,eAAe,CACxD,EAGA,MAAM,KAAK,6CAA+C,GACxD,wCACE,EACA,EAAE,wBACF,eACF,CACF,EACA,MAAM,KAAK,8BAAgC,GACzC,cAAc,EAAa,EAAE,SAAU,eAAe,CACxD,CACF,CAAC,CACH,CAAC,EAED,MAAM,EAAS,gCAAiC,SAAY,CAC1D,MAAM,kBAAmB,GAAM,cAAc,EAAQ,EAAE,SAAU,QAAQ,CAAC,EAC1E,MAAM,kBAAmB,GACvB,wCAAwC,EAAQ,EAAE,wBAAyB,QAAQ,CACrF,EACA,MAAM,kBAAmB,GAAM,cAAc,EAAQ,EAAE,SAAU,QAAQ,CAAC,EAC1E,MAAM,kBAAmB,GAAM,mBAAmB,EAAQ,EAAE,cAAe,QAAQ,CAAC,EACpF,MAAM,kBAAmB,GAAM,eAAe,EAAQ,EAAE,UAAW,QAAQ,CAAC,EAC5E,MAAM,kBAAmB,GACvB,mBAAmB,EAAQ,EAAE,cAAe,SAAU,EAAE,WAAW,CACrE,CACF,CAAC,EAED,MAAM,EAAS,0BAA2B,SAAY,CACpD,MAAM,kBAAmB,GAAM,iBAAiB,EAAQ,EAAE,IAAK,QAAQ,CAAC,CAC1E,CAAC,EAED,MAAM,EAAS,+BAAgC,SAAY,CACzD,MAAM,kBAAmB,GAAM,cAAc,EAAQ,EAAE,SAAU,iBAAiB,CAAC,EACnF,MAAM,kBAAmB,GAAM,UAAU,EAAQ,EAAE,KAAM,iBAAiB,CAAC,EAC3E,MAAM,kBAAmB,GAAM,SAAS,EAAQ,EAAE,IAAK,iBAAiB,CAAC,EACzE,MAAM,kBAAmB,GAAM,cAAc,EAAQ,EAAE,SAAU,iBAAiB,CAAC,CACrF,CAAC,EAED,MAAM,EAAS,gBAAiB,SAAY,CAC1C,MAAM,kBAAmB,GACvB,sBAAsB,EAAQ,EAAa,EAAE,iBAAkB,QAAQ,CACzE,CACF,CAAC,CACH,CC7JA,SAAS,iBACP,EACA,EACA,EACA,EACM,CACN,GAAI,EAAO,IAAI,CAAI,EACjB,MAAM,EAAS,CACb,KAAM,iCACN,QAAS,aAAa,EAAK,gBAAgB,EAAK,uBAClD,CAAC,EAEH,EAAO,IAAI,EAAM,CAAI,CACvB,CAEA,SAAS,kBACP,EACA,EACA,EACM,CACN,IAAK,GAAM,CAAC,EAAM,KAAS,EACzB,iBAAiB,EAAQ,EAAM,EAAM,CAAI,CAE7C,CASA,SAAgB,oBACd,EACyC,CACzC,IAAM,EAA0D,CAC9D,UAAW,IAAI,IACf,UAAW,IAAI,IACf,aAAc,IAAI,IAClB,UAAW,IAAI,GACjB,EAEA,IAAK,IAAM,KAAU,EACnB,kBAAkB,EAAe,UAAW,EAAO,eAAe,UAAW,UAAU,EACvF,kBAAkB,EAAe,UAAW,EAAO,eAAe,UAAW,UAAU,EACvF,kBACE,EAAe,aACf,EAAO,eAAe,aACtB,cACF,EACA,kBAAkB,EAAe,UAAW,EAAO,eAAe,UAAW,WAAW,EAG1F,OAAO,CACT,CCvCA,eAAsB,kCACpB,EACA,EACe,CACX,KAAQ,SAAW,EAEvB,GAAO,KACL,2FACF,EACA,IAAK,IAAM,KAAU,EAAQ,UAAU,EAAG,IAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC,EACpF,EAAO,IAAI,KAAK,EAAO,UAAU,EAAE,EACnC,EAAO,IACL,mBAAmB,sBAAsB,EAAO,IAAI,EAAE,KAAK,sBAAsB,EAAO,EAAE,GAC5F,EACA,EAAO,IACL,6BAA6B,EAAO,eAAiB,UAAU,KAAK,EAAO,aAC7E,EAEF,KAAO,IAAI,sDAAsD,EACjE,EAAO,IAAI,gFAAgF,EAEvF,IAMA,CAAC,MALmB,EAAO,QAAQ,CACrC,QACE,gGACF,QAAS,EACX,CAAC,EAEC,MAAM,EAAS,CACb,KAAM,mBACN,QAAS,gEACX,CAAC,CAvBH,CAyBF,CAeA,eAAsB,qBACpB,EACA,EACA,EACA,EACe,CACf,GAAI,EAAU,SAAW,EAAG,OAI5B,IAAM,EAAe,EAAU,OAAQ,GAAM,EAAE,eAAiB,CAAO,EACjE,EAAiB,EAAU,OAAQ,GAAM,EAAE,eAAiB,CAAO,EAErE,EAAa,OAAS,GACxB,MAAO,EACH,sBAAsB,EAAc,EAAS,CAAG,EAChD,uBAAuB,EAAc,EAAS,CAAG,GAEnD,EAAe,OAAS,GAC1B,MAAM,oBAAoB,EAAgB,EAAS,CAAG,CAE1D,CAEA,eAAe,sBACb,EACA,EACA,EACe,CAGf,GAFA,cAAc,uCAAuC,EAAQ,IAAK,CAAS,EAEvE,EAAK,CACP,EAAO,QAAQ,iEAAkE,CAC/E,KAAM,OACR,CAAC,EACD,MACF,CAMA,GAAI,CAAC,MAJmB,EAAO,QAAQ,CACrC,QAAS,+CAA+C,EAAQ,MAAM,EAAO,IAAI,yGAAyG,IAC1L,QAAS,EACX,CAAC,EAEC,MAAM,EAAS,CACb,KAAM,mBACN,QAAS,CAAE;;;KAIb,CAAC,CAEL,CAEA,SAAS,cAAc,EAAiB,EAAkC,CACxE,EAAO,KAAK,CAAO,EACnB,EAAO,IAAI,iEAAiE,EAC5E,EAAO,QAAQ,EACf,EAAO,IAAI,KAAK,EAAO,KAAK,WAAW,EAAE,EAAE,EAC3C,IAAK,IAAM,KAAK,EACd,EAAO,IAAI,SAAS,EAAO,KAAK,EAAE,YAAY,EAAE,GAAG,EAAO,KAAK,IAAI,EAAE,aAAa,EAAE,GAAG,CAE3F,CAEA,eAAe,uBACb,EACA,EACA,EACe,CAGf,GAFA,cAAc,mCAAmC,EAAQ,IAAK,CAAS,EAEnE,EAAK,CACP,EAAO,QAAQ,6DAA8D,CAAE,KAAM,OAAQ,CAAC,EAC9F,MACF,CAMA,GAAI,CAAC,MAJmB,EAAO,QAAQ,CACrC,QAAS,wDAAwD,EAAQ,MAAM,EAAO,IAAI,wFAAwF,IAClL,QAAS,EACX,CAAC,EAEC,MAAM,EAAS,CACb,KAAM,mBACN,QAAS,CAAE;;;KAIb,CAAC,CAEL,CAEA,eAAe,oBACb,EACA,EACA,EACe,CACf,IAAM,EAAgB,CAAC,GAAG,IAAI,IAAI,EAAU,IAAK,GAAM,EAAE,YAAY,CAAC,CAAC,EAEvE,EAAO,KAAK,qCAAqC,EAEjD,EAAO,IACL,KAAK,EAAO,QAAQ,wBAAwB,EAAE,IAAI,EAAc,IAAK,GAAM,EAAO,KAAK,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,GAC7G,EACA,EAAO,IAAI,KAAK,EAAO,QAAQ,iBAAiB,EAAE,WAAW,EAAO,KAAK,IAAI,EAAQ,EAAE,GAAG,EAC1F,EAAO,QAAQ,EACf,EAAO,IAAI,KAAK,EAAO,KAAK,WAAW,EAAE,EAAE,EAC3C,IAAK,IAAM,KAAK,EACd,EAAO,IAAI,SAAS,EAAO,KAAK,EAAE,YAAY,EAAE,GAAG,EAAO,KAAK,IAAI,EAAE,aAAa,EAAE,GAAG,EAGzF,GAAI,EAAK,CACP,EAAO,QAAQ,+CAAgD,CAC7D,KAAM,OACR,CAAC,EACD,MACF,CAEA,IAAM,EACJ,EAAc,SAAW,EACrB,4CAA4C,EAAQ,MAAM,EAAO,IAAI,yCAAyC,IAC9G,4CAA4C,EAAQ,IAK1D,GAAI,CAAC,MAJmB,EAAO,QAAQ,CACrC,QAAS,EACT,QAAS,EACX,CAAC,EAEC,MAAM,EAAS,CACb,KAAM,mBACN,QAAS,CAAE;;;KAIb,CAAC,CAEL,CASA,eAAsB,0BACpB,EACA,EACA,EACe,CACX,KAAU,SAAW,EAIzB,CAFA,EAAO,KAAK,sDAAsD,EAElE,EAAO,IAAI,KAAK,EAAO,KAAK,WAAW,EAAE,EAAE,EAC3C,IAAK,IAAM,KAAK,EACd,EAAO,IAAI,SAAS,EAAO,KAAK,EAAE,YAAY,EAAE,GAAG,EAAO,KAAK,IAAI,EAAE,aAAa,EAAE,GAAG,EASzF,GAPA,EAAO,QAAQ,EACf,EAAO,IAAI,mFAAmF,EAC9F,EAAO,IAAI,wDAAwD,EACnE,EAAO,IACL,gGACF,EAEI,EAAK,CACP,EAAO,QAAQ,cAAc,EAAQ,6BAA8B,CACjE,KAAM,OACR,CAAC,EACD,MACF,CAMA,GAAI,CAAC,MAJmB,EAAO,QAAQ,CACrC,QAAS,+CAA+C,EAAQ,IAChE,QAAS,EACX,CAAC,EAEC,MAAM,EAAS,CACb,KAAM,mBACN,QAAS,CAAE;;;KAIb,CAAC,CA7BwC,CA+B7C,CAaA,eAAsB,iCACpB,EACA,EACe,CACX,KAAU,SAAW,EAIzB,CAFA,EAAO,KAAK,0CAA0C,EAEtD,EAAO,IAAI,KAAK,EAAO,KAAK,WAAW,EAAE,EAAE,EAC3C,IAAK,IAAM,KAAK,EACd,EAAO,IAAI,SAAS,EAAO,KAAK,EAAE,YAAY,EAAE,GAAG,EAAO,MAAM,IAAI,EAAE,aAAa,EAAE,GAAG,EAO1F,GALA,EAAO,QAAQ,EACf,EAAO,IACL,EAAO,QAAQ,yEAAyE,CAC1F,EAEI,EAAK,CACP,EAAO,QAAQ,+CAAgD,CAC7D,KAAM,OACR,CAAC,EACD,MACF,CAMA,GAAI,CAAC,MAJmB,EAAO,QAAQ,CACrC,QAAS,mDACT,QAAS,EACX,CAAC,EAEC,MAAM,EAAS,CACb,KAAM,mBACN,QAAS,CAAE;;;KAIb,CAAC,CA3BwC,CA6B7C,CA0BA,eAAsB,4BACpB,EACA,EACe,CACX,KAAQ,SAAW,EAEvB,GAAO,KAAK,gEAAgE,EAC5E,IAAK,IAAM,KAAS,EAClB,EAAO,IACL,wBAAwB,EAAO,KAAK,EAAM,KAAK,EAAE,cAAc,EAAO,KAAK,EAAM,QAAQ,EAAE,IAAI,EAAM,OAAO,EAC9G,EAQF,GANA,EAAO,QAAQ,EACf,EAAO,IAAI,4EAA4E,EACvF,EAAO,IAAI,8EAA8E,EACzF,EAAO,IAAI,sEAAsE,EACjF,EAAO,IAAI,wBAAwB,EAE/B,EAAK,CACP,EAAO,KAAK,gFAAgF,EAC5F,MACF,CAMA,GAAI,CAAC,MAJmB,EAAO,QAAQ,CACrC,QAAS,yBACT,QAAS,EACX,CAAC,EAEC,MAAM,EAAS,CACb,KAAM,mBACN,QAAS,CAAE;;;KAIb,CAAC,CA5ByE,CA8B9E,CChUA,SAAS,oBACP,EACA,EACA,EACA,EACsB,CACtB,IAAM,EAAkC,CAAC,EAEzC,IAAK,IAAM,KAAW,EAAY,iBAChC,IAAK,GAAM,CAAC,EAAW,KAAS,OAAO,QAAQ,EAAQ,KAAK,EACtD,EAAK,SAAS,gBAAkB,IAAA,IAClC,EAAU,KAAK,CACb,IAAK,gBAAgB,EAAa,EAAQ,UAAW,CAAS,EAC9D,IAAK,EAAe,aAAa,EAAQ,UAAW,CAAS,EAC7D,MAAO,WACP,MAAO,GAAiB,aAAa,CAAS,CAChD,CAAC,EAKP,IAAK,IAAM,KAAW,EAAY,iBAChC,IAAK,IAAM,KAAY,OAAO,OAAO,EAAQ,SAAS,EAChD,EAAS,gBAAkB,IAAA,IAC7B,EAAU,KAAK,CACb,IAAK,YAAY,EAAa,EAAQ,UAAW,EAAS,IAAI,EAC9D,IAAK,EAAe,SAAS,EAAQ,UAAW,EAAS,IAAI,EAC7D,MAAO,WACP,MAAO,GAAiB,SAAS,EAAS,IAAI,CAChD,CAAC,EAKP,IAAK,IAAM,KAAO,EAAY,YACxB,EAAI,gBAAkB,IAAA,IACxB,EAAU,KAAK,CACb,IAAK,YAAY,EAAa,MAAO,EAAI,IAAI,EAC7C,IAAK,EAAe,IAAI,EAAI,IAAI,EAChC,MAAO,WACP,MAAO,GAAiB,WAAW,EAAI,IAAI,CAC7C,CAAC,EAOL,IAAM,EAAgB,IAAI,KACvB,EAAY,iBAAiB,MAAQ,CAAC,EAAA,CAAG,IAAK,GAAQ,CAAC,EAAI,KAAM,EAAI,aAAa,CAAC,CACtF,EACM,EAAqB,2BAA2B,CACpD,UAAW,OAAO,OAAO,EAAY,iBAAiB,WAAa,CAAC,CAAC,EACrE,YAAa,EACb,aAAe,GAAiB,EAAe,IAAI,EAAe,aAAa,CAAY,CAAC,CAC9F,CAAC,EACD,IAAK,IAAM,KAAY,OAAO,OAAO,EAAY,iBAAiB,WAAa,CAAC,CAAC,EAAG,CAClF,IAAM,EAAM,YAAY,EAAa,WAAY,EAAS,IAAI,EAC1D,EAAS,gBAAkB,IAAA,IAC7B,EAAU,KAAK,CACb,MACA,IAAK,EAAe,SAAS,EAAS,IAAI,EAC1C,MAAO,WACP,MAAO,GAAiB,SAAS,EAAS,IAAI,CAChD,CAAC,GAKc,EAAe,EAAS,QAAQ,OAAS,CAAC,EAAA,CAEhD,KACN,GAAY,EAAc,IAAI,CAAO,IAAM,IAAA,IAAa,CAAC,EAAmB,IAAI,CAAO,CAC1F,GAEA,EAAU,KAAK,CACb,MACA,IAAK,EAAe,aAAa,EAAS,IAAI,EAC9C,MAAO,OACP,MAAO,GAAiB,aAAa,EAAS,IAAI,CACpD,CAAC,CAEL,CAEA,OAAO,CACT,CAsBA,eAAsB,0BAA0B,EAOb,CACjC,GAAM,CAAE,SAAQ,cAAa,cAAa,YAAW,iBAAgB,kBAAmB,EAexF,OAAO,MAda,QAAQ,IAC1B,oBAAoB,EAAa,EAAa,EAAgB,CAAc,CAAC,CAC1E,QAAQ,CAAE,SAAU,CAAC,EAAe,IAAI,CAAG,CAAC,CAAC,CAC7C,IAAI,MAAO,CAAE,MAAK,QAAO,WAEjB,sBAAqB,MADL,MAAgB,EAAO,YAAY,CAAE,KAAI,CAAC,CAAC,EACtC,EAAU,UAAU,OAAQ,CAAK,CAAC,CAC3D,OAAQ,GAAe,CAAC,EAAU,IAAI,EAAW,KAAK,CAAC,CAAC,CACxD,IAAK,IAAgB,CACpB,SAAU,EACV,MAAO,EAAW,MAClB,OAAQ,EAAW,MACrB,EAAE,CACL,CACL,EAAA,CACa,KAAK,CACpB,CCvKA,MAAM,GAAwB,EAAE,OAAO,CACrC,WAAY,EAAE,OAAO,EACrB,YAAa,EAAE,OAAO,CACxB,CAAC,EAGK,GAAmB,EAAE,OAAO,CAChC,KAAM,EAAE,QAAQ,QAAQ,EACxB,UAAW,EAAE,OAAO,EACpB,gBAAiB,EAAE,MAAM,EAAE,OAAO,CAAC,EACnC,YAAa,EAAE,MAAM,EAAqB,EAC1C,UAAW,EAAE,OAAO,CACtB,CAAC,EAGK,GAAsB,EAAE,OAAO,CACnC,QAAS,EAAE,QAAQ,CAAC,EACpB,WAAY,EAAE,OAAO,EACrB,aAAc,EAAE,OAAO,CAAC,CAAC,SAAS,EAClC,QAAS,EAAE,OAAO,EAAE,OAAO,EAAG,EAAgB,CAChD,CAAC,ECeD,SAAS,iBAAiB,EAAiC,CAEzD,IAAI,EAAmD,KAEvD,SAAS,cAAuB,CAC9B,OAAO,EAAK,KAAK,EAAO,SAAU,eAAiB,CACrD,CAEA,SAAS,YAAqB,CAC5B,OAAO,EAAK,KAAK,EAAO,SAAU,SAAW,CAC/C,CAEA,SAAS,WAAW,EAA0B,CAC5C,OAAO,EAAK,KAAK,WAAW,EAAG,GAAG,GAAY,CAAQ,EAAE,IAAI,CAC9D,CAEA,SAAS,cAA0C,CACjD,GAAI,CACF,IAAM,EAAMC,EAAG,aAAa,aAAa,EAAG,OAAO,EAC7C,EAAS,GAAoB,UAAU,KAAK,MAAM,CAAG,CAAC,EAE5D,GAAI,CAAC,EAAO,QAAS,CACnB,EAAiB,IAAA,GACjB,MACF,CAGA,MADA,GAAiB,EAAO,KACjB,CACT,MAAQ,CAEN,EAAiB,IAAA,GACjB,MACF,CACF,CAEA,SAAS,oBAAgD,CAIvD,OAHI,IAAmB,MACrB,aAAa,EAER,GAAkB,IAAA,EAC3B,CAEA,SAAS,sBAAsC,CAW7C,OAVI,IAAmB,MACrB,aAAa,EAEf,AACE,IAAiB,CACf,QAAS,EACT,WAAY,GACZ,QAAS,CAAC,CACZ,EAEK,CACT,CAEA,SAAS,aAAa,EAA+B,CACnD,EAAG,UAAU,EAAO,SAAU,CAAE,UAAW,EAAK,CAAC,EAEjD,IAAM,EAAS,aAAa,EACtB,EAAU,EAAK,KAAK,EAAO,SAAU,aAAa,QAAQ,IAAI,KAAK,EAGzE,GAAI,CACF,EAAG,cAAc,EAAS,KAAK,UAAU,EAAU,KAAM,CAAC,EAAG,OAAO,EACpE,EAAG,WAAW,EAAS,CAAM,CAC/B,OAAS,EAAG,CACV,GAAI,CACF,EAAG,OAAO,EAAS,CAAE,MAAO,EAAK,CAAC,CACpC,MAAQ,CAER,CACA,MAAM,CACR,CAEA,EAAiB,CACnB,CAEA,SAAS,SAAS,EAAqC,CAErD,OADiB,qBACH,CAAC,CAAC,QAAQ,EAC1B,CAEA,SAAS,SAAS,EAAa,EAAyB,CACtD,IAAM,EAAW,qBAAqB,EACtC,EAAS,QAAQ,GAAO,CAC1B,CAEA,SAAS,YAAY,EAAmB,CACtC,IAAM,EAAW,qBAAqB,EAEtC,OAAO,EAAS,QAAQ,EAC1B,CAEA,SAAS,mBAAmB,EAAkB,EAAuB,CACnE,IAAM,EAAM,WAAW,EACvB,EAAG,UAAU,EAAK,CAAE,UAAW,EAAK,CAAC,EACrC,EAAG,cAAc,WAAW,CAAQ,EAAG,EAAS,OAAO,CACzD,CAEA,SAAS,qBAAqB,EAAsC,CAClE,GAAI,CACF,OAAOA,EAAG,aAAa,WAAW,CAAQ,EAAG,OAAO,CACtD,OAAS,EAAG,CACV,GAAK,EAA4B,OAAS,SAAU,OACpD,MAAM,CACR,CACF,CAEA,SAAS,OAAc,CACrB,EAAG,OAAO,EAAO,SAAU,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,EAC3D,EAAiB,IACnB,CAEA,MAAO,CACL,aACA,mBACA,aACA,SACA,SACA,YACA,mBACA,qBACA,KACF,CACF,CChIA,SAAS,mBAAmB,EAA4C,CAGtE,GAAI,EAFY,EAAQ,SAAW,IAGjC,MAAO,CACL,QAAS,GACT,YAAa,CACX,YAAa,CAEb,EACA,MAAO,CAEP,CACF,EACA,UAAW,CAEX,CACF,EAKF,IAAM,EAAQ,iBAAiB,CAAE,SAFhB,EAAQ,UAAY,EAAK,QAAQ,GAAW,EAAG,OAAO,CAE7B,CAAC,EAGrC,EAAmB,EAAM,aAAa,EAe5C,OAdI,IACE,EAAiB,aAAe,EAAQ,WAKjC,EAAiB,eAAiB,EAAQ,eACnD,EAAO,MAAM,qCAAqC,EAClD,EAAM,MAAM,IANZ,EAAO,MACL,+CAA+C,EAAiB,WAAW,MAAM,EAAQ,YAC3F,EACA,EAAM,MAAM,IAST,CACL,QAAS,GACT,YAJkB,GAAkB,CAI1B,EACV,UAAW,CACT,IAAM,EAAkB,EAAM,mBAAmB,GAAK,CACpD,QAAS,EACT,WAAY,EAAQ,WACpB,aAAc,EAAQ,aACtB,QAAS,CAAC,CACZ,EACM,EAAiB,EAAM,aAAa,EACpC,EACJ,GAAgB,aAAe,EAAQ,YACvC,EAAe,eAAiB,EAAQ,aACpC,CACE,GAAG,EACH,QAAS,CACP,GAAG,EAAe,QAClB,GAAG,EAAgB,OACrB,CACF,EACA,EACN,EAAS,WAAa,EAAQ,WAC9B,EAAS,aAAe,EAAQ,aAChC,EAAM,aAAa,CAAQ,CAC7B,CACF,CACF,CC1DA,SAAgB,4BAA4B,EAAwC,CAClF,OAAO,4BAA4B,CAAM,CAC3C,CAIA,MAAM,kBAAqB,GAAuB,6BAA6B,KAAK,CAAC,EAcrF,SAAgB,uBACd,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACQ,CAIR,IAAM,EAAkB,EACpB,OAAO,QAAQ,CAAU,CAAC,CACvB,KAAK,CAAC,EAAK,CAAE,OAAM,eAAgB,OAAO,IAAM,EAAW,IAAM,GAAG,IAAI,EAAK,EAAE,CAAC,CAChF,KAAK;CAAI,EACZ,GAEE,EACJ,CAAC,GAAc,OAAO,KAAK,CAAU,CAAC,CAAC,SAAW,EAC9C,KACA;EACN,EAAgB;KAOV,EAAW;gBAHA,EAAgB,IAAI,EAAc,QAAU,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,GAAK,KAIhE;KAMjB,EAAY,EACd,OAAO,QAAQ,CAAG,CAAC,CAChB,KACE,CAAC,EAAK,KACL,OAAO,kBAAkB,CAAG,EAAI,EAAM,KAAK,UAAU,CAAG,EAAE,IAAI,OAAO,EAAM,EAC/E,CAAC,CACA,KAAK;CAAI,EACZ,GAEE,EACJ,CAAC,GAAO,OAAO,KAAK,CAAG,CAAC,CAAC,SAAW,EAChC,KACA;EACN,EAAU;KAIJ,EAAoB,GAAkB,OACxC,EACG,IAAK,GAAS,OAAO,kBAAkB,CAAI,EAAI,EAAO,KAAK,UAAU,CAAI,EAAE,QAAQ,CAAC,CACpF,KAAK;CAAI,EACZ,GAEE,EACJ,CAAC,GAAoB,EAAiB,SAAW,EAC7C,KACA;EACN,EAAkB;KAIZ,EAAgB,GAAU,OAC5B,EACG,IAAK,GAAS,OAAO,kBAAkB,CAAI,EAAI,EAAO,KAAK,UAAU,CAAI,EAAE,QAAQ,CAAC,CACpF,KAAK;CAAI,EACZ,GAEE,EACJ,CAAC,GAAY,EAAS,SAAW,EAC7B,KACA;EACN,EAAc;KAIR,EAAuB,GAAiB,OAC1C,EACG,IAAK,GAAS,OAAO,kBAAkB,CAAI,EAAI,EAAO,KAAK,UAAU,CAAI,EAAE,QAAQ,CAAC,CACpF,KAAK;CAAI,EACZ,GAEE,EACJ,CAAC,GAAmB,EAAgB,SAAW,EAC3C,KACA;EACN,EAAqB;KAIf,EAAsB,GAAgB,OACxC,EACG,IAAK,GAAS,OAAO,kBAAkB,CAAI,EAAI,EAAO,KAAK,UAAU,CAAI,EAAE,QAAQ,CAAC,CACpF,KAAK;CAAI,EACZ,GAEE,EACJ,CAAC,GAAkB,EAAe,SAAW,EACzC,KACA;EACN,EAAoB;KAId,EAA0B,GAAoB,OAChD,EACG,IAAK,GAAS,OAAO,kBAAkB,CAAI,EAAI,EAAO,KAAK,UAAU,CAAI,EAAE,QAAQ,CAAC,CACpF,KAAK;CAAI,EACZ,GAEE,EACJ,CAAC,GAAsB,EAAmB,SAAW,EACjD,KACA;EACN,EAAwB;KAGxB,MAAO,EAAY;;;;;;yBAMI,EAAe;4BACZ,EAAS;kBACnB,EAAQ;sCACY,EAAgB;8BACxB,EAAY;qCACL,EAAmB;oCACpB,EAAkB;wCACd,EAAsB;;;;;CAM9D,CAEA,SAAS,4BAA4B,EAAwC,CAG3E,IAAM,EAAW,EAAO,KAAK,OAAS,CAAC,GAAG,IAAI,IAAI,EAAO,IAAI,IAAK,GAAQ,EAAI,IAAI,CAAC,CAAC,EAAI,IAAA,GAGlF,EAAiB,EAAO,YAAY,OACtC,CAAC,GAAG,IAAI,IAAI,EAAO,WAAW,IAAK,GAAY,EAAQ,IAAI,CAAC,CAAC,EAC7D,IAAA,GAEE,EAAO,EAAO,KAGd,EACJ,GAAQ,OAAO,GAAS,UAAY,OAAO,EAAK,MAAS,SAAW,CAAC,EAAK,IAAI,EAAI,IAAA,GAEpF,GAAI,CAAC,GAAQ,OAAO,GAAS,SAC3B,MAAO,CAAE,WAAU,iBAAgB,oBAAmB,EAIxD,IAAM,EAAmB,EAAoD,aACvE,EACJ,GAAmB,OAAO,GAAoB,SAC1C,OAAO,KAAK,CAAe,EAC3B,IAAA,GAGA,EAAkB,EAAmD,YACrE,EACJ,GAAkB,OAAO,GAAmB,SAAW,OAAO,KAAK,CAAc,EAAI,IAAA,GAEjF,mBAAsB,GAAkD,CAC5E,IAAM,EAAO,GAAO,KACd,EAAW,GAAO,SAGxB,GAAI,CAAC,EACH,MAAO,CAAE,KAAM,QAAS,EAG1B,IAAI,EAAU,SAcd,OAZI,IAAS,UACX,EAAU,UACD,IAAS,QAAU,EAAS,gBAErC,EAAU,EAAS,cAAc,IAAK,GAAM,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,KAAK,GAIpE,EAAS,QACX,EAAU,EAAQ,SAAS,KAAK,EAAI,IAAI,EAAQ,KAAO,GAAG,EAAQ,KAG7D,CAAE,KAAM,EAAS,SAAU,EAAS,WAAa,EAAM,CAChE,EAGA,GAAI,gBAAiB,EAAM,CACzB,IAAM,EACJ,EASA,YAEI,EAAqB,GAAa,WAClC,EAAS,GAAa,MAAM,OAC5B,EAAgB,GAAa,cAUnC,MAAO,CACL,WAR+C,EAC7C,OAAO,KAAK,CAAkB,CAAC,CAAC,QAAQ,EAAK,KAC3C,EAAI,GAAO,mBAAmB,IAAS,EAAI,EACpC,GACN,CAAC,CAAqB,EACzB,IAAA,GAIF,gBACA,mBACA,WACA,kBACA,iBACA,oBACF,CACF,CAEA,GAAI,0BAA2B,EAAM,CACnC,IAAM,EACJ,EAGA,sBAWF,OATK,EASE,CACL,WANiB,OAAO,QAAQ,CAAqB,CAAC,CAAC,QAAQ,EAAK,CAAC,EAAK,MAC1E,EAAI,GAAO,mBAAmB,CAAK,EAC5B,GACN,CAAC,CAGO,EACT,mBACA,WACA,kBACA,iBACA,oBACF,EAfS,CAAE,mBAAkB,WAAU,kBAAiB,iBAAgB,oBAAmB,CAgB7F,CAEA,MAAO,CAAE,mBAAkB,WAAU,kBAAiB,iBAAgB,oBAAmB,CAC3F,CAWA,SAAgB,0BAA0B,EAA4B,CACpE,IAAM,EAAU,QAAQ,IAAI,gBAI5B,OAHI,EACK,EAAK,QAAQ,CAAO,EAEtB,EAAK,KAAK,EAAK,QAAQ,EAAK,QAAQ,CAAU,CAAC,EAAG,aAAa,CACxE,CAiBA,eAAsB,kBAAkB,EAAkD,CACxF,GAAM,CAAE,SAAQ,cAAe,EAC/B,GAAI,CACF,GAAM,CACJ,aACA,gBACA,mBACA,WACA,kBACA,iBACA,sBACE,4BAA4B,CAAM,EAClC,CAAC,GAAc,CAAC,GAClB,EAAO,KAAK,uCAAwC,CAAE,KAAM,OAAQ,CAAC,EAGnE,GACF,EAAO,MAAM,yBAAyB,KAAK,UAAU,CAAU,GAAG,EAEhE,GACF,EAAO,MAAM,4BAA4B,KAAK,UAAU,CAAa,GAAG,EAEtE,GAAkB,QACpB,EAAO,MAAM,+BAA+B,KAAK,UAAU,CAAgB,GAAG,EAE5E,GAAU,QACZ,EAAO,MAAM,uBAAuB,KAAK,UAAU,CAAQ,GAAG,EAE5D,GAAiB,QACnB,EAAO,MAAM,8BAA8B,KAAK,UAAU,CAAe,GAAG,EAE1E,GAAgB,QAClB,EAAO,MAAM,6BAA6B,KAAK,UAAU,CAAc,GAAG,EAExE,GAAoB,QACtB,EAAO,MAAM,iCAAiC,KAAK,UAAU,CAAkB,GAAG,EAGpF,IAAM,EAAM,EAAO,IACf,GACF,EAAO,MAAM,kBAAkB,KAAK,UAAU,CAAG,GAAG,EAItD,IAAM,EAAiB,uBACrB,EACA,EACA,EACA,EACA,EACA,EACA,EACA,CACF,EACM,EAAa,0BAA0B,CAAU,EAGvD,EAAG,UAAU,EAAK,QAAQ,CAAU,EAAG,CAAE,UAAW,EAAK,CAAC,EAC1D,EAAG,cAAc,EAAY,CAAc,EAC3C,IAAM,EAAe,EAAK,SAAS,QAAQ,IAAI,EAAG,CAAU,EAC5D,EAAO,QAAQ,EACf,EAAO,QAAQ,+BAA+B,IAAgB,CAC5D,KAAM,OACR,CAAC,CACH,OAAS,EAAO,CACd,EAAO,MAAM,wBAAwB,EACrC,EAAO,MAAM,OAAO,CAAK,CAAC,CAE5B,CACF,CCxaA,MAAM,GAAoB,oDAiB1B,SAAgB,iBAAiB,EAAiC,CAC5D,IACJ,EAAO,KAAK,sCAAsC,EAClD,EAAO,IACL;;;;2FAKF,EACF,CAOA,MAAa,GAAY,kEAOzB,SAAS,sBAAsB,EAAe,EAAiC,CAC7E,GAAI,CAAC,GAAQ,OAAO,GAAS,SAAU,OACvC,IAAM,EAAI,EAEV,GAAI,EAAE,OAAS,iBAAkB,CAC/B,IAAM,EAAK,EACX,GAAI,EAAG,OAAO,OAAS,cAAgB,EAAG,OAAO,OAAS,eAAgB,CACxE,IAAM,EAAM,EAAG,UAAU,GAGnB,EAAY,GAAO,EAAI,OAAS,mBAAqB,EAAM,KACjE,EAAQ,KAAK,CAAE,SAAU,EAAI,WAAU,CAAC,CAC1C,CACF,CAEA,IAAK,IAAM,KAAO,OAAO,KAAK,CAAC,EAAG,CAChC,IAAM,EAAQ,EAAE,GAChB,GAAI,MAAM,QAAQ,CAAK,EACrB,IAAK,IAAM,KAAK,EAAO,sBAAsB,EAAG,CAAO,OAC9C,GAAS,OAAO,GAAU,UACnC,sBAAsB,EAAO,CAAO,CAExC,CACF,CAEA,SAAS,iBAAiB,EAAyC,CACjE,IAAM,EAA0B,CAAC,EACjC,IAAK,IAAM,KAAQ,EAAI,WACjB,EAAK,OAAS,aAEhB,EAAK,IAAI,OAAS,aACd,EAAK,IAAI,KACT,EAAK,IAAI,OAAS,UACf,EAAK,IAA4B,MAClC,QACQ,MAAM,EAAM,KAAK,CAAI,EAEvC,OAAO,CACT,CAEA,SAAS,eAAe,EAA8C,CACpE,OAAO,iBAAiB,CAAG,CAAC,CAAC,IAAM,IACrC,CAEA,SAAS,QAAQ,EAAoC,CACnD,OACG,GAAM,OAAS,cAAgB,EAAK,OAAS,MAC7C,GAAM,OAAS,WAAa,EAAK,QAAU,IAEhD,CAGA,SAAS,cAAc,EAAwB,CAC7C,GAAI,CAAC,GAAQ,OAAO,GAAS,SAAU,MAAO,GAC9C,IAAM,EAAI,EAMV,OALI,EAAE,OAAS,oBAAsB,QAAQ,EAAE,QAA+B,GAC1E,EAAE,OAAS,iBACM,EAAE,WACN,KAAM,GAAM,EAAE,OAAS,YAAc,QAAQ,EAAE,GAAc,CAAC,EAAU,GAElF,OAAO,OAAO,CAAC,CAAC,CAAC,KAAM,GAC5B,MAAM,QAAQ,CAAK,EAAI,EAAM,KAAK,aAAa,EAAI,cAAc,CAAK,CACxE,CACF,CAUA,eAAsB,eAAe,EAA0D,CAC7F,IAAM,EAAS,MAAMC,EAAG,SAAS,SAAS,EAAY,OAAO,EACvD,CAAE,WAAY,GAAU,EAAY,CAAM,EAE1C,EAA0B,CAAC,EAGjC,GAFA,sBAAsB,EAAS,CAAK,EAEhC,EAAM,SAAW,EAEnB,OAAO,KAET,GAAI,EAAM,OAAS,EACjB,MAAM,EAAS,CACb,KAAM,yBACN,QAAS,0CAA0C,EAAW,yBAChE,CAAC,EAGH,GAAM,CAAE,aAAc,EAAc,EAAM,GAAI,gCAAgC,EAC9E,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,yBACN,QAAS,+DAA+D,EAAW,uCACrF,CAAC,EAGH,IAAM,EAAS,eAAe,CAAS,EACvC,GAAI,EAAQ,CACV,IAAM,EAAQ,EAAO,MACrB,GAAI,EAAM,OAAS,UACjB,MAAM,EAAS,CACb,KAAM,oBACN,QAAS,iBAAiB,EAAW,4BACrC,WAAY,EACd,CAAC,EAEH,IAAM,EAAgB,EAA8B,MACpD,GAAI,OAAO,GAAiB,UAAY,IAAiB,GACvD,MAAM,EAAS,CACb,KAAM,oBACN,QAAS,iBAAiB,EAAW,sCACrC,WAAY,EACd,CAAC,EAEH,GAAI,CAAC,GAAU,KAAK,CAAY,EAC9B,MAAM,EAAS,CACb,KAAM,oBACN,QAAS,iBAAiB,EAAW,kBACrC,WAAY,EACd,CAAC,EAEH,MAAO,CAAE,GAAI,EAAc,SAAU,EAAM,CAC7C,CAEA,IAAM,EAAK,OAAO,WAAW,EACvB,EAAY,iBAAiB,EAAQ,EAAW,CAAE,EAKxD,OAJA,MAAMA,EAAG,SAAS,UAAU,EAAY,EAAW,OAAO,EAE1D,EAAO,KAAK,iCAAiC,EAAW,IAAI,GAAI,EAEzD,CAAE,KAAI,SAAU,EAAK,CAC9B,CAUA,eAAe,aAAa,EAA2D,CACrF,IAAM,EAAS,MAAMA,EAAG,SAAS,SAAS,EAAY,OAAO,EACvD,CAAE,WAAY,GAAU,EAAY,CAAM,EAC1C,EAA0B,CAAC,EAEjC,GADA,sBAAsB,EAAS,CAAK,EAChC,EAAM,SAAW,EAAG,OAAO,KAG/B,GAAI,EAAM,OAAS,EACjB,MAAM,EAAS,CACb,KAAM,yBACN,QAAS,0CAA0C,EAAW,yBAChE,CAAC,EAEH,GAAM,CAAE,aAAc,EAAc,EAAM,GAAI,gCAAgC,EAC9E,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,yBACN,QAAS,+DAA+D,EAAW,uCACrF,CAAC,EAEH,IAAM,EAAS,eAAe,CAAS,EACvC,GAAI,CAAC,GAAU,EAAO,MAAM,OAAS,UAAW,MAAO,CAAE,GAAI,IAAK,EAClE,IAAM,EAAS,EAAO,MAA8B,MACpD,MAAO,CAAE,GAAI,OAAO,GAAU,UAAY,IAAU,GAAK,EAAQ,IAAK,CACxE,CAQA,eAAe,mBAAmB,EAAmC,CACnE,IAAM,EAAS,MAAM,aAAa,CAAU,EACxC,OAAW,KAGf,IAAI,CAAC,EAAO,GACV,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,uCACT,QACE,4GACF,WAAY,yDACd,CAAC,EAIH,GAAI,CAAC,GAAU,KAAK,EAAO,EAAE,EAC3B,MAAM,EAAS,CACb,KAAM,oBACN,QAAS,WAAW,EAAW,kBAC/B,WAAY,EACd,CAAC,CATA,CAWL,CAoBA,eAAsB,wBAAwB,EAI5B,CAChB,GAAM,CAAE,aAAY,SAAQ,aAAc,EAC1C,GAAI,EAAW,OAEf,IAAM,EAAmB,GAAa,QAAQ,IAAI,4BAA4B,IAAM,GAC9E,EAAW,IAAQ,CAAC,EAE1B,GAAI,EAAQ,CACN,GACF,MAAM,mBAAmB,CAAU,EAErC,MACF,CAEA,GAAI,EAAU,CACZ,MAAM,mBAAmB,CAAU,EACnC,MACF,CAEA,MAAM,eAAe,CAAU,CACjC,CAEA,MAAM,GACJ,0FAEF,SAAS,iBAAiB,EAAgB,EAA6B,EAAoB,CACzF,IAAM,EAAY,OAAO,KAAK,UAAU,CAAE,IAC1C,GAAI,EAAU,WAAW,OAAS,EAAG,CACnC,IAAM,EAAY,EAAc,EAAU,WAAW,GAAI,wBAAwB,EAC3E,EAAY,EAAO,YAAY;EAAM,EAAU,MAAQ,CAAC,EAAI,EAC5D,EAAS,EAAO,MAAM,EAAW,EAAU,KAAK,EACtD,GAAI,CAAC,WAAW,KAAK,CAAM,EAKzB,OAAO,EAAO,MAAM,EAAG,EAAU,KAAK,EAAI,GAAG,EAAU,IAAM,EAAO,MAAM,EAAU,KAAK,EAE3F,IAAM,EAAY,GAAG,GAAU,IAAI,IAAS,EAAU,KAAK,IAC3D,OAAO,EAAO,MAAM,EAAG,EAAU,KAAK,EAAI,EAAY,EAAO,MAAM,EAAU,KAAK,CACpF,CAIA,IAAM,EAAe,EAAU,MAAQ,EACjC,EAAiB,EAAO,YAAY;EAAM,EAAU,KAAK,EAAI,EAC7D,EAAa,EAAO,MAAM,CAAc,CAAC,CAAC,MAAM,SAAS,CAAC,GAAG,IAAM,GACnE,EAAc,GAAG,EAAW,IAC5B,EAAY,KAAK,IAAc,GAAU,IAAI,IAAc,EAAU,KAAK,IAChF,OAAO,EAAO,MAAM,EAAG,CAAY,EAAI,EAAY,EAAO,MAAM,CAAY,CAC9E,CAEA,SAAS,iBACP,EACA,EACA,EACQ,CACR,IAAM,EAAS,qBAAqB,EAAQ,CAAI,EAChD,GAAI,EAAU,WAAW,OAAS,EAAG,OAAO,EAE5C,IAAM,EAAY,EAAU,KAAO,EAAO,OAAS,EAAO,QAE1D,OADc,EAAO,MAAM,EAAU,MAAQ,EAAG,EAAY,CACjD,CAAC,CAAC,KAAK,IAAM,GACpB,GAAG,EAAO,MAAM,EAAG,EAAU,MAAQ,CAAC,IAAI,EAAO,MAAM,EAAY,CAAC,IACpE,CACN,CAEA,SAAS,qBAAqB,EAAgB,EAA8B,CAC1E,IAAI,EAAM,EAAK,IACT,EAAgB,WAAW,KAAK,EAAO,MAAM,CAAG,CAAC,EACnD,IAAe,GAAO,EAAc,EAAE,CAAC,QAE3C,IAAM,EAAY,EAAO,YAAY;EAAM,EAAK,MAAQ,CAAC,EAAI,EACvD,EAAe,EAAO,QAAQ;EAAM,CAAG,EACvC,EAAU,IAAiB,GAAK,EAAO,OAAS,EAAe,EAIrE,GAFE,WAAW,KAAK,EAAO,MAAM,EAAW,EAAK,KAAK,CAAC,GACnD,aAAa,KAAK,EAAO,MAAM,EAAK,CAAO,CAAC,CAAC,QAAQ,MAAO,EAAE,CAAC,EACpD,CACX,IAAI,EAAc,EAClB,GAAI,EAAY,EAAG,CACjB,IAAM,EAAgB,EAAO,YAAY;EAAM,EAAY,CAAC,EAAI,EAC5D,EAAO,MAAM,EAAe,CAAS,CAAC,CAAC,KAAK,IAAM,KAAW,EAAc,EACjF,CACA,OAAO,EAAO,MAAM,EAAG,CAAW,EAAI,EAAO,MAAM,CAAO,CAC5D,CACA,GAAI,EAAe,CACjB,IAAM,EAAU,UAAU,KAAK,EAAO,MAAM,CAAG,CAAC,CAAC,GAAG,EAAE,CAAC,QAAU,EACjE,OAAO,EAAO,MAAM,EAAG,EAAK,KAAK,EAAI,EAAO,MAAM,EAAM,CAAO,CACjE,CAEA,IAAM,EAAS,EAAO,MAAM,EAAG,EAAK,KAAK,EACnC,EAAY,YAAY,KAAK,CAAM,CAAC,GAAG,EAAE,CAAC,QAAU,EAC1D,OAAO,EAAO,MAAM,EAAG,EAAO,OAAS,CAAS,EAAI,EAAO,MAAM,CAAG,CACtE,CAiBA,eAAsB,eAAe,EAAoB,EAAsC,CAC7F,IAAM,EAAS,MAAMA,EAAG,SAAS,SAAS,EAAY,OAAO,EACvD,CAAE,WAAY,GAAU,EAAY,CAAM,EAC1C,EAA0B,CAAC,EACjC,sBAAsB,EAAS,CAAK,EACpC,IAAM,EAAY,EAAM,SAAW,EAAI,EAAM,EAAE,EAAE,UAAY,KAC7D,GAAI,CAAC,GAAa,cAAc,CAAO,EAAG,MAAO,GAEjD,IAAM,EAAU,iBAAiB,CAAS,EACpC,EAAS,EAAQ,SAAW,EAAI,EAAQ,GAAK,IAAA,GACnD,GAAI,CAAC,GAAU,EAAO,MAAM,OAAS,UAAW,MAAO,GACvD,IAAM,EAAS,EAAO,MAA8B,MACpD,GAAI,OAAO,GAAU,UAAY,EAAM,YAAY,IAAM,EAAW,YAAY,EAAG,MAAO,GAE1F,IAAM,EAAS,iBAAiB,EAAQ,EAAW,CAAM,EAGzD,OAFI,GAAU,EAAY,CAAM,CAAC,CAAC,OAAO,OAAS,EAAU,IAC5D,MAAMA,EAAG,SAAS,UAAU,EAAY,EAAQ,OAAO,EAChD,GACT,CCxYA,MAAa,EAAuB,sBAMvB,GAAsB,EAE7B,GACJ,wEACoB,EAAqB,qBAc3C,SAAS,cAAc,EAAkD,CACvE,OAAO,OAAO,GAAU,YAAY,GAAkB,CAAC,MAAM,QAAQ,CAAK,CAC5E,CAEA,SAAS,wBAAwB,EAAsB,CAErD,OADI,IAAQ,IAAM,EAAK,WAAW,CAAG,GAAK,EAAI,SAAS,IAAI,EAAU,GAC9D,EAAI,MAAM,GAAG,CAAC,CAAC,MAAO,GAAY,IAAY,IAAM,IAAY,KAAO,IAAY,IAAI,CAChG,CAEA,SAAS,mBAAmB,EAAoB,CAC9C,IAAK,IAAM,IAAgB,CAAC,UAAW,CAAoB,EACzD,GAAI,CACF,GAAIC,EAAG,UAAU,EAAK,KAAK,EAAM,CAAY,CAAC,CAAC,CAAC,eAAe,EAC7D,MAAM,EAAS,CACb,KAAM,sBACN,QAAS,mBAAmB,EAAqB,KAAK,EAAa,sBACrE,CAAC,CAEL,OAAS,EAAO,CACd,GAAI,aAAiB,OAAS,SAAU,GAAS,EAAM,OAAS,SAAU,SAC1E,MAAM,CACR,CAEJ,CAWA,SAAgB,YAAY,EAAwB,CAClD,GAAI,IAAU,IAAA,GAAW,MAAO,CAAC,EACjC,GAAI,CAAC,cAAc,CAAK,EACtB,MAAM,EAAS,CACb,KAAM,sBACN,QAAS,GAAG,EAAqB,uFACjC,WAAY,EACd,CAAC,EAEH,IAAM,EAAS,IAAI,IACnB,IAAK,GAAM,CAAC,EAAK,KAAO,OAAO,QAAQ,CAAK,EAAG,CAC7C,GAAI,CAAC,wBAAwB,CAAG,EAC9B,MAAM,EAAS,CACb,KAAM,sBACN,QAAS,GAAG,EAAqB,iBAAiB,EAAI,wFACtD,WAAY,EACd,CAAC,EAEH,GAAI,OAAO,GAAO,UAAY,CAAC,GAAU,KAAK,CAAE,EAC9C,MAAM,EAAS,CACb,KAAM,sBACN,QAAS,GAAG,EAAqB,uBAAuB,EAAI,mBAC5D,WAAY,EACd,CAAC,EAEH,IAAM,EAAQ,EAAO,IAAI,EAAG,YAAY,CAAC,EACzC,GAAI,IAAU,IAAA,GACZ,MAAM,EAAS,CACb,KAAM,kBACN,QAAS,GAAG,EAAqB,4BAA4B,EAAG,SAAS,EAAM,SAAS,EAAI,IAC5F,WACE,uHACJ,CAAC,EAEH,EAAO,IAAI,EAAG,YAAY,EAAG,CAAG,CAClC,CACA,OAAO,CACT,CAEA,SAAS,YAAY,EAA8B,CACjD,mBAAmB,CAAI,EACvB,IAAM,EAAO,EAAK,KAAK,EAAM,CAAoB,EACjD,GAAI,CAACA,EAAG,WAAW,CAAI,EAAG,OAAO,KACjC,IAAI,EACJ,GAAI,CACF,EAAOA,EAAG,aAAa,EAAM,OAAO,CACtC,OAAS,EAAO,CACd,MAAM,EAAS,CACb,KAAM,yBACN,QAAS,GAAG,EAAqB,SAAS,EAAK,qBAC/C,OACF,CAAC,CACH,CACA,IAAI,EACJ,GAAI,CACF,EAAS,KAAK,MAAM,CAAI,CAC1B,OAAS,EAAO,CACd,MAAM,EAAS,CACb,KAAM,sBACN,QAAS,GAAG,EAAqB,qBACjC,WAAY,GACZ,OACF,CAAC,CACH,CACA,GAAI,CAAC,cAAc,CAAM,GAAK,OAAO,EAAO,SAAY,SACtD,MAAM,EAAS,CACb,KAAM,sBACN,QAAS,GAAG,EAAqB,gCACjC,WAAY,EACd,CAAC,EAEH,GAAI,EAAO,QAAA,EACT,MAAM,EAAS,CACb,KAAM,kCACN,QAAS,GAAG,EAAqB,4CAA4C,OAAO,EAAO,OAAO,EAAE,IACpG,WAAY,gFACd,CAAC,EAEH,OAAO,CACT,CAOA,SAAgB,cAAc,EAAgC,CAC5D,IAAM,EAAM,YAAY,CAAI,EAE5B,OADI,IAAQ,KAAa,KAClB,CAAE,OAAM,OAAQ,YAAY,EAAI,MAAM,CAAE,CACjD,CAUA,SAAgB,cAAc,EAAsC,CAClE,IAAI,EAAM,EAAK,QAAQ,CAAU,EACjC,OAAS,CACP,GAAIA,EAAG,WAAW,EAAK,KAAK,EAAA,qBAAyB,CAAC,EAAG,OAAO,cAAc,CAAG,EACjF,IAAM,EAAS,EAAK,QAAQ,CAAG,EAC/B,GAAI,IAAW,GAAOA,EAAG,WAAW,EAAK,KAAK,EAAK,MAAM,CAAC,EAAG,OAAO,KACpE,EAAM,CACR,CACF,CASA,SAAgB,aAAa,EAAc,EAA4B,CACrE,IAAM,EAAM,EAAK,SAAS,EAAM,CAAU,EAC1C,GAAI,CAAC,wBAAwB,CAAG,EAC9B,MAAM,EAAS,CACb,KAAM,4BACN,QAAS,GAAG,EAAW,wCAAwC,EAAqB,IAAI,EAAK,GAC/F,CAAC,EAEH,OAAO,CACT,CA2CA,SAAS,yBAAyB,EAAmB,CACnD,EAAO,KACL,GAAG,EAAI,kDAAkD,EAAqB,4GAGhF,CACF,CAEA,SAAS,uBAAuB,EAAmB,CACjD,EAAO,KACL,iBAAiB,EAAI,mDAAmD,EAAqB,2CACjD,EAAqB,EACnE,CACF,CAEA,SAAS,uBAAuB,EAAmB,CACjD,EAAO,KAAK,6BAA6B,EAAI,MAAM,EAAqB,EAAE,EAC1E,EAAO,IACL;;yFAGF,CACF,CAEA,SAAS,kBAAkB,EAAoC,CAC7D,MACE,GAAG,EAAqB,8CAA8C,EAAQ,KAAK,IAAI,EAAE,8IAI7F,CAEA,SAAS,iBAAiB,EAAyB,EAAmC,CACpF,IAAI,EAAa,0CAA0C,EAAqB,GAEhF,OADI,EAAQ,OAAS,IAAG,GAAc,IAAI,kBAAkB,CAAO,KAC5D,EAAS,CACd,KAAM,2BACN,QAAS,6BAA6B,EAAK,KAAK,IAAI,EAAE,MAAM,EAAqB,+BACjF,QACE,uGACF,YACF,CAAC,CACH,CAEA,eAAe,YAAY,EAAc,EAA8B,CACrE,GAAI,CAAC,UAAU,EACb,MAAM,EAAS,CACb,KAAM,sBACN,QAAS,6BAA6B,EAAG,GACzC,WAAY,kBAAkB,CAAC,CAAI,CAAC,CACtC,CAAC,EAMH,OAJA,EAAO,KACL,GAAG,EAAqB,yBAAyB,EAAK,gCAC7C,EAAG,WACd,EACO,EAAO,QAAQ,CACpB,QAAS,OAAO,EAAK,YAAY,EAAG,iDACpC,QAAS,EACX,CAAC,CACH,CAaA,eAAsB,WAAW,EAA8C,CAC7E,GAAM,CAAE,OAAM,UAAS,QAAS,EAC1B,EAAiC,CAAE,GAAG,EAAK,MAAO,EACpD,EAAU,GACR,EAAyC,EAAQ,QAAU,IAAA,EAAS,EACpE,EAAwE,CAAC,EAGzE,EAAU,IAAI,IAClB,OAAO,QAAQ,CAAM,CAAC,CAAC,KAAK,CAAC,EAAK,KAAQ,CAAC,EAAG,YAAY,EAAG,CAAG,CAAC,CACnE,EACM,OAAU,GAAyBA,EAAG,WAAW,EAAK,KAAK,EAAK,KAAM,CAAG,CAAC,EAEhF,EAAQ,SAAS,CAAE,aAAY,YAAY,IAAU,CACnD,IAAM,EAAM,aAAa,EAAK,KAAM,CAAU,EACxC,EAAW,EAAO,GACxB,GAAI,IAAa,IAAA,GAAW,CAC1B,GAAI,IAAa,IAAA,IAAa,EAAS,YAAY,IAAM,EAAS,YAAY,EAC5E,MAAM,EAAS,CACb,KAAM,kBACN,QAAS,GAAG,EAAqB,mBAAmB,EAAS,QAAQ,EAAI,8BAA8B,EAAS,IAChH,WACE,mJACJ,CAAC,EAEH,IAAM,EAAiB,IAAa,IAAA,IAAa,IAAS,QACtD,IAAa,IAAA,IAAa,CAAC,GAAgB,yBAAyB,CAAG,EAC3E,EAAQ,GAAS,CAAE,aAAY,MAAK,GAAI,EAAU,OAAQ,OAAQ,gBAAe,EACjF,MACF,CACA,GAAI,IAAa,IAAA,GAAW,CAC1B,GAAI,CAAC,GAAU,KAAK,CAAQ,EAC1B,MAAM,EAAS,CACb,KAAM,oBACN,QAAS,WAAW,EAAW,kBAC/B,WAAY,mDACd,CAAC,EAEH,IAAM,EAAQ,EAAQ,IAAI,EAAS,YAAY,CAAC,EAC1C,EAAY,IAAU,IAAA,IAAa,IAAU,GAAO,CAAC,OAAO,CAAK,EAAI,EAAQ,IAAA,GACnF,GAAI,IAAU,IAAA,IAAa,IAAU,GAAO,IAAc,IAAA,GACxD,MAAM,EAAS,CACb,KAAM,kBACN,QAAS,GAAG,EAAW,2CAA2C,EAAM,MAAM,EAAqB,GACnG,WACE,kFACJ,CAAC,EAEH,EAAQ,IAAI,EAAS,YAAY,EAAG,CAAG,EACvC,IAAM,EAAiB,IAAS,QAC5B,GACE,IAAc,IAAA,KAChB,OAAO,EAAO,GACd,EAAO,KAAK,yBAAyB,EAAU,OAAO,EAAI,IAAI,GAAU,GAE1E,EAAO,GAAO,EACd,EAAU,IAEV,uBAAuB,CAAG,EAE5B,EAAQ,GAAS,CAAE,aAAY,MAAK,GAAI,EAAU,OAAQ,SAAU,gBAAe,EACnF,MACF,CACA,EAAW,KAAK,CAAE,QAAO,aAAY,KAAI,CAAC,CAC5C,CAAC,EAED,IAAM,YAA2B,CAC/B,SACA,UACA,QAAS,EAAQ,IAAK,GAAU,EAAc,EAAO,sBAAsB,CAAC,CAC9E,GACA,GAAI,EAAW,SAAW,EAAG,OAAO,OAAO,EAC3C,GAAI,IAAS,OAAQ,CACnB,IAAK,GAAM,CAAE,QAAO,aAAY,SAAS,EACvC,uBAAuB,CAAG,EAC1B,EAAQ,GAAS,CAAE,aAAY,MAAK,GAAI,IAAA,GAAW,OAAQ,OAAQ,eAAgB,EAAM,EAE3F,OAAO,OAAO,CAChB,CAEA,IAAM,EAAU,OAAO,KAAK,CAAM,CAAC,CAAC,OAAQ,GAAQ,CAAC,OAAO,CAAG,CAAC,EAC1D,EAAO,CAAC,GAAG,IAAI,IAAI,EAAW,KAAK,CAAE,SAAU,CAAG,CAAC,CAAC,EAC1D,GAAI,IAAS,UAAW,MAAM,iBAAiB,EAAM,CAAO,EAE5D,IAAI,EACJ,GAAI,EAAQ,SAAW,GAAK,EAAK,SAAW,EAAG,CAC7C,IAAM,EAAO,EAAc,EAAQ,GAAI,gBAAgB,EACjD,EAAM,EAAc,EAAK,GAAI,aAAa,EAC5C,MAAM,YAAY,EAAM,CAAG,IAAG,EAAQ,CAAE,OAAM,KAAI,EACxD,MAAO,GAAI,EAAQ,OAAS,EAC1B,MAAM,EAAS,CACb,KAAM,sBACN,QAAS,6BAA6B,EAAK,KAAK,IAAI,EAAE,GACtD,WAAY,kBAAkB,CAAO,CACvC,CAAC,EAGH,IAAK,GAAM,CAAE,QAAO,aAAY,SAAS,EAAY,CACnD,IAAM,EAAiB,EAAO,GAC9B,GAAI,IAAmB,IAAA,GAAW,CAChC,EAAQ,GAAS,CACf,aACA,MACA,GAAI,EACJ,OAAQ,YACR,eAAgB,EAClB,EACA,QACF,CACA,IAAI,EACA,GAAO,MAAQ,GACjB,EAAK,EAAc,EAAO,EAAM,MAAO,yBAAyB,EAChE,OAAO,EAAO,EAAM,MACpB,EAAO,KAAK,yBAAyB,EAAM,KAAK,OAAO,EAAI,IAAI,GAAI,IAEnE,EAAK,OAAO,WAAW,EACvB,EAAO,KAAK,wBAAwB,EAAI,IAAI,GAAI,GAElD,EAAO,GAAO,EACd,EAAU,GACV,IAAM,EAAS,GAAO,MAAQ,EAAM,OAAS,YAC7C,EAAQ,GAAS,CAAE,aAAY,MAAK,KAAI,SAAQ,eAAgB,EAAM,CACxE,CACA,OAAO,OAAO,CAChB,CAeA,SAAgB,YAAY,EAAiC,CAC3D,GAAM,CAAE,OAAM,UAAW,EACnB,EAAM,YAAY,EAAK,IAAI,EACjC,GAAI,IAAQ,KACV,MAAM,EAAS,CACb,KAAM,wBACN,QAAS,GAAG,EAAqB,wBAAwB,EAAK,KAAK,GACnE,WAAY,gCACd,CAAC,EAEH,IAAM,EAAiC,CAAE,GAAG,YAAY,EAAI,MAAM,CAAE,EACpE,IAAK,IAAM,KAAO,OAAO,KAAK,EAAK,MAAM,EACjC,KAAO,GAAS,OAAO,EAAO,GAEtC,IAAK,GAAM,CAAC,EAAK,KAAO,OAAO,QAAQ,CAAM,EACvC,EAAK,OAAO,KAAS,IAAI,EAAO,GAAO,GAE7C,IAAM,EAAO,CAAE,GAAG,EAAK,QAAA,EAA8B,OAAQ,CAAO,EACpE,EAAG,cACD,EAAK,KAAK,EAAK,KAAM,CAAoB,EACzC,GAAG,KAAK,UAAU,EAAM,KAAM,CAAC,EAAE,IACjC,OACF,CACF,CAeA,eAAsB,uBACpB,EACuC,CACvC,IAAI,EAAe,GACb,EAAS,IAAI,IACnB,IAAK,IAAM,KAAS,EAAK,QAClB,EAAM,gBAAkB,EAAM,KAAO,IAAA,IAAa,GAAO,IAAI,EAAM,UAAU,IAClF,EAAO,IAAI,EAAM,UAAU,EACvB,MAAM,eAAe,EAAM,WAAY,EAAM,EAAE,GACjD,EAAe,GACf,EAAO,KAAK,uBAAuB,EAAM,IAAI,wBAAwB,EAAqB,EAAE,GAE5F,EAAO,KACL,iBAAiB,EAAM,IAAI,kBAAkB,EAAqB,6FAE7D,EAAM,WAAW,WACxB,GAGJ,MAAO,CAAE,cAAa,CACxB,CAQA,eAAsB,oBAAoB,EAA8C,CACtF,IAAM,EAAO,MAAM,WAAW,CAAM,EAKpC,OAJI,EAAO,OAAS,UACd,EAAK,SAAS,YAAY,CAAE,KAAM,EAAO,KAAM,OAAQ,EAAK,MAAO,CAAC,EACxE,MAAM,uBAAuB,CAAI,GAE5B,CACT,CASA,SAAgB,uBAAuB,EAAgC,CACrE,IAAM,EAAmB,GAAa,QAAQ,IAAI,4BAA4B,IAAM,GAEpF,OADI,IAAQ,CAAC,EAAyB,UAC/B,EAAS,OAAS,OAC3B,CCxdA,SAAgB,uBAAuB,EAAgD,CACrF,IAAM,EAAgB,GAAc,QAAQ,IAAI,gCAChD,GAAI,IAAkB,IAAA,GACpB,MAAO,CAAC,IAAA,EAAS,EAGnB,IAAM,EAAc,EAAc,MAAM,GAAG,CAAC,CAAC,IAAK,GAAU,EAAM,KAAK,CAAC,EACxE,GAAI,EAAY,KAAM,GAAU,EAAM,SAAW,CAAC,EAChD,MAAM,EAAS,CACb,KAAM,yBACN,QAAS,4DACT,QAAS,QACX,CAAC,EAEH,OAAO,CACT,CACA,eAAe,sBACb,EACgC,CAChC,GAAM,CAAE,aAAY,eAAc,SAAQ,YAAW,UAAS,iBAAgB,YAAa,EACrF,CAAE,SAAQ,WACd,GACA,GACG,MAAM,kBAAkB,CAAE,YAAa,CAAC,CAAU,EAAG,SAAQ,WAAU,CAAC,EAAA,CAAG,GAC5E,uBACF,EAEI,EAAY,EAAK,QAAQ,EAAO,IAAI,EACpC,EACJ,GAAW,iBAAkB,CAAE,IAAK,CAAU,CAAC,GAC/C,GAAW,oBAAqB,CAAE,IAAK,CAAU,CAAC,GAClD,GAAW,YAAa,CAAE,IAAK,CAAU,CAAC,GAC1C,GAAW,WAAY,CAAE,IAAK,CAAU,CAAC,EACrC,EAAe,mBAAmB,CACtC,QAAS,CAAC,EACV,WACA,WAAY,EACZ,aAAc,EAAe,GAAS,CAAY,EAAI,IAAA,EACxD,CAAC,EAEG,EACA,EAAQ,OAAS,IACnB,EAAgB,IAAI,GAAc,CAAO,GAG3C,MAAM,EAAS,8BACb,kBAAkB,CAAE,SAAQ,WAAY,EAAO,IAAK,CAAC,CACvD,EAEA,IAAI,EACA,EACA,EACA,EACJ,GAAI,CACF,IAAM,EAAS,MAAM,EAAS,4BAC5B,GAAgB,CACd,SACA,gBACA,YAAa,EAAa,WAC5B,CAAC,CACH,EACA,EAAc,EAAO,YACrB,EAAsB,EAAO,oBAC7B,EAAyB,EAAO,uBAChC,EAAiB,EAAO,cAC1B,QAAU,CACR,EAAa,SAAS,CACxB,CAEA,MAAO,CACL,SACA,cACA,sBACA,yBACA,gBACF,CACF,CAEA,SAAS,0BAA0B,EAAoD,CACrF,IAAM,EAAY,eAAe,CAAU,EAC3C,GAAI,CAAC,EAAW,OAEhB,IAAM,EAAe,EAAK,QAAQ,QAAQ,IAAI,EAAG,CAAS,EAC1D,OAAOC,EAAG,WAAW,CAAY,EAAI,EAAe,IAAA,EACtD,CAKA,eAAe,qBAAqB,EAAgD,CAClF,GAAM,CAAE,cAAa,SAAQ,aAAc,EAC3C,GAAI,EAAW,OACf,IAAM,EAAgB,IAAI,IACxB,EACG,IAAI,yBAAyB,CAAC,CAC9B,OAAQ,GAAqC,IAAe,IAAA,EAAS,CAC1E,EAEA,MAAM,QAAQ,IACZ,CAAC,GAAG,CAAa,CAAC,CAAC,IAAK,GACtB,EAAS,sBAAuB,SAAY,CACtC,cAAc,CAAU,IAAM,MAClC,MAAM,wBAAwB,CAAE,aAAY,SAAQ,WAAU,CAAC,CACjE,CAAC,CACH,CACF,CACF,CAEA,eAAe,yBACb,EAC6B,CAC7B,OAAO,EAAS,uBAA0B,WAAW,EAAO,UAAU,CAAC,CACzE,CAQA,eAAe,oBACb,EAC+B,CAC/B,GAAM,CAAE,SAAQ,SAAQ,aAAc,EAEtC,GAAI,EAAW,MAAO,CAAC,GAAG,CAAM,EAEhC,IAAM,EAAW,CAAC,GAAG,CAAM,EACrB,EAAa,IAAI,IACvB,EAAO,SAAS,EAAO,IAAU,CAC/B,IAAM,EAAO,cAAc,EAAM,OAAO,IAAI,EAC5C,GAAI,IAAS,KAAM,CACjB,iBAAiB,EAAM,OAAO,EAAE,EAChC,MACF,CACA,IAAM,EAAQ,EAAW,IAAI,EAAK,IAAI,GAAK,CAAE,OAAM,QAAS,CAAC,CAAE,EAC/D,EAAM,QAAQ,KAAK,CAAK,EACxB,EAAW,IAAI,EAAK,KAAM,CAAK,CACjC,CAAC,EAED,IAAM,EAAO,uBAAuB,CAAM,EAC1C,IAAK,GAAM,CAAE,OAAM,aAAa,EAAW,OAAO,EAAG,CACnD,IAAM,EAAO,MAAM,oBAAoB,CACrC,OACA,OACA,QAAS,EAAQ,IAAK,GAAU,CAC9B,GAAM,CAAE,UAAW,EAAc,EAAO,GAAQ,uBAAuB,EACvE,MAAO,CAAE,WAAY,EAAO,KAAM,SAAU,EAAO,EAAG,CACxD,CAAC,CACH,CAAC,EACD,EAAQ,SAAS,EAAO,IAAa,CACnC,IAAM,EAAQ,EAAc,EAAO,GAAQ,uBAAuB,EAC5D,EAAK,EAAc,EAAK,QAAQ,GAAW,8BAA8B,CAAC,CAAC,GACjF,EAAS,GAAS,CAAE,GAAG,EAAO,OAAQ,CAAE,GAAG,EAAM,OAAQ,IAAG,CAAE,CAChE,CAAC,CACH,CACA,OAAO,CACT,CAEA,eAAsB,kBACpB,EAC+B,CAK/B,OAJA,MAAM,qBAAqB,CAAM,EAI1B,oBAAoB,CAAE,OAAA,MAHR,QAAQ,IAC3B,EAAO,YAAY,IAAK,GAAe,yBAAyB,CAAE,GAAG,EAAQ,YAAW,CAAC,CAAC,CAC5F,EACqC,OAAQ,EAAO,OAAQ,UAAW,EAAO,SAAU,CAAC,CAC3F,CAEA,eAAsB,uBACpB,EACkC,CAClC,GAAM,CACJ,cACA,cAAe,EACf,cACA,GAAG,GACD,EACJ,GACE,IAA0B,IAAA,KACzB,EAAsB,SAAW,EAAY,QAC5C,EAAY,MAAM,EAAG,IAAU,EAAsB,KAAW,IAAA,EAAS,GAE3E,MAAM,EAAc,mEAAmE,EAEzF,IAAM,EACJ,IAAgB,IAAA,IAAa,IAA0B,IAAA,GACnD,MAAM,kBAAkB,CACtB,cACA,OAAQ,EAAO,OACf,UAAW,EAAO,SACpB,CAAC,EACD,EACA,EAAQ,GAAe,sBAE7B,OAAO,QAAQ,IACb,EAAY,KAAK,EAAY,IAC3B,EAAM,CACJ,GAAG,EACH,aACA,aAAc,IAAgB,EAChC,CAAC,CACH,CACF,CACF,CCzQA,SAAS,8BACP,EACA,EACA,EACM,CACN,GAAI,EAAW,IAAI,CAAG,EAAG,CACnB,EAAW,IAAI,CAAG,IAAM,GAC1B,EAAW,IAAI,EAAK,IAAA,EAAS,EAE/B,MACF,CACA,EAAW,IAAI,EAAK,CAAS,CAC/B,CAgBA,SAAS,wBAAiC,EAAyD,CACjG,GAAM,CAAE,cAAa,eAAc,gBAAe,cAAa,eAAc,eAC3E,EACI,EAAc,EAAc,CAAW,EACvC,EAAS,EAAa,EAC5B,IAAK,IAAM,KAAa,EACtB,IAAK,IAAM,KAAY,EAAY,CAAS,EACrC,EAAY,IAAI,EAAS,aAAa,GAG3C,EAAY,EAAQ,EAAS,YAAa,EAAS,aAAa,EAGpE,OAAO,CACT,CAEA,SAAS,qCACP,EACqB,CACrB,OAAO,IAAI,IAAI,CACb,GAAG,EAAY,iBAAiB,IAAK,GAAY,EAAQ,SAAS,EAClE,GAAG,EAAY,0BACjB,CAAC,CACH,CAEA,SAAU,sBAAsB,EAA+D,CAC7F,IAAK,IAAM,KAAW,EAAY,iBAChC,IAAK,IAAM,KAAa,OAAO,KAAK,EAAQ,KAAK,EAC/C,KAAM,CAAE,cAAe,EAAQ,UAAW,YAAa,CAAU,CAGvE,CAEA,SAAgB,qCACd,EACA,EACyC,CACzC,OAAO,wBAAwB,CAC7B,cACA,eACA,cAAe,qCACf,YAAa,sBACb,iBAAoB,IAAI,IACxB,YAAa,6BACf,CAAC,CACH,CAEA,SAAS,qCACP,EACqB,CACrB,OAAO,IAAI,IACT,EAAY,UACT,OAAQ,GAAa,EAAS,OAAS,UAAU,CAAC,CAClD,IAAK,GAAa,EAAS,IAAI,CACpC,CACF,CAEA,SAAU,iBAAiB,EAA+D,CACxF,IAAK,IAAM,KAAQ,2BAA2B,CAAW,EACvD,KAAM,CAAE,cAAe,EAAM,YAAa,CAAK,CAEnD,CAEA,SAAgB,uBACd,EACA,EACqB,CACrB,OAAO,wBAAwB,CAC7B,cACA,eACA,cAAe,2BACf,YAAa,iBACb,iBAAoB,IAAI,IACxB,aAAc,EAAO,IAAS,CAC5B,EAAM,IAAI,CAAI,CAChB,CACF,CAAC,CACH,CAEA,SAAU,kBAAkB,EAA+D,CACzF,IAAK,IAAM,KAAW,EAAY,iBAChC,IAAK,IAAM,KAAY,OAAO,OAAO,EAAQ,SAAS,EACpD,KAAM,CAAE,cAAe,EAAQ,UAAW,YAAa,EAAS,IAAK,CAG3E,CAEA,SAAgB,iCACd,EACA,EACyC,CACzC,OAAO,wBAAwB,CAC7B,cACA,eACA,cAAe,qCACf,YAAa,kBACb,iBAAoB,IAAI,IACxB,YAAa,6BACf,CAAC,CACH,CCvGA,SAAS,kBACP,EACA,EACoB,CACpB,GAAI,EAAQ,KAAO,KACjB,OAAO,EAAQ,IAEjB,IAAM,EAAO,2BAA2B,CAAW,EACnD,GAAI,EAAK,OAAS,EAChB,OAEF,GAAM,CAAC,GAAQ,EACf,OAAO,CACT,CAwCA,SAAS,oBACP,EACA,EACA,EACQ,CACR,IAAM,EAAU,aAAa,EAAa,kBAAkB,EAAO,SAAS,4CACtE,EAAW,EAAO,aAAa,CAAU,EAc/C,OAbI,EACK,GAAG,EAAQ,wBAAwB,EAAS,+CAGnD,EAAO,QAAQ,OAAS,qBACxB,EAAO,QAAQ,OAAS,uBAGtB,GAAG,EAAQ,yNAKR,GAAG,EAAQ,8EACpB,CAYA,SAAgB,0BACd,EACqB,CACrB,IAAM,EAAqC,CAAC,EACtC,EAAe,EAAQ,IAAK,GAAW,EAAO,WAAW,EAC/D,IAAK,IAAM,KAAc,EAAS,CAChC,IAAM,EAAY,EAAW,YAAY,iBAAiB,WAAa,CAAC,EAClE,EAAa,4BAA4B,EAAY,CAAY,EACvE,IAAK,IAAM,KAAY,OAAO,OAAO,CAAS,EAAG,CAC/C,IAAM,EAAS,kBAAkB,EAAU,EAAY,CAAU,EACjE,GAAI,CAAC,EACH,SAEF,IAAM,EAAQ,CACZ,aACA,aAAc,EAAS,KACvB,SAAU,EAAO,SACjB,SAAU,CAAC,mBAAmB,CAAQ,EACtC,QAAS,EAAO,OAClB,EACA,GAAI,EAAO,WAAW,CAAU,EAAG,CACjC,EAAc,KAAK,CACjB,GAAG,EACH,MAAO,EACP,OAAQ,EAAO,OAAO,CAAU,EAChC,IAAK,EAAO,MAAM,CAAU,CAC9B,CAAC,EACD,QACF,CACA,IAAM,EAAQ,EAAQ,OACnB,GAAW,EAAO,OAAO,OAAS,EAAW,OAAO,MAAQ,EAAO,WAAW,CAAM,CACvF,EACM,EAAS,EAAO,aAAa,CAAK,EAGxC,GAAI,IAAW,YACb,SAEF,GAAM,CAAC,GAAS,EAChB,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,qCACN,QAAS,oBAAoB,EAAS,KAAM,EAAQ,CAAU,CAChE,CAAC,EAEH,EAAc,KAAK,CACjB,GAAG,EACH,QACA,OAAQ,EAAO,OAAO,CAAK,EAC3B,IAAK,EAAO,MAAM,CAAK,CACzB,CAAC,CACH,CACF,CACA,OAAO,CACT,CAYA,SAAgB,uBACd,EACA,EACqB,CACrB,OAAO,IAAI,IACT,wBAAwB,mBAAmB,EAAe,CAAK,CAAC,CAAC,CAAC,QAC/D,GAAiB,EAAa,KAAO,CAAC,CACzC,CACF,CACF,CAQA,SAAgB,mBACd,EACA,EACqB,CACrB,OAAO,EAAc,OAClB,GAAiB,EAAa,MAAM,OAAO,OAAS,EAAM,OAAO,IACpE,CACF,CAaA,SAAS,wBACP,EACkC,CAClC,OAAO,EAAc,OAAQ,GAAiB,CAAC,EAAa,QAAQ,CACtE,CAOA,SAAgB,yBACd,EACqB,CACrB,OAAO,IAAI,IACT,wBAAwB,CAAa,CAAC,CAAC,QAAS,GAC9C,EAAa,QAAQ,OAAS,WAAa,CAAC,EAAa,QAAQ,SAAS,EAAI,CAAC,CACjF,CACF,CACF,CAOA,SAAgB,oBACd,EACqB,CACrB,OAAO,IAAI,IACT,wBAAwB,CAAa,CAAC,CAAC,QAAS,GAC9C,EAAa,QAAQ,OAAS,mBAAqB,CAAC,EAAa,QAAQ,YAAY,EAAI,CAAC,CAC5F,CACF,CACF,CAOA,SAAgB,eACd,EACqB,CACrB,OAAO,IAAI,IACT,wBAAwB,CAAa,CAAC,CAAC,QAAS,GAC9C,EAAa,QAAQ,OAAS,UAC1B,CACE,kBAAkB,EAAa,WAAW,YAAa,EAAa,OAAO,GAAK,CAAC,CACnF,CAAC,CAAC,KAAK,EACP,CAAC,CACP,CACF,CACF,CAOA,SAAgB,oBAAoB,EAGlC,CACA,IAAM,EAAY,CAAE,cAAe,IAAI,GAAc,EAC/C,EAAe,CAAE,cAAe,IAAI,GAAc,EACxD,IAAK,GAAM,CAAE,aAAa,wBAAwB,CAAa,EACzD,EAAQ,OAAS,oBACnB,EAAU,cAAc,IAAI,EAAQ,YAAY,EACvC,EAAQ,OAAS,wBAC1B,EAAa,cAAc,IAAI,EAAQ,YAAY,EAGvD,MAAO,CAAE,YAAW,cAAa,CACnC,CAuBA,SAAgB,qBACd,EACyB,CACzB,IAAM,EAAa,IAAI,IACvB,IAAK,GAAM,CAAE,aAAY,QAAO,SAAQ,SAAS,wBAAwB,CAAa,EAAG,CACvF,GAAI,EAAW,OAAO,OAAS,EAAM,OAAO,MAAQ,GAAU,IAAQ,IAAA,GACpE,SAEF,IAAM,EAAQ,EAAW,YAAY,GACrC,GAAI,IAAU,IAAA,GACZ,SAEF,IAAM,EAAa,EAAW,IAAI,CAAG,GAAK,IAAI,IAC9C,EAAW,IAAI,EAAO,gBAAgB,EACtC,EAAW,IAAI,EAAK,CAAU,CAChC,CACA,OAAO,CACT,CAOA,SAAgB,gCACd,EAC8B,CAC9B,IAAM,EAAmB,IAAI,IAC7B,IAAK,IAAM,KAAO,EAAO,YAAY,iBAAiB,MAAQ,CAAC,EACzD,EAAI,gBAAkB,IAAA,IACxB,EAAiB,IAAI,EAAI,KAAM,EAAI,aAAa,EAGpD,OAAO,CACT,CA0BA,SAAS,4BACP,EACA,EACsB,CACtB,MAAO,CACL,cAAe,qCAAqC,EAAW,YAAa,CAAY,EACxF,UAAW,iCAAiC,EAAW,YAAa,CAAY,EAChF,KAAM,uBAAuB,EAAW,YAAa,CAAY,CACnE,CACF,CA4CA,SAAS,2BAA2B,EAAsD,CACxF,OAAO,EAAO,YAAY,0BAC5B,CAEA,SAAS,sBACP,EACA,EACA,EACU,CACV,OAAO,EAAO,YAAY,UACvB,OAAQ,GAAa,EAAS,OAAS,GAAgB,CAAC,EAAW,IAAI,EAAS,IAAI,CAAC,CAAC,CACtF,IAAK,GAAa,EAAS,IAAI,CACpC,CAEA,SAAS,2BAA2B,EAAyC,CAE3E,OAAO,sBAAsB,EAAQ,WAAY,IAD/B,IAAI,EAAO,YAAY,iBAAiB,IAAK,GAAY,EAAQ,SAAS,CACvC,CAAC,CACxD,CAEA,SAAS,iBAAiB,EAAyC,CAEjE,OAAO,sBAAsB,EAAQ,MAAO,IAD1B,IAAI,EAAO,YAAY,YAAY,IAAK,GAAQ,EAAI,IAAI,CAC1B,CAAC,CACnD,CAQA,SAAS,iBAAiB,EAAc,EAAkD,CACpF,KAAM,SAAW,EAIrB,MAAO,YADQ,EAAM,SAAW,EAAI,EAAO,GAAG,EAAK,GACzB,GAAG,EAAM,IAAK,GAAS,IAAI,EAAK,EAAE,CAAC,CAAC,KAAK,IAAI,GACzE,CAEA,SAAS,qBACP,EACA,EACqB,CACrB,OACE,EAAO,YAAY,iBAAiB,KAAM,GAAY,EAAQ,MAAM,EAAU,GAAK,IAAA,EAEvF,CAEA,SAAS,iBACP,EACA,EACqB,CACrB,OACE,EAAO,YAAY,iBAAiB,KAAM,GACxC,OAAO,OAAO,EAAQ,SAAS,CAAC,CAAC,KAAM,GAAa,EAAS,OAAS,CAAY,CACpF,GAAK,IAAA,EAET,CAEA,SAAS,YAAY,EAA+B,EAAsC,CACxF,OAAO,EAAO,YAAY,YAAY,KAAM,GAAU,EAAM,OAAS,CAAO,GAAK,IAAA,EACnF,CAEA,SAAS,iBACP,EACA,EACqB,CAErB,OADkB,OAAO,OAAO,EAAO,YAAY,iBAAiB,WAAa,CAAC,CACnE,CAAC,CAAC,KAAM,GAAU,EAAM,OAAS,CAAY,GAAK,IAAA,EACnE,CAKA,SAAS,iBAAiB,EAA+B,EAA4B,CACnF,IAAK,IAAM,KAAW,EAAO,YAAY,iBAAkB,CACzD,IAAM,EAAO,EAAQ,MAAM,GAC3B,GAAI,EAAM,OAAO,EAAK,SAAS,gBAAkB,IAAA,EACnD,CACA,MAAO,EACT,CAKA,SAAS,eACP,EACA,EACA,EACS,CACT,OAAO,EAAO,YAAY,iBAAiB,KACxC,GACC,EAAQ,YAAc,GACtB,OAAO,OAAO,EAAQ,SAAS,CAAC,CAAC,KAC9B,GAAa,EAAS,OAAS,GAAgB,EAAS,gBAAkB,IAAA,EAC7E,CACJ,CACF,CAEA,SAAS,QAAQ,EAA+B,EAA0B,CACxE,OAAO,EAAO,YAAY,YAAY,KACnC,GAAU,EAAM,OAAS,GAAW,EAAM,gBAAkB,IAAA,EAC/D,CACF,CAEA,SAAS,aAAa,EAA+B,EAA+B,CAClF,OAAO,OAAO,OAAO,EAAO,YAAY,iBAAiB,WAAa,CAAC,CAAC,CAAC,CAAC,KACvE,GAAU,EAAM,OAAS,GAAgB,EAAM,gBAAkB,IAAA,EACpE,CACF,CAMA,SAAS,uBAAuB,EAA+B,EAA+B,CAC5F,IAAM,EAAW,OAAO,OAAO,EAAO,YAAY,iBAAiB,WAAa,CAAC,CAAC,CAAC,CAAC,KACjF,GAAU,EAAM,OAAS,CAC5B,EACA,GAAI,IAAa,IAAA,GAAW,MAAO,GACnC,IAAM,EAAW,EAAO,qBAAqB,YAAY,EAAS,QAAQ,OAAS,CAAC,EAC9E,EAAW,gCAAgC,CAAM,EACvD,OAAO,EAAS,OAAS,GAAK,EAAS,MAAO,GAAY,EAAS,IAAI,CAAO,CAAC,CACjF,CAEA,SAAS,wBACP,EACA,EACoB,CACpB,OAAO,EAAO,YAAY,iBAAiB,KAAM,GAAY,EAAQ,MAAM,EAAU,CAAC,EAAE,SAC1F,CAKA,SAAS,yBAAyB,EAKd,CAClB,GAAM,CAAE,aAAY,UAAS,cAAa,cAAe,EACzD,GAAI,CAAC,EAAQ,IAAI,CAAW,EAAG,MAAO,CAAC,EACvC,IAAM,EAAY,EAAQ,IAAI,CAAW,EAEzC,OADI,IAAc,IAAA,GAAkB,YAC7B,EAAW,OAAQ,GAAW,EAAW,EAAQ,CAAS,CAAC,CACpE,CAEA,SAAS,uBACP,EACA,EACA,EACS,CACT,OAAO,EAAO,YAAY,iBAAiB,KACxC,GAAY,EAAQ,YAAc,GAAa,EAAQ,EAAQ,MAAM,EACxE,CACF,CAEA,SAAS,mBACP,EACA,EACA,EACS,CACT,OAAO,EAAO,YAAY,iBAAiB,KACxC,GACC,EAAQ,YAAc,GACtB,OAAO,OAAO,EAAQ,SAAS,CAAC,CAAC,KAAM,GAAa,EAAS,OAAS,CAAY,CACtF,CACF,CASA,SAAS,kBACP,EACA,EACA,EAC+B,CAC/B,GAAM,CAAE,WAAY,EACpB,OAAQ,EAAQ,KAAhB,CACE,IAAK,WACH,MAAO,CACL,SAAU,GAAsB,aAAa,EAAQ,SAAS,CAAC,CAAC,SAChE,UACA,WAAa,GAAW,qBAAqB,EAAQ,EAAQ,SAAS,EACtE,OAAS,GAAW,iBAAiB,EAAQ,EAAQ,SAAS,EAC9D,MAAQ,GAAU,CAChB,IAAM,EAAY,wBAAwB,EAAO,EAAQ,SAAS,EAClE,OAAO,GAAa,EAAe,aAAa,EAAW,EAAQ,SAAS,CAC9E,EACA,aAAe,GACb,yBAAyB,CACvB,aACA,QAAS,EAAW,cACpB,YAAa,EAAQ,UACrB,YAAa,EAAQ,IACnB,uBAAuB,EAAQ,EAAW,EAAQ,SAAS,CAC/D,CAAC,EACH,aAAe,GACb,iBAAiB,qBAAsB,2BAA2B,CAAM,CAAC,CAC7E,EACF,IAAK,mBAAoB,CAOvB,IAAM,EACJ,sBAAsB,EAAW,YAAa,EAAQ,YAAY,GAClE,EAAW,UAAU,IAAI,EAAQ,YAAY,EAC/C,MAAO,CACL,SAAU,GAAsB,SAAS,EAAQ,YAAY,CAAC,CAAC,SAC/D,UACA,WAAa,GAAW,iBAAiB,EAAQ,EAAQ,YAAY,EACrE,OAAS,GACP,IAAc,IAAA,IAAa,eAAe,EAAQ,EAAW,EAAQ,YAAY,EACnF,UAAa,GAAa,EAAe,SAAS,EAAW,EAAQ,YAAY,EACjF,aAAe,GACb,yBAAyB,CACvB,aACA,QAAS,EAAW,UACpB,YAAa,EAAQ,aACrB,YAAa,EAAQ,IACnB,mBAAmB,EAAQ,EAAW,EAAQ,YAAY,CAC9D,CAAC,EACH,aAAe,GACb,iBAAiB,qBAAsB,2BAA2B,CAAM,CAAC,CAC7E,CACF,CACA,IAAK,UAAW,CACd,IAAM,EAAU,kBAAkB,EAAW,YAAa,CAAO,EAIjE,OAHI,IAAY,IAAA,GACd,OAEK,CACL,SAAU,GAAsB,WAAW,CAAO,CAAC,CAAC,SACpD,UACA,WAAa,GAAW,YAAY,EAAQ,CAAO,EACnD,OAAS,GAAW,QAAQ,EAAQ,CAAO,EAC3C,UAAa,EAAe,IAAI,CAAO,EAGvC,aAAe,GACb,EAAW,KAAK,IAAI,CAAO,EACvB,EAAW,OAAQ,GAAW,YAAY,EAAQ,CAAO,CAAC,EAC1D,CAAC,EAEP,aAAe,GACb,iBACE,MACA,iBAAiB,CAAM,CAAC,CAAC,OAAQ,GAAS,IAAS,CAAO,CAC5D,CACJ,CACF,CACA,IAAK,oBACL,IAAK,uBACH,MAAO,CAGL,SACE,EAAQ,OAAS,oBACb,GAAiB,SAAS,EAAQ,YAAY,EAC9C,GAAiB,aAAa,EAAQ,YAAY,EACxD,UACA,WAAa,GAAW,iBAAiB,EAAQ,EAAQ,YAAY,EACrE,OAAS,GACP,EAAQ,OAAS,oBACb,aAAa,EAAQ,EAAQ,YAAY,EACzC,uBAAuB,EAAQ,EAAQ,YAAY,EACzD,UACE,EAAQ,OAAS,oBACb,EAAe,SAAS,EAAQ,YAAY,EAC5C,EAAe,aAAa,EAAQ,YAAY,EACtD,aAAe,GACb,EAAW,OAAQ,GAAW,iBAAiB,EAAQ,EAAQ,YAAY,CAAC,EAE9E,iBAAoB,IAAA,EACtB,EACF,QACE,MACJ,CACF,CAcA,SAAgB,6BACd,EACA,EACM,CACN,IAAK,GAAM,CAAE,aAAY,QAAO,eAAc,WAAU,YAAY,wBAClE,CACF,EAAG,CAGD,GAFI,EAAW,OAAO,OAAS,EAAM,OAAO,MACxC,GACA,CAAC,EAAQ,SACb,IAAM,EAAQ,EAAW,YAAY,GAIrC,GAAI,IAAU,IAAA,IAAa,sBAAsB,CAAK,IAAM,IAAA,GAAW,SACvE,IAAM,EACJ,IAAU,IAAA,GACN,GAAG,EAAW,OAAO,KAAK,sGAE1B,GAAG,EAAW,OAAO,KAAK,uBAAuB,EAAM,kDAEvD,EACJ,IAAU,IAAA,GACN,iCAAiC,EAAW,OAAO,KAAK,iCACxD,kCAAkC,EAAW,OAAO,KAAK,UAC/D,MAAM,EAAS,CACb,KAAM,sCACN,QAAS,aAAa,EAAa,OAAO,EAAW,OAAO,KAAK,iBAAiB,EAAS,MAAM,EAAM,OAAO,KAAK,oEAAoE,EAAM,oEAC7L,QAAS,aAAa,EAAM,OAAO,KAAK,6DACxC,WAAY,CACd,CAAC,CACH,CACF,CCpuBA,SAAgB,2BAA2B,EAI9B,CACX,GAAM,CAAE,YAAW,iBAAgB,qBAAsB,EAEzD,MAAO,CAAC,GAAG,IADgB,IAAI,EAAU,IAAK,GAAM,EAAE,YAAY,CAC1C,CAAC,CAAC,CAAC,OACxB,GAAU,CAAC,EAAe,IAAI,CAAK,GAAK,CAAC,EAAkB,IAAI,CAAK,CACvE,CACF,CAUA,SAAgB,gCACd,EACM,CACN,IAAK,IAAM,KAAS,GAAqC,CACvD,IAAM,EAAO,IAAI,IACjB,IAAK,IAAM,KAAU,EACnB,IAAK,IAAM,KAAQ,EAAM,QAAQ,CAAM,EAAG,CACxC,GAAI,EAAK,IAAI,CAAI,EACf,MAAM,EAAS,CACb,KAAM,iCACN,QAAS,aAAa,EAAM,cAAc,SAAS,EAAK,yBAAyB,EAAM,cAAc,6DACvG,CAAC,EAEH,EAAK,IAAI,CAAI,CACf,CAEJ,CACF,CAcA,SAAS,sBAAsB,EAA2D,CACxF,OAAO,OAAO,OAAO,CAAO,CAC9B,CAEA,SAAgB,sBAAsB,EAAuC,CAC3E,OAAO,sBAAsB,CAAO,CAAC,CAAC,QAAS,GAAS,EAAK,SAAS,CACxE,CAEA,SAAgB,0BAA0B,EAA2C,CACnF,OAAO,sBAAsB,CAAO,CAAC,CAAC,QAAS,GAAS,EAAK,SAAS,CACxE,CAEA,SAAS,sBAAsB,EAAmC,CAChE,OAAO,IAAI,IAAI,sBAAsB,CAAO,CAAC,CAAC,QAAS,GAAS,CAAC,GAAG,EAAK,cAAc,CAAC,CAAC,CAC3F,CAEA,SAAgB,kCACd,EAC6B,CAC7B,IAAM,EAAkD,CAAC,EACzD,IAAK,IAAM,KAAO,EAAQ,SAAS,UAAU,KAAK,QAChD,EAAmB,KAAK,CACtB,aAAc,iBACd,aAAc,EAAI,IACpB,CAAC,EAEH,IAAK,IAAM,KAAO,EAAQ,cAAc,UAAU,QAChD,EAAmB,KAAK,CACtB,aAAc,gBACd,aAAc,EAAI,IACpB,CAAC,EAEH,IAAK,IAAM,KAAO,EAAQ,UAAU,UAAU,QAC5C,EAAmB,KAAK,CACtB,aAAc,YACd,aAAc,EAAI,IACpB,CAAC,EAEH,IAAK,IAAM,KAAO,EAAQ,KAAK,UAAU,aAAa,QACpD,EAAmB,KAAK,CACtB,aAAc,gBACd,aAAc,EAAI,IACpB,CAAC,EAEH,IAAK,IAAM,KAAW,EAAQ,KAAK,UAAU,aAAa,SACxD,EAAmB,KAAK,CACtB,aAAc,qCACd,aAAc,EAAQ,IACxB,CAAC,EAEH,IAAK,IAAM,KAAO,EAAQ,KAAK,UAAU,WAAW,QAClD,EAAmB,KAAK,CACtB,aAAc,kBACd,aAAc,EAAI,IACpB,CAAC,EAEH,IAAK,IAAM,KAAO,EAAQ,cAAc,eAAe,QACrD,EAAmB,KAAK,CACtB,aAAc,uBACd,aAAc,EAAI,IACpB,CAAC,EAEH,IAAK,IAAM,KAAO,EAAQ,cAAc,gBAAgB,QACtD,EAAmB,KAAK,CACtB,aAAc,wBACd,aAAc,EAAI,IACpB,CAAC,EAEH,OAAO,CACT,CAqBA,SAAS,kBAAkB,EAA2B,EAAmC,CACvF,IAAM,EAAa,EACnB,IAAK,IAAM,IAAgB,CAAC,UAAW,gBAAiB,eAAe,EAAG,CACxE,IAAM,EAAU,EAAW,GAC3B,GAAI,GAAW,OAAO,GAAY,UAAY,KAAS,EAAS,CAC9D,IAAM,EAAS,EAAoC,GACnD,OAAO,GAAS,KAAO,IAAA,GAAY,OAAO,CAAK,CACjD,CACF,CAEA,IAAM,EAAQ,EAAW,GACzB,OAAO,GAAS,KAAO,IAAA,GAAY,OAAO,CAAK,CACjD,CAEA,SAAS,oBAAoB,EAA6B,EAAmC,CAI3F,OAHI,EAAM,QACD,EAAM,QAAQ,CAAI,EAEnB,EAAiB,IAC3B,CAEA,SAAS,mBAAmB,EAA6B,EAAmC,CAC1F,IAAM,EAAY,EAAM,iBACpB,IAAK,GAAU,kBAAkB,EAAM,CAAK,CAAC,CAAC,CAC/C,KAAM,GAAU,IAAU,IAAA,EAAS,EAChC,EAAO,oBAAoB,EAAO,CAAI,EAC5C,OAAO,IAAc,IAAA,GAEjB,GAAG,EAAM,aAAa,GAAG,IADzB,GAAG,EAAM,aAAa,GAAG,EAAU,GAAG,GAE5C,CAEA,SAAS,yBACP,EACA,EACoB,CACpB,GAAI,CAAC,EAAM,2BACT,OAEF,IAAM,EAAY,EAAM,iBACpB,IAAK,GAAU,kBAAkB,EAAM,CAAK,CAAC,CAAC,CAC/C,KAAM,GAAU,IAAU,IAAA,EAAS,EACtC,OAAO,IAAc,IAAA,GAAiE,IAAA,GAArD,GAAG,EAAM,2BAA2B,GAAG,GAC1E,CAEA,SAAS,yBACP,EACA,EACA,EACM,CACN,EAAO,IAAI,mBAAmB,EAAO,CAAI,CAAC,EAC1C,IAAM,EAAoB,yBAAyB,EAAO,CAAI,EAC1D,GACF,EAAO,IAAI,CAAiB,CAEhC,CAEA,SAAS,yBACP,EACA,EACA,EACS,CACT,GAAI,EAAO,IAAI,mBAAmB,EAAO,CAAI,CAAC,EAC5C,MAAO,GAET,IAAM,EAAoB,yBAAyB,EAAO,CAAI,EAC9D,OAAO,EAAoB,EAAO,IAAI,CAAiB,EAAI,EAC7D,CAEA,SAAS,wBACP,EACA,EACM,CACN,IAAI,EAAa,EACjB,IAAK,IAAM,KAAQ,EAAM,UAAU,QAAS,CAC1C,GAAI,yBAAyB,EAAa,EAAO,CAAI,EAAG,CACtD,EAAO,MACL,sBAAsB,mBAAmB,EAAO,CAAI,EAAE,kDACxD,EACA,QACF,CACA,EAAM,UAAU,QAAQ,GAAc,EACtC,GAAc,CAChB,CACA,EAAM,UAAU,QAAQ,OAAS,CACnC,CAEA,SAAS,yBAAyB,EAAsD,CACtF,IAAM,EAAW,IAAI,IACrB,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAgB,EAA+C,aAChE,SAAM,QAAQ,CAAY,EAG/B,IAAK,IAAM,KAAW,EAChB,OAAO,GAAY,UACrB,EAAS,IAAI,CAAO,CAG1B,CACA,MAAO,CAAC,GAAG,CAAQ,CAAC,CAAC,IAAK,IAAU,CAAE,MAAK,EAAE,CAC/C,CAEA,SAAS,iCAAiC,EAA4C,CACpF,MAAO,CACL,UAAW,CACT,QAAS,yBAAyB,EAAQ,SAAS,UAAU,OAAO,EACpE,QAAS,yBAAyB,EAAQ,SAAS,UAAU,OAAO,EACpE,SAAU,yBAAyB,EAAQ,SAAS,UAAU,QAAQ,EACtE,UAAW,CAAC,GAAG,EAAQ,SAAS,yBAAyB,CAAC,CAAC,IAAK,IAAU,CAAE,MAAK,EAAE,EACnF,QAAS,EAAQ,SAAS,kBAC5B,EACA,aAAc,wBACd,QAAU,GAAU,oBAAqB,EAAO,EAAK,gBAAkB,EAAK,IAC9E,CACF,CAEA,MAAM,EAAoC,CACxC,gBACA,gBACA,YACA,mBACF,EAQM,GAAsF,CAC1F,CACE,cAAe,cACf,aAAc,cACd,QAAU,GAAW,CAAC,EAAO,YAAY,IAAI,EAC7C,YAAc,GAAY,EAAQ,GACpC,EACA,CACE,cAAe,WACf,aAAc,WACd,QAAU,GACR,OAAO,OAAO,EAAO,YAAY,iBAAiB,WAAa,CAAC,CAAC,CAAC,CAAC,IAChE,GAAa,EAAS,IACzB,EACF,YAAc,GAAY,EAAQ,SAAS,SAC7C,EACA,CACE,cAAe,eACf,aAAc,wBACd,QAAU,GAAW,EAAO,eAAe,aAAa,KAAK,EAC7D,YAAc,GAAY,iCAAiC,CAAO,CAAC,CAAC,UACpE,QAAU,GAAU,oBAAqB,EAAO,EAAK,gBAAkB,EAAK,IAC9E,EACA,CACE,cAAe,WACf,aAAc,WACd,QAAU,GACR,OAAO,OAAO,EAAO,YAAY,iBAAiB,WAAa,CAAC,CAAC,CAAC,CAAC,IAChE,GAAa,EAAS,IACzB,EACF,YAAc,GAAY,EAAQ,SAAS,SAC7C,EACA,CACE,cAAe,4BACf,aAAc,yCACd,QAAU,GACR,OAAO,OAAO,EAAO,OAAO,UAAU,mBAAqB,CAAC,CAAC,CAAC,CAAC,IAAK,GAAW,EAAO,IAAI,EAC5F,YAAc,GAAY,EAAQ,wBAAwB,SAC5D,EACA,CACE,cAAe,kBACf,aAAc,kBACd,gBAAiB,EACjB,2BAA4B,eAC5B,QAAU,GAAW,OAAO,KAAK,EAAO,YAAY,aAAa,aAAe,CAAC,CAAC,EAClF,YAAc,GAAY,EAAQ,KAAK,UAAU,UACnD,EACA,CACE,cAAe,gBACf,aAAc,gBACd,QAAU,GAAW,EAAO,YAAY,sBAAsB,IAAK,GAAY,EAAQ,IAAI,EAC3F,YAAc,GAAY,EAAQ,cAAc,SAClD,EACA,CACE,cAAe,qBACf,aAAc,mBACd,QAAU,GAAW,EAAO,YAAY,iBAAiB,IAAK,GAAY,EAAQ,SAAS,EAC3F,YAAc,GAAY,EAAQ,SAAS,UAAU,OACvD,EACA,CACE,cAAe,iBACf,aAAc,eACd,QAAU,GAAW,CACnB,IAAM,EAAO,EAAO,YAAY,aAAa,OAAO,KACpD,OAAO,IAAS,IAAA,GAAY,CAAC,EAAI,CAAC,CAAI,CACxC,EACA,YAAc,GAAY,EAAQ,KAAK,UAAU,OACnD,EACA,CACE,cAAe,gBACf,aAAc,cACd,QAAU,GAAW,EAAO,YAAY,YAAY,IAAK,GAAQ,EAAI,IAAI,EACzE,YAAc,GAAY,EAAQ,IAAI,UAAU,OAClD,EACA,CACE,cAAe,qBACf,aAAc,mBACd,QAAU,GAAW,EAAO,YAAY,iBAAiB,IAAK,GAAY,EAAQ,SAAS,EAC3F,YAAc,GAAY,EAAQ,SAAS,UAAU,OACvD,EACA,CACE,cAAe,YACf,aAAc,YACd,QAAU,GAAW,EAAO,YAAY,kBAAkB,IAAK,GAAY,EAAQ,IAAI,EACvF,YAAc,GAAY,EAAQ,UAAU,SAC9C,EACA,CACE,cAAe,uBACf,aAAc,eACd,QAAU,GAAW,EAAO,YAAY,QAAQ,IAAK,GAAU,EAAM,SAAS,EAC9E,YAAc,GAAY,EAAQ,cAAc,cAClD,CACF,EAEA,SAAS,mCACP,EACA,EACsB,CACtB,GAAM,CAAE,cAAa,QAAS,EAAU,cAAe,EAAgB,GAAG,GAAU,EACpF,MAAO,CACL,GAAG,EACH,UAAW,EAAY,CAAO,CAChC,CACF,CAEA,SAAS,sBAAsB,EAA8C,CAC3E,MAAO,CACL,CAAE,UAAW,EAAQ,iBAAiB,UAAW,aAAc,mBAAoB,EACnF,GAAG,GAAoC,IAAK,GAC1C,mCAAmC,EAAY,CAAO,CACxD,EACA,CACE,UAAW,EAAQ,SAAS,UAAU,KACtC,aAAc,gBACd,gBAAiB,EACjB,2BAA4B,kBAC9B,EACA,CACE,UAAW,EAAQ,SAAS,UAAU,cACtC,aAAc,0BACd,gBAAiB,EACjB,2BAA4B,kBAC9B,EACA,CACE,UAAW,EAAQ,cAAc,sBACjC,aAAc,8BACd,gBAAiB,EACjB,2BAA4B,eAC9B,EACA,CACE,UAAW,EAAQ,IAAI,UAAU,OACjC,aAAc,aACd,gBAAiB,EACjB,2BAA4B,aAC9B,EACA,CACE,UAAW,EAAQ,KAAK,UAAU,UAClC,aAAc,kBACd,gBAAiB,EACjB,2BAA4B,cAC9B,EACA,CACE,UAAW,EAAQ,KAAK,UAAU,kBAClC,aAAc,2BACd,gBAAiB,EACjB,2BAA4B,cAC9B,EACA,CACE,UAAW,EAAQ,KAAK,UAAU,aAClC,aAAc,qBACd,gBAAiB,EACjB,2BAA4B,cAC9B,EACA,CACE,UAAW,EAAQ,KAAK,UAAU,YAClC,aAAc,oBACd,gBAAiB,EACjB,2BAA4B,cAC9B,EACA,CACE,UAAW,EAAQ,KAAK,UAAU,aAClC,aAAc,qBACd,gBAAiB,EACjB,2BAA4B,cAC9B,EACA,CACE,UAAW,EAAQ,KAAK,UAAU,SAClC,aAAc,YACd,gBAAiB,EACjB,2BAA4B,cAC9B,EACA,CACE,UAAW,EAAQ,KAAK,UAAU,KAClC,aAAc,YACd,gBAAiB,EACjB,2BAA4B,cAC9B,EACA,CACE,UAAW,EAAQ,KAAK,UAAU,aAClC,aAAc,qBACd,gBAAiB,EACjB,2BAA4B,cAC9B,EACA,CACE,UAAW,EAAQ,SAAS,UAAU,SACtC,aAAc,oBACd,gBAAiB,EACjB,2BAA4B,kBAC9B,EACA,CACE,UAAW,EAAQ,cAAc,gBACjC,aAAc,gBACd,gBAAiB,EACjB,2BAA4B,cAC9B,CACF,CACF,CAEA,SAAgB,kCACd,EACM,CACN,IAAM,EAAqB,EAAY,IAAK,GAC1C,sBAAsB,sBAAsB,CAAU,CAAC,CACzD,EACM,EAAqB,EAAmB,IAAK,GACjD,EAAO,QAAQ,EAAQ,IAAU,CAC/B,IAAK,IAAM,IAAQ,CACjB,GAAG,EAAM,UAAU,QACnB,GAAG,EAAM,UAAU,QACnB,GAAG,EAAM,UAAU,SACnB,GAAG,EAAM,UAAU,SACrB,EACE,yBAAyB,EAAQ,EAAO,CAAI,EAE9C,OAAO,CACT,EAAG,IAAI,GAAa,CACtB,EAEA,EAAmB,SAAS,EAAQ,IAAoB,CACtD,IAAM,EAAc,IAAI,IACxB,EAAmB,SAAS,EAAQ,IAAe,CAC7C,OAAe,EAGnB,IAAK,IAAM,KAAS,EAClB,EAAY,IAAI,CAAK,CAEzB,CAAC,EAED,IAAK,IAAM,KAAS,EAClB,wBAAwB,EAAO,CAAW,CAE9C,CAAC,CACH,CAEA,SAAgB,gCACd,EACa,CACb,IAAM,EAAS,IAAI,IACnB,IAAK,IAAM,KAAc,EACvB,IAAK,IAAM,KAAS,sBAAsB,sBAAsB,CAAU,CAAC,EACzE,EAAO,IAAI,CAAK,EAGpB,OAAO,CACT,CCngBA,SAAS,iBACP,EAC0B,CAC1B,IAAM,EAAU,IAAI,IACpB,IAAK,IAAM,KAAe,EAIxB,GAHA,EAAQ,IAAI,GAAG,GAAgB,IAAI,EAAY,OAAQ,EACpD,IAAkB,EAAY,IACjC,CAAC,EACG,EAAY,GAAI,CAClB,IAAM,EAAQ,mBAAmB,EAAY,EAAE,EAC/C,EAAQ,IAAI,GAAG,GAAiB,IAAI,IAAS,EAAG,IAAmB,CAAM,CAAC,CAC5E,CAEF,MAAO,CAAC,GAAG,EAAQ,OAAO,CAAC,CAC7B,CAYA,eAAsB,2BACpB,EACyB,CACzB,GAAM,CAAE,SAAQ,cAAa,gBAAiB,EACxC,EAAQ,MAAM,QAAQ,IAC1B,iBAAiB,CAAY,CAAC,CAAC,IAAK,GAClC,EAAiB,MAAO,EAAW,IAAgB,CACjD,GAAM,CAAE,UAAS,iBAAkB,MAAM,EAAO,aAAa,CAC3D,cACA,SACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAS,CAAa,CAChC,CAAC,CACH,CACF,EACM,EAAgB,IAAI,IAC1B,IAAK,IAAM,KAAU,EAAM,KAAK,EAC1B,EAAO,UAAU,EAAc,IAAI,EAAO,IAAK,EAAO,QAAQ,EAGpE,IAAM,EAAgB,IAAI,IACpB,aAA8C,EAAS,IAAY,CACvE,IAAM,EAAW,EAAc,IAAI,EAAQ,KAAO,EAAE,EACpD,GAAI,EACF,OAAO,QAAQ,QAAQ,GAAO,GAA2B,CAAE,UAAS,CAAC,CAAC,EAExE,IAAM,EAAM,EAAQ,KAAO,GACvB,EAAW,EAAc,IAAI,CAAG,EAKpC,OAJK,IACH,EAAW,EAAO,YAAY,EAAS,CAAO,EAC9C,EAAc,IAAI,EAAK,CAAQ,GAE1B,CACT,EAEA,OAAO,IAAI,MAAM,EAAQ,CACvB,IAAI,EAAQ,EAAU,EAAU,CAC9B,OAAO,IAAa,cAAgB,YAAc,QAAQ,IAAI,EAAQ,EAAU,CAAQ,CAC1F,CACF,CAAC,CACH,CCrCA,SAAS,gBAAgB,EAAkC,CACzD,IAAM,EAAkB,4BACtB,EAAQ,SAAS,UACjB,4BAA4B,EAAQ,SAAS,SAAS,EACtD,EAAQ,iBAAiB,uBAC3B,EACM,EAAkB,4BACtB,EAAQ,SAAS,UAAU,SAC3B,EAAQ,iBAAiB,uBAC3B,EACM,EAAkB,4BACtB,EAAQ,SAAS,UACjB,EAAQ,iBAAiB,kBAC3B,EACM,EAAiC,uBACrC,EAAQ,wBAAwB,UAChC,CAAC,iBAAiB,CACpB,EACM,EAAkB,4BACtB,EAAQ,KAAK,UAAU,SACvB,EAAQ,iBAAiB,uBAC3B,EACM,EAA0B,oCAC9B,EAAQ,SAAS,UAAU,KAC3B,EAAQ,SAAS,UAAU,aAC7B,EACM,EACJ,EAAQ,SAAS,QAAQ,kBAAkB,IAAK,IAAY,CAC1D,OAAQ,SACR,OAAQ,GAAe,OACvB,KAAM,wBAAwB,sBAAsB,EAAO,IAAI,EAAE,KAAK,sBAAsB,EAAO,EAAE,IACrG,OAAQ,CAAC,qBAAqB,EAC9B,UAAW,EAAO,SACpB,EAAE,EACE,EAAyC,CAC7C,GAAG,EACH,GAAG,CACL,EACM,EAAyC,CAAC,GAAG,CAAe,EAC5D,YAAe,GAAkB,CACrC,GACE,YAAa,GACb,EAAK,SACL,OAAO,EAAK,SAAY,UACxB,kBAAmB,EAAK,QAExB,OAAO,EAAK,QAAQ,cAEtB,GAAI,kBAAmB,EACrB,OAAO,EAAK,aAGhB,EACM,gBAAmB,GACvB,YAAa,GACb,EAAK,SACL,OAAO,EAAK,SAAY,UACxB,kBAAmB,EAAK,QACnB,EAAK,QAAQ,cACd,IAAA,GACA,EAAoC,CACxC,GAAG,uBAAuB,EAAQ,IAAI,UAAU,OAAQ,CAAC,QAAQ,EAAG,WAAW,CACjF,EACM,EAAqC,CACzC,GAAG,uBAAuB,EAAQ,KAAK,UAAU,UAAW,CAAC,WAAW,EAAG,WAAW,EACtF,GAAG,uBACD,EAAQ,KAAK,UAAU,kBACvB,CAAC,mBAAmB,EACpB,WACF,EACA,GAAG,uBAAuB,EAAQ,KAAK,UAAU,aAAc,CAAC,cAAc,EAAG,WAAW,EAC5F,GAAG,uBAAuB,EAAQ,KAAK,UAAU,YAAa,CAAC,aAAa,EAAG,eAAe,EAC9F,GAAG,EACH,GAAG,uBAAuB,EAAQ,KAAK,UAAU,aAAc,CAAC,cAAc,EAAG,WAAW,EAC5F,GAAG,uBAAuB,EAAQ,KAAK,UAAU,KAAM,CAAC,YAAY,EAAG,WAAW,EAClF,GAAG,uBAAuB,EAAQ,KAAK,UAAU,aAAc,CAAC,cAAc,EAAG,WAAW,EAC5F,GAAG,uBAAuB,EAAQ,KAAK,UAAU,WAAY,CAAC,YAAY,EAAG,WAAW,CAC1F,EAEM,CAAE,aAAc,GAAiC,6BACrD,EAAQ,iBAAiB,SAC3B,EACM,EAAyB,sBAAsB,EAAQ,SAAS,UAAU,OAAO,EACjF,EAAyB,sBAAsB,EAAQ,SAAS,UAAU,OAAO,EACjF,EAAoB,sBAAsB,EAAQ,IAAI,UAAU,OAAO,EACvE,EAAqB,sBAAsB,EAAQ,KAAK,UAAU,OAAO,EAEzE,EAAoB,CACxB,GAAG,EACH,GAAG,EACH,GAAG,EACH,GAAG,EACH,GAAG,EACH,GAAG,EACH,GAAG,CACL,EAOM,EAAU,qBAAqB,EAAS,EAAmB,CAL/D,GAAG,EACH,GAAG,EACH,GAAG,EACH,GAAG,CAE4E,CAAC,EAE5E,EAAe,CACnB,GAAG,EAAQ,iBAAiB,UAC5B,GAAG,EAAQ,SAAS,UACpB,GAAG,EAAQ,cAAc,UACzB,GAAG,EAAQ,UAAU,UACrB,GAAG,EAAQ,IAAI,UACf,GAAG,EAAQ,KAAK,UAChB,GAAG,EAAQ,SAAS,UACpB,GAAG,EAAQ,SAAS,UACpB,GAAG,EAAQ,SAAS,UACpB,GAAG,EAAQ,cAAc,SAC3B,EACM,EAAe,CACnB,GAAG,EAAQ,iBAAiB,UAC5B,GAAG,EAAQ,SAAS,UACpB,GAAG,EAAQ,cAAc,UACzB,GAAG,EAAQ,UAAU,UACrB,GAAG,EAAQ,IAAI,UACf,GAAG,EAAQ,KAAK,UAChB,GAAG,EAAQ,SAAS,UACpB,GAAG,EAAQ,SAAS,UACpB,GAAG,EAAQ,SAAS,UACpB,GAAG,EAAQ,cAAc,SAC3B,EAoCM,EAAU,CAjCd,GAAG,EACH,GAAG,EAAuB,KAAK,CAAE,SAAQ,WAAY,CACnD,SACA,OACA,OAAQ,CAAC,UAAU,EACnB,UAAW,IAAA,EACb,EAAE,EACF,GAAG,EAAuB,KAAK,CAAE,SAAQ,WAAY,CACnD,SACA,OACA,OAAQ,CAAC,UAAU,EACnB,UAAW,IAAA,EACb,EAAE,EACF,GAAG,EAAkB,KAAK,CAAE,SAAQ,WAAY,CAC9C,SACA,OACA,OAAQ,CAAC,KAAK,EACd,UAAW,IAAA,EACb,EAAE,EACF,GAAG,EAAmB,KAAK,CAAE,SAAQ,WAAY,CAC/C,SACA,OACA,OAAQ,CAAC,MAAM,EACf,UAAW,IAAA,EACb,EAAE,EACF,GAAG,uBAAuB,CAA4B,EACtD,GAAG,uBAAuB,EAAQ,cAAc,UAAW,CAAC,eAAe,CAAC,EAC5E,GAAG,uBAAuB,EAAQ,cAAc,sBAAuB,CAAC,cAAc,CAAC,EACvF,GAAG,uBAAuB,EAAQ,UAAU,UAAW,CAAC,WAAW,CAAC,EACpE,GAAG,uBAAuB,EAAQ,IAAK,CAAC,aAAa,CAAC,EACtD,GAAG,uBAAuB,EAAQ,cAAc,eAAgB,CAAC,OAAO,CAAC,EACzE,GAAG,uBAAuB,EAAQ,cAAc,gBAAiB,CAAC,QAAQ,CAAC,CAEpD,CAAC,CAAC,KAAK,CAAE,SAAQ,OAAM,SAAQ,gBAAiB,CACvE,SACA,OACA,SACA,WACF,EAAE,EACI,EAAW,CACf,GAAG,EAAa,KAAK,CAAE,eAAc,mBAAoB,CACvD,KAAM,YACN,eACA,KAAM,CACR,EAAE,EACF,GAAG,EAAQ,cAAc,eAAe,IAAK,IAAU,CACrD,KAAM,gBACN,aAAc,SACd,MACF,EAAE,CACJ,EACM,EAAY,EAAa,KAAK,CAAE,eAAc,eAAc,mBAAoB,CACpF,eACA,KAAM,EACN,cACF,EAAE,EAEI,EAAqB,CACzB,GAAG,yBACD,EAAQ,iBAAiB,UAAU,MACnC,uBAAuB,CAA4B,CACrD,EACA,GAAG,EAAQ,cAAc,UAAU,MAAM,EACzC,GAAG,EAAQ,cAAc,sBAAsB,MAAM,EACrD,GAAG,EAAQ,UAAU,UAAU,MAAM,EACrC,GAAG,EAAQ,IAAI,MAAM,EACrB,GAAG,yBAAyB,WAAY,EAAiB,CAAsB,EAC/E,GAAG,yBAAyB,WAAY,EAAiB,CAAsB,EAC/E,GAAG,yBAAyB,WAAY,CAAe,EACvD,GAAG,yBAAyB,WAAY,CAAe,EACvD,GAAG,yBAAyB,MAAO,EAAY,CAAiB,EAChE,GAAG,yBAAyB,OAAQ,EAAa,CAAkB,EACnE,GAAG,EAAQ,cAAc,eAAe,MAAM,EAC9C,GAAG,EAAQ,cAAc,gBAAgB,MAAM,CACjD,EAEA,GAAI,EAAa,OAAS,EAAG,CAC3B,EAAS,KAAK,EAAO,KAAK,sCAAsC,CAAC,EACjE,IAAK,GAAM,CAAE,eAAc,kBAAkB,EAC3C,EAAS,KAAK,KAAK,EAAO,QAAQ,GAAG,EAAE,GAAG,EAAO,KAAK,CAAY,EAAE,IAAI,EAAa,EAAE,CAE3F,CAEA,GAAI,EAAQ,cAAc,eAAe,OAAS,EAAG,CACnD,EAAS,KAAK,EAAO,KAAK,uDAAuD,CAAC,EAClF,IAAK,IAAM,KAAQ,EAAQ,cAAc,eACvC,EAAS,KAAK,KAAK,EAAO,IAAI,GAAG,EAAE,GAAG,GAAM,CAEhD,CAEA,GAAI,EAAa,OAAS,EAAG,CAC3B,EAAS,KAAK,EAAO,KAAK,uDAAuD,CAAC,EAClF,IAAK,GAAM,CAAE,eAAc,eAAc,kBAAkB,EACzD,EAAS,KACP,KAAK,EAAO,QAAQ,GAAG,EAAE,GAAG,EAAO,KAAK,CAAY,EAAE,IAAI,EAAa,gBAAgB,EAAa,EACtG,CAEJ,CAIA,OAFA,EAAS,KAAK,kBAAkB,CAAO,CAAC,EAEjC,CACL,UACA,KAAM,CAAE,UAAS,UAAS,WAAU,WAAU,EAC9C,MAAO,CACT,CACF,CAUA,SAAgB,iBAAiB,EAAsB,EAAsC,CAC3F,IAAM,EAAS,gBAAgB,CAAO,EAEtC,GAAI,EAAO,UAAY,GAAM,OAE3B,OADA,EAAO,IAAI,EAAO,IAAI,EACf,EAAO,QAGhB,IAAM,EAAS,EAAO,MAAM,KAAK;CAAI,EAOrC,OANI,GAAM,OACR,EAAO,IAAI,CAAM,EAEjB,EAAO,IAAI,CAAM,EAGZ,EAAO,OAChB,CASA,SAAgB,qBACd,EACA,EACA,EACa,CACb,IAAM,EAAuB,CAAE,OAAQ,EAAG,OAAQ,EAAG,OAAQ,EAAG,QAAS,CAAE,EAG3E,IAAK,IAAM,KAAS,EAClB,EAAQ,EAAM,SAAW,EAI3B,IAAK,IAAM,KAAM,EACf,EAAQ,EAAG,SAAW,EAIxB,GAAM,CAAE,gBAAiB,6BAA6B,EAAQ,iBAAiB,SAAS,EAClF,EAAa,oBAAoB,CACrC,EACA,EAAQ,cAAc,UACtB,EAAQ,cAAc,sBACtB,EAAQ,UAAU,UAClB,EAAQ,IACR,EAAQ,cAAc,eACtB,EAAQ,cAAc,eACxB,CAAC,EAMD,MALA,GAAQ,QAAU,EAAW,OAC7B,EAAQ,QAAU,EAAW,OAC7B,EAAQ,QAAU,EAAW,OAC7B,EAAQ,SAAW,EAAW,QAEvB,CACT,CACA,SAAS,iBAAiB,EAAoD,CAC5E,OAAO,EAAU,QACd,EAAK,KAAa,CACjB,OAAQ,EAAI,OAAS,EAAQ,OAC7B,OAAQ,EAAI,OAAS,EAAQ,OAC7B,OAAQ,EAAI,OAAS,EAAQ,OAC7B,QAAS,EAAI,QAAU,EAAQ,OACjC,GACA,CAAE,OAAQ,EAAG,OAAQ,EAAG,OAAQ,EAAG,QAAS,CAAE,CAChD,CACF,CAEA,SAAgB,qBACd,EACA,EACa,CACb,GAAI,EAAO,UAAY,GAAM,OAAQ,CACnC,IAAM,EAAU,EAAY,IAAK,GAC/B,gBAAgB,sBAAsB,CAAU,CAAC,CACnD,EACM,EAAU,iBAAiB,EAAQ,IAAK,GAAW,EAAO,OAAO,CAAC,EAOxE,OANA,EAAO,IAAI,CACT,UACA,QAAS,EAAQ,QAAS,GAAW,EAAO,KAAK,OAAO,EACxD,SAAU,EAAQ,QAAS,GAAW,EAAO,KAAK,QAAQ,EAC1D,UAAW,EAAQ,QAAS,GAAW,EAAO,KAAK,SAAS,CAC9D,CAAC,EACM,CACT,CAKA,OAAO,iBAHW,EAAY,IAAK,GACjC,iBAAiB,sBAAsB,CAAU,EAAG,CAAI,CAE1B,CAAC,CACnC,CC/RA,MAAM,GAAa,IAAI,IAMvB,SAAS,aAAa,EAAgC,CACpD,IAAM,EAAS,GAAW,IAAI,EAAO,QAAQ,EAC7C,GAAI,EACF,OAAO,EAET,IAAM,EAAY,GAAgB,CAAE,SAAU,GAAe,EAAQ,GAAG,GAAU,CAAM,CAAC,CAAE,CAAC,EAE5F,OADA,GAAW,IAAI,EAAO,SAAU,CAAS,EAClC,CACT,CAEA,SAAS,cAAwC,EAAyC,CACxF,GAAM,CAAE,SAAQ,OAAM,SAAQ,QAAO,aAAY,cAAe,EAChE,GAAI,EAAM,SAAW,EACnB,OAEF,IAAM,EAAY,aAAa,CAAM,EACrC,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAQ,EAAiC,GACzC,EAAM,GAAO,EAAQ,CAAa,EAClC,EAAS,EAAU,SAAS,EAAQ,CAAG,EAC7C,GAAI,EAAO,OAAS,UAClB,IAAK,IAAM,KAAK,EAAO,WACrB,EAAW,KAAK,CACd,OACA,KAAM,EAAK,KACX,SACA,UAAW,EAAE,MAAM,OAAS,EAAI,GAAa,EAAE,KAAK,EAAI,YACxD,QAAS,EAAE,OACb,CAAC,OAEM,EAAO,OAAS,SAEzB,EAAO,KAAK,sBAAsB,EAAK,IAAI,EAAK,KAAK,KAAK,EAAO,KAAK,EAAO,MAAM,SAAS,CAEhG,CACF,CAwBA,eAAsB,aAAa,EAAyC,CAC1E,GAAM,CACJ,WACA,gBACA,YACA,MACA,OACA,WACA,MACA,WACA,WACA,0BACA,iBACE,EAEE,EAA+B,CAAC,EAEtC,SAAS,QACP,EACA,EACA,EACM,CACN,cAAc,CACZ,SACA,OACA,OAAQ,SACR,QACA,WAAY,UACZ,YACF,CAAC,CACH,CAEA,SAAS,QACP,EACA,EACA,EACM,CACN,cAAc,CACZ,SACA,OACA,OAAQ,SACR,QACA,WAAY,UACZ,YACF,CAAC,CACH,CAEA,SAAS,SACP,EACA,EACA,EACM,CACN,cAAc,CACZ,SACA,OACA,OAAQ,UACR,QACA,WAAY,gBACZ,YACF,CAAC,CACH,CAEA,SAAS,gBACP,EACA,EACA,EACM,CACN,cAAc,CACZ,SACA,OACA,OAAQ,UACR,QACA,WAAY,gBACZ,YACF,CAAC,CACH,CAGA,QACE,GACA,mBACA,EAAS,UAAU,QAAQ,OAC7B,EAEA,QACE,GACA,iBACA,EAAS,UAAU,KAAK,OAC1B,EACA,QACE,GACA,iBACA,EAAS,UAAU,KAAK,OAC1B,EAEA,QACE,EACA,gBACA,EAAc,UAAU,OAC1B,EACA,QACE,GACA,gBACA,EAAc,UAAU,OAC1B,EACA,QACE,GACA,8BACA,EAAc,sBAAsB,OACtC,EAGA,QACE,GACA,YACC,EAAU,UAAU,QAAyB,IAAK,IAAU,CAC3D,KAAM,EAAK,KACX,QAAS,CAAE,GAAI,EAAK,QAAqC,KAAM,IAAA,EAAU,CAC3E,EAAE,CACJ,EACA,QACE,GACA,YACC,EAAU,UAAU,QAAyB,IAAK,IAAU,CAC3D,KAAM,EAAK,KACX,QAAS,CAAE,GAAI,EAAK,QAAqC,KAAM,IAAA,EAAU,CAC3E,EAAE,CACJ,EAOA,IACM,2BAA8B,GAAiC,CACnE,IAAM,EAAU,EAAK,QACf,EAAU,EAAQ,gBAAgB,qBACxC,GAAI,CAAC,MAAM,QAAQ,CAAO,GAAK,EAAQ,SAAW,EAChD,OAAO,EAMT,IAAM,EAAc,EAAQ,IAAK,GAC/B,OAAO,GAAW,UAAY,wCAAwC,KAAK,CAAM,EAC7E,8BACA,CACN,EACA,MAAO,CACL,GAAG,EACH,QAAS,CACP,GAAG,EACH,eAAgB,CAAE,GAAG,EAAQ,eAAgB,qBAAsB,CAAY,CACjF,CACF,CACF,EACA,QACE,EACA,cACC,EAAI,UAAU,QAAQ,QAAyB,IAAI,0BAA0B,CAChF,EACA,QACE,GACA,cACC,EAAI,UAAU,QAAQ,QAAyB,IAAI,0BAA0B,CAChF,EAIA,IAAM,EAAsB,CAC1B,GAAG,EAAI,UAAU,OAAO,QAAQ,IAAK,IAAO,CAC1C,WAAY,EAAE,QAAQ,QAAQ,MAAQ,GACtC,cAAe,EAAE,QAAQ,eAAiB,GAC1C,YAAa,EAAE,QAAQ,aAAe,EACxC,EAAE,EACF,GAAG,EAAI,UAAU,OAAO,QAAQ,IAAK,IAAO,CAC1C,WAAY,EAAE,KACd,cAAe,EAAE,cACjB,YAAa,EAAE,WACjB,EAAE,CACJ,EACA,QACE,EACA,oBACA,EAAoB,IAAK,IAAU,CACjC,KAAM,EAAK,WACX,QAAS,CACP,YAAa,EAAK,YAClB,uBAAwB,mBAAmB,EAAK,cAAe,EAAK,UAAU,CAChF,CACF,EAAE,CACJ,EACA,QACE,EACA,oBACA,EAAoB,IAAK,IAAU,CACjC,KAAM,EAAK,WACX,QAAS,CACP,YAAa,EAAK,YAClB,uBAAwB,mBAAmB,EAAK,cAAe,EAAK,UAAU,EAC9E,wBAAyB,oBAAoB,EAAK,cAAe,EAAK,UAAU,CAClF,CACF,EAAE,CACJ,EAEA,QACE,GACA,eACA,EAAK,UAAU,QAAQ,OACzB,EACA,QACE,GACA,eACA,EAAK,UAAU,QAAQ,OACzB,EAEA,QACE,GACA,kBACA,EAAK,UAAU,UAAU,OAC3B,EACA,QACE,GACA,kBACA,EAAK,UAAU,UAAU,OAC3B,EAEA,QACE,GACA,2BACA,EAAK,UAAU,kBAAkB,OACnC,EACA,QACE,GACA,2BACA,EAAK,UAAU,kBAAkB,OACnC,EAEA,QACE,GACA,qBACA,EAAK,UAAU,aAAa,OAC9B,EACA,QACE,GACA,qBACA,EAAK,UAAU,aAAa,OAC9B,EAEA,QACE,GACA,oBACA,EAAK,UAAU,YAAY,OAC7B,EACA,QACE,GACA,oBACA,EAAK,UAAU,YAAY,OAC7B,EAEA,QACE,GACA,YACA,EAAK,UAAU,SAAS,OAC1B,EACA,QACE,GACA,YACA,EAAK,UAAU,SAAS,OAC1B,EAEA,QACE,GACA,mBACA,EAAK,UAAU,KAAK,OACtB,EACA,QACE,GACA,mBACA,EAAK,UAAU,KAAK,OACtB,EAEA,QACE,GACA,qBACA,EAAK,UAAU,aAAa,OAC9B,EACA,QACE,GACA,qBACA,EAAK,UAAU,aAAa,OAC9B,EAEA,QACE,GACA,gBACA,EAAK,UAAU,aAAa,OAC9B,EACA,QACE,GACA,gBACA,EAAK,UAAU,aAAa,OAC9B,EACA,SACE,GACA,gBACA,EAAK,UAAU,aAAa,QAC9B,EAEA,QACE,EACA,mBACA,EAAS,UAAU,QAAQ,OAC7B,EACA,QACE,GACA,mBACA,EAAS,UAAU,QAAQ,OAC7B,EACA,QACE,GACA,WACA,EAAS,UAAU,SAAS,OAC9B,EACA,QACE,EACA,WACA,EAAS,UAAU,SAAS,OAC9B,EAEA,QACE,GACA,WACA,EAAS,UAAU,OACrB,EACA,QACE,GACA,WACA,EAAS,UAAU,OACrB,EAEA,QACE,GACA,WACA,EAAS,UAAU,QAAQ,IAAK,IAAU,CACxC,KAAM,EAAK,KACX,QAAS,6BAA6B,EAAK,YAAa,EAAK,QAAQ,CACvE,EAAE,CACJ,EACA,QACE,GACA,WACA,EAAS,UAAU,QAAQ,IAAK,IAAU,CACxC,KAAM,EAAK,KACX,QAAS,6BAA6B,EAAK,YAAa,EAAK,QAAQ,CACvE,EAAE,CACJ,EAGA,IAAM,EACJ,EAAS,UAAU,QAAQ,EAAE,EAAE,aAAe,EAAS,UAAU,QAAQ,EAAE,EAAE,aAAe,GAC9F,GAAI,EAA4B,CAC9B,IAAM,EAAc,IAAI,IACxB,IAAK,IAAM,IAAQ,CAAC,GAAG,EAAS,UAAU,QAAS,GAAG,EAAS,UAAU,OAAO,EAC9E,IAAK,IAAM,KAAW,EAAK,aACzB,EAAY,IAAI,CAAO,EAG3B,IAAK,IAAM,KAAW,EAAS,0BAC7B,EAAY,IAAI,CAAO,EAEzB,QACE,GACA,wBACA,CAAC,GAAG,CAAW,CAAC,CAAC,IAAK,IAAa,CACjC,KAAM,EACN,QAAS,CACP,YAAa,EACb,gBAAiB,EACjB,UAAW,CACb,CACF,EAAE,CACJ,CACF,CA+FA,GA7FA,QACE,GACA,4BAGA,CACE,GAAG,EAAwB,UAAU,QACrC,GAAG,EAAwB,UAAU,QACvC,CAAC,CAAC,IAAK,IAAU,CACf,KAAM,EAAK,KACX,QAAS,CACP,YAAa,EAAK,YAClB,oBAAqB,EAAK,OAAO,KACjC,mBAAoB,6BAA6B,EAAK,MAAM,EAC5D,GAAI,EAAK,OAAO,mBAAqB,CACnC,kBAAmB,CACjB,wBAAyB,EAAK,OAAO,kBAAkB,uBACzD,CACF,CACF,CACF,EAAE,CACJ,EACA,QACE,GACA,4BACA,EAAwB,UAAU,QAAQ,IAAK,IAAU,CACvD,KAAM,EAAK,KACX,QAAS,CACP,YAAa,EAAK,YAClB,oBAAqB,EAAK,OAAO,KACjC,GAAI,EAAK,OAAO,mBAAqB,CACnC,kBAAmB,CACjB,wBAAyB,EAAK,OAAO,kBAAkB,uBACzD,CACF,CACF,CACF,EAAE,CACJ,EAEA,QACE,EACA,uBACA,EAAc,eAAe,QAAQ,IAAK,IAAU,CAClD,KAAM,EAAK,KACX,QAAS,mBAAmB,CAAI,CAClC,EAAE,CACJ,EACA,QACE,EACA,wBACA,EAAc,gBAAgB,QAAQ,IAAK,IAAU,CACnD,KAAM,EAAK,KACX,QAAS,oBAAoB,CAAI,CACnC,EAAE,CACJ,EACA,QACE,GACA,wBACA,EAAc,gBAAgB,QAAQ,IAAK,IAAU,CACnD,KAAM,EAAK,KACX,QAAS,oBAAoB,CAAI,CACnC,EAAE,CACJ,EAGA,QACE,GACA,cACA,EAAI,QAAQ,IAAK,IAAU,CACzB,KAAM,EAAK,KACX,QAAS,CAAE,GAAG,EAAK,QAAS,KAAM,IAAA,EAAU,CAC9C,EAAE,CACJ,EACA,QACE,EACA,cACA,CAAC,GAAG,EAAI,QAAS,GAAG,EAAI,SAAS,CAAC,CAAC,IAAK,IAAU,CAChD,KAAM,EAAK,KACX,QAAS,CAAE,GAAG,EAAK,QAAS,KAAM,IAAA,EAAU,CAC9C,EAAE,CACJ,EAEA,QACE,GACA,kBACA,EAAK,UAAU,WAAW,OAC5B,EACA,gBACE,GACA,kBACA,EAAK,UAAU,WAAW,QAC5B,EAEI,EAAW,SAAW,EACxB,OAGF,IAAM,EAAgB,IAAI,IAAI,EAAW,IAAK,GAAM,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,CAAC,EAC1E,EAAO,MACL,+BAA+B,EAAW,OAAO,uBAAuB,EAAc,KAAK,cAC7F,EACA,IAAK,IAAM,KAAK,EACd,EAAO,IACL,KAAK,EAAO,aAAa,EAAE,IAAI,EAAE,GAAG,EAAO,aAAa,EAAE,IAAI,EAAE,IAC1D,EAAE,OAAO,MAAM,EAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,SACtD,EAGF,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,GAAG,EAAW,OAAO,gCAAgC,EAAc,KAAK,aACnF,CAAC,CACH,CCvpBA,SAAgB,aAAa,EAAsC,CACjE,OAAO,EAAO,IAAK,GAAU,EAAM,OAAO,CAAC,CAAC,KAAK,IAAI,GAAK,iBAC5D,CAEA,SAAgB,aACd,EACA,EACkB,CAClB,IAAM,EAAS,EAAO,UAAU,CAAO,EACvC,GAAI,CAAC,EAAO,QACV,MAAU,MAAM,aAAa,EAAO,MAAM,MAAM,CAAC,EAEnD,OAAO,EAAO,IAChB,CCbA,MAAa,GAAoB,EAAE,OAAO,CAAC,CAAC,IAAI,EAAG,2BAA2B,ECWjE,GAAsB,EAChC,OAAO,CAAC,CACR,IAAI,EAA2B,oCAA+D,CAAC,CAC/F,IAAI,GAA2B,oCAA8D,CAAC,CAC9F,MAAM,eAAgB,+DAAmE,CAAC,CAC1F,OACE,GAAS,CAAC,EAAK,WAAW,GAAG,GAAK,CAAC,EAAK,SAAS,GAAG,EACrD,wCACF,EAOF,SAAgB,sBAAsB,EAA6B,CACjE,IAAM,EAAS,GAAoB,UAAU,CAAI,EACjD,OAAO,EAAO,QAAU,GAAO,aAAa,EAAO,MAAM,MAAM,CACjE,CC5BA,MAAM,GAAa,mBAEb,GAAc,CAClB,EAAG,IACH,EAAG,IACH,EAAG,KACH,EAAG,KACL,EAEa,GAAS,EAAE,OAAO,CAAC,CAAC,MAAM,GAAY,CACjD,QAAS,4EACX,CAAC,EAOD,SAAgB,SAAS,EAAqB,CAC5C,IAAM,EAAQ,EAAI,MAAM,EAAU,EAClC,GAAI,CAAC,IAAQ,IAAM,CAAC,EAAM,GACxB,MAAM,EAAS,CACb,KAAM,oBACN,QAAS,uBAAuB,IAChC,QAAS,iBACX,CAAC,EAEH,IAAM,EAAO,EAAM,GACnB,OAAO,SAAS,EAAM,GAAI,EAAE,EAAI,GAAY,EAC9C,CC3BA,MAAa,GAAoB,iBAK3B,GAAwB,iBAU9B,SAAgB,aAAa,EAA6B,CACxD,MAAO,oBAAoB,GAC7B,CAOA,SAAgB,gBAAgB,EAAyB,CACvD,MAAO,KAAK,KAAK,MAAM,EAAU,QAAQ,EAAI,GAAI,GACnD,CAWA,SAAgB,gBAAgB,EAA6C,CAC3E,IAAM,EAAQ,GAAO,MAAM,EAAqB,EAChD,GAAI,CAAC,IAAQ,GAAI,OACjB,IAAM,EAAU,OAAO,EAAM,EAAE,EAC/B,GAAI,CAAC,OAAO,cAAc,CAAO,EAAG,OACpC,IAAM,EAAY,IAAI,KAAK,EAAU,GAAI,EACzC,OAAO,OAAO,MAAM,EAAU,QAAQ,CAAC,EAAI,IAAA,GAAY,CACzD,CAeA,SAAgB,oBACd,EACA,EACiB,CACjB,IAAM,EAAQ,IAAS,IACvB,GAAI,IAAU,IAAA,IAAa,IAAU,GAAI,MAAO,CAAE,MAAO,OAAQ,EACjE,IAAM,EAAY,gBAAgB,CAAK,EAEvC,OADK,EACE,EAAU,QAAQ,GAAK,EAAI,QAAQ,EACtC,CAAE,MAAO,UAAW,WAAU,EAC9B,CAAE,MAAO,UAAW,WAAU,EAHX,CAAE,MAAO,UAAW,OAAM,CAInD,CAaA,eAAsB,qBACpB,EACA,EACA,EACyD,CACzD,GAAI,CAEF,MAAO,CAAE,OAAQ,qBAAoB,MADd,EAAO,YAAY,CAAE,IAAK,aAAa,CAAW,CAAE,CAAC,EAAA,CAC9B,UAAU,OAAQ,CAAG,CAAE,CACvE,OAAS,EAAO,CACd,MAAO,CAAE,MAAO,GAAQ,CAAK,CAAE,CACjC,CACF,CAWA,eAAsB,qBACpB,EACA,EACA,EACe,CACf,MAAM,0BAA0B,EAAQ,CACtC,IAAK,aAAa,CAAW,EAC7B,OAAQ,EAAG,IAAoB,gBAAgB,CAAS,CAAE,CAC5D,CAAC,CACH,CAUA,eAAsB,qBACpB,EACA,EACe,CACf,MAAM,0BAA0B,EAAQ,CACtC,IAAK,aAAa,CAAW,EAC7B,OAAQ,CAAC,EAAiB,CAC5B,CAAC,CACH,CAcA,SAAgB,eACd,EACgB,CAChB,GAAI,UAAW,EAAQ,MAAO,cAC9B,OAAQ,EAAO,OAAO,MAAtB,CACE,IAAK,QACH,OAAO,KACT,IAAK,UACH,MAAO,UACT,QACE,OAAO,EAAO,OAAO,UAAU,YAAY,CAC/C,CACF,CASA,eAAsB,sBACpB,EACA,EACA,EAC2B,CAC3B,IAAM,EAAQ,GAAmB,EACjC,OAAO,QAAQ,IACb,EAAa,IAAI,KAAO,IAEf,eAAe,MADD,MAAY,qBAAqB,EAAQ,EAAa,CAAG,CAAC,CACnD,CAC7B,CACH,CACF,CC7KA,SAAgB,gBAAgB,EAA+C,CAC7E,GAAI,CAAC,EACH,OAAO,KAET,IAAM,EAAO,EAAc,CAAS,EAIpC,OAHI,OAAO,MAAM,EAAK,QAAQ,CAAC,EACtB,KAEF,CACT,CASA,SAAgB,YAAY,EAAmB,EAAmC,CAChF,OAAO,GAAY,EAAM,CAAM,CACjC,CAOA,SAAgB,oBAAoB,EAAkC,CACpE,OAAO,YAAY,EAAM,CAAE,WAAY,EAAK,CAAC,CAC/C,CAwCA,SAAgB,qBAAqB,EAAqC,CACxE,GAAI,IAAU,KACZ,MAAO,MAET,IAAM,EAAO,aAAiB,KAAO,EAAQ,IAAI,KAAK,CAAK,EAI3D,OAHI,OAAO,MAAM,EAAK,QAAQ,CAAC,EACtB,OAAO,GAAU,SAAW,EAAQ,MAEtC,GAA0B,EAAM,CAAE,UAAW,EAAK,CAAC,CAC5D,CCjEA,MAAa,eAAiB,EAAsB,IAAuC,CACzF,IAAM,EAAO,CACX,GAAI,EAAU,GACd,KAAM,EAAU,KAChB,OAAQ,EAAU,OAClB,GAAI,EAAU,eAAiB,CAAE,eAAgB,EAAU,cAAe,EAAI,CAAC,EAC/E,GAAI,EAAU,SAAW,CAAE,SAAU,EAAU,QAAS,EAAI,CAAC,EAC7D,UAAW,gBAAgB,EAAU,UAAU,EAC/C,UAAW,gBAAgB,EAAU,UAAU,CACjD,EACA,OAAO,EAAa,CAAE,GAAG,EAAM,YAAW,EAAI,CAChD,EAEM,kBAAoB,EAAsB,KACvC,CACL,GAAG,cAAc,EAAW,CAAU,EACtC,iBAAkB,EAAU,iBAC5B,eAAgB,EAAU,eAC1B,SAAU,EAAU,QACtB,GAGF,eAAsB,2BACpB,EACA,EAC6B,CACzB,GAAC,EAAU,gBAAmB,EAAU,SAE5C,GAAI,CAMF,OAAO,MALgB,EAAO,sBAAsB,CAClD,eAAgB,EAAU,eAC1B,SAAU,EAAU,QACtB,CAAC,EAAA,CAEe,QAAQ,MAAQ,IAAA,EAClC,OAAS,EAAO,CACd,GACE,aAAiB,IAChB,EAAM,OAAS,EAAK,UAAY,EAAM,OAAS,EAAK,kBAErD,OAEF,EAAO,KAAK,4CAA4C,GAAO,EAC/D,MACF,CACF,CAEA,SAAS,kCAAkC,EAAwB,CACjE,IAAM,EAAQ,IAAI,IAElB,MAAQ,IAAsD,CAC5D,GAAI,CAAC,EAAU,gBAAkB,CAAC,EAAU,SAAU,OAAO,QAAQ,QAAQ,IAAA,EAAS,EAEtF,IAAM,EAAW,GAAG,EAAU,eAAe,GAAG,EAAU,WACpD,EAAS,EAAM,IAAI,CAAQ,EACjC,GAAI,EAAQ,OAAO,EAEnB,IAAM,EAAU,2BAA2B,EAAQ,CAAS,EAE5D,OADA,EAAM,IAAI,EAAU,CAAO,EACpB,CACT,CACF,CAEA,eAAsB,4BACpB,EACA,EACwB,CACxB,IAAM,EAAa,MAAM,2BAA2B,EAAQ,CAAS,EACrE,OAAO,cAAc,EAAW,CAAU,CAC5C,CAEA,eAAsB,+BACpB,EACA,EAC2B,CAC3B,IAAM,EAAa,MAAM,2BAA2B,EAAQ,CAAS,EACrE,OAAO,iBAAiB,EAAW,CAAU,CAC/C,CAEA,eAAsB,8BACpB,EACA,EAC0B,CAC1B,IAAM,EAAoB,kCAAkC,CAAM,EAC5D,EAAQ,GAAO,CAAC,EACtB,OAAO,QAAQ,IACb,EAAW,IAAK,GACd,EAAM,SAAY,cAAc,EAAW,MAAM,EAAkB,CAAS,CAAC,CAAC,CAChF,CACF,CACF,CAEA,SAAgB,qBAAqB,EAAuD,CAC1F,OAAO,EAAU,WAAa,GAAG,EAAU,WAAW,GAAG,EAAU,OAAS,EAAU,IACxF,CAEA,SAAgB,+BACd,EACA,EAC+B,CAC/B,OAAQ,EAAgB,IAAyB,CAC/C,IAAM,EAAY,EACZ,EAAO,EAAU,GACjB,EAAa,EAAU,GAI7B,OAHI,OAAO,GAAS,UAAY,OAAO,GAAe,SAC7C,qBAAqB,CAAE,OAAM,YAAW,CAAC,EAE3C,OAAO,GAAS,EAAE,CAC3B,CACF,CAEA,MAAa,GAA2B,+BAA+B,OAAQ,YAAY,ECzFrF,GAA+B,EAAE,OAAO,CAC5C,KAAM,GACN,OAAQ,EAAE,OAAO,EACjB,iBAAkB,EAAE,QAAQ,CAAC,CAAC,SAAS,EACvC,eAAgB,EAAE,KAAK,CAAC,CAAC,SAAS,EAClC,SAAU,EAAE,KAAK,CAAC,CAAC,SAAS,EAC5B,IAAK,GAAO,SAAS,EACrB,QAAS,GAAkB,SAAS,CACtC,CAAC,EAQK,eAAiB,MAAO,EAAgB,IAA2B,CACvE,IAAM,EAAmB,MAAM,EAAO,8BAA8B,CAAC,CAAC,EACtE,GAAI,CAAC,EAAiB,QAAQ,SAAS,CAAM,EAC3C,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,0BAA0B,EAAiB,QAAQ,KAAK,IAAI,EAAE,GACvE,QAAS,kBACX,CAAC,CAEL,EAEA,SAAS,wBAAwB,EAAuC,CACtE,IAAM,EACJ,GAAgB,gBAAkB,QAAQ,IAAI,iCAI1C,EAAqB,GAAgB,YAAc,QAAQ,IAAI,4BAErE,MAAO,CACL,GAAI,GAAkB,CAAc,EAChC,CAAC,EACD,CAAE,aAAc,GAAmB,CAAc,CAAE,EACvD,GAAI,EAAoB,CAAE,iBAAkB,GAAkB,CAAc,CAAE,EAAI,CAAC,EACnF,GAAI,EAAqB,CAAE,YAAa,GAAiB,CAAkB,CAAE,EAAI,CAAC,CACpF,CACF,CAOA,eAAsBC,kBACpB,EAC+B,CAC/B,IAAM,EAAY,+BAA+B,CAAO,EAClD,EAAc,MAAM,gBAAgB,CAAE,QAAS,EAAU,OAAQ,CAAC,EAClE,EAAiB,MAAM,yBAAyB,CAAE,QAAS,EAAU,OAAQ,CAAC,EAC9E,EAAS,MAAM,EAAmB,EAAa,CAAc,EAEnE,OADA,MAAM,eAAe,EAAU,OAAQ,CAAM,EACtC,mCAAmC,EAAQ,CAAS,CAC7D,CAQA,eAAsB,mCACpB,EACA,EAC+B,CAE/B,IAAM,EAAO,MAAM,EAAO,gBAAgB,CACxC,cAAe,EAAQ,KACvB,gBAAiB,EAAQ,OACzB,iBAAkB,EAAQ,kBAAoB,GAC9C,eAAgB,EAAQ,eACxB,SAAU,EAAQ,QACpB,CAAC,EAEK,EAAY,EAAc,EAAK,UAAW,4CAA4C,EACtF,EACJ,EAAQ,MAAQ,IAAA,GACZ,IAAA,GACA,MAAM,UAAU,EAAQ,EAAU,GAAI,EAAQ,IAAK,EAAU,UAAU,EAEvE,EAAO,MAAM,4BAA4B,EAAQ,CAAS,EAChE,OAAO,EAAM,CAAE,GAAG,EAAM,KAAI,EAAI,CAClC,CAyBA,eAAe,UACb,EACA,EACA,EACA,EACyB,CACzB,IAAM,EAAY,EAAa,EAAc,CAAU,EAAI,IAAI,KACzD,EAAY,IAAI,KAAK,EAAU,QAAQ,EAAI,SAAS,CAAG,CAAC,EAC9D,GAAI,CAEF,OADA,MAAM,qBAAqB,EAAQ,EAAa,CAAS,EAClD,CAAE,MAAO,UAAW,WAAU,CACvC,OAAS,EAAO,CAGd,MAAO,CACL,MAAO,cACP,YACA,UAAW,EACX,QAAS,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAChE,CACF,CACF,CAOA,SAAgB,+BACd,EACiC,CACjC,OAAO,aAAa,GAA8B,CAAO,CAC3D,CAIA,MAAaC,GAAgB,EAAiB,CAC5C,KAAM,SACN,YAAa,0CACb,KAAM,EAAE,aAAa,CAGnB,KAAM,EAAI,GAAqB,CAC7B,MAAO,IACP,YAAa,gBACf,CAAC,EACD,OAAQ,EAAI,EAAE,OAAO,EAAG,CACtB,MAAO,IACP,YAAa,4CACf,CAAC,EACD,oBAAqB,EAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAK,EAAG,CACnD,MAAO,IACP,YAAa,0BACf,CAAC,EACD,kBAAmB,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CAC5C,MAAO,IACP,YAAa,8CACb,IAAK,iCACP,CAAC,EACD,YAAa,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CACtC,MAAO,IACP,YAAa,wCACb,IAAK,2BACP,CAAC,EACD,IAAK,EAAI,GAAO,SAAS,EAAG,CAC1B,YACE,+IACJ,CAAC,EACD,eAAgB,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CACzC,MAAO,IACP,YAAa,wBACf,CAAC,EACD,QAAS,EAAI,GAAkB,SAAS,EAAG,CACzC,YAAa,mEACb,IAAK,yBACP,CAAC,EACD,eAAgB,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CACzC,YACE,yFACJ,CAAC,EACD,WAAY,EAAI,EAAE,KAAK,CAAC,QAAS,MAAM,CAAC,CAAC,CAAC,QAAQ,OAAO,EAAG,CAC1D,YACE,6GACJ,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,MAAM,eAAe,CAAE,QAAS,EAAK,OAAQ,CAAC,EAC9C,IAAM,EAAc,EAAK,gBACrB,EAOJ,GAAI,EAAa,CACf,IAAM,EAAS,MAAM,mBAAmB,EACxC,GAAI,EAAO,SAAS,GAClB,MAAM,EAAS,CACb,KAAM,iBACN,QAAS,YAAY,EAAY,kBACnC,CAAC,EAGH,IAAM,EAAoB,EAAK,QACzB,EAAqB,EAAoB,EAAO,SAAS,GAAqB,IAAA,GAC9E,EAAiB,EACnB,0BAA0B,CAAkB,EAC5C,IAAA,GACE,EAAc,EAAK,iBAAmB,GAAoB,MAAQ,EAAO,aAC/E,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,eACN,QAAS,0BACT,WAAY,wDACZ,QAAS,kBACX,CAAC,EAGH,IAAM,EAAsB,kBAAkB,EAAQ,EAAa,CAAc,EACjF,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,iBACN,QAAS,SAAS,EAAY,cAC9B,WAAY,mCACZ,KAAM,CACJ,QAAS,SACT,KAAM,CAAC,QAAS,GAAG,oBAAoB,CAAE,QAAS,CAAkB,CAAC,CAAC,CACxE,CACF,CAAC,EAEH,EAAe,CACb,KAAM,EACN,KAAM,EACN,iBAAkB,wBAAwB,CAAc,CAC1D,CACF,CAGA,IAAM,EAAY,MAAMD,kBAAgB,CACtC,KAAM,EAAK,KACX,OAAQ,EAAK,OACb,iBAAkB,EAAK,qBACvB,eAAgB,EAAK,mBACrB,SAAU,EAAK,aACf,IAAK,EAAK,IACV,QAAS,EAAK,OAChB,CAAC,EAEG,EACJ,GAAI,EAAc,CAChB,IAAM,EAAS,MAAM,mBAAmB,EAClC,EAAmB,EAAa,iBACtC,EAAO,SAAS,EAAa,MAAQ,CACnC,KAAM,EAAa,KACnB,aAAc,EAAU,GACxB,GAAI,EAAK,aAAe,OAAS,CAAE,SAAU,EAAK,EAAI,CAAC,EACvD,GAAG,CACL,EACA,oBAAoB,CAAM,EAC1B,EAAc,CACZ,KAAM,EAAa,KACnB,KAAM,EAAa,KACnB,YAAa,EAAU,GACvB,WAAY,EAAK,WACjB,GAAI,EAAiB,aAAe,CAAE,YAAa,EAAiB,YAAa,EAAI,CAAC,EACtF,GAAI,EAAiB,iBACjB,CAAE,eAAgB,EAAiB,gBAAiB,EACpD,CAAC,EACL,GAAI,EAAiB,YAAc,CAAE,WAAY,EAAiB,WAAY,EAAI,CAAC,CACrF,EAEK,EAAK,MACR,EAAO,QAAQ,YAAY,EAAa,KAAK,wBAAwB,CAEzE,CAEA,GAAM,CAAE,MAAK,GAAG,GAAoB,EAoBpC,GAnBK,EAAK,OACR,EAAO,QAAQ,cAAc,qBAAqB,CAAS,EAAE,wBAAwB,EACjF,GAAK,QAAU,WACjB,EAAO,KAAK,iCAAiC,EAAI,UAAU,YAAY,EAAE,EAAE,GAI3E,EAAK,MAAQ,EACf,EAAO,IAAI,CAAE,GAAG,EAAiB,QAAS,CAAY,CAAC,GAEvD,EAAO,IAAI,EAAiB,CAC1B,QAAS,CAAE,KAAM,GAA0B,WAAY,IAAK,CAC9D,CAAC,EACG,IACF,EAAO,IAAI,UAAU,EACrB,EAAO,IAAI,CAAW,IAItB,GAAK,QAAU,cACjB,MAAM,EAAS,CACb,KAAM,6BACN,QAAS,cAAc,qBAAqB,CAAS,EAAE,mDAAmD,EAAI,UAC9G,QACE,+HACF,QAAS,CACP,YAAa,EAAU,GACvB,mBAAoB,EAAI,UAAU,YAAY,EAC9C,GAAI,EAAc,CAAE,eAAgB,EAAY,IAAK,EAAI,CAAC,CAC5D,EACA,KAAM,CACJ,QAAS,SACT,KAAM,CACJ,YACA,MACA,MACA,QACA,EAAI,UACJ,GAAG,oBAAoB,CAAE,YAAa,EAAU,GAAI,QAAS,EAAK,OAAQ,CAAC,CAC7E,CACF,CACF,CAAC,CAEL,CACF,CAAC,EC/VD,eAAsB,eAAe,EAA2D,CAC9F,IAAM,EAAU,GAAkB,SAAS,CAAC,CAAC,MAAM,GAAS,OAAO,EAC7D,EAAc,MAAM,gBAAgB,CAAE,SAAQ,CAAC,EAC/C,EAAiB,MAAM,yBAAyB,CAAE,SAAQ,CAAC,EAEjE,OAAO,yBAAyB,MADX,EAAmB,EAAa,CAAc,EAC3B,CAAO,CACjD,CAUA,eAAsB,yBACpB,EACoC,CACpC,IAAM,EAAU,GAAkB,SAAS,CAAC,CAAC,MAAM,GAAS,OAAO,EAC7D,EAAc,MAAM,gBAAgB,CAAE,SAAQ,CAAC,EAC/C,EAAiB,MAAM,yBAAyB,CAAE,SAAQ,CAAC,EAC3D,EAAS,MAAM,EAAmB,EAAa,CAAc,EAC7D,EAAa,MAAM,yBAAyB,EAAQ,CAAO,EAC3D,EAAW,MAAM,sBACrB,EACA,EAAW,KAAK,CAAE,QAAS,CAAE,EAC7B,IAAI,IACN,EACA,OAAO,EAAW,KAAK,EAAW,IAAU,CAC1C,IAAM,EAAY,EAAS,GAC3B,MAAO,CAAE,GAAG,EAAW,UAAW,IAAc,IAAA,GAAY,cAAgB,CAAU,CACxF,CAAC,CACH,CAQA,eAAsB,yBACpB,EACA,EAC0B,CAC1B,IAAM,EAAgB,gBAAgB,GAAS,KAAK,EAapD,OAAO,8BAA8B,EAAQ,MAZpB,GACvB,MAAO,EAAW,IAAa,CAC7B,GAAM,CAAE,aAAY,iBAAkB,MAAM,EAAO,eAAe,CAChE,YACA,WACA,eACF,CAAC,EACD,MAAO,CAAC,EAAY,CAAa,CACnC,EACA,CAAE,MAAO,GAAS,KAAM,CAC1B,CAEuD,CACzD,CAEA,MAAaE,GAAc,EAAiB,CAC1C,KAAM,OACN,YAAa,uCACb,KAAM,EAAE,aAAa,CACnB,GAAG,eAAe,EAClB,QAAS,EAAI,GAAkB,SAAS,EAAG,CACzC,YAAa,mEACb,IAAK,yBACP,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAa,MAAM,yBAAyB,CAChD,MAAO,EAAK,MACZ,MAAO,EAAK,MACZ,QAAS,EAAK,OAChB,CAAC,EACD,EAAO,IAAI,EAAY,CACrB,QAAS,CACP,KAAM,GACN,WAAY,KACZ,eAAgB,KAChB,SAAU,KACV,UAAW,IACb,CACF,CAAC,CACH,CACF,CAAC,EC7GK,GAAyB,EAAE,OAAO,CACtC,QAAS,EAAE,QAAQ,CAAC,EACpB,YAAa,EAAE,IAAI,EACnB,cAAe,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAC1C,YAAa,EAAE,KAAK,CACtB,CAAC,EAID,SAAS,mBAA4B,CACnC,OAAO,GAAQ,QAAQ,IAAI,EAAG,kBAAkB,CAClD,CAEA,SAAS,YAAY,EAA4B,CAC/C,OAAO,GAAK,GAAQ,CAAU,EAAG,GAAW,EAAG,GAAG,GAAS,CAAU,EAAE,cAAc,CACvF,CAUA,eAAsB,qBACpB,EACA,EAAa,kBAAkB,EAC/B,EACuC,CACvC,IAAI,EACJ,GAAI,CACF,EAAW,MAAM,GAAS,YAAY,CAAU,EAAG,MAAM,CAC3D,OAAS,EAAO,CACd,GAAI,aAAiB,OAAS,SAAU,GAAS,EAAM,OAAS,SAAU,OAC1E,MAAM,CACR,CAEA,IAAI,EACJ,GAAI,CACF,EAAQ,KAAK,MAAM,CAAQ,CAC7B,MAAQ,CACN,MACF,CAEA,IAAM,EAAS,GAAuB,UAAU,CAAK,EAEnD,MAAC,EAAO,SACR,EAAO,KAAK,cAAgB,GAC3B,IAAkB,IAAA,IAAa,EAAO,KAAK,gBAAkB,GAIhE,OAAO,EAAO,IAChB,CAQA,eAAsB,qBACpB,EACA,EAAa,kBAAkB,EAC/B,EACe,CACf,IAAM,EAAY,GAAuB,MAAM,CAC7C,GAAG,EACH,GAAI,IAAkB,IAAA,GAAY,CAAC,EAAI,CAAE,eAAc,CACzD,CAAC,EACK,EAAiB,GAAK,GAAQ,CAAU,EAAG,GAAW,CAAC,EACvD,EAAa,YAAY,CAAU,EACnC,EAAa,GAAG,KAAK,UAAU,EAAW,KAAM,CAAC,EAAE,IACzD,GAAI,CACF,GAAK,MAAM,GAAS,EAAY,MAAM,IAAO,EAAY,MAC3D,MAAQ,CAER,CACA,IAAM,EAAgB,GAAG,EAAW,GAAG,QAAQ,IAAI,GAAG,GAAW,EAAE,MACnE,MAAM,GAAM,EAAgB,CAAE,UAAW,EAAK,CAAC,EAC/C,GAAI,CACF,MAAM,GAAU,EAAe,EAAY,CAAE,KAAM,GAAM,CAAC,EAC1D,MAAM,GAAO,EAAe,CAAU,CACxC,OAAS,EAAO,CAEd,MADA,MAAM,GAAG,EAAe,CAAE,MAAO,EAAK,CAAC,CAAC,CAAC,UAAY,IAAA,EAAS,EACxD,CACR,CACF,CCvCA,SAAS,wBAAiC,CACxC,IAAM,EAAO,GAAS,QAAQ,IAAI,CAAC,CAAC,CACjC,YAAY,CAAC,CACb,WAAW,eAAgB,GAAG,CAAC,CAC/B,WAAW,WAAY,EAAE,CAAC,CAC1B,MAAM,EAAG,EAAE,CAAC,CACZ,QAAQ,MAAO,EAAE,EACpB,OAAO,sBAAsB,CAAI,IAAM,GAAO,EAAO,cACvD,CAEA,SAAS,iBAAiB,EAA6C,CACrE,MAAO,CAAE,QAAS,SAAU,MAAK,CACnC,CAEA,SAAS,WAAW,EAA2D,CAC7E,OAAO,EAAQ,YAAc,CAAC,QAAQ,CACxC,CAEA,SAAS,qBAAqB,EAA2D,CACvF,OAAO,EAAQ,sBAAwB,CAAC,CAC1C,CAEA,SAAS,iBACP,EACA,EACA,EACmB,CACnB,MAAO,CACL,GAAG,WAAW,CAAO,EACrB,qBACA,mBACA,EACA,qBACA,EACA,GAAI,EAAQ,eAAiB,CAAC,oBAAqB,EAAQ,cAAc,EAAI,CAAC,EAC9E,GAAI,EAAQ,SAAW,CAAC,cAAe,EAAQ,QAAQ,EAAI,CAAC,CAC9D,CACF,CAEA,SAAS,iBAAiB,EAA2D,CACnF,MAAO,CAAC,GAAG,WAAW,CAAO,EAAG,iBAAkB,gBAAgB,CACpE,CAEA,SAAS,eAAe,EAAkC,CACxD,IAAM,EAAe,EAAU,gBAAkB,WACjD,MAAO,GAAG,qBAAqB,CAAS,EAAE,IAAI,EAAU,OAAO,SAAS,EAAa,QAAQ,EAAU,GAAG,EAC5G,CAEA,SAAS,kCACP,EACA,EACS,CACT,OACE,EAAQ,gBAAkB,EAAU,MACpC,EAAQ,kBAAoB,EAAU,QACtC,EAAQ,iBAAmB,EAAU,gBACrC,EAAQ,WAAa,EAAU,QAEnC,CAEA,SAAS,kBAAkB,EAA0B,CACnD,GAAM,CAAE,KAAI,OAAM,SAAQ,iBAAgB,YAAa,EACvD,MAAO,CAAE,KAAI,OAAM,SAAQ,iBAAgB,UAAS,CACtD,CAEA,SAAS,sBACP,EACsC,CACjC,KACL,MAAO,CAAC,GAAG,IAAI,IAAI,EAAe,IAAK,GAAW,CAAC,EAAO,WAAY,CAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAC1F,CAEA,eAAe,oBACb,EACA,EAC6B,CAC7B,IAAM,EAAU,sBAAsB,CAAc,EACpD,GAAI,CAAC,GAAW,EAAQ,SAAW,EAAG,CACpC,IAAM,EAAU,MAAM,qBAAqB,CAAW,EACtD,OAAO,EAAU,CAAC,CAAO,EAAI,CAAC,CAChC,CAMA,OAAO,MALgB,QAAQ,IAC7B,EAAQ,KAAK,CAAE,aAAY,mBACzB,qBAAqB,EAAa,EAAY,CAAa,CAC7D,CACF,EAAA,CACgB,OAAQ,GAAyC,IAAY,IAAA,EAAS,CACxF,CAEA,eAAe,wBACb,EACA,EACe,CACf,IAAM,EAAU,sBAAsB,CAAc,EACpD,GAAI,CAAC,GAAW,EAAQ,SAAW,EAAG,CACpC,MAAM,qBAAqB,CAAO,EAClC,MACF,CAMA,IAAM,GAAW,MALK,QAAQ,WAC5B,EAAQ,KAAK,CAAE,aAAY,mBACzB,qBAAqB,EAAS,EAAY,CAAa,CACzD,CACF,EAAA,CACyB,OAAQ,GAAW,EAAO,SAAW,UAAU,EACxE,GAAI,EAAS,OAAS,EACpB,MAAM,EAAS,CACb,KAAM,gCACN,QAAS,EACN,KAAK,CAAE,YAAc,aAAkB,MAAQ,EAAO,QAAU,OAAO,CAAM,CAAE,CAAC,CAChF,KAAK,IAAI,CACd,CAAC,CAEL,CAEA,eAAe,yBACb,EACA,EACA,EAA6C,mBAC9B,CACX,MAAQ,OACZ,GAAI,CACF,MAAM,wBAAwB,EAAS,EAAQ,cAAc,CAC/D,OAAS,EAAO,CAEd,IADyB,sBAAsB,EAAQ,cAAc,CAAC,EAAE,QAC/C,GAAK,GAAK,IAAkB,mBACnD,MAAM,EAAS,CACb,KAAM,gCACN,QAAS,2EACT,QAAS,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAC9D,WAAY,0EACZ,KAAM,iBAAiB,CACrB,GAAG,WAAW,CAAO,EACrB,GAAG,oBAAoB,CAAE,YAAa,EAAQ,WAAY,CAAC,CAC7D,CAAC,EACD,QAAS,CACP,YAAa,EAAQ,YACrB,YAAa,EAAQ,gBAAgB,KAAK,CAAE,gBAAiB,CAAU,CACzE,CACF,CAAC,EAEH,EAAO,KACL,mDAAmD,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAAE,kCAAkC,EAAQ,YAAY,gBAClK,CACF,CACF,CAEA,eAAe,aACb,EACA,EACA,EACA,EACA,EAA6C,mBACX,CAWlC,OAVA,MAAM,yBACJ,CACE,QAAS,EACT,cACA,YAAa,EAAU,EACzB,EACA,EACA,CACF,EACA,EAAO,KAAK,oBAAoB,eAAe,CAAS,GAAG,EACpD,CAAE,SAAQ,YAAa,EAAU,EAAG,CAC7C,CAEA,SAAS,uBACP,EACA,EACyB,CAEzB,OADA,EAAO,KAAK,oCAAoC,eAAe,CAAS,GAAG,EACpE,CAAE,SAAQ,YAAa,EAAU,EAAG,CAC7C,CAEA,MAAM,GAA8B,uBAEpC,eAAe,gBACb,EACA,EACA,EACA,EACkC,CAClC,IAAM,EAAc,MAAM,EAAO,OAAO,CACtC,QAAS,qBACT,QAAS,CACP,GAAG,EAAW,IAAK,IAAe,CAChC,KAAM,eAAe,CAAS,EAC9B,MAAO,EAAU,EACnB,EAAE,EACF,CAAE,KAAM,uBAAwB,MAAO,EAA4B,CACrE,CACF,CAAC,EACD,GAAI,IAAgB,GAClB,OAAO,yBAAyB,EAAQ,EAAa,CAAO,EAE9D,IAAM,EAAY,EAAW,MAAM,CAAE,QAAS,IAAO,CAAW,EAChE,GAAI,CAAC,EAAW,MAAM,EAAc,kCAAkC,EACtE,OAAO,aAAa,EAAQ,EAAa,EAAW,CAAO,CAC7D,CAEA,SAAS,0BACP,EACA,EACA,EACA,EACO,CACP,OAAO,EAAS,CACd,KAAM,mCACN,QAAS,0CACT,UACA,WAAY,2DACZ,KAAM,iBAAiB,iBAAiB,EAAS,EAAM,CAAM,CAAC,CAChE,CAAC,CACH,CAEA,eAAe,gBACb,EACA,EACA,EACA,EACA,EACkC,CAClC,IAAI,EAAO,EAAQ,cACf,EAAS,EAAQ,gBACf,EAAc,UAAU,EAE9B,GAAI,EACF,IAAS,MAAM,EAAO,KAAK,CACzB,QAAS,iBACT,QAAS,uBAAuB,EAChC,SAAU,qBACZ,CAAC,EACD,IAAW,MAAM,EAAO,OAAO,CAC7B,QAAS,mBACT,QAAS,EAAiB,IAAK,IAAW,CAAE,KAAM,EAAO,OAAM,EAAE,CACnE,CAAC,MACI,CACL,IAAM,EAAiB,CACrB,GAAI,IAAS,IAAA,GAAY,CAAC,kBAAkB,EAAI,CAAC,EACjD,GAAI,IAAW,IAAA,GAAY,CAAC,oBAAoB,EAAI,CAAC,CACvD,EACA,GAAI,EAAe,OAAS,EAC1B,MAAM,EAAS,CACb,KAAM,oCACN,QAAS,yEACT,WAAY,4DACZ,KAAM,iBAAiB,iBAAiB,EAAS,GAAQ,SAAU,GAAU,UAAU,CAAC,EACxF,QAAS,CAAE,gBAAe,CAC5B,CAAC,CAEL,CAEA,GAAI,CAAC,GAAQ,CAAC,EAAQ,MAAM,EAAc,8CAA8C,EAExF,IAAI,EAAY,EAChB,GAAI,CAAC,EAAW,CACd,GAAI,CACF,EAAY,+BAA+B,CACzC,OACA,SACA,eAAgB,EAAQ,eACxB,SAAU,EAAQ,QACpB,CAAC,CACH,OAAS,EAAO,CACd,MAAM,0BACJ,EACA,EACA,EACA,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CACvD,CACF,CACA,GAAI,CAAC,EAAiB,SAAS,CAAM,EACnC,MAAM,0BACJ,EACA,EACA,EACA,0BAA0B,EAAiB,KAAK,IAAI,EAAE,EACxD,CAEJ,CAEA,GAAI,EAAa,CACf,IAAM,EAAQ,CACZ,EAAQ,eAAiB,iBAAiB,EAAQ,iBAAmB,IAAA,GACrE,EAAQ,SAAW,WAAW,EAAQ,WAAa,IAAA,EACrD,CAAC,CAAC,OAAQ,GAA2B,IAAU,IAAA,EAAS,EAKxD,GAAI,CAAC,MAJmB,EAAO,QAAQ,CACrC,QAAS,qBAAqB,EAAK,OAAO,IAAS,EAAM,OAAS,EAAI,KAAK,EAAM,KAAK,IAAI,EAAE,GAAK,GAAG,GACpG,QAAS,EACX,CAAC,EAEC,MAAM,EAAS,CACb,KAAM,+BACN,QAAS,mCACX,CAAC,CAEL,CAEA,IAAI,EACJ,GAAI,CACF,EAAY,MAAM,mCAAmC,EAAQ,CAAS,CACxE,OAAS,EAAO,CAed,MAbE,aAAiB,GACjB,CAAC,CACC,EAAK,SACL,EAAK,QACL,EAAK,iBACL,EAAK,QACL,EAAK,SACL,EAAK,YACL,EAAK,QACP,CAAC,CAAC,SAAS,EAAM,IAAI,EAEf,EAEF,EAAS,CACb,KAAM,4BACN,QAAS,oDACT,QAAS,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAC9D,WACE,8FACF,KAAM,iBAAiB,CAAC,YAAa,OAAQ,GAAG,qBAAqB,CAAO,EAAG,QAAQ,CAAC,CAC1F,CAAC,CACH,CAmBA,OAjBA,MAAM,yBACJ,CACE,QAAS,EACT,cACA,YAAa,EAAU,EACzB,EACA,CACF,EACA,EAAO,QAAQ,sBAAsB,eAAe,CAAS,GAAG,EAChE,EAAO,KACL,8BAA8B,GAAsB,CAClD,SACA,SACA,GAAG,oBAAoB,CAAE,YAAa,EAAU,GAAI,QAAS,EAAQ,OAAQ,CAAC,CAChF,CAAC,GACH,EACA,EAAO,KAAK,uCAAuC,EAAU,GAAG,EAAE,EAC3D,CAAE,SAAQ,YAAa,EAAU,EAAG,CAC7C,CAEA,eAAe,yBACb,EACA,EACA,EACA,EACA,EACkC,CAClC,IAAM,EAAU,IAAqB,MAAM,EAAO,8BAA8B,CAAC,CAAC,EAAA,CAAG,QACrF,GAAI,EAAQ,OACV,MAAM,EAAS,CACb,KAAM,yCACN,QAAS,2EACT,WACE,oFACF,QAAS,CAAE,iBAAkB,CAAQ,CACvC,CAAC,EAEH,OAAO,gBAAgB,EAAQ,EAAa,EAAS,EAAS,CAAgB,CAChF,CAQA,eAAsB,uBACpB,EAAyC,CAAC,EACR,CAClC,IAAM,EAAoB,CACxB,EAAQ,gBAAkB,IAAA,GAAiC,IAAA,GAArB,mBACtC,EAAQ,kBAAoB,IAAA,GAAmC,IAAA,GAAvB,oBAC1C,CAAC,CAAC,OAAQ,GAAyB,IAAS,IAAA,EAAS,EACrD,GAAI,CAAC,EAAQ,iBAAmB,EAAkB,OAAS,EACzD,MAAM,EAAS,CACb,KAAM,iCACN,QAAS,yDACT,WAAY,mEACZ,KAAM,iBACJ,iBACE,EACA,EAAQ,eAAiB,SACzB,EAAQ,iBAAmB,UAC7B,CACF,EACA,QAAS,CAAE,QAAS,CAAkB,CACxC,CAAC,EAEH,GAAI,EAAQ,iBAAmB,EAAQ,gBAAkB,IAAA,GAAW,CAClE,IAAM,EAAiB,sBAAsB,EAAQ,aAAa,EAClE,GAAI,IAAmB,GACrB,MAAM,0BACJ,EACA,EAAQ,cACR,EAAQ,iBAAmB,WAC3B,CACF,CAEJ,CACA,GAAI,EAAQ,iBAAmB,EAAQ,kBAAoB,GACzD,MAAM,0BACJ,EACA,EAAQ,eAAiB,SACzB,EAAQ,gBACR,2BACF,EAGF,IAAM,EAAsB,MAAM,mBAAmB,CACnD,YAAa,EAAQ,YACrB,QAAS,EAAQ,OACnB,CAAC,EACK,EAAc,MAAM,gBAAgB,CAAE,QAAS,EAAQ,OAAQ,CAAC,EAChE,EAAiB,MAAM,yBAAyB,CACpD,QAAS,EAAQ,QACjB,oBAAqB,IAAwB,IAAA,EAC/C,CAAC,EACK,EAAc,GAAmB,CAAc,EAC/C,EAAS,MAAM,EAAmB,EAAa,CAAc,EAEnE,GAAI,EAAqB,CACvB,IAAI,EACJ,GAAI,CACF,EAAW,MAAM,EAAO,aAAa,CAAE,YAAa,CAAoB,CAAC,CAC3E,OAAS,EAAO,CAOd,MANI,aAAiB,GAAgB,EAAM,OAAS,EAAK,SACjD,EAAS,CACb,KAAM,sBACN,QAAS,cAAc,EAAoB,iBAC7C,CAAC,EAEG,CACR,CACA,GAAI,CAAC,EAAS,UACZ,MAAM,EAAS,CACb,KAAM,sBACN,QAAS,cAAc,EAAoB,iBAC7C,CAAC,EAEH,OAAO,aAAa,EAAQ,EAAa,cAAc,EAAS,SAAS,EAAG,EAAS,MAAM,CAC7F,CAEA,IAAI,EACJ,GACE,EAAQ,iBACR,EAAQ,gBAAkB,IAAA,IAC1B,EAAQ,kBAAoB,IAAA,GAE5B,GAAI,CACF,EAAyB,+BAA+B,CACtD,KAAM,EAAQ,cACd,OAAQ,EAAQ,gBAChB,eAAgB,EAAQ,eACxB,SAAU,EAAQ,QACpB,CAAC,CACH,OAAS,EAAO,CACd,MAAM,0BACJ,EACA,EAAQ,cACR,EAAQ,gBACR,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CACvD,CACF,CAGF,GAAM,CAAC,EAAU,GAAc,MAAM,QAAQ,IAAI,CAC/C,oBAAoB,EAAa,EAAQ,cAAc,EACvD,yBAAyB,CAAM,CACjC,CAAC,EACK,EAAc,UAAU,EAExB,EAAsB,IAAI,IAAI,EAAS,KAAK,CAAE,iBAAkB,CAAW,CAAC,EAC5E,EACJ,EAAoB,OAAS,EACzB,EAAW,MAAM,CAAE,QAAS,EAAoB,IAAI,CAAE,CAAC,EACvD,IAAA,GACN,GACE,IACC,CAAC,EAAQ,iBAAmB,kCAAkC,EAAiB,CAAO,GACvF,CACA,IAAM,EAAqB,sBAAsB,EAAQ,cAAc,CAAC,EAAE,QAAU,EACpF,OAAO,EAAS,SAAW,EACvB,uBAAuB,EAAQ,CAAe,EAC9C,aAAa,EAAQ,EAAa,EAAiB,CAAO,CAChE,CAEA,IAAM,EAAgB,EAAW,SAAW,EAAI,EAAW,GAAK,IAAA,GAC1D,EACJ,IAAkB,IAAA,IAClB,IAA2B,IAAA,IAC3B,kCAAkC,EAAe,CAAO,EACtD,EACJ,GAAI,GAA0B,CAAC,IAC7B,EAAmB,MAAM,EAAO,8BAA8B,CAAC,CAAC,EAC5D,CAAC,EAAiB,QAAQ,SAAS,EAAuB,MAAM,GAClE,MAAM,0BACJ,EACA,EAAuB,KACvB,EAAuB,OACvB,0BAA0B,EAAiB,QAAQ,KAAK,IAAI,EAAE,EAChE,EAIJ,GACE,EAAW,SAAW,IACrB,GAAe,EAAQ,iBAAmB,EAAS,SAAW,GAC/D,CACA,IAAM,EACJ,GAAkB,UAAY,MAAM,EAAO,8BAA8B,CAAC,CAAC,EAAA,CAAG,QAChF,GAAI,EAAQ,QAAU,GAAe,EAAQ,gBAC3C,OAAO,yBACL,EACA,EACA,EACA,EACA,CACF,EAGF,MAAM,EAAS,CACb,KAAM,sBACN,QAAS,gDACT,WACE,6FACF,KAAM,iBAAiB,iBAAiB,EAAS,SAAU,UAAU,CAAC,EACtE,QAAS,CAAE,iBAAkB,CAAQ,CACvC,CAAC,CACH,CAEA,GAAI,EAAoB,KAAO,EAAG,CAChC,IAAM,EACJ,EAAQ,kBAAoB,IAC5B,EAAQ,gBAAkB,IAAA,IAC1B,EAAQ,kBAAoB,IAAA,IAC5B,EAAW,SAAW,EACxB,GAAI,CAAC,GAAe,CAAC,EACnB,MAAM,EAAS,CACb,KAAM,6BACN,QAAS,uEACT,WAAY,+DACZ,KAAM,iBAAiB,iBAAiB,CAAO,CAAC,EAChD,QAAS,CAAE,kBAAmB,CAAC,GAAG,CAAmB,CAAE,CACzD,CAAC,EAEH,GAAI,EAAW,OAAS,GAAK,CAAC,EAAQ,gBACpC,OAAO,gBAAgB,EAAQ,EAAa,EAAY,CAAO,CAEnE,CAEA,GAAI,CAAC,GAAmB,EAAS,OAAS,EAAG,CAC3C,IAAM,EACJ,EAAQ,kBAAoB,IAC5B,EAAQ,gBAAkB,IAAA,IAC1B,EAAQ,kBAAoB,IAAA,IAC5B,EAAW,QAAU,EACvB,GAAI,CAAC,GAAe,CAAC,EACnB,MAAM,EAAS,CACb,KAAM,0BACN,QAAS,sDACT,WAAY,6DACZ,KAAM,iBAAiB,iBAAiB,CAAO,CAAC,EAChD,QAAS,CACP,kBAAmB,CAAC,GAAG,CAAmB,EAC1C,WAAY,EAAW,IAAI,iBAAiB,CAC9C,CACF,CAAC,EAEH,GAAI,EAAW,OAAS,GAAK,GAAe,CAAC,EAAQ,gBACnD,OAAO,gBAAgB,EAAQ,EAAa,EAAY,CAAO,CAEnE,CAEA,GAAI,EAAW,SAAW,EAAG,CAC3B,GAAM,CAAC,GAAa,EACpB,GAAI,CAAC,EAAW,MAAM,EAAc,gDAAgD,EAEpF,GAAI,EAAQ,iBAAmB,CAAC,kCAAkC,EAAW,CAAO,EAClF,MAAM,EAAS,CACb,KAAM,4BACN,QAAS,iEACT,WACE,kGACF,KAAM,iBAAiB,CACrB,YACA,SACA,GAAG,qBAAqB,CAAO,EAC/B,GAAI,EAAQ,qBAAuB,CAAC,QAAQ,EAAI,CAAC,EACjD,SACA,EAAQ,eAAiB,SACzB,WACA,EAAQ,iBAAmB,WAC3B,GAAI,EAAQ,eAAiB,CAAC,oBAAqB,EAAQ,cAAc,EAAI,CAAC,EAC9E,GAAI,EAAQ,SAAW,CAAC,cAAe,EAAQ,QAAQ,EAAI,CAAC,CAC9D,CAAC,EACD,QAAS,CACP,kBAAmB,kBAAkB,CAAS,CAChD,CACF,CAAC,EAOH,OAJI,GAAe,CAAC,EAAQ,gBACnB,gBAAgB,EAAQ,EAAa,EAAY,CAAO,EAG1D,aAAa,EAAQ,EAAa,EAAW,CAAO,CAC7D,CAEA,GAAI,EAAW,OAAS,EAAG,CACzB,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,+BACN,QAAS,qCACT,WAAY,wDACZ,KAAM,iBAAiB,iBAAiB,CAAO,CAAC,EAChD,QAAS,CACP,WAAY,EAAW,IAAI,iBAAiB,CAC9C,CACF,CAAC,EAGH,OAAO,gBAAgB,EAAQ,EAAa,EAAY,CAAO,CACjE,CAEA,MAAM,EAAc,gDAAgD,CACtE,CCnjBA,SAAS,uCACP,EACqB,CACrB,IAAM,EAAe,IAAI,IACzB,IAAK,IAAM,KAAU,EACnB,IAAK,IAAM,KAAW,EAAO,YAAY,sBACvC,EAAa,IAAI,EAAQ,IAAI,EAGjC,OAAO,CACT,CAWA,eAAsB,oBACpB,EACA,EACA,EACA,EACA,CACA,IAAM,GACJ,MAAM,iBAAiB,CACrB,IAAK,YAAY,EAAa,cAAe,EAAY,IAAI,EAC7D,QAAS,EAAY,KACrB,MAAO,EAAY,EACrB,CAAC,EAAA,CACD,OACI,EAAgB,IAAI,IAEtB,EAAY,UAAU,OAAS,GACjC,EAAc,IAAI,YAAY,EAAa,cAAe,EAAY,IAAI,CAAC,EAE7E,EAAY,sBAAsB,QAAS,GAAY,CACrD,EAAc,IAAI,YAAY,EAAa,gBAAiB,EAAQ,IAAI,CAAC,CAC3E,CAAC,EACD,EAAY,kBAAkB,QAAS,GAAY,CACjD,EAAc,IAAI,YAAY,EAAa,YAAa,EAAQ,IAAI,CAAC,CACvE,CAAC,EACD,EAAY,iBAAiB,QAAS,GAAa,CACjD,EAAc,IAAI,YAAY,EAAa,WAAY,EAAS,SAAS,CAAC,CAC5E,CAAC,EACD,EAAY,YAAY,QAAS,GAAQ,CACvC,EAAc,IAAI,YAAY,EAAa,MAAO,EAAI,IAAI,CAAC,CAC7D,CAAC,EACG,EAAY,aACd,EAAc,IAAI,YAAY,EAAa,OAAQ,EAAY,YAAY,OAAO,IAAI,CAAC,EAEzF,OAAO,OAAO,EAAY,iBAAiB,WAAa,CAAC,CAAC,CAAC,CAAC,QAAS,GAAa,CAChF,EAAc,IAAI,YAAY,EAAa,WAAY,EAAS,IAAI,CAAC,CACvE,CAAC,EACD,OAAO,OAAO,EAAY,iBAAiB,WAAa,CAAC,CAAC,CAAC,CAAC,QAAS,GAAa,CAChF,EAAc,IAAI,YAAY,EAAa,WAAY,EAAS,IAAI,CAAC,CACvE,CAAC,EACD,EAAY,iBAAiB,QAAS,GAAY,CAChD,EAAc,IAAI,YAAY,EAAa,WAAY,EAAQ,SAAS,CAAC,CAC3E,CAAC,EACD,EAAY,QAAQ,QAAS,GAAU,CACrC,EAAc,IAAI,YAAY,EAAa,QAAS,EAAM,SAAS,CAAC,CACtE,CAAC,EACD,EAAgB,QAAS,GAAU,CACjC,EAAc,IAAI,YAAY,EAAa,oBAAqB,EAAM,IAAI,CAAC,CAC7E,CAAC,EAED,IAAM,EAAU,MAAM,QAAQ,WAC5B,CAAC,GAAG,CAAa,CAAC,CAAC,IAAK,GACtB,EAAU,SAAY,CACpB,GAAM,CAAE,YAAa,MAAM,EAAO,YAAY,CAAE,KAAI,CAAC,EACrD,OAAO,CACT,CAAC,CACH,CACF,EAQA,GANoB,EAAQ,KACzB,GACC,EAAO,SAAW,aAClB,EAAO,OAAO,OAAA,cAA4B,EAAY,MACtD,CAAC,sBAAsB,EAAO,MAAM,OAAQ,CAAa,CAE/C,EACZ,MAAO,GAET,IAAM,EAAU,EAAQ,KAAM,GAAW,EAAO,SAAW,UAAU,EACrE,GAAI,EACF,MAAM,EAAQ,OAEhB,MAAO,EACT,CAwCA,SAAS,wBACP,EACA,EACmB,CACnB,MAAO,CACL,GAAI,GAAY,QAAU,CAAC,aAAc,EAAK,QAAQ,QAAQ,IAAI,EAAG,EAAW,OAAO,CAAC,EAAI,CAAC,EAC7F,GAAI,GAAY,gBACZ,CAAC,uBAAwB,EAAK,QAAQ,QAAQ,IAAI,EAAG,EAAW,eAAe,CAAC,EAChF,CAAC,EACL,GAAG,oBAAoB,CAAE,QAAS,GAAS,OAAQ,CAAC,CACtD,CACF,CAEA,SAAS,mBAAmB,EAAkD,CAC5E,MAAO,CACL,GAAI,GAAY,QAAU,CAAC,WAAW,EAAI,CAAC,EAC3C,GAAI,GAAY,MAAQ,EAAO,SAAW,CAAC,QAAQ,EAAI,CAAC,CAC1D,CACF,CAEA,SAAS,gBACP,EACA,EACA,EACmB,CACnB,MAAO,CACL,SACA,WACA,EAAY,KAAK,GAAG,EACpB,GAAG,wBAAwB,EAAS,CAAU,EAC9C,GAAI,GAAS,OAAS,CAAC,WAAW,EAAI,CAAC,EACvC,GAAI,GAAS,IAAM,CAAC,OAAO,EAAI,CAAC,EAChC,GAAI,GAAS,cAAgB,CAAC,mBAAmB,EAAI,CAAC,EACtD,GAAI,GAAS,WAAa,CAAC,eAAe,EAAI,CAAC,EAC/C,GAAI,GAAS,QAAU,CAAC,YAAY,EAAI,CAAC,EACzC,GAAI,GAAS,WAAa,CAAC,eAAe,EAAI,CAAC,EAC/C,GAAG,mBAAmB,CAAU,CAClC,CACF,CAEA,SAAS,sBACP,EACA,EACmB,CACnB,MAAO,CACL,GAAG,wBAAwB,EAAS,CAAU,EAC9C,GAAI,GAAY,QAAU,CAAC,WAAW,EAAI,CAAC,CAC7C,CACF,CAEA,SAAS,uCACP,EACA,EACiC,CACjC,IAAM,EAAqB,IAAI,IAAI,EAAO,YAAY,0BAA0B,EAKhF,OAJI,EAAmB,OAAS,EACvB,CAAC,EAGH,EAAQ,QAAS,GACtB,EAAU,YAAY,iBAAiB,OAAQ,GAC7C,EAAmB,IAAI,EAAQ,SAAS,CAC1C,CACF,CACF,CAEA,SAAgB,kCACd,EACyC,CACzC,IAAM,EAAiB,IAAI,IAC3B,IAAK,IAAM,KAAU,EAAS,CAC5B,IAAM,EAAc,EAAO,YAAY,YACvC,GAAI,CAAC,EACH,SAEF,GAAM,CAAE,QAAS,EAAY,OACvB,EAAgB,EAAY,OAAO,YAAY,KACrD,GAAI,EAAe,IAAI,CAAI,GAAK,EAAe,IAAI,CAAI,IAAM,EAC3D,MAAM,EAAS,CACb,KAAM,0BACN,QACE,mBAAmB,EAAK,6IAE5B,CAAC,EAEH,EAAe,IAAI,EAAM,CAAa,CACxC,CACA,OAAO,CACT,CAEA,SAAS,2BACP,EACA,EACqB,CACrB,IAAM,EAAqB,0BAA0B,CAAO,EAE5D,OADA,6BAA6B,EAAoB,CAAM,EAChD,CACL,qBACA,UAAW,IAAI,IACb,EAAQ,IAAK,GAAW,EAAO,YAAY,EAAE,CAAC,CAAC,OAAQ,GAAO,IAAO,IAAA,EAAS,CAChF,EACA,gCAAiC,uCAAuC,CAAO,EAC/E,2BAA4B,kCAAkC,CAAO,CACvE,CACF,CAEA,eAAe,qBACb,EAC4B,CAC5B,GAAM,CACJ,SACA,UACA,YACA,SACA,cACA,gBACA,yBACA,0BACE,EACE,CAAE,SAAQ,cAAa,sBAAqB,yBAAwB,kBACxE,EACI,EAAQ,mBAAmB,EAAU,mBAAoB,CAAM,EAE/D,EAAwB,EAAY,iBAAiB,IAAK,GAAY,CAC1E,IAAM,EAAW,GAAwB,IAAI,EAAQ,SAAS,EAC9D,OAAO,EAAW,CAAE,GAAG,EAAS,MAAO,EAAS,OAAQ,eAAgB,CAAC,CAAE,EAAI,CACjF,CAAC,EACD,MAAM,EAAS,qCACb,GAA0C,CACxC,SACA,cACA,iBAAkB,EAClB,2BAA4B,EAAY,2BACxC,gCAAiC,uCAAuC,EAAQ,CAAO,CACzF,CAAC,CACH,EAEA,IAAM,EAAkB,EAAY,gBAK9B,EAAkB,uBAAuB,EAJnB,0BAC1B,GAAiB,MAAQ,CAAC,EAC1B,GAAqB,cAAgB,CAAC,CAEoB,EAAqB,CAAc,EACzF,EAAgB,MAAM,EAAS,kCACnC,oBAAoB,EAAQ,EAAa,EAAa,CAAe,CACvE,EAEA,OAAO,EAAS,OAAQ,SAAY,CAClC,IAAM,EAAe,EAAQ,IAAK,GAAW,EAAO,WAAW,EACzD,EAAyB,qCAAqC,EAAa,CAAY,EACvF,EAAqB,iCAAiC,EAAa,CAAY,EAC/E,EAAW,uBAAuB,EAAa,CAAY,EAC3D,EAAmB,CACvB,SACA,cACA,cACA,WAAY,GACZ,SACA,gBACA,yBACA,yBACA,gBACA,GAAG,EACH,sBAAuB,eAAe,CAAK,EAC3C,2BAA4B,yBAAyB,CAAK,EAC1D,sBAAuB,oBAAoB,CAAK,EAChD,cAAe,qBAAqB,CAAK,EACzC,yBACA,qBACA,UACF,EACM,EAAmB,MAAM,EAAS,4BACtC,qBAAqB,EAAQ,EAAa,EAAY,KAAM,EAAY,GAAI,CAAe,CAC7F,EACM,EAAwB,IAAI,IAChC,EAAiB,UAAU,UACxB,OAAQ,GAAU,EAAM,KAAK,WAAW,EAAe,CAAC,CAAC,CACzD,IAAK,GAAU,EAAM,KAAK,MAAM,EAAsB,CAAC,CAC5D,EACM,CACJ,EACA,EACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,IACE,MAAM,QAAQ,IAAI,CACpB,EAAS,oBAAuB,aAAa,CAAG,CAAC,EACjD,EAAS,yBAA4B,kBAAkB,CAAG,CAAC,EAC3D,EAAS,qBAAwB,cAAc,CAAG,CAAC,EACnD,EAAS,eAAkB,QAAQ,CAAG,CAAC,EACvC,EAAS,gBAAmB,SAAS,CAAG,CAAC,EACzC,EAAS,oBAAuB,aAAa,CAAG,CAAC,EACjD,EAAS,uBAA0B,gBAAgB,EAAK,CAAsB,CAAC,EAC/E,EAAS,oBAAuB,aAAa,CAAG,CAAC,EACjD,EAAS,oBACP,aACE,EACA,EACA,EAAY,KACZ,EAAY,GACZ,GAAiB,WAAa,CAAC,EAC/B,GAAqB,aAAe,CAAC,EACrC,EACA,CACE,GAAG,oBAAoB,CAAK,EAC5B,iBAAkB,gCAAgC,CAAM,EACxD,cAAe,EAAI,cACnB,UAAW,EAAI,SACjB,CACF,CACF,EACA,EAAS,mCACP,uCACE,EACA,EACA,EAAY,KACZ,EAAY,GACZ,EAAO,UAAU,mBAAqB,CAAC,CACzC,CACF,EACA,EAAS,yBAA4B,kBAAkB,CAAG,CAAC,CAC7D,CAAC,EAED,MAAO,CACL,cACA,mBACA,WACA,gBACA,aACA,OACA,QACA,YACA,OACA,YACA,YACA,2BACA,gBACF,CACF,CAAC,CACH,CAEA,eAAsB,sBACpB,EAC8B,CAC9B,GAAM,CAAE,UAAS,aAAa,qBAAsB,GAAG,GAAe,EACtE,OAAO,QAAQ,IACb,EAAQ,IAAK,GACX,EAAW,CACT,GAAG,EACH,SACA,SACF,CAAC,CACH,CACF,CACF,CAEA,eAAsB,uBAAuB,EAAqD,CAChG,GAAM,CAAE,cAAa,MAAK,SAAS,GAAO,uBAAuB,CAAC,GAAM,EACnE,GACH,MAAM,kCACJ,EAAY,QAAS,GAAe,EAAW,SAAS,QAAQ,iBAAiB,EACjF,CACF,EAEF,MAAM,4BAA4B,EAAsB,CAAG,EAC3D,IAAM,EAAiB,IAAI,IAAI,EAAY,IAAK,GAAe,EAAW,YAAY,IAAI,CAAC,EACrF,EAAiB,gCAAgC,CAAW,EAC5D,EAA6B,IAAI,IACjC,EAAkD,CAAC,EAEzD,IAAK,IAAM,KAAc,EAAa,CACpC,IAAM,EAAU,sBAAsB,CAAU,EAC1C,EAAY,sBAAsB,CAAO,EAC/C,MAAM,qBACJ,EACA,EAAW,YAAY,KACvB,EACA,EAAW,YAAY,EACzB,EAGA,MAAM,0BADY,0BAA0B,CACZ,EAAW,EAAW,YAAY,KAAM,CAAG,EAE3E,EAAmB,KAAK,GAAG,kCAAkC,CAAO,CAAC,EAErE,IAAM,EAAY,2BAA2B,CAC3C,YACA,iBACA,kBAAmB,CACrB,CAAC,EACD,IAAK,IAAM,KAAY,EACjB,EAA2B,IAAI,CAAQ,IAG3C,EAA2B,IAAI,CAAQ,EACvC,EAAW,IAAI,QAAQ,KAAK,CAC1B,KAAM,EACN,QAAS,CACP,YAAa,EAAW,SAAS,QAAQ,YACzC,gBAAiB,CACnB,CACF,CAAC,EAEL,CAEA,MAAM,iCAAiC,EAAoB,CAAG,CAChE,CAEA,eAAe,wBACb,EACe,CACf,IAAK,IAAM,KAAc,EACvB,MAAM,aAAa,sBAAsB,CAAU,CAAC,CAExD,CAYA,SAAgB,kCACd,EACA,EACa,CACb,GAAI,CAAC,GAAiB,uBACpB,OAAO,EAET,IAAM,EAAc,EAAgB,yBAA2B,IAAA,GACzD,EACJ,GAAe,EAAY,YACvB,CAAE,GAAG,EAAY,YAAa,YAAa,IAAA,EAAU,EACrD,EAAY,YACZ,EAAwB,CAC5B,GAAG,EACH,gBAAiB,EAAc,IAAA,GAAY,EAAY,gBACvD,cACA,sBAAuB,EAAY,sBAAsB,IAAK,IAAa,CACzE,GAAG,EACH,cAAe,IAAA,EACjB,EAAE,EACF,IAAI,cAAe,CACjB,MAAO,CAAC,CAAQ,CAClB,CACF,EACA,OAAO,CACT,CASA,eAAe,eACb,EACA,EACA,EACA,CACA,OAAO,EAAS,SAAU,KAAO,IAAa,CAC5C,EAAS,aAAa,iBAAkB,GAAS,QAAU,EAAK,EAKhE,GAAmB,EACnB,EAAoB,EAEpB,IAAM,EAAc,uBAAuB,GAAS,UAAU,EACxD,EAAS,GAAS,QAAU,GAC5B,EACJ,GAAS,WAAa,GAAa,QAAQ,IAAI,wBAAwB,IAAM,GACzE,EAAmB,EACrB,CAAC,EACD,MAAM,EAAS,uBACb,kBAAkB,CAAE,cAAa,SAAQ,WAAU,CAAC,CACtD,EACE,EAAsB,EAAiB,KAAK,CAAE,YAAa,EAAO,IAAI,EACtE,EAA0B,EAAiB,KAAK,CAAE,aAAc,CACpE,WAAY,EAAO,KACnB,cAAe,EAAO,IAAM,QAAQ,EAAO,MAC7C,EAAE,EACI,EAAY,EACd,IAAA,GACA,MAAM,uBAAuB,CAC3B,YAAa,GAAS,YACtB,QAAS,GAAS,QAClB,gBAAiB,GAAS,gBAC1B,cAAe,GAAS,cACxB,gBAAiB,GAAS,gBAC1B,eAAgB,GAAS,eACzB,SAAU,GAAS,SACnB,SACA,eAAgB,EAChB,WAAY,gBAAgB,EAAS,EAAqB,CAAU,EACpE,qBAAsB,sBAAsB,EAAS,CAAU,EAC/D,qBAAsB,GAAY,MAAQ,EAAO,QACnD,CAAC,EACC,EAAU,MAAM,EAAS,QAAS,SAAY,CAClD,IAAM,EAAU,GAAS,SAAW,GAC9B,EAAc,MAAM,GAAgB,EACpC,EAAW,EAAK,QAAQ,GAAW,EAAG,OAAO,EAgBnD,OAfI,GAAS,aACX,EAAG,OAAO,EAAU,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,EACpD,EAAO,KAAK,sBAAsB,GAa7B,MAVe,uBAAuB,CAC3C,cACA,cAAe,EAAY,IAAA,GAAY,EACvC,SACA,YACA,UACA,eAAgB,EAAY,SAAW,UACvC,UACF,CAAC,CAGH,CAAC,EACD,GAAI,EACF,MAAO,CAAE,eAAgB,oBAAoB,CAAO,CAAE,EAUxD,GAPA,gCAAgC,CAAO,EAOnC,CAAC,EAAW,MAAM,EAAc,4BAA4B,EAChE,GAAM,CAAE,SAAQ,eAAgB,EAEhC,EAAS,aAAa,WAAY,EAAQ,IAAK,GAAW,EAAO,YAAY,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,EAC5F,EAAS,aAAa,eAAgB,CAAW,EAEjD,IAAM,EAAc,EAAQ,IAAK,IAAY,CAC3C,GAAG,EACH,YAAa,kCAAkC,EAAO,YAAa,CAAe,CACpF,EAAE,EACI,EAAiB,MAAM,EAAS,0BACpC,2BAA2B,CACzB,SACA,cACA,aAAc,EAAY,KAAK,CAAE,iBAAkB,CAAW,CAChE,CAAC,CACH,EACM,EAAY,2BAA2B,EAAa,CAAC,GAAS,MAAM,EACpE,EAAc,MAAM,sBAAsB,CAC9C,QAAS,EACT,YACA,OAAQ,EACR,cACA,cAAe,GAAS,cACxB,uBAAwB,GAAiB,uBACzC,uBAAwB,GAAiB,sBAC3C,CAAC,EAEK,EAAM,GAAS,KAAO,GAE5B,kCAAkC,CAAW,EAG7C,IAAM,GACJ,MAAM,QAAQ,IACZ,EAAY,IAAK,GACf,0BAA0B,CACxB,OAAQ,EACR,cACA,YAAa,EAAO,YACpB,UAAW,EAAU,WAAa,IAAI,IACtC,eAAgB,uBAAuB,EAAU,mBAAoB,CAAM,EAC3E,eAAgB,EAAO,qBAAqB,aAAe,CAAC,CAC9D,CAAC,CACH,CACF,EAAA,CACA,KAAK,EAEP,MAAM,EAAS,UAAW,SAAY,CACpC,MAAM,uBAAuB,CAAE,cAAa,MAAK,SAAQ,sBAAqB,CAAC,CACjF,CAAC,EAED,IAAM,EAAc,qBAAqB,EAAa,CAAE,OAAQ,GAAS,MAAO,CAAC,EAQjF,GANI,GAAS,WACX,EAAO,KAAK,iDAAiD,EAE7D,MAAM,wBAAwB,CAAW,EAGvC,EAAQ,CACV,EAAO,KAAK,sCAAsC,EAClD,MACF,CAEA,MAAM,qBAAqB,EAAQ,EAAa,CAAW,EAEtD,GAAiB,uBAChB,EAAO,SACT,EAAO,IAAI,CAAE,QAAS,EAAa,OAAQ,SAAU,CAAC,EAEtD,EAAO,QAAQ,+BAA+B,EAKpD,CAAC,CACH,CAOA,SAAgB,OAAO,EAAyB,CAC9C,OAAO,eAAe,CAAO,CAC/B,CASA,SAAgB,4BACd,EACA,EACA,EACA,CACA,OAAO,eAAe,EAAS,IAAA,GAAW,CACxC,uBAAwB,EACxB,uBAAwB,EACxB,qBAAsB,EACxB,CAAC,CACH,CAQA,SAAgB,0BACd,EACA,EACA,CACA,OAAO,eAAe,EAAS,IAAA,GAAW,CACxC,uBAAwB,EACxB,qBAAsB,EACxB,CAAC,CACH,CAQA,SAAgB,cAAc,EAAoC,EAA8B,CAC9F,OAAO,eAAe,EAAS,CAAU,CAC3C,CC3yBA,SAAgB,0BAA0B,EAAwB,CAChE,OAAQ,EAAR,CACE,IAAK,UACH,OAAO,EAAO,IAAI,CAAM,EAC1B,IAAK,UACH,OAAO,EAAO,KAAK,CAAM,EAC3B,IAAK,UACH,OAAO,EAAO,QAAQ,CAAM,EAC9B,IAAK,SACH,OAAO,EAAO,MAAM,CAAM,EAC5B,IAAK,WACH,OAAO,EAAO,QAAQ,CAAM,EAC9B,QACE,OAAO,CACX,CACF,CAOA,SAAS,4BAA4B,EAAoC,CACvE,OAAO,2BAA2B,CAAM,GAAK,2BAA2B,CAAM,CAChF,CAOA,SAAS,2BAA2B,EAAoC,CACtE,OAAO,IAAW,EAAkB,OACtC,CAOA,SAAS,2BAA2B,EAAoC,CACtE,OAAO,IAAW,EAAkB,QAAU,IAAW,EAAkB,QAC7E,CAOA,SAAS,6BAA6B,EAAoC,CACxE,OACE,IAAW,EAAkB,aAC7B,IAAW,EAAkB,SAC7B,IAAW,EAAkB,OAEjC,CAOA,SAAgB,0BAA0B,EAAmD,CAW3F,OAVI,2BAA2B,CAAM,EAC5B,UAEL,4BAA4B,CAAM,EAC7B,WAEL,6BAA6B,CAAM,EAC9B,YAIX,CAOA,SAAgB,uBAAuB,EAAmC,CAExE,OADoB,EAAO,YACT,EAAlB,CACE,IAAK,UACH,OAAO,EAAkB,QAC3B,IAAK,UACH,OAAO,EAAkB,QAC3B,IAAK,UACH,OAAO,EAAkB,QAC3B,IAAK,SACH,OAAO,EAAkB,OAC3B,IAAK,WACH,OAAO,EAAkB,SAC3B,QACE,MAAM,EAAS,CACb,KAAM,0BACN,QAAS,mBAAmB,EAAO,4DACrC,CAAC,CACL,CACF,CAWA,SAAgB,2BAA2B,EAAwC,CACjF,OAAQ,EAAR,CACE,KAAK,EAAmB,QACtB,MAAO,UACT,KAAK,EAAmB,eACtB,MAAO,UACT,KAAK,EAAmB,SACtB,MAAO,WACT,KAAK,EAAmB,aACtB,MAAO,eACT,KAAK,EAAmB,SACtB,MAAO,WACT,QACE,MAAO,aACX,CACF,CAOA,SAAgB,4BAA4B,EAA0C,CACpF,OAAQ,EAAR,CACE,KAAK,GAAoB,SACvB,MAAO,WACT,KAAK,GAAoB,MACvB,MAAO,QACT,KAAK,GAAoB,iBACvB,MAAO,mBACT,QACE,MAAO,aACX,CACF,CC/HA,SAAS,0BAA0B,EAAmC,CACpE,OAAQ,EAAR,CACE,KAAK,EAAkB,QACrB,MAAO,UACT,KAAK,EAAkB,QACrB,MAAO,UACT,KAAK,EAAkB,QACrB,MAAO,UACT,KAAK,EAAkB,OACrB,MAAO,SACT,KAAK,EAAkB,SACrB,MAAO,WACT,QACE,MAAO,aACX,CACF,CAOA,SAAgB,sBAAsB,EAAuC,CAC3E,MAAO,CACL,GAAI,EAAI,GACR,aAAc,EAAI,aAClB,OAAQ,0BAA0B,EAAI,MAAM,EAC5C,UAAW,EAAI,UAAY,EAAc,EAAI,SAAS,CAAC,CAAC,YAAY,EAAI,KAC1E,CACF,CAOA,SAAgB,kBAAkB,EAAmC,CACnE,MAAO,CACL,GAAI,EAAI,GACR,aAAc,EAAI,aAClB,OAAQ,0BAA0B,EAAI,MAAM,EAC5C,YAAa,EAAI,YAAc,EAAc,EAAI,WAAW,CAAC,CAAC,YAAY,EAAI,MAC9E,UAAW,EAAI,UAAY,EAAc,EAAI,SAAS,CAAC,CAAC,YAAY,EAAI,MACxE,UAAW,EAAI,UAAY,EAAc,EAAI,SAAS,CAAC,CAAC,YAAY,EAAI,KAC1E,CACF,CAOA,SAAgB,yBAAyB,EAAqD,CAC5F,MAAO,CACL,GAAI,EAAQ,GACZ,MAAO,EAAQ,MACf,OAAQ,0BAA0B,EAAQ,MAAM,EAChD,MAAO,EAAQ,OAAS,GACxB,UAAW,EAAQ,UAAY,EAAc,EAAQ,SAAS,CAAC,CAAC,YAAY,EAAI,MAChF,WAAY,EAAQ,WAAa,EAAc,EAAQ,UAAU,CAAC,CAAC,YAAY,EAAI,MACnF,mBAAoB,EAAQ,oBAAsB,EACpD,CACF,CAuBA,SAAS,mBAAmB,EAAiB,EAAuC,CAClF,IAAM,EAAU,EACb,IAAK,GAAc,EAAU,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,GAAK,CAAS,CAAC,CAC5D,KAAK,IAAI,EACZ,OAAO,EAAU,UAAU,EAAQ,GAAG,IAAY,UAAU,GAC9D,CAEA,SAAS,wBAAwB,EAAmD,CAClF,IAAM,EAAc,EAAO,YAC3B,GAAI,EAAY,OAAS,IAAA,GACvB,OAAO,KAGT,OAAQ,EAAY,KAApB,CACE,IAAK,WACH,OAAO,mBAAmB,EAAY,MAAM,SAAU,EAAY,MAAM,UAAU,EACpF,IAAK,WACH,OAAO,mBAAmB,EAAY,MAAM,aAAc,EAAY,MAAM,UAAU,EACxF,IAAK,MACH,OAAO,mBAAmB,WAAY,EAAY,MAAM,UAAU,EACpE,IAAK,OACH,OAAO,mBAAmB,oBAAqB,EAAY,MAAM,UAAU,EAC7E,QACE,OAAO,IACX,CACF,CAYA,SAAS,kBAAkB,EAAoC,CAC7D,IAAM,EAAS,EAAS,eAAe,OACvC,GAAI,CAAC,GAAU,EAAO,OAAS,IAAA,GAC7B,OAAO,4BAA4B,EAAS,WAAW,EAGzD,OAAQ,EAAO,KAAf,CACE,IAAK,WACH,MAAO,aAAa,EAAO,MAAM,UAAU,IAAI,EAAO,MAAM,SAAS,GACvE,IAAK,QAAS,CACZ,IAAM,EAAe,wBAAwB,EAAO,KAAK,EACzD,GAAI,EACF,OAAO,EAET,IAAM,EAAe,6BAA6B,EAAO,KAAK,EAI9D,OAHK,EAAa,UAGX,mBAAmB,EAAa,UAAW,EAAa,SAAS,EAF/D,4BAA4B,EAAS,WAAW,CAG3D,CACA,IAAK,kBACH,MAAO,UACT,QACE,OAAO,4BAA4B,EAAS,WAAW,CAC3D,CACF,CAEA,SAAS,6BAA6B,EAGpC,CAEA,MAAO,CAAE,UAAW,EAAO,UAAW,UAAW,EAAO,WAAW,IAAK,CAC1E,CAQA,SAAS,mBAAmB,EAAmB,EAA4B,CACzE,IAAM,EAAQ,EAAU,MAAM,GAAG,EACjC,GAAI,EAAM,OAAS,EACjB,MAAO,UAAU,IAGnB,GAAM,CAAC,EAAS,EAAU,GAAU,EAGpC,GAAI,EAAW,CAEb,IAAM,EAAgB,EAAU,MAAM,0CAA0C,EAChF,GAAI,EACF,MAAO,UAAU,EAAc,GAAG,GAAG,IAIvC,IAAM,EAAoB,EAAU,MAAM,8CAA8C,EACxF,GAAI,EACF,MAAO,UAAU,EAAkB,GAAG,GAAG,GAE7C,CAGA,MAAO,UAAU,EAAQ,GAAG,EAAS,GAAG,GAC1C,CAOA,SAAS,oBAAoB,EAAqD,CAChF,IAAM,EAAS,EAAS,eAAe,OACvC,GAAI,CAAC,GAAU,EAAO,OAAS,IAAA,GAC7B,MAAO,CAAC,EAGV,OAAQ,EAAO,KAAf,CACE,IAAK,WACH,MAAO,CACL,SAAU,EAAO,MAAM,SACvB,UAAW,EAAO,MAAM,SAC1B,EACF,IAAK,QACH,OAAO,yBAAyB,EAAO,KAAK,EAC9C,IAAK,kBACH,MAAO,CACL,OAAQ,EAAO,MAAM,OAAS,MAAQ,EACxC,EACF,QACE,MAAO,CAAC,CACZ,CACF,CAEA,SAAS,yBAAyB,EAA6D,CAC7F,IAAM,EAAc,EAAO,YAC3B,GAAI,EAAY,OAAS,IAAA,GAAW,CAClC,IAAM,EAAe,6BAA6B,CAAM,EACxD,MAAO,CACL,UAAW,EAAa,UACxB,UAAW,EAAa,WAAa,EACvC,CACF,CAKA,GAAI,EAAY,OAAS,WACvB,MAAO,CACL,KAAM,EAAY,KAClB,WAAY,EAAY,MAAM,WAC9B,UAAW,EAAY,MAAM,WAAW,MAAQ,GAChD,GAAI,EAAY,MAAM,cAAgB,CAAE,aAAc,EAAY,MAAM,YAAa,CACvF,EAGF,IAAM,EAAO,CACX,KAAM,EAAY,KAClB,WAAY,EAAY,MAAM,WAC9B,cAAe,EAAY,MAAM,cACjC,UAAW,EAAY,MAAM,WAAW,MAAQ,EAClD,EAEA,OAAQ,EAAY,KAApB,CACE,IAAK,WACH,MAAO,CAAE,GAAG,EAAM,SAAU,EAAY,MAAM,QAAS,EACzD,IAAK,WACH,MAAO,CAAE,GAAG,EAAM,aAAc,EAAY,MAAM,YAAa,EACjE,QACE,OAAO,CACX,CACF,CAOA,SAAS,mBAAmB,EAAqD,CAC/E,IAAM,EAAS,EAAS,cAAc,OACtC,GAAI,CAAC,GAAU,EAAO,OAAS,IAAA,GAC7B,MAAO,CAAC,EAGV,OAAQ,EAAO,KAAf,CACE,IAAK,UACH,MAAO,CACL,IAAK,EAAO,MAAM,KAAK,MAAQ,GAC/B,QAAS,EAAO,MAAM,QAAQ,MAChC,EACF,IAAK,gBACH,MAAO,CACL,QAAS,EAAO,MAAM,QACtB,MAAO,EAAO,MAAM,KACtB,EACF,IAAK,WACH,MAAO,CACL,KAAM,EAAO,MAAM,IACrB,EACF,IAAK,WACH,MAAO,CACL,aAAc,EAAO,MAAM,YAC7B,EACF,QACE,MAAO,CAAC,CACZ,CACF,CAOA,SAAgB,mBAAmB,EAA8C,CAC/E,MAAO,CACL,KAAM,EAAS,KACf,YAAa,kBAAkB,CAAQ,EACvC,WAAY,2BAA2B,EAAS,UAAU,EAC1D,SAAU,EAAS,QACrB,CACF,CAOA,SAAgB,eAAe,EAA0C,CACvE,MAAO,CACL,KAAM,EAAS,KACf,YAAa,EAAS,YACtB,YAAa,kBAAkB,CAAQ,EACvC,WAAY,2BAA2B,EAAS,UAAU,EAC1D,SAAU,EAAS,SACnB,cAAe,oBAAoB,CAAQ,EAC3C,aAAc,mBAAmB,CAAQ,CAC3C,CACF,CCtVA,MAAMC,GAAW,CACf,KAAM,EAAI,EAAE,OAAO,EAAG,CACpB,WAAY,GACZ,YAAa,eACf,CAAC,CACH,EAeA,eAAe,gBACb,EACA,EACA,EACA,CACA,GAAM,CAAE,YAAa,MAAM,EAAO,oBAAoB,CACpD,cACA,MACF,CAAC,EACD,GAAI,CAAC,EACH,MAAM,EAAS,CAAE,KAAM,qBAAsB,QAAS,aAAa,EAAK,aAAc,CAAC,EAEzF,OAAO,CACT,CAOA,eAAsB,YACpB,EACuB,CACvB,IAAM,EAAO,EAAQ,SAAS,KACxB,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAQ,QACjB,YAAa,EAAQ,WACvB,CAAC,EAED,GAAI,CAEF,OAAO,eAAe,MADC,gBAAgB,EAAQ,EAAa,CAAI,CAClC,CAChC,OAAS,EAAO,CAQd,MAPI,aAAiB,GAAgB,EAAM,OAAS,EAAK,SACjD,EAAS,CACb,KAAM,qBACN,QAAS,aAAa,EAAK,cAC3B,MAAO,CACT,CAAC,EAEG,CACR,CACF,CAEA,MAAaC,GAAa,EAAiB,CACzC,KAAM,MACN,YAAa,uBACb,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,GAAGD,EACL,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAW,MAAM,YAAY,CACjC,SAAU,CAAE,KAAM,EAAK,IAAK,EAC5B,YAAa,EAAK,gBAClB,QAAS,EAAK,OAChB,CAAC,EAED,EAAO,IAAI,EAAU,CACnB,QAAS,CACP,cAAe,KACf,aAAc,IAChB,CACF,CAAC,CACH,CACF,CAAC,EC3ED,SAAgB,gCAAgC,EAA0C,CACxF,OAAQ,EAAR,CACE,KAAK,EAAyB,QAC5B,MAAO,UACT,KAAK,EAAyB,QAC5B,MAAO,UACT,KAAK,EAAyB,OAC5B,MAAO,SACT,KAAK,EAAyB,QAC5B,MAAO,UACT,KAAK,EAAyB,UAC5B,MAAO,YACT,KAAK,EAAyB,SAC5B,MAAO,WACT,QACE,MAAO,aACX,CACF,CAOA,SAAgB,gCAAgC,EAAwB,CACtE,OAAQ,EAAR,CACE,IAAK,UACH,OAAO,EAAO,KAAK,CAAM,EAC3B,IAAK,UACH,OAAO,EAAO,QAAQ,CAAM,EAC9B,IAAK,SACH,OAAO,EAAO,MAAM,CAAM,EAC5B,QACE,OAAO,CACX,CACF,CAOA,SAAgB,kCAAkC,EAA2C,CAC3F,OACE,IAAW,EAAyB,SACpC,IAAW,EAAyB,QACpC,IAAW,EAAyB,QAExC,CAOA,SAAgB,4BAA4B,EAAuC,CACjF,OAAQ,EAAR,CACE,KAAK,EAAoB,IACvB,MAAO,MACT,KAAK,EAAoB,MACvB,MAAO,QACT,KAAK,EAAoB,KACvB,MAAO,OACT,KAAK,EAAoB,QACvB,MAAO,UACT,KAAK,EAAoB,MACvB,MAAO,QACT,QACE,MAAO,aACX,CACF,CAOA,SAAgB,uBAAuB,EAA+C,CACpF,MAAO,CACL,QAAS,EAAM,QACf,SAAU,4BAA4B,EAAM,QAAQ,EACpD,UAAW,EAAM,UAAY,EAAc,EAAM,SAAS,EAAI,IAChE,CACF,CAEA,SAAS,oBAAoB,EAA0B,CACrD,IAAM,EAAQ,IAAI,EAAS,GAC3B,OAAQ,EAAR,CACE,IAAK,QACH,OAAO,EAAO,MAAM,CAAK,EAC3B,IAAK,UACH,OAAO,EAAO,QAAQ,CAAK,EAC7B,IAAK,QACH,OAAO,EAAO,IAAI,CAAK,EACzB,QACE,OAAO,CACX,CACF,CAOA,SAAgB,uBAAuB,EAAqC,CAC1E,IAAM,EAAY,EAAM,UAAY,EAAM,UAAU,YAAY,EAAI,MACpE,MAAO,GAAG,EAAO,IAAI,CAAS,EAAE,GAAG,oBAAoB,EAAM,QAAQ,EAAE,GAAG,EAAM,SAClF,CASA,SAAgB,uBACd,EACA,EACU,CAIV,OAHI,GAAc,EAAW,OAAS,EAC7B,EAAW,IAAI,sBAAsB,EAEvC,EAAO,EAAK,MAAM;CAAI,EAAI,CAAC,CACpC,CC9IA,SAAgB,gBAAgB,EAAwB,CACtD,OAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAC9D,CAOA,SAAgB,qBAAqB,EAAyB,CAI5D,OAHM,aAAiB,EAIrB,EAAM,OAAS,EAAK,SACpB,EAAM,OAAS,EAAK,mBACpB,EAAM,OAAS,EAAK,YALb,EAOX,CClBA,MAAM,GAAuB,EAAE,KAAK,CAClC,UACA,YACA,UACF,CAAC,EAEY,GAAW,CACtB,KAAM,EAAI,EAAE,OAAO,EAAG,CACpB,WAAY,GACZ,YAAa,eACf,CAAC,CACH,EAEa,GAA0B,CACrC,SAAU,EAAI,GAAY,QAAQ,IAAI,EAAG,CACvC,MAAO,IACP,YAAa,2DACf,CAAC,EACD,QAAS,EAAI,GAAY,QAAQ,KAAK,EAAG,CACvC,MAAO,IACP,YAAa,2CACf,CAAC,EACD,MAAO,EAAI,GAAqB,QAAQ,UAAU,EAAG,CACnD,MAAO,IACP,YAAa,4CACf,CAAC,EACD,KAAM,EAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAK,EAAG,CACpC,MAAO,IACP,YAAa,6CACf,CAAC,CACH,EAEa,GAAW,CACtB,KAAM,EAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAK,EAAG,CACpC,MAAO,IACP,YAAa,gCACf,CAAC,EACD,GAAG,EACL,ECzBA,SAAS,iCAAiC,EAA2C,CACnF,OAAO,IAAW,EAAyB,OAC7C,CAOA,SAAS,sCAAsC,EAA8C,CAC3F,OACE,IAAW,GAA4B,SAAW,IAAW,GAA4B,OAE7F,CAOA,SAAgB,mCAAmC,EAA2C,CAC5F,OACE,IAAW,EAAyB,gBACpC,IAAW,EAAyB,OAExC,CAOA,SAAgB,iCAAiC,EAA2C,CAC1F,OAAO,IAAW,EAAyB,MAC7C,CAOA,SAAS,mCAAmC,EAA2C,CACrF,OACE,IAAW,EAAyB,aACpC,IAAW,EAAyB,SACpC,IAAW,EAAyB,SACpC,IAAW,EAAyB,aAExC,CAOA,SAAS,kCAAkC,EAA2C,CACpF,OACE,iCAAiC,CAAM,GACvC,iCAAiC,CAAM,GACvC,mCAAmC,CAAM,CAE7C,CAOA,SAAgB,gCACd,EACuC,CAiBvC,OAhBI,kCAAkC,EAAU,MAAM,EAChD,iCAAiC,EAAU,MAAM,EAC5C,CAAE,YAAa,UAAW,OAAQ,EAAU,MAAO,EAExD,iCAAiC,EAAU,MAAM,EAC5C,CAAE,YAAa,UAAW,OAAQ,EAAU,MAAO,EAErD,CAAE,YAAa,YAAa,OAAQ,EAAU,MAAO,EAE1D,EAAU,cAAc,KAAM,GAAQ,sCAAsC,EAAI,MAAM,CAAC,EAClF,CAAE,YAAa,YAAa,OAAQ,EAAU,MAAO,GAE1D,mCAAmC,EAAU,MAAM,EAC9C,CAAE,YAAa,YAAa,OAAQ,EAAU,MAAO,EAIhE,CAQA,SAAgB,6BACd,EACA,EACS,CACT,OAAQ,EAAR,CACE,IAAK,UACH,OAAO,EAAe,cAAgB,UACxC,IAAK,YACH,OAAO,EAAe,cAAgB,YACxC,IAAK,WACH,OACE,EAAe,cAAgB,WAC/B,EAAe,cAAgB,WAC/B,EAAe,cAAgB,WAErC,CACF,CClFA,SAAS,gCAAgC,EAA0C,CACjF,OAAQ,EAAR,CACE,KAAK,EAAyB,QAC5B,MAAO,UACT,KAAK,EAAyB,eAC5B,MAAO,iBACT,KAAK,EAAyB,QAC5B,MAAO,UACT,KAAK,EAAyB,QAC5B,MAAO,UACT,KAAK,EAAyB,OAC5B,MAAO,SACT,KAAK,EAAyB,cAC5B,MAAO,gBACT,KAAK,EAAyB,QAC5B,MAAO,UACT,QACE,MAAO,aACX,CACF,CAOA,SAAS,mCAAmC,EAA6C,CACvF,OAAQ,EAAR,CACE,KAAK,GAA4B,QAC/B,MAAO,UACT,KAAK,GAA4B,QAC/B,MAAO,UACT,KAAK,GAA4B,QAC/B,MAAO,UACT,KAAK,GAA4B,OAC/B,MAAO,SACT,KAAK,GAA4B,QAC/B,MAAO,UACT,QACE,MAAO,aACX,CACF,CAOA,SAAgB,mBAAmB,EAAsC,CACvE,MAAO,CACL,KAAM,EAAS,KACf,QAAS,EAAS,oBAClB,aAAc,OAAO,KAAK,EAAS,YAAY,CAAC,CAAC,OACjD,UAAW,EAAS,UAAY,EAAc,EAAS,SAAS,EAAI,IACtE,CACF,CAOA,SAAgB,eAAe,EAAkC,CAC/D,IAAM,EAAuC,CAAC,EAC9C,IAAK,GAAM,CAAC,EAAM,KAAY,OAAO,QAAQ,EAAS,YAAY,EAChE,EAAa,GAAQ,EAAQ,SAAS,EAGxC,MAAO,CACL,KAAM,EAAS,KACf,GAAI,EAAS,GACb,QAAS,EAAS,oBACJ,eACd,UAAW,EAAS,UAAY,EAAc,EAAS,SAAS,EAAI,KACpE,UAAW,EAAS,UAAY,EAAc,EAAS,SAAS,EAAI,IACtE,CACF,CAOA,SAAgB,2BACd,EAC0B,CAC1B,MAAO,CACL,GAAI,EAAa,GACjB,eAAgB,EAAa,eAC7B,OAAQ,mCAAmC,EAAa,MAAM,EAC9D,YAAa,EAAa,YAC1B,UAAW,EAAa,UAAY,EAAc,EAAa,SAAS,EAAI,KAC5E,WAAY,EAAa,WAAa,EAAc,EAAa,UAAU,EAAI,IACjF,CACF,CAOA,SAAgB,wBAAwB,EAAqD,CAC3F,MAAO,CACL,GAAI,EAAU,GACd,aAAc,EAAU,aACxB,OAAQ,gCAAgC,EAAU,MAAM,EACxD,cAAe,EAAU,cAAc,OACvC,UAAW,EAAU,UAAY,EAAc,EAAU,SAAS,EAAI,KACtE,WAAY,EAAU,WAAa,EAAc,EAAU,UAAU,EAAI,IAC3E,CACF,CC1GA,SAASE,aAAW,EAAoB,CACtC,OAAO,EAAK,mBAAmB,QAAS,CAAE,OAAQ,EAAM,CAAC,CAC3D,CAEA,SAAS,eAAe,EAA0C,CAChE,IAAM,EAAa,EAAyB,GAC5C,OAAQ,EAAR,CACE,KAAK,EAAyB,QAC9B,KAAK,EAAyB,YAC5B,OAAO,EAAO,IAAI,CAAU,EAC9B,KAAK,EAAyB,eAC9B,KAAK,EAAyB,cAC9B,KAAK,EAAyB,QAC5B,OAAO,EAAO,QAAQ,CAAU,EAClC,KAAK,EAAyB,QAC5B,OAAO,EAAO,KAAK,CAAU,EAC/B,KAAK,EAAyB,QAC5B,OAAO,EAAO,QAAQ,CAAU,EAClC,KAAK,EAAyB,OAC5B,OAAO,EAAO,MAAM,CAAU,EAChC,QACE,OAAO,CACX,CACF,CAEA,SAAS,cAAc,EAAsC,CAC3D,OAAO,EAAU,cACd,OACE,GACC,EAAI,SAAW,GAA4B,SAC3C,EAAI,SAAW,GAA4B,SAC3C,EAAI,SAAW,GAA4B,OAC/C,CAAC,CACA,IAAK,GAAQ,EAAI,cAAc,CAAC,CAChC,KAAK,IAAI,CACd,CAWA,SAAS,yBAAyB,EAA8D,CAC9F,IAAM,EAAY,KAAK,IAAI,EAAI,EAAQ,UACvC,GAAI,EAAQ,UAAW,CACrB,IAAM,EAAiB,gCAAgC,EAAQ,SAAS,EACxE,MAAO,CACL,GAAG,wBAAwB,EAAQ,SAAS,EAC5C,YAAa,EAAe,YAC5B,YACA,SAAU,EAAQ,SAClB,SAAU,EAAQ,SAClB,UAAW,EAAQ,SACrB,CACF,CACA,MAAO,CACL,GAAI,EAAQ,YACZ,aAAc,GACd,OAAQ,UACR,YAAa,UACb,cAAe,EACf,UAAW,KACX,WAAY,KACZ,YACA,SAAU,EAAQ,SAClB,SAAU,EAAQ,SAClB,UAAW,EAAQ,SACrB,CACF,CAOA,eAAsB,yBACpB,EAC6B,CAC7B,IAAM,EAAW,EAAQ,UAAY,IAC/B,EAAQ,EAAQ,OAAS,WACzB,EAAY,KAAK,IAAI,EACrB,EAAK,EAAQ,aACf,QAAQ,CAAE,OAAQ,CAAE,CAAC,CAAC,CAAC,MAAM,qCAAqC,EAClE,KAEA,EAAW,EACX,EACA,EAA2B,KAC3B,EACA,EAEJ,GAAI,CAEF,OAAa,CACX,IAAM,EAAY,KAAK,IAAI,EAAI,EACzB,EAAc,EAAQ,UAAY,IAAA,GAAY,IAAA,GAAY,EAAQ,QAAU,EAClF,GAAI,IAAgB,IAAA,IAAa,GAAe,EAE9C,OADA,GAAI,KAAK,0BAA0B,EAC5B,yBAAyB,CAC9B,YAAa,EAAQ,YACrB,UAAW,EACX,YACA,WACA,SAAU,GACV,WACF,CAAC,EAGH,GAAI,CACF,GAAY,EACZ,GAAM,CAAE,aAAc,MAAM,EAAQ,OAAO,qBAAqB,CAC9D,YAAa,EAAQ,YACrB,YAAa,EAAQ,WACvB,CAAC,EAED,GAAI,CAAC,EAEH,MADA,GAAI,KAAK,cAAc,EAAQ,YAAY,aAAa,EAClD,EAAS,CACb,KAAM,+BACN,QAAS,cAAc,EAAQ,YAAY,aAC7C,CAAC,EAGH,EAAgB,EAChB,EAAY,KAEZ,IAAM,EAAiB,gCAAgC,CAAS,EAC1D,EAAgB,eAAe,EAAU,MAAM,EAcrD,GAZI,EAAU,SAAW,IACnB,EAAQ,eACV,GAAI,KAAK,EACT,EAAO,KAAK,WAAW,IAAiB,CACtC,KAAM,SACN,OAAQ,CACV,CAAC,EACD,GAAI,MAAM,qCAAqC,GAEjD,EAAa,EAAU,QAGrB,EAAQ,UAAW,CACrB,IAAM,EAAa,cAAc,CAAS,EACtC,GAAc,IAAe,IAC3B,EAAQ,eACV,GAAI,KAAK,EACT,EAAO,KAAK,SAAS,EAAW,IAAI,IAAiB,CACnD,KAAM,SACN,OAAQ,CACV,CAAC,EACD,GAAI,MAAM,qCAAqC,GAEjD,EAAiB,EAErB,CAMA,GAJI,IACF,EAAG,KAAO,wCAAwCA,aAAW,IAAI,IAAM,EAAE,IAIzE,6BAA6B,EAAgB,CAAK,GAClD,EAAe,cAAgB,WAC9B,IAAU,aAAe,EAAe,cAAgB,UAWzD,OATI,EAAU,SAAW,EAAyB,QAChD,GAAI,QAAQ,cAAc,GAAe,EAChC,iCAAiC,EAAU,MAAM,EAC1D,GAAI,KAAK,cAAc,GAAe,EAC7B,mCAAmC,EAAU,MAAM,EAC5D,GAAI,KAAK,cAAc,GAAe,EAEtC,GAAI,QAAQ,cAAc,GAAe,EAEpC,yBAAyB,CAC9B,YAAa,EAAQ,YACrB,YACA,YACA,WACA,SAAU,GACV,WACF,CAAC,CAEL,OAAS,EAAO,CACd,GAAI,CAAC,qBAAqB,CAAK,EAC7B,MAAM,EAER,EAAY,gBAAgB,CAAK,EAC7B,EAAQ,cACN,IACF,EAAG,KAAO,qCAAqCA,aAAW,IAAI,IAAM,EAAE,GAG5E,CAEA,IAAM,EAAgB,KAAK,IAAI,EAAI,EAC7B,EACJ,EAAQ,UAAY,IAAA,GAAY,IAAA,GAAY,EAAQ,QAAU,EAChE,GAAI,IAAoB,IAAA,IAAa,GAAmB,EAEtD,OADA,GAAI,KAAK,0BAA0B,EAC5B,yBAAyB,CAC9B,YAAa,EAAQ,YACrB,UAAW,EACX,YACA,WACA,SAAU,GACV,WACF,CAAC,EAGH,MAAMC,GACJ,IAAoB,IAAA,GAAY,EAAW,KAAK,IAAI,EAAU,CAAe,CAC/E,CACF,CACF,QAAU,CACR,GAAI,KAAK,CACX,CACF,CAOA,eAAsB,6BACpB,EAC6B,CAC7B,GAAM,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAQ,QACjB,YAAa,EAAQ,WACvB,CAAC,EAED,OAAO,MAAM,yBAAyB,CACpC,SACA,cACA,YAAa,EAAQ,YACrB,SAAU,EAAQ,SAClB,QAAS,EAAQ,QACjB,MAAO,EAAQ,MACf,aAAc,EAAQ,aACtB,UAAW,EAAQ,SACrB,CAAC,CACH,CAQA,SAAgB,uBACd,EACA,EACsB,CACtB,IAAM,EAAU,CAAE,YAAa,EAAO,GAAI,OAAQ,EAAO,MAAO,EAChE,GAAI,EAAO,SACT,OAAO,EAAS,CACd,KAAM,wBACN,QAAS,6CAA6C,EAAO,GAAG,aAAa,EAAM,iBAAiB,EAAO,OAAO,GAClH,SACF,CAAC,EAEH,GAAI,EAAO,SAAW,SACpB,OAAO,EAAS,CACd,KAAM,4BACN,QAAS,uBAAuB,EAAO,GAAG,WAC1C,SACF,CAAC,EAEH,GAAI,IAAU,WAAa,EAAO,cAAgB,UAChD,OAAO,EAAS,CACd,KAAM,oCACN,QAAS,uBAAuB,EAAO,GAAG,YAAY,EAAO,OAAO,kBACpE,SACF,CAAC,EAEH,GAAI,IAAU,aAAe,EAAO,cAAgB,YAClD,OAAO,EAAS,CACd,KAAM,mCACN,QAAS,uBAAuB,EAAO,GAAG,YAAY,EAAO,OAAO,qBACpE,SACF,CAAC,CAGL,CC9PA,SAAS,YAAY,EAA0C,CAE7D,OADoB,EAAO,YACT,EAAlB,CACE,IAAK,UACH,OAAO,EAAyB,QAClC,IAAK,iBACH,OAAO,EAAyB,eAClC,IAAK,UACH,OAAO,EAAyB,QAClC,IAAK,UACH,OAAO,EAAyB,QAClC,IAAK,SACH,OAAO,EAAyB,OAClC,IAAK,gBACH,OAAO,EAAyB,cAClC,IAAK,UACH,OAAO,EAAyB,QAClC,IAAK,cACH,OAAO,EAAyB,YAClC,QACE,MAAM,EAAS,CACb,KAAM,0BACN,QAAS,mBAAmB,EAAO,wGACnC,QAAS,qBACX,CAAC,CACL,CACF,CAYA,eAAsB,uBACpB,EACkC,CAClC,IAAM,EAAe,GAAS,UAAU,KAClC,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,GAAS,QAClB,YAAa,GAAS,WACxB,CAAC,EAEK,EAA4D,CAAC,EAEnE,GAAI,GAAS,OAAQ,CACnB,IAAM,EAAc,YAAY,EAAQ,MAAM,EAC9C,EAAQ,KACN,GAAO,GAAc,CACnB,UAAW,GAAO,GAAiB,CACjC,MAAO,SACP,SAAU,GAAmB,GAC7B,MAAO,CAAE,KAAM,CAAE,KAAM,cAAe,MAAO,CAAY,CAAE,CAC7D,CAAC,CACH,CAAC,CACH,CACF,CAEA,IAAM,EACJ,EAAQ,OAAS,EACb,GAAO,GAAc,CACnB,IAAK,CACP,CAAC,EACD,IAAA,GAEA,EAAgB,gBAAgB,GAAS,OAAS,MAAM,EAgB9D,OAAO,MAfkB,GACvB,MAAO,EAAW,IAAa,CAC7B,GAAM,CAAE,aAAY,iBAAkB,MAAM,EAAO,uBAAuB,CACxE,cACA,aAAc,GAAgB,GAC9B,YACA,WACA,gBACA,QACF,CAAC,EACD,MAAO,CAAC,EAAY,CAAa,CACnC,EACA,CAAE,MAAO,GAAS,KAAM,CAC1B,EAAA,CAEkB,IAAI,uBAAuB,CAC/C,CAOA,eAAsB,qBACpB,EACqC,CACrC,GAAM,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAQ,QACjB,YAAa,EAAQ,WACvB,CAAC,EAED,eAAe,uBACb,EACwC,CACxC,GAAI,CACF,GAAM,CAAE,aAAc,MAAM,EAAO,qBAAqB,CACtD,cACA,YAAa,CACf,CAAC,EACD,OAAO,CACT,OAAS,EAAO,CACR,aAAiB,GAAgB,EAAM,OAAS,EAAK,UACzD,EAAO,KACL,gDAAgD,EAAoB,KAAK,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,GAChI,EAEF,MACF,CACF,CAEA,eAAe,uBACb,EACA,EACsC,CACtC,GAAM,CAAE,aAAc,MAAM,EAAO,qBAAqB,CACtD,cACA,aACF,CAAC,EAED,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,+BACN,QAAS,cAAc,EAAY,aACrC,CAAC,EAGH,IAAM,EAAsC,wBAAwB,CAAS,EAyB7E,OAvBI,GAAe,EAAU,cAAc,OAAS,IAClD,EAAO,WAAa,MAAM,QAAQ,IAChC,EAAU,cAAc,IAAI,KAAO,IAAQ,CACzC,IAAM,EAAU,2BAA2B,CAAG,EAC9C,GAAI,EAAI,YAAa,CACnB,IAAM,EAAoB,MAAM,uBAAuB,EAAI,WAAW,EACtE,GAAI,EACF,MAAO,CACL,GAAG,EACH,KAAM,EAAkB,MAAQ,IAAA,GAChC,WACE,EAAkB,WAAW,OAAS,EAClC,EAAkB,WAAW,IAAI,sBAAsB,EACvD,IAAA,GACN,OAAQ,EAAkB,QAAU,IAAA,EACtC,CAEJ,CACA,OAAO,CACT,CAAC,CACH,GAGK,CACT,CAEA,eAAe,mBAAwD,CACrE,IAAM,EAAW,EAAQ,UAAY,IAC/B,EAAa,MAAM,yBAAyB,CAChD,SACA,cACA,YAAa,EAAQ,YACrB,WACA,QAAS,EAAQ,QACjB,MAAO,EAAQ,OAAS,UAC1B,CAAC,EAED,MAAO,CACL,GAAG,MAFmB,uBAAuB,EAAQ,YAAa,EAAQ,MAAQ,EAAK,EAGvF,YAAa,EAAW,YACxB,UAAW,EAAW,UACtB,SAAU,EAAW,SACrB,SAAU,EAAW,SACrB,UAAW,EAAW,SACxB,CACF,CAIA,MAAO,CACL,UAAA,MAHsB,uBAAuB,EAAQ,YAAa,EAAQ,MAAQ,EAAK,EAIvF,KAAM,iBACR,CACF,CAMA,SAAgB,uBAAuB,EAA8C,CAEnF,IAAM,WAAc,GAA+B,EAAO,EAAK,YAAY,EAAI,MAGzE,EAAkC,CACtC,CAAC,KAAM,EAAU,EAAE,EACnB,CAAC,eAAgB,EAAU,YAAY,EACvC,CAAC,SAAU,EAAU,MAAM,EAC3B,CAAC,gBAAiB,EAAU,cAAc,SAAS,CAAC,EACpD,CAAC,YAAa,WAAW,EAAU,SAAS,CAAC,EAC7C,CAAC,aAAc,WAAW,EAAU,UAAU,CAAC,CACjD,EAIA,GAHA,EAAO,IAAI,oBAAoB,CAAW,CAAC,EAGvC,EAAU,YAAc,EAAU,WAAW,OAAS,EAAG,CAC3D,EAAO,IAAI,EAAO,KAAK;gBAAmB,CAAC,EAC3C,IAAK,IAAM,KAAO,EAAU,WAAY,CACtC,EAAO,IAAI,EAAO,KAAK,SAAS,EAAI,eAAe,KAAK,CAAC,EACzD,EAAO,IAAI,aAAa,EAAI,QAAQ,EACpC,EAAO,IAAI,cAAc,WAAW,EAAI,SAAS,GAAG,EACpD,EAAO,IAAI,eAAe,WAAW,EAAI,UAAU,GAAG,EAEtD,IAAM,EAAW,uBAAuB,EAAI,WAAY,EAAI,IAAI,EAChE,GAAI,EAAS,OAAS,EAAG,CACvB,EAAO,IAAI,EAAO,QAAQ;QAAW,CAAC,EACtC,IAAK,IAAM,KAAQ,EACjB,EAAO,IAAI,OAAO,GAAM,CAE5B,CAEA,GAAI,EAAI,OAAQ,CACd,EAAO,IAAI,EAAO,QAAQ;UAAa,CAAC,EACxC,GAAI,CACF,IAAM,EAAS,KAAK,MAAM,EAAI,MAAM,EACpC,EAAO,IAAI,OAAO,KAAK,UAAU,EAAQ,KAAM,CAAC,CAAC,CAAC,MAAM;CAAI,CAAC,CAAC,KAAK;KAAQ,GAAG,CAChF,MAAQ,CACN,EAAO,IAAI,OAAO,EAAI,QAAQ,CAChC,CACF,CACF,CACF,CACF,CAEA,MAAa,GAAoB,EAAiB,CAChD,KAAM,aACN,YAAa,mCACb,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,GAAG,GACH,eAAgB,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CACzC,WAAY,GACZ,YAAa,2CACf,CAAC,EACD,gBAAiB,EACf,EACG,OAAO,CAAC,CACR,MACC,oCACA,kGACF,CAAC,CACA,SAAS,EACZ,CACE,MAAO,IACP,YAAa,0CACf,CACF,EACA,OAAQ,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CACjC,MAAO,IACP,YAAa,mCACf,CAAC,EACD,GAAG,GACH,KAAM,EAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAK,EAAG,CACpC,YAAa,+CACf,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAa,EAAO,UAAY,EAAK,KAC3C,GAAI,EAAK,YAAa,CACpB,IAAM,EAAW,cAAc,EAAK,QAAQ,EAM5C,GAJK,GACH,EAAO,KAAK,iBAAiB,EAAK,cAAe,CAAE,KAAM,QAAS,CAAC,EAGjE,EAAK,KAAM,CACb,IAAM,EAAS,MAAM,6BAA6B,CAChD,YAAa,EAAK,YAClB,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,WACA,QAAS,cAAc,EAAK,OAAO,EACnC,MAAO,EAAK,MACZ,aAAc,CAAC,EACf,UAAW,EACb,CAAC,EAED,GAAI,EAAK,MAAQ,CAAC,EAAY,CAC5B,GAAM,CAAE,aAAc,MAAM,qBAAqB,CAC/C,YAAa,EAAK,YAClB,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,KAAM,EACR,CAAC,EACD,uBAAuB,CAAS,CAClC,MAAO,GAAI,EAAK,KAAM,CACpB,GAAM,CAAE,aAAc,MAAM,qBAAqB,CAC/C,YAAa,EAAK,YAClB,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,KAAM,EACR,CAAC,EACK,EAA+E,CACnF,GAAG,EACH,WAAY,EAAU,UACxB,EACA,EAAO,IAAI,CAAM,CACnB,MACE,EAAO,IAAI,CAAM,EAGnB,IAAM,EAAU,uBAAuB,EAAQ,EAAK,KAAK,EACzD,GAAI,EACF,MAAM,EAER,MACF,CAEA,GAAM,CAAE,aAAc,MAAM,qBAAqB,CAC/C,YAAa,EAAK,YAClB,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,WACA,KAAM,EAAK,IACb,CAAC,EAEG,EAAK,MAAQ,CAAC,EAChB,uBAAuB,CAAS,EAEhC,EAAO,IAAI,CAAS,CAExB,KAAO,CACL,IAAM,EAAa,MAAM,uBAAuB,CAC9C,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,SAAU,EAAK,mBAAqB,IAAA,GAAY,IAAA,GAAY,CAAE,KAAM,EAAK,gBAAiB,EAC1F,OAAQ,EAAK,OACb,MAAO,EAAK,MACZ,MAAO,EAAK,KACd,CAAC,EACD,EAAO,IAAI,CAAU,CACvB,CACF,CACF,CAAC,EC3ZD,eAAsB,gBACpB,EACA,EACA,EACA,CACA,GAAM,CAAE,YAAa,MAAM,EAAO,kBAAkB,CAClD,cACA,aAAc,CAChB,CAAC,EACD,GAAI,CAAC,EACH,MAAM,EAAS,CAAE,KAAM,qBAAsB,QAAS,aAAa,EAAK,aAAc,CAAC,EAEzF,OAAO,CACT,CAOA,eAAsB,YACpB,EACuB,CACvB,IAAM,EAAO,EAAQ,SAAS,KACxB,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAQ,QACjB,YAAa,EAAQ,WACvB,CAAC,EAED,GAAI,CAEF,OAAO,eAAe,MADC,gBAAgB,EAAQ,EAAa,CAAI,CAClC,CAChC,OAAS,EAAO,CAQd,MAPI,aAAiB,GAAgB,EAAM,OAAS,EAAK,SACjD,EAAS,CACb,KAAM,qBACN,QAAS,aAAa,EAAK,cAC3B,MAAO,CACT,CAAC,EAEG,CACR,CACF,CAEA,MAAaC,GAAa,EAAiB,CACzC,KAAM,MACN,YAAa,wBACb,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,GAAG,EACL,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAW,MAAM,YAAY,CACjC,SAAU,CAAE,KAAM,EAAK,IAAK,EAC5B,YAAa,EAAK,gBAClB,QAAS,EAAK,OAChB,CAAC,EAED,EAAO,IAAI,CAAQ,CACrB,CACF,CAAC,ECkBD,eAAe,kBACb,EACsC,CACtC,GAAM,CAAE,SAAQ,cAAa,gBAAiB,EAE9C,GAAI,CACF,IAAM,EAAW,MAAM,gBAAgB,EAAQ,EAAa,CAAY,EAClE,EAAU,GAAO,GAAmB,EAAQ,OAAO,EACnD,EACJ,EAAQ,MAAQ,IAAA,GACZ,IAAA,GACA,OAAO,EAAQ,KAAQ,SACrB,EAAQ,IACR,KAAK,UAAU,EAAQ,GAAG,EAE5B,CAAE,eAAgB,MAAM,EAAO,cAAc,CACjD,cACA,WAAY,EAAS,GACrB,YAAa,EACb,KACF,CAAC,EAED,MAAO,CACL,cACA,KAAO,GACL,yBAAyB,CACvB,SACA,cACA,cACA,SAAU,EAAQ,UAAY,IAC9B,QAAS,GAAa,QACtB,MAAO,GAAa,MACpB,aAAc,GAAa,aAC3B,UAAW,EACb,CAAC,CACL,CACF,OAAS,EAAO,CAQd,MAPI,aAAiB,GAAgB,EAAM,OAAS,EAAK,SACjD,EAAS,CACb,KAAM,qBACN,QAAS,aAAa,EAAa,cACnC,MAAO,CACT,CAAC,EAEG,CACR,CACF,CAEA,eAAe,gCAAgC,EAI3B,CAClB,GAAM,CAAE,UAAW,MAAM,WAAW,EAAQ,UAAU,EAChD,CAAE,eAAgB,MAAM,EAAQ,OAAO,eAAe,CAC1D,YAAa,EAAQ,YACrB,gBAAiB,EAAO,IAC1B,CAAC,EACK,EAAgB,GAAa,eAAiB,EAAO,MAAM,KACjE,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,uBACN,QAAS,eAAe,EAAO,KAAK,sCACtC,CAAC,EAEH,OAAO,CACT,CASA,eAAsB,oBACpB,EACsC,CACtC,IAAM,EAAc,MAAM,oBAAoB,CAC5C,YAAa,EAAQ,YACrB,kBAAmB,EAAQ,kBAC3B,QAAS,EAAQ,OACnB,CAAC,EACD,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,wBACN,QAAS,4BACT,WACE,uJACJ,CAAC,EAGH,GAAM,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAQ,QACjB,YAAa,EAAQ,WACvB,CAAC,EAEK,EAAgB,MAAM,gCAAgC,CAC1D,SACA,cACA,WAAY,EAAQ,UACtB,CAAC,EAED,OAAO,MAAM,kBAAkB,CAC7B,SACA,cACA,aAAc,EAAQ,KACtB,QAAS,CACP,UAAW,EACX,gBAAiB,CACnB,EACA,IAAK,EAAQ,IACb,SAAU,EAAQ,QACpB,CAAC,CACH,CAOA,eAAsB,cACpB,EACsC,CACtC,GAAM,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAQ,QACjB,YAAa,EAAQ,WACvB,CAAC,EACK,EAAgB,MAAM,gCAAgC,CAC1D,SACA,cACA,WAAY,EAAQ,UACtB,CAAC,EAED,OAAO,MAAM,kBAAkB,CAC7B,SACA,cACA,aAAc,EAAQ,SAAS,KAC/B,QAAS,CACP,UAAW,EACX,gBAAiB,EAAQ,OAC3B,EACA,IAAK,EAAQ,IACb,SAAU,EAAQ,QACpB,CAAC,CACH,CAEA,MAAa,GAAe,EAAiB,CAC3C,KAAM,QACN,YAAa,8BACb,KAAM,EAAE,aAAa,CACnB,GAAG,GACH,GAAG,GACH,eAAgB,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CACzC,MAAO,IACP,YAAa,8EACb,IAAK,mCACP,CAAC,EACD,IAAK,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CAC9B,MAAO,IACP,YAAa,iCACf,CAAC,EACD,GAAG,EACL,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,GAAM,CAAE,cAAa,QAAS,MAAM,oBAAoB,CACtD,KAAM,EAAK,KACX,YAAa,EAAK,gBAClB,kBAAmB,8BAA8B,EAAK,eAAe,EACrE,IAAK,EAAK,IACV,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,WAAY,EAAK,OACjB,SAAU,cAAc,EAAK,QAAQ,CACvC,CAAC,EACK,EAAa,EAAO,SAI1B,GAFA,EAAO,KAAK,iBAAiB,IAAe,CAAE,KAAM,QAAS,CAAC,EAE1D,EAAK,KAAM,CACb,IAAM,EAAS,MAAM,EAAK,CACxB,aAAc,CAAC,EACf,QAAS,cAAc,EAAK,OAAO,EACnC,MAAO,EAAK,KACd,CAAC,EACD,GAAI,EAAK,MAAQ,CAAC,EAAY,CAC5B,GAAM,CAAE,aAAc,MAAM,qBAAqB,CAC/C,cACA,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,KAAM,EACR,CAAC,EACD,uBAAuB,CAAS,CAClC,MAAO,GAAI,EAAK,KAAM,CACpB,GAAM,CAAE,aAAc,MAAM,qBAAqB,CAC/C,cACA,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,KAAM,EACR,CAAC,EACD,EAAO,IAAI,CAAE,GAAG,EAAQ,WAAY,EAAU,UAAW,CAAC,CAC5D,MACE,EAAO,IAAI,CAAM,EAEnB,IAAM,EAAU,uBAAuB,EAAQ,EAAK,KAAK,EACzD,GAAI,EACF,MAAM,CAEV,MACE,EAAO,IAAI,CAAE,aAAY,CAAC,CAE9B,CACF,CAAC,EC9MD,SAAS,WAAW,EAAoB,CACtC,OAAO,EAAK,mBAAmB,QAAS,CAAE,OAAQ,EAAM,CAAC,CAC3D,CAEA,SAAS,yBAAyB,EAAsB,EAAsC,CAC5F,MAAO,CACL,GAAI,EACJ,eACA,OAAQ,UACR,YAAa,MACb,UAAW,MACX,UAAW,KACb,CACF,CAYA,eAAsB,iBACpB,EACgC,CAChC,IAAM,EAAe,EAAQ,SAAS,KAChC,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAQ,QACjB,YAAa,EAAQ,WACvB,CAAC,EAEK,EAA4D,CAAC,EAEnE,GAAI,EAAQ,OAAQ,CAClB,IAAM,EAAc,uBAAuB,EAAQ,MAAM,EACzD,EAAQ,KACN,GAAO,GAAc,CACnB,UAAW,GAAO,GAAiB,CACjC,MAAO,SACP,SAAU,GAAmB,GAC7B,MAAO,CAAE,KAAM,CAAE,KAAM,cAAe,MAAO,CAAY,CAAE,CAC7D,CAAC,CACH,CAAC,CACH,CACF,CAEA,IAAM,EAAS,EAAQ,OAAS,EAAI,GAAO,GAAc,CAAE,IAAK,CAAQ,CAAC,EAAI,IAAA,GAEvE,EAAgB,gBAAgB,EAAQ,OAAS,MAAM,EAE7D,GAAI,CAgBF,OAAO,MAfY,GACjB,MAAO,EAAW,IAAa,CAC7B,GAAM,CAAE,OAAM,iBAAkB,MAAM,EAAO,iBAAiB,CAC5D,cACA,eACA,YACA,WACA,gBACA,QACF,CAAC,EACD,MAAO,CAAC,EAAM,CAAa,CAC7B,EACA,CAAE,MAAO,EAAQ,KAAM,CACzB,EAAA,CAEY,IAAI,qBAAqB,CACvC,OAAS,EAAO,CAQd,MAPI,aAAiB,GAAgB,EAAM,OAAS,EAAK,SACjD,EAAS,CACb,KAAM,qBACN,QAAS,aAAa,EAAa,cACnC,MAAO,CACT,CAAC,EAEG,CACR,CACF,CAOA,eAAsB,eACpB,EACgC,CAChC,IAAM,EAAe,EAAQ,SAAS,KAChC,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAQ,QACjB,YAAa,EAAQ,WACvB,CAAC,EAED,GAAI,CACF,GAAM,CAAE,OAAQ,MAAM,EAAO,eAAe,CAC1C,cACA,eACA,MAAO,EAAQ,KACjB,CAAC,EAED,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,yBACN,QAAS,QAAQ,EAAQ,MAAM,aACjC,CAAC,EAGH,IAAM,EAAU,kBAAkB,CAAG,EAErC,GAAI,EAAQ,SAAU,CACpB,IAAM,EAAW,MAAM,GAAS,MAAO,EAAW,IAAgB,CAChE,GAAM,CAAE,WAAU,iBAAkB,MAAM,EAAO,wBAAwB,CACvE,cACA,MAAO,EAAQ,MACf,YACA,SAAU,EACV,cAAe,GAAc,IAC/B,CAAC,EACD,MAAO,CAAC,EAAU,CAAa,CACjC,CAAC,EAED,MAAO,CACL,GAAG,EACH,SAAU,EAAS,IAAI,wBAAwB,CACjD,CACF,CAEA,OAAO,CACT,OAAS,EAAO,CAQd,MAPI,aAAiB,GAAgB,EAAM,OAAS,EAAK,SACjD,EAAS,CACb,KAAM,yBACN,QAAS,QAAQ,EAAQ,MAAM,4BAA4B,EAAa,IACxE,MAAO,CACT,CAAC,EAEG,CACR,CACF,CAOA,eAAsB,iBACpB,EACiC,CACjC,IAAM,EAAe,EAAQ,SAAS,KAChC,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAQ,QACjB,YAAa,EAAQ,WACvB,CAAC,EAEK,EAAW,EAAQ,UAAY,IAC/B,EAAU,EAAQ,QAClB,EAAe,EAAQ,cAAgB,CAAC,EAAO,SAC/C,EAAY,KAAK,IAAI,EACrB,EAAK,EAAe,QAAQ,CAAC,CAAC,MAAM,yCAAyC,EAAI,KAEnF,EAAW,EACX,EAA2B,KAOzB,qBAA6C,CAC7C,OAAY,IAAA,GAGhB,OAAO,GAAW,KAAK,IAAI,EAAI,EACjC,EAEM,kBACJ,EACA,KAC4B,CAC5B,GAAG,EACH,UAAW,KAAK,IAAI,EAAI,EACxB,WACA,WACA,WACF,GAEM,eACJ,EACA,IAEA,iBACE,CACE,IAAK,EAAM,kBAAkB,CAAG,EAAI,yBAAyB,EAAc,EAAQ,KAAK,EACxF,YACF,EACA,EACF,EAEF,GAAI,CAEF,GAAM,CAAE,YAAa,MAAM,EAAO,oBAAoB,CACpD,cACA,KAAM,CACR,CAAC,EAED,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,qBACN,QAAS,aAAa,EAAa,aACrC,CAAC,EAGH,IAAM,EAAa,EAAS,WACtB,EAAgB,2BAA2B,CAAU,EAGvD,EAGJ,OAAa,CACX,IAAM,EAAc,iBAAiB,EACrC,GAAI,IAAgB,IAAA,IAAa,GAAe,EAE9C,OADA,GAAI,KAAK,8BAA8B,EAChC,cAAc,EAAe,CAAG,EAGzC,GAAI,CASF,GARA,GAAY,EAOZ,GAAM,MANiB,EAAO,eAAe,CAC3C,cACA,eACA,MAAO,EAAQ,KACjB,CAAC,EAAA,CAEc,IACX,CAAC,EACH,MAAM,EAAS,CACb,KAAM,yBACN,QAAS,QAAQ,EAAQ,MAAM,aACjC,CAAC,EAIH,GAFA,EAAY,KAER,0BAA0B,EAAI,MAAM,IAAM,YAC5C,KAEJ,OAAS,EAAO,CACd,GAAI,CAAC,qBAAqB,CAAK,EAC7B,MAAM,EAER,EAAY,gBAAgB,CAAK,EAC7B,IACF,EAAG,KAAO,kCAAkC,WAAW,IAAI,IAAM,EAAE,GAEvE,CAEA,IAAM,EAAkB,iBAAiB,EACzC,GAAI,IAAoB,IAAA,IAAa,GAAmB,EAEtD,OADA,GAAI,KAAK,8BAA8B,EAChC,cAAc,EAAe,CAAG,EAGrC,IACF,EAAG,KAAO,gCAAgC,WAAW,IAAI,IAAM,EAAE,IAEnE,MAAMC,GACJ,IAAoB,IAAA,GAAY,EAAW,KAAK,IAAI,EAAU,CAAe,CAC/E,CACF,CAEA,IAAM,EAAU,kBAAkB,CAAG,EAC/B,EAAgB,0BAA0B,EAAQ,MAAM,EAE1D,EAAI,SAAW,EAAkB,QACnC,GAAI,QAAQ,2BAA2B,GAAe,EAEtD,GAAI,KAAK,2BAA2B,GAAe,EAerD,IAAM,GAAe,MAXQ,GAAS,MAAO,EAAW,IAAgB,CACtE,GAAM,CAAE,SAAU,EAAa,iBAAkB,MAAM,EAAO,wBAAwB,CACpF,cACA,MAAO,EAAQ,MACf,YACA,SAAU,EACV,cAAe,GAAc,IAC/B,CAAC,EACD,MAAO,CAAC,EAAa,CAAa,CACpC,CAAC,EAAA,CAEmC,IAAI,wBAAwB,EAC1D,EAAmC,CACvC,GAAG,EACH,SAAU,CACZ,EAGM,EADgB,EAAa,EACK,EAAE,mBAG1C,GAAI,EACF,OAAQ,EAAR,CACE,KAAK,EAAmB,SAEtB,GAAI,KAAK,EAET,GAAI,CACF,IAAM,EAAkB,iBAAiB,EACzC,GAAI,IAAoB,IAAA,IAAa,GAAmB,EACtD,OAAO,iBACL,CACE,IAAK,EACL,WAAY,EACZ,oBAAqB,CACvB,EACA,EACF,EAIF,IAAM,EAAkB,MAAMC,yBAAiB,CAC7C,SACA,cACA,YAAa,EACb,WACA,QAAS,EACT,eACA,UAAW,EACb,CAAC,EACD,GAAY,EAAgB,SAC5B,EAAY,EAAgB,UAG5B,IAAI,EACJ,GAAI,EAAQ,KACV,GAAI,CACF,GAAM,CAAE,UAAW,GAAiB,MAAM,qBAAqB,CAC7D,YAAa,EACb,YAAa,EAAQ,YACrB,QAAS,EAAQ,QACjB,KAAM,EACR,CAAC,EACG,EAAa,aACf,EAAkB,EAAa,WAC5B,OAAQ,GAAQ,EAAI,MAAQ,EAAI,MAAM,CAAC,CACvC,IAAK,IAAS,CACb,QAAS,EAAI,gBAAkB,EAAI,GACnC,KAAM,EAAI,KACV,OAAQ,EAAI,MACd,EAAE,EAER,OAAS,EAAO,CACd,EAAO,KACL,4CAA4C,aAAiB,MAAQ,EAAM,QAAU,GACvF,CACF,CAGF,OAAO,iBACL,CACE,IAAK,EACL,WAAY,EACZ,oBAAqB,EACrB,eAAgB,EAAgB,OAChC,iBACF,EACA,EAAgB,QAClB,CACF,OAAS,EAAO,CAId,OAHA,EAAO,KACL,uCAAuC,aAAiB,MAAQ,EAAM,QAAU,GAClF,EACO,iBACL,CACE,IAAK,EACL,WAAY,EACZ,oBAAqB,CACvB,EACA,EACF,CACF,CAGF,KAAK,EAAmB,SACxB,KAAK,EAAmB,aAGpB,GAAI,MAAM,kCAAkC,EAAmB,IAAI,EAEnE,GAAI,CACF,IAAI,EAEJ,OAAa,CACX,IAAM,EAAkB,iBAAiB,EACzC,GAAI,IAAoB,IAAA,IAAa,GAAmB,EAEtD,OADA,GAAI,KAAK,oCAAoC,EACtC,iBACL,CACE,IAAK,EACL,WAAY,EACZ,oBAAqB,EACrB,gBACF,EACA,EACF,EAGF,GAAI,CACF,GAAY,EACZ,GAAM,CAAE,aAAc,MAAM,EAAO,qBAAqB,CACtD,cACA,YAAa,CACf,CAAC,EAED,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,+BACN,QAAS,uBAAuB,EAAmB,aACrD,CAAC,EAMH,GAHA,EAAY,KACZ,EAAiB,gCAAgC,EAAU,MAAM,EAE7D,kCAAkC,EAAU,MAAM,EAAG,CACvD,IAAM,EAAkB,gCAAgC,CAAc,EAMtE,OALI,EAAU,SAAW,EAAyB,QAChD,GAAI,QAAQ,iCAAiC,GAAiB,EAE9D,GAAI,KAAK,iCAAiC,GAAiB,EAEtD,iBACL,CACE,IAAK,EACL,WAAY,EACZ,oBAAqB,EACrB,iBACA,aAAc,EAAQ,MAAO,EAAU,MAAoB,IAAA,EAC7D,EACA,EACF,CACF,CACF,OAAS,EAAO,CACd,GAAI,CAAC,qBAAqB,CAAK,EAC7B,MAAM,EAER,EAAY,gBAAgB,CAAK,EAC7B,IACF,EAAG,KAAO,wCAAwC,WAAW,IAAI,IAAM,EAAE,GAE7E,CAEA,IAAM,EAAsB,iBAAiB,EAC7C,GAAI,IAAwB,IAAA,IAAa,GAAuB,EAE9D,OADA,GAAI,KAAK,oCAAoC,EACtC,iBACL,CACE,IAAK,EACL,WAAY,EACZ,oBAAqB,EACrB,gBACF,EACA,EACF,EAGE,IACF,EAAG,KAAO,sCAAsC,WAAW,IAAI,IAAM,EAAE,IAEzE,MAAMD,GACJ,IAAwB,IAAA,GACpB,EACA,KAAK,IAAI,EAAU,CAAmB,CAC5C,CACF,CACF,OAAS,EAAO,CAId,OAHA,GAAI,KACF,uCAAuC,aAAiB,MAAQ,EAAM,QAAU,GAClF,EACO,iBACL,CACE,IAAK,EACL,WAAY,EACZ,oBAAqB,CACvB,EACA,EACF,CACF,CAMN,CAGF,OAAO,iBAAiB,CAAE,IAAK,EAAW,WAAY,CAAc,EAAG,EAAK,CAC9E,QAAU,CACR,GAAI,KAAK,CACX,CACF,CAOA,SAAgB,uBAAuB,EAAsD,CAC3F,IAAM,EAAU,CACd,MAAO,EAAO,IAAI,GAClB,OAAQ,EAAO,IAAI,OACnB,oBAAqB,EAAO,oBAC5B,oBAAqB,EAAO,mBAC9B,EACA,GAAI,EAAO,SACT,OAAO,EAAS,CACd,KAAM,wBACN,QAAS,uCAAuC,EAAO,IAAI,GAAG,kBAAkB,EAAO,IAAI,OAAO,GAClG,SACF,CAAC,EAEH,GAAI,EAAO,IAAI,SAAW,UAAY,EAAO,IAAI,SAAW,WAC1D,OAAO,EAAS,CACd,KAAM,sBACN,QAAS,iBAAiB,EAAO,IAAI,GAAG,0BAA0B,EAAO,IAAI,OAAO,GACpF,SACF,CAAC,EAEH,GAAI,EAAO,iBAAmB,SAC5B,OAAO,EAAS,CACd,KAAM,4BACN,QAAS,uBAAuB,EAAO,oBAAoB,WAC3D,SACF,CAAC,EAEH,GAAI,EAAO,iBAAmB,SAC5B,OAAO,EAAS,CACd,KAAM,4BACN,QAAS,uBAAuB,EAAO,oBAAoB,WAC3D,SACF,CAAC,EAEH,GAAI,EAAO,iBAAmB,WAC5B,OAAO,EAAS,CACd,KAAM,8BACN,QAAS,uBAAuB,EAAO,oBAAoB,iBAC3D,SACF,CAAC,CAGL,CAOA,SAAgB,8BAA8B,EAAoD,CAChG,OAAO,uBAAuB,CAAM,CAAC,EAAE,OACzC,CAEA,SAAS,qBAAqB,EAAkC,CAE9D,IAAM,EAAkC,CACtC,CAAC,KAAM,EAAI,EAAE,EACb,CAAC,eAAgB,EAAI,YAAY,EACjC,CAAC,SAAU,EAAI,MAAM,EACrB,CAAC,cAAe,EAAI,WAAW,EAC/B,CAAC,YAAa,EAAI,SAAS,EAC3B,CAAC,YAAa,EAAI,SAAS,CAC7B,EAIA,GAHA,EAAO,IAAI,oBAAoB,CAAW,CAAC,EAGvC,EAAI,UAAY,EAAI,SAAS,OAAS,EAAG,CAC3C,EAAO,IAAI,EAAO,KAAK;UAAa,CAAC,EACrC,IAAK,IAAM,KAAW,EAAI,SAMxB,GALA,EAAO,IAAI,EAAO,KAAK,iBAAiB,EAAQ,GAAG,KAAK,CAAC,EACzD,EAAO,IAAI,aAAa,EAAQ,QAAQ,EACxC,EAAO,IAAI,cAAc,EAAQ,WAAW,EAC5C,EAAO,IAAI,eAAe,EAAQ,YAAY,EAE1C,EAAQ,MAAO,CACjB,EAAO,IAAI,EAAO,MAAM;SAAY,CAAC,EACrC,IAAM,EAAa,EAAQ,MAAM,MAAM;CAAI,EAC3C,IAAK,IAAM,KAAQ,EACjB,EAAO,IAAI,OAAO,GAAM,CAE5B,CAEJ,CACF,CAEA,MAAa,GAAc,EAAiB,CAC1C,KAAM,OACN,YAAa,6BACb,SAAU,CACR,CACE,IAAK,cACL,KAAM,8CACR,EACA,CAAE,IAAK,yBAA0B,KAAM,0BAA2B,EAClE,CAAE,IAAK,yBAA0B,KAAM,kBAAmB,EAC1D,CAAE,IAAK,uBAAwB,KAAM,iBAAkB,EACvD,CACE,IAAK,kCACL,KAAM,+BACR,EACA,CAAE,IAAK,0BAA2B,KAAM,0BAA2B,EACnE,CACE,IAAK,6BACL,KAAM,wBACR,CACF,EACA,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,gBAAiB,EAAI,EAAE,OAAO,EAAG,CAC/B,WAAY,GACZ,YAAa,eACf,CAAC,EACD,SAAU,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CACnC,WAAY,GACZ,YAAa,yCACf,CAAC,EACD,OAAQ,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CACjC,MAAO,IACP,YACE,iFACJ,CAAC,EACD,SAAU,EAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAK,EAAG,CACxC,YAAa,yDACf,CAAC,EACD,KAAM,EAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAK,EAAG,CACpC,MAAO,IACP,YACE,uGACJ,CAAC,EACD,SAAU,EAAI,GAAY,QAAQ,IAAI,EAAG,CACvC,MAAO,IACP,YAAa,gEACf,CAAC,EACD,QAAS,EAAI,GAAY,QAAQ,IAAI,EAAG,CACtC,MAAO,IACP,YAAa,4DACf,CAAC,EACD,GAAG,GACH,MAAO,EAAI,GAAkB,QAAQ,EAAE,EAAG,CACxC,YAAa,6EACf,CAAC,EACD,KAAM,EAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAK,EAAG,CACpC,MAAO,IACP,YAAa,oEACf,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAa,EAAO,UAAY,EAAK,KAC3C,GAAI,EAAK,MAAO,CACd,GAAI,EAAK,KAAM,CACb,IAAM,EAAS,MAAM,iBAAiB,CACpC,SAAU,CAAE,KAAM,EAAK,YAAa,EACpC,MAAO,EAAK,MACZ,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,SAAU,cAAc,EAAK,QAAQ,EACrC,QAAS,cAAc,EAAK,OAAO,EACnC,KAAM,EAAK,KACX,aAAc,CAAC,CACjB,CAAC,EAGD,GAAK,EA+CH,EAAO,IAAI,CAAM,MA/CF,CAGf,GAFA,EAAO,IAAI,EAAO,KAAK,gBAAgB,EAAO,WAAW,GAAG,CAAC,EAC7D,qBAAqB,EAAO,GAAG,EAC3B,EAAO,sBACT,EAAO,IAAI,EAAO,KAAK;oBAAuB,CAAC,EAC/C,EAAO,IAAI,SAAS,EAAO,qBAAqB,EAC5C,EAAO,gBACT,EAAO,IAAI,aAAa,EAAO,gBAAgB,EAE7C,EAAO,iBAAmB,EAAO,gBAAgB,OAAS,GAC5D,IAAK,IAAM,KAAU,EAAO,gBAAiB,CAE3C,GADA,EAAO,IAAI,EAAO,KAAK,YAAY,EAAO,SAAS,CAAC,EAChD,EAAO,KAAM,CACf,EAAO,IAAI,EAAO,IAAI,WAAW,CAAC,EAClC,IAAK,IAAM,KAAQ,EAAO,KAAK,MAAM;CAAI,EACvC,EAAO,IAAI,SAAS,GAAM,CAE9B,CACA,GAAI,EAAO,OAAQ,CACjB,EAAO,IAAI,EAAO,IAAI,aAAa,CAAC,EACpC,GAAI,CACF,IAAM,EAAS,KAAK,MAAM,EAAO,MAAM,EACjC,EAAY,KAAK,UAAU,EAAQ,KAAM,CAAC,EAChD,IAAK,IAAM,KAAQ,EAAU,MAAM;CAAI,EACrC,EAAO,IAAI,SAAS,GAAM,CAE9B,MAAQ,CACN,EAAO,IAAI,SAAS,EAAO,QAAQ,CACrC,CACF,CACF,CAGJ,GAAI,EAAO,sBACT,EAAO,IAAI,EAAO,KAAK;oBAAuB,CAAC,EAC/C,EAAO,IAAI,SAAS,EAAO,qBAAqB,EAC5C,EAAO,gBACT,EAAO,IAAI,aAAa,EAAO,gBAAgB,EAE7C,EAAO,cAAc,CACvB,EAAO,IAAI,EAAO,IAAI,SAAS,CAAC,EAChC,IAAK,IAAM,KAAQ,EAAO,aAAa,MAAM;CAAI,EAC/C,EAAO,IAAI,OAAO,GAAM,CAE5B,CAEJ,CAGA,IAAM,EAAU,uBAAuB,CAAM,EAC7C,GAAI,EACF,MAAM,EAER,MACF,CAEA,IAAM,EAAM,MAAM,eAAe,CAC/B,SAAU,CAAE,KAAM,EAAK,YAAa,EACpC,MAAO,EAAK,MACZ,SAAU,EAAK,SACf,YAAa,EAAK,gBAClB,QAAS,EAAK,OAChB,CAAC,EACG,EAAK,UAAY,CAAC,EACpB,qBAAqB,CAAG,EAExB,EAAO,IAAI,CAAG,CAElB,KAAO,CACD,EAAK,MACP,EAAO,KAAK,gEAAgE,EAE9E,IAAM,EAAO,MAAM,iBAAiB,CAClC,SAAU,CAAE,KAAM,EAAK,YAAa,EACpC,OAAQ,EAAK,OACb,MAAO,EAAK,MACZ,MAAO,EAAK,MACZ,YAAa,EAAK,gBAClB,QAAS,EAAK,OAChB,CAAC,EACD,EAAO,IAAI,CAAI,CACjB,CACF,CACF,CAAC,EC10BD,eAAsB,cAAc,EAA6D,CAC/F,GAAM,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,GAAS,QAClB,YAAa,GAAS,WACxB,CAAC,EAEK,EAAgB,gBAAgB,GAAS,KAAK,EAcpD,OAAO,MAbiB,GACtB,MAAO,EAAW,IAAa,CAC7B,GAAM,CAAE,YAAW,iBAAkB,MAAM,EAAO,sBAAsB,CACtE,cACA,YACA,WACA,eACF,CAAC,EACD,MAAO,CAAC,EAAW,CAAa,CAClC,EACA,CAAE,MAAO,GAAS,KAAM,CAC1B,EAAA,CAEiB,IAAK,GAAM,mBAAmB,CAAC,CAAC,CACnD,CAEA,MAAaE,GAAc,EAAiB,CAC1C,KAAM,OACN,YAAa,qBACb,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,GAAG,eAAe,CACpB,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAa,EAAO,SACpB,EAAY,MAAM,cAAc,CACpC,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,MAAO,EAAK,MACZ,MAAO,EAAK,KACd,CAAC,EAED,GAAI,EAAU,SAAW,EAAG,CAC1B,EAAO,KAAK,qBAAqB,EAC7B,GACF,EAAO,IAAI,CAAC,CAAC,EAEf,MACF,CASA,GAPA,EAAO,IAAI,EAAW,CACpB,QAAS,CACP,SAAW,GAAO,EAAI,EAAO,QAAQ,MAAM,EAAI,EAAO,IAAI,OAAO,CACnE,CACF,CAAC,EAGG,CAAC,GACgB,EAAU,KAAM,GAAM,EAAE,cAAgB,SAC9C,EAAG,CACd,IAAM,EAAe,GAAsB,CACzC,SACA,WACA,UACA,OACA,GAAG,oBAAoB,CAAE,QAAS,EAAK,QAAS,YAAa,EAAK,eAAgB,CAAC,CACrF,CAAC,EACD,EAAO,KAAK,6BAA6B,GAAc,CACzD,CAEJ,CACF,CAAC,EC5EK,GAAc,EACjB,OAAO,CAAC,CACR,UAAW,GAAQ,CAClB,GAAI,CACF,OAAO,KAAK,MAAM,CAAG,CACvB,MAAQ,CACN,MAAM,EAAS,CACb,KAAM,wBACN,QAAS,sBAAsB,EAAI,uCACnC,QAAS,kBACX,CAAC,CACH,CACF,CAAC,CAAC,CACD,OAAQ,GAAuB,OAAO,GAAM,YAAY,GAAc,CAAC,MAAM,QAAQ,CAAC,EAAG,CACxF,QAAS,8DACX,CAAC,EAMG,GAAY,EACf,OAAO,CAAC,CACR,aAAa,EAAK,IAAQ,CACpB,EAAI,SAAS,GAAG,GACnB,EAAI,SAAS,CACX,KAAM,SACN,QAAS,2BAA2B,EAAI,iCAC1C,CAAC,CAEL,CAAC,CAAC,CACD,UAAW,GAAQ,CAClB,IAAM,EAAa,EAAI,QAAQ,GAAG,EAClC,MAAO,CACL,IAAK,EAAI,MAAM,EAAG,CAAU,CAAC,CAAC,KAAK,EACnC,MAAO,EAAI,MAAM,EAAa,CAAC,CAAC,CAAC,KAAK,CACxC,CACF,CAAC,CAAC,CACD,OAAQ,GAAM,EAAE,IAAI,OAAS,EAAG,CAC/B,QAAS,6BACX,CAAC,EAiCH,eAAe,sBACb,EACgC,CAChC,GAAM,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAQ,QACjB,YAAa,EAAQ,WACvB,CAAC,EAED,GAAI,CAOF,MAAO,CAAE,OAAO,MANO,EAAO,gBAAgB,CAC5C,cACA,aAAc,EAAQ,aACtB,QAAS,EAAQ,OACnB,CAAC,EAAA,CAEwB,KAAM,CACjC,OAAS,EAAO,CAed,MAdI,aAAiB,GAAgB,EAAM,OAAS,EAAK,SACjD,EAAS,CACb,KAAM,qBACN,QAAS,aAAa,EAAQ,aAAa,cAC3C,MAAO,CACT,CAAC,EAEC,aAAiB,GAAgB,EAAM,OAAS,EAAK,gBACjD,EAAS,CACb,KAAM,4BACN,QAAS,qBAAqB,EAAM,UACpC,MAAO,CACT,CAAC,EAEG,CACR,CACF,CAOA,eAAsB,gBACpB,EACgC,CAChC,GAAI,EAAQ,SAAS,QAAQ,OAAS,mBAAqB,EAAQ,UAAY,IAAA,GAC7E,MAAM,EAAS,CACb,KAAM,+BACN,QACE,aAAa,EAAQ,SAAS,KAAK,SAAS,EAAQ,SAAS,QAAQ,KAAK,kFAE9E,CAAC,EAGH,OAAO,MAAM,sBAAsB,CACjC,aAAc,EAAQ,SAAS,KAC/B,QAAS,EAAQ,QACjB,YAAa,EAAQ,YACrB,QAAS,EAAQ,OACnB,CAAC,CACH,CAEA,MAAa,GAAiB,EAAiB,CAC7C,KAAM,UACN,YAAa,gCACb,MAAO,i5BAcP,SAAU,CACR,CAAE,IAAK,cAAe,KAAM,qBAAsB,EAClD,CACE,IAAK,wCACL,KAAM,mBACR,EACA,CACE,IAAK,oFACL,KAAM,+BACR,EACA,CAAE,IAAK,iBAAkB,KAAM,iCAAkC,EACjE,CAAE,IAAK,oBAAqB,KAAM,8BAA+B,CACnE,EACA,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,gBAAiB,EAAI,EAAE,OAAO,EAAG,CAC/B,WAAY,GACZ,YAAa,eACf,CAAC,EACD,KAAM,EAAI,GAAY,SAAS,EAAG,CAChC,MAAO,IACP,YAAa,4BACf,CAAC,EACD,OAAQ,EAAI,GAAU,MAAM,CAAC,CAAC,SAAS,EAAG,CACxC,MAAO,IACP,qBAAsB,GACtB,YAAa,wEACf,CAAC,EACD,KAAM,EAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAK,EAAG,CACpC,MAAO,IACP,YACE,oFACJ,CAAC,EACD,SAAU,EAAI,GAAY,QAAQ,IAAI,EAAG,CACvC,MAAO,IACP,YAAa,gEACf,CAAC,EACD,QAAS,EAAI,GAAY,QAAQ,IAAI,EAAG,CACtC,MAAO,IACP,YAAa,4DACf,CAAC,EACD,KAAM,EAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAK,EAAG,CACpC,MAAO,IACP,YAAa,oEACf,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAa,EAAO,UAAY,EAAK,KAC3C,MAAM,eAAe,CAAE,QAAS,EAAK,OAAQ,CAAC,EAE9C,GAAM,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAK,QACd,YAAa,EAAK,eACpB,CAAC,EAEK,CAAE,YAAa,MAAM,EAAO,oBAAoB,CACpD,cACA,KAAM,EAAK,YACb,CAAC,EAED,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,qBACN,QAAS,aAAa,EAAK,aAAa,aAC1C,CAAC,EAIH,GAAI,EAAS,cAAgB,GAAoB,MAC/C,MAAM,EAAS,CACb,KAAM,+BACN,QACE,aAAa,EAAK,aAAa,SAAS,4BAA4B,EAAS,WAAW,EAAE,0IAE9F,CAAC,EAIH,GAAI,EAAS,cAAgB,GAAoB,WAAa,EAAK,MAAQ,EAAK,QAC9E,MAAM,EAAS,CACb,KAAM,mCACN,QACE,aAAa,EAAK,aAAa,wHAEjC,QAAS,kBACX,CAAC,EAGH,IAAI,EAGE,EAA+B,EAAK,KACpC,EAAkC,CAAC,EACzC,GAAI,EAAK,OACP,IAAK,IAAM,KAAK,EAAK,OACnB,EAAQ,EAAE,KAAO,EAAE,OAInB,IAAS,IAAA,IAAa,OAAO,KAAK,CAAO,CAAC,CAAC,OAAS,KACtD,EAAU,CACR,KAAM,GAAQ,CAAC,EACf,SACF,GAGF,IAAM,EAAS,MAAM,sBAAsB,CACzC,aAAc,EAAK,aACnB,UACA,YAAa,EAAK,gBAClB,QAAS,EAAK,OAChB,CAAC,EAED,GAAI,CAAC,EAAO,MAAO,CACjB,EAAO,QAAQ,aAAa,EAAK,aAAa,0BAA0B,EACpE,EAAK,MACP,EAAO,KAAK,qEAAqE,EAEnF,MACF,CAMA,GAJA,EAAO,QACL,aAAa,EAAK,aAAa,oCAAoC,EAAO,OAC5E,EAEI,EAAK,KAAM,CACb,IAAM,EAAc,MAAM,iBAAiB,CACzC,SAAU,CAAE,KAAM,EAAK,YAAa,EACpC,MAAO,EAAO,MACd,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,SAAU,cAAc,EAAK,QAAQ,EACrC,QAAS,cAAc,EAAK,OAAO,EACnC,KAAM,EAAK,KACX,aAAc,CAAC,CACjB,CAAC,EAGD,GAAK,EAgDH,EAAO,IAAI,CAAW,MAhDP,CAIf,GAHA,EAAO,IAAI,EAAO,KAAK,kBAAkB,EAAY,YAAY,CAAC,EAClE,EAAO,IAAI,eAAe,EAAY,IAAI,QAAQ,EAE9C,EAAY,sBACd,EAAO,IAAI,EAAO,KAAK;oBAAuB,CAAC,EAC/C,EAAO,IAAI,SAAS,EAAY,qBAAqB,EACjD,EAAY,gBACd,EAAO,IAAI,aAAa,EAAY,gBAAgB,EAElD,EAAY,iBAAmB,EAAY,gBAAgB,OAAS,GACtE,IAAK,IAAM,KAAU,EAAY,gBAAiB,CAEhD,GADA,EAAO,IAAI,EAAO,KAAK,YAAY,EAAO,SAAS,CAAC,EAChD,EAAO,KAAM,CACf,EAAO,IAAI,EAAO,IAAI,WAAW,CAAC,EAClC,IAAK,IAAM,KAAQ,EAAO,KAAK,MAAM;CAAI,EACvC,EAAO,IAAI,SAAS,GAAM,CAE9B,CACA,GAAI,EAAO,OAAQ,CACjB,EAAO,IAAI,EAAO,IAAI,aAAa,CAAC,EACpC,GAAI,CACF,IAAM,EAAS,KAAK,MAAM,EAAO,MAAM,EACjC,EAAY,KAAK,UAAU,EAAQ,KAAM,CAAC,EAChD,IAAK,IAAM,KAAQ,EAAU,MAAM;CAAI,EACrC,EAAO,IAAI,SAAS,GAAM,CAE9B,MAAQ,CACN,EAAO,IAAI,SAAS,EAAO,QAAQ,CACrC,CACF,CACF,CAGJ,GAAI,EAAY,sBACd,EAAO,IAAI,EAAO,KAAK;oBAAuB,CAAC,EAC/C,EAAO,IAAI,SAAS,EAAY,qBAAqB,EACjD,EAAY,gBACd,EAAO,IAAI,aAAa,EAAY,gBAAgB,EAElD,EAAY,cAAc,CAC5B,EAAO,IAAI,EAAO,IAAI,SAAS,CAAC,EAChC,IAAK,IAAM,KAAQ,EAAY,aAAa,MAAM;CAAI,EACpD,EAAO,IAAI,OAAO,GAAM,CAE5B,CAEJ,CAGA,IAAM,EAAU,uBAAuB,CAAW,EAClD,GAAI,EACF,MAAM,CAEV,CACF,CACF,CAAC,EC1UD,eAAsB,qBACpB,EACgC,CAChC,GAAM,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,GAAS,QAClB,YAAa,GAAS,WACxB,CAAC,EAEK,EAAgB,gBAAgB,GAAS,KAAK,EAcpD,OAAO,MAbgB,GACrB,MAAO,EAAW,IAAa,CAC7B,GAAM,CAAE,WAAU,iBAAkB,MAAM,EAAO,6BAA6B,CAC5E,cACA,YACA,WACA,eACF,CAAC,EACD,MAAO,CAAC,EAAU,CAAa,CACjC,EACA,CAAE,MAAO,GAAS,KAAM,CAC1B,EAAA,CAEgB,IAAK,IAAO,CAC1B,KAAM,EAAE,aACR,WAAY,EAAE,IACd,SAAU,EAAE,QACd,EAAE,CACJ,CAEA,MAAM,GAAqB,EAAiB,CAC1C,KAAM,OACN,YAAa,gDACb,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,GAAG,eAAe,CACpB,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAa,EAAO,SACpB,EAAY,MAAM,qBAAqB,CAC3C,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,MAAO,EAAK,MACZ,MAAO,EAAK,KACd,CAAC,EAED,GAAI,EAAU,SAAW,EAAG,CAC1B,EAAO,KAAK,6BAA6B,EACrC,GACF,EAAO,IAAI,CAAC,CAAC,EAEf,MACF,CAQA,GANA,EAAO,IAAI,EAAW,CACpB,QAAS,CACP,SAAW,GAAO,EAAI,EAAO,QAAQ,MAAM,EAAI,EAAO,IAAI,OAAO,CACnE,CACF,CAAC,EAEG,CAAC,EAAY,CACf,IAAM,EAAU,GAAsB,CACpC,SACA,WACA,UACA,SACA,KACA,kBACA,GAAG,oBAAoB,CAAE,QAAS,EAAK,QAAS,YAAa,EAAK,eAAgB,CAAC,CACrF,CAAC,EACD,EAAO,KAAK,2BAA2B,GAAS,CAClD,CACF,CACF,CAAC,EAEY,GAAiB,GAAc,CAC1C,KAAM,UACN,YAAa,2BACb,YAAa,CACX,KAAM,EACR,EACA,MAAM,KAAM,CACV,MAAM,qBAAqB,EAAkB,CAC/C,CACF,CAAC,ECxGY,qBAAwB,IAC5B,CACL,KAAM,EAAG,KACT,YAAa,EAAG,YAChB,UAAW,EAAG,UAAU,SAAS,EACjC,YAAa,EAAG,YAChB,UAAW,gBAAgB,EAAG,SAAS,EACvC,UAAW,gBAAgB,EAAG,SAAS,CACzC,GCPI,GAAmC,EAAE,OAAO,CAChD,YAAa,EAAE,KAAK,CAAE,QAAS,mCAAoC,CAAC,CAAC,CAAC,SAAS,EAC/E,QAAS,EAAE,OAAO,CAAC,CAAC,SAAS,EAC7B,KAAM,EAAE,OAAO,CAAC,CAAC,IAAI,EAAG,CAAE,QAAS,kBAAmB,CAAC,CACzD,CAAC,EAID,eAAeC,eAAY,EAAqC,CAC9D,IAAM,EAAY,aAAa,GAAkC,CAAO,EAElE,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAU,QACnB,YAAa,EAAU,WACzB,CAAC,EAED,MAAO,CACL,SACA,cACA,KAAM,EAAU,IAClB,CACF,CAOA,eAAsB,oBACpB,EAC+B,CAC/B,GAAM,CAAE,SAAQ,cAAa,QAAS,MAAMA,eAAY,CAAO,EAEzD,EAAuB,sBAAsB,EAAK,cACxD,GAAI,CACF,IAAM,EAAW,MAAM,EAAO,oBAAoB,CAChD,cACA,MACF,CAAC,EAED,GAAI,CAAC,EAAS,SACZ,MAAM,EAAS,CAAE,KAAM,qBAAsB,QAAS,CAAqB,CAAC,EAG9E,OAAO,qBAAqB,EAAS,QAAQ,CAC/C,OAAS,EAAO,CAId,MAHI,aAAiB,GAAgB,EAAM,OAAS,EAAK,SACjD,EAAS,CAAE,KAAM,qBAAsB,QAAS,EAAsB,MAAO,CAAM,CAAC,EAEtF,CACR,CACF,CAEA,MAAaC,GAAa,EAAiB,CACzC,KAAM,MACN,YAAa,kCACb,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,KAAM,EAAI,EAAE,OAAO,EAAG,CACpB,YAAa,gBACb,MAAO,GACT,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAK,MAAM,oBAAoB,CACnC,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,KAAM,EAAK,IACb,CAAC,EAEK,EAAY,EAAK,KACnB,EACA,CACE,GAAG,EACH,UAAW,qBAAqB,EAAG,SAAS,EAC5C,UAAW,qBAAqB,EAAG,SAAS,CAC9C,EAEJ,EAAO,IAAI,CAAS,CACtB,CACF,CAAC,ECjFK,GAAsC,EAAE,OAAO,CACnD,YAAa,EAAE,KAAK,CAAE,QAAS,mCAAoC,CAAC,CAAC,CAAC,SAAS,EAC/E,QAAS,EAAE,OAAO,CAAC,CAAC,SAAS,EAC7B,MAAO,EAAE,KAAK,CAAC,MAAO,MAAM,CAAC,CAAC,CAAC,SAAS,EACxC,MAAO,EAAE,OAAO,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,SAAS,CACxD,CAAC,EAID,eAAeC,eAAY,EAAwC,CACjE,IAAM,EAAY,aAAa,GAAqC,CAAO,EAErE,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAU,QACnB,YAAa,EAAU,WACzB,CAAC,EAED,MAAO,CACL,SACA,cACA,MAAO,EAAU,MACjB,MAAO,EAAU,KACnB,CACF,CAOA,eAAsB,uBACpB,EACiC,CACjC,GAAM,CAAE,SAAQ,cAAa,QAAO,SAAU,MAAMA,eAAY,CAAO,EACjE,EAAgB,gBAAgB,CAAK,EAuB3C,OAAO,MArBkB,GACvB,MAAO,EAAW,IAAa,CAC7B,GAAI,CACF,GAAM,CAAE,YAAW,iBAAkB,MAAM,EAAO,uBAAuB,CACvE,cACA,YACA,WACA,OAAQ,aACR,eACF,CAAC,EACD,MAAO,CAAC,EAAW,CAAa,CAClC,OAAS,EAAO,CACd,GAAI,aAAiB,GAAgB,EAAM,OAAS,EAAK,SACvD,MAAO,CAAC,CAAC,EAAG,EAAE,EAEhB,MAAM,CACR,CACF,EACA,CAAE,OAAM,CACV,EAAA,CAEkB,IAAI,oBAAoB,CAC5C,CAEA,MAAaC,GAAc,EAAiB,CAC1C,KAAM,OACN,YAAa,0CACb,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,GAAG,eAAe,CACpB,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAa,EAAO,SACpB,EAAa,MAAM,uBAAuB,CAC9C,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,MAAO,EAAK,MACZ,MAAO,EAAK,KACd,CAAC,EAEK,EAAY,EACd,EACA,EAAW,KAAK,CAAE,YAAW,YAAW,GAAG,MAAY,CACrD,GAAG,EACH,UAAW,qBAAqB,CAAS,EACzC,UAAW,qBAAqB,CAAS,CAC3C,EAAE,EAEN,EAAO,IAAI,CAAS,CACtB,CACF,CAAC,ECpBD,eAAsB,iBACpB,EACA,EACA,EACA,EAAuB,IACO,CAG9B,OAAa,CACX,GAAM,CAAE,aAAc,MAAM,EAAO,qBAAqB,CACtD,cACA,aACF,CAAC,EAED,GAAI,CAAC,EACH,MAAU,MAAM,cAAc,EAAY,aAAa,EAIzD,GACE,EAAU,SAAW,EAAyB,SAC9C,EAAU,SAAW,EAAyB,QAC9C,EAAU,SAAW,EAAyB,SAE9C,MAAO,CACL,OAAQ,EAAU,OAClB,KAAM,EAAU,KAChB,OAAQ,EAAU,MACpB,EAIF,MAAM,IAAI,QAAS,GAAY,WAAW,EAAS,CAAY,CAAC,CAClE,CACF,CAYA,eAAsB,cACpB,EACgC,CAChC,GAAM,CAAE,SAAQ,cAAa,OAAM,OAAM,MAAK,UAAS,gBAAiB,EAGlE,EAAW,MAAM,EAAO,WAAW,CACvC,cACA,OACA,OACA,IAAK,KAAK,UAAU,IAAQ,IAAA,GAAY,CAAC,EAAI,CAAG,EAChD,SACF,CAAC,EACK,EAAc,EAAS,YAGvB,EAAS,MAAM,iBAAiB,EAAQ,EAAa,EAAa,CAAY,EASlF,OAPE,EAAO,SAAW,EAAyB,QACtC,CACL,QAAS,GACT,KAAM,EAAO,KACb,OAAQ,EAAO,MACjB,EAEO,CACL,QAAS,GACT,KAAM,EAAO,KACb,OAAQ,EAAO,QAAU,EAAS,OAClC,MACE,EAAO,QACP,EAAS,SACR,EAAO,SAAW,EAAyB,SACxC,gCACA,6CACR,CAEJ,CCzJA,SAAgB,qBAAqB,EAAgC,CACnE,IAAM,EAAa,IAAI,IAEvB,GAAI,EAAO,GACT,IAAK,IAAM,KAAiB,OAAO,KAAK,EAAO,EAAE,EAC/C,EAAW,IAAI,CAAa,EAIhC,OAAO,MAAM,KAAK,CAAU,CAC9B,CAUA,SAAgB,uBAAuB,EAAgC,CACrE,IAAM,EAAa,IAAI,IAEvB,GAAI,EAAO,GACT,IAAK,GAAM,CAAC,EAAe,KAAa,OAAO,QAAQ,EAAO,EAAE,EAC1D,aAAc,GAClB,EAAW,IAAI,CAAa,EAIhC,OAAO,MAAM,KAAK,CAAU,CAC9B,CCaA,eAAsB,0BACpB,EAAyC,CAAC,EACJ,CACtC,GAAM,CAAE,SAAQ,WAAY,MAAM,WAAW,EAAQ,UAAU,EAE/D,MAAM,kBAAkB,CAAE,SAAQ,WAAY,EAAO,IAAK,CAAC,EAE3D,IAAM,EAAgB,EAAQ,OAAS,EAAI,IAAI,GAAc,CAAO,EAAI,IAAA,GAClE,EAAc,GAAkB,CACpC,SACA,eACF,CAAC,EACK,EACJ,OAAO,EAAQ,YAAe,WAC1B,EAAQ,WAAW,EAAQ,CAAO,EAClC,EAAQ,WACR,EAAkB,EAAiB,IAAI,IAAI,CAAc,EAAI,IAAA,GAC7D,EAAW,EACb,EAAY,iBAAiB,OAAQ,GAAO,EAAgB,IAAI,EAAG,SAAS,CAAC,EAC7E,EAAY,iBAEhB,GAAI,GAAmB,EAAS,SAAW,EAAgB,KAAM,CAC/D,IAAM,EAAQ,IAAI,IAAI,EAAS,IAAK,GAAO,EAAG,SAAS,CAAC,EAClD,EAAU,CAAC,GAAG,CAAe,CAAC,CAAC,OAAQ,GAAO,CAAC,EAAM,IAAI,CAAE,CAAC,CAAC,CAAC,KAAK,IAAI,EACvE,EAAY,EAAY,iBAAiB,IAAK,GAAO,EAAG,SAAS,CAAC,CAAC,KAAK,IAAI,EAClF,MAAU,MACR,uBAAuB,EAAQ,kCAC5B,EAAY,gCAAgC,IAAc,GAC/D,CACF,CAEA,IAAM,EAAsC,CAAC,EAE7C,IAAK,IAAM,KAAM,EACf,MAAM,EAAG,UAAU,EACnB,MAAM,EAAG,wBAAwB,EACjC,EAAW,KAAK,CACd,UAAW,EAAG,UACd,OAAQ,CAAE,GAAG,EAAG,KAAM,EACtB,WAAY,IAAI,IAAI,OAAO,QAAQ,EAAG,cAAc,CAAC,EACrD,kBAAmB,EAAG,iBACxB,CAAC,EAGH,MAAO,CAAE,SAAQ,UAAS,cAAa,YAAW,CACpD,CASA,eAAsB,uBACpB,EAAyC,CAAC,EACP,CACnC,GAAM,CAAE,SAAQ,UAAS,cAAe,MAAM,0BAA0B,CAAO,EAC/E,MAAO,CAAE,SAAQ,UAAS,YAAW,CACvC,CClGA,SAAgB,oBACd,EACA,EACsC,CAEtC,OADe,EAAQ,KAAM,GAAc,EAAU,KAAO,CAChD,CAAC,EAAE,YACjB,CCVA,SAAgB,aAAa,EAA0D,CACrF,IAAM,EAAc,EAAY,YAChC,GAAI,CAAC,EAAa,OAElB,IAAM,EAAa,EAAY,OACzB,EAAc,EAAY,YAChC,MAAO,CACL,KAAM,EAAW,KACjB,YAAa,EACT,CACE,UAAW,EAAY,KAAK,KAC5B,UAAW,EAAY,UACvB,cAAe,EAAY,aAC7B,EACA,IAAA,GACJ,aAAc,EAAW,aACzB,cAAe,EAAW,cAC1B,WAAY,EAAW,UACzB,CACF,CCCA,SAAS,mBAAmB,EAAc,EAAyB,CACjE,GAAI,OAAO,GAAU,SAAU,OAAO,GAAc,CAAK,EACzD,GAAI,OAAO,GAAU,UAAY,OAAO,GAAU,WAAa,IAAU,KAAM,CAC7E,IAAM,EAAO,KAAK,UAAU,CAAK,EAC3B,EAAW,GAAc,CAAI,EACnC,OAAO,IAAa,EAAO,EAAQ,CACrC,CACA,OAAO,CACT,CAaA,SAAgB,YACd,EACA,EAC8D,CAC9D,IAAM,EAAW,gBAAgB,EAAO,CAAO,EAC/C,GAAI,EAAE,aAAiB,OAAQ,OAAO,EAEtC,GAAM,CAAE,SAAQ,UAAS,SAAU,EAAW,GAAG,GAAgB,GAAoB,CAAK,EAC1F,MAAO,CACL,MAAO,CACL,GAAG,EAAS,MACZ,GAAG,EACH,GAAI,GAAW,EACX,CACE,QAAS,CACP,GAAG,EACH,GAAG,OAAO,YACR,OAAO,QAAQ,GAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAO,KAAW,CACnD,EACA,YAAY,EAAO,CAAO,CAAC,CAAC,KAC9B,CAAC,CACH,CACF,CACF,EACA,CAAC,CACP,CACF,CACF,CAEA,SAAS,gBACP,EACA,EAC8D,CAC9D,GAAI,GAAW,CAAK,EAClB,MAAO,CACL,MAAO,CACL,KAAM,EAAM,MAAQ,YACpB,QAAS,EAAM,QACf,GAAI,EAAM,QAAU,CAAE,QAAS,EAAM,OAAQ,EAAI,CAAC,EAClD,GAAI,EAAM,WAAa,CAAE,WAAY,EAAM,UAAW,EAAI,CAAC,EAC3D,GAAI,EAAM,QACN,CACE,KAAM,qBAAqB,EAAM,OAAO,CAC1C,EACA,CAAC,EACL,GAAI,EAAM,KAAO,CAAE,KAAM,EAAM,IAAK,EAAI,CAAC,EACzC,GAAI,EAAM,QAAU,CAAE,QAAS,EAAM,OAAQ,EAAI,CAAC,EAClD,GAAI,GAAS,cAAgB,EAAM,MAAQ,CAAE,MAAO,EAAM,KAAM,EAAI,CAAC,CACvE,CACF,EAEF,GAAI,aAAiB,EAAc,CACjC,IAAM,EAAW,EAAK,EAAM,MAK5B,MAAO,CACL,MAAO,CACL,KAAM,OALR,OAAO,GAAa,SAChB,EAAS,WAAW,qBAAsB,OAAO,CAAC,CAAC,YAAY,EAC/D,QAAQ,EAAM,SAIhB,QAAS,EAAM,QACf,GAAI,GAAS,cAAgB,EAAM,MAAQ,CAAE,MAAO,EAAM,KAAM,EAAI,CAAC,CACvE,CACF,CACF,CACA,GAAI,aAAiB,MAAO,CAC1B,IAAM,EAAa,GAAmB,CAAK,EAC3C,MAAO,CACL,MAAO,CACL,KAAM,EAAM,OAAS,gBAAkB,8BAAgC,mBACvE,QAAS,EAAM,QACf,GAAI,EAAa,CAAE,YAAW,EAAI,CAAC,EACnC,GAAI,GAAS,cAAgB,EAAM,MAAQ,CAAE,MAAO,EAAM,KAAM,EAAI,CAAC,CACvE,CACF,CACF,CACA,MAAO,CAAE,MAAO,CAAE,KAAM,gBAAiB,QAAS,OAAO,CAAK,CAAE,CAAE,CACpE,CA2BA,SAAgB,eAAe,EAAgB,EAAsC,CACnF,IAAM,EAAW,YAAY,EAAO,CAAO,EAC3C,GAAI,CACF,OAAO,KAAK,UAAU,EAAU,kBAAkB,CACpD,MAAQ,CACN,IAAM,EAAgB,CAAE,GAAG,EAAS,KAAM,EAG1C,OAFA,OAAO,EAAc,QACrB,OAAO,EAAc,MACd,KAAK,UAAU,CAAE,MAAO,CAAc,EAAG,kBAAkB,CACpE,CACF,CAEA,SAAS,qBAAqB,EAAqC,CACjE,MAAO,CACL,QAAS,SACT,KAAM,CAAC,GAAG,EAAQ,MAAM,KAAK,CAAC,CAAC,OAAO,OAAO,EAAG,QAAQ,CAC1D,CACF,CC/GA,SAAgB,wBAAwB,EAIlB,CACpB,GAAM,CAAE,cAAa,SAAQ,iBAAkB,EACzC,EAAU,EAAK,KAAK,GAAW,EAAG,WAAW,EACnD,EAAG,UAAU,EAAS,CAAE,UAAW,EAAK,CAAC,EAEzC,IAAM,EAIF,CAAE,SAAU,CAAC,EAAG,SAAU,CAAC,EAAG,SAAU,CAAC,CAAE,EAGzC,EAAoB,GAAe,8BAA8B,GAAK,CAAC,EAU7E,SAAS,mBAA6C,CACpD,OAAO,OAAO,QAAQ,EAAS,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAW,MAAW,CACnE,YACA,OAAQ,EAAK,MACb,WAAY,IAAI,IAAI,OAAO,QAAQ,EAAK,UAAU,CAAC,EACnD,kBAAmB,EAAK,iBAC1B,EAAE,CACJ,CAMA,SAAS,mBAA6C,CACpD,OAAO,OAAO,QAAQ,EAAS,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAW,MAAgB,CACxE,YACA,WACF,EAAE,CACJ,CAQA,eAAe,mBACb,EACA,EACe,CAEf,GAAI,CADS,EAAO,GACT,OAEX,IAAM,EAAgB,EAAK,KAAK,EAAS,EAAO,EAAE,EAC5C,EAAO,aAAa,CAAW,EAC/B,EAAW,kBAAkB,EAE/B,EAEJ,OAAQ,EAAR,CACE,IAAK,kBACH,EAAS,MAAM,EACb,EAAO,gBACP,qCACF,CAAC,CAAC,CACA,WACA,OACA,QAAS,EACT,WAAY,EAAO,KACnB,aAAc,EAAO,YACvB,CAAC,EACD,MACF,IAAK,kBACH,EAAS,MAAM,EACb,EAAO,gBACP,qCACF,CAAC,CAAC,CACA,WACA,UAAW,kBAAkB,EAC7B,OACA,QAAS,EACT,WAAY,EAAO,KACnB,aAAc,EAAO,YACvB,CAAC,EACD,MACF,IAAK,kBACH,EAAS,MAAM,EACb,EAAO,gBACP,qCACF,CAAC,CAAC,CACA,WACA,UAAW,kBAAkB,EAC7B,UAAW,CAAE,GAAG,EAAS,QAAS,EAClC,OACA,QAAS,EACT,WAAY,EAAO,KACnB,aAAc,EAAO,YACvB,CAAC,CAEL,CAEA,MAAM,oBAAoB,EAAO,GAAI,CAAM,CAC7C,CAQA,eAAe,cACb,EACe,CACf,IAAM,EAAU,EAAkB,OAAQ,GAAM,EAAE,IAAa,IAAI,EACnE,GAAI,EAAQ,SAAW,EAAG,OAY1B,IAAM,GAAW,MAXK,QAAQ,WAC5B,EAAQ,IAAI,KAAO,IAAW,CAC5B,GAAI,CACF,MAAM,mBAAmB,EAAQ,CAAQ,CAC3C,OAAS,EAAO,CAGd,MAFA,EAAO,MAAM,2BAA2B,EAAO,KAAK,EAAO,EAAE,EAAE,IAAI,EAAS,EAAE,EAC9E,EAAO,MAAM,OAAO,CAAK,CAAC,EACpB,CACR,CACF,CAAC,CACH,EAAA,CACyB,SAAS,EAAQ,IACxC,EAAO,SAAW,WACd,CACE,CACE,OAAQ,EAAc,EAAQ,GAAQ,sCAAsC,CAAC,CAAC,GAC9E,OAAQ,EAAO,MACjB,CACF,EACA,CAAC,CACP,EACA,GAAI,EAAS,OAAS,EACpB,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,mCAAmC,EAAS,GACrD,QAAS,EACN,KACE,CAAE,SAAQ,YACT,GAAG,EAAO,IAAI,GAAW,CAAM,EAAI,GAAyB,EAAO,OAAO,CAAC,EAAI,OAAO,CAAM,GAChG,CAAC,CACA,KAAK;CAAI,EACZ,QAAS,CACP,KAAM,EACN,SAAU,EAAS,KAAK,CAAE,SAAQ,aAAc,CAC9C,SACA,MAAO,YAAY,EAAQ,CAAE,aAAc,EAAO,OAAQ,CAAC,CAAC,CAAC,KAC/D,EAAE,CACJ,CACF,CAAC,CAEL,CAWA,eAAe,oBAAoB,EAAkB,EAAwC,CAC3F,MAAM,QAAQ,IACZ,EAAO,MAAM,IAAI,KAAO,KACtB,EAAG,UAAU,EAAK,QAAQ,EAAK,IAAI,EAAG,CAAE,UAAW,EAAK,CAAC,EAClD,IAAI,SAAe,EAAS,IAAW,CAC5C,GAAI,EAAK,cAAgBC,EAAG,WAAW,EAAK,IAAI,EAAG,CACjD,IAAM,EAAe,EAAK,SAAS,QAAQ,IAAI,EAAG,EAAK,IAAI,EAE3D,OADA,EAAO,MAAM,GAAG,EAAS,oBAAoB,GAAc,EACpD,EAAQ,CACjB,CAEA,EAAG,UAAU,EAAK,KAAM,EAAK,QAAU,GAAQ,CAC7C,GAAI,EAAK,CACP,IAAM,EAAe,EAAK,SAAS,QAAQ,IAAI,EAAG,EAAK,IAAI,EAC3D,EAAO,MAAM,sBAAsB,EAAO,KAAK,CAAY,GAAG,EAC9D,EAAO,MAAM,OAAO,CAAG,CAAC,EACxB,EAAO,CAAG,CACZ,KAAO,CACL,IAAM,EAAe,EAAK,SAAS,QAAQ,IAAI,EAAG,EAAK,IAAI,EAC3D,EAAO,MAAM,GAAG,EAAS,eAAe,EAAO,QAAQ,CAAY,GAAG,EAElE,EAAK,WACP,EAAG,MAAM,EAAK,KAAM,IAAQ,GAAa,CACvC,GAAI,EAAU,CACZ,IAAM,EAAe,EAAK,SAAS,QAAQ,IAAI,EAAG,EAAK,IAAI,EAC3D,EAAO,MACL,0CAA0C,EAAO,KAAK,CAAY,GACpE,EACA,EAAO,MAAM,OAAO,CAAQ,CAAC,EAC7B,EAAO,CAAQ,CACjB,MACE,EAAQ,CAEZ,CAAC,EAED,EAAQ,CAEZ,CACF,CAAC,CACH,CAAC,EACF,CACH,EACI,EAAO,MAAM,OAAS,GACxB,EAAO,IAAI,GAAG,EAAS,uBAAuB,CAElD,CAEA,MAAO,CACL,cACA,UACA,WAEA,MAAM,UAA0B,CAC9B,EAAO,QAAQ,EACf,EAAO,IAAI,+BAA+B,EAAO,UAAU,EAAY,OAAO,IAAI,GAAG,EAErF,IAAM,EAAM,EAGZ,MAAM,EAAS,6BAA8B,KAAO,IAAS,CAC3D,EAAK,aAAa,2BAA4B,EAAI,iBAAiB,MAAM,EACzE,IAAK,IAAM,KAAM,EAAI,iBAAkB,CACrC,IAAM,EAAY,EAAG,UACrB,MAAM,EAAS,sBAAsB,IAAa,SAAY,CAC5D,GAAI,CACF,MAAM,EAAG,UAAU,EAInB,MAAM,EAAG,wBAAwB,EAEjC,EAAS,SAAS,GAAa,CAC7B,MAAO,EAAG,MACV,WAAY,EAAG,eACf,kBAAmB,EAAG,iBACxB,CACF,OAAS,EAAO,CAGd,MAFA,EAAO,MAAM,6CAA6C,EAAO,KAAK,CAAS,GAAG,EAClF,EAAO,MAAM,OAAO,CAAK,CAAC,EACpB,CACR,CACF,CAAC,CACH,CACA,GAAI,CACF,GAAmC,CACjC,iBAAkB,EAAI,gBACxB,CAAC,CACH,OAAS,EAAO,CAGd,MAFA,EAAO,MAAM,uCAAuC,EACpD,EAAO,MAAM,OAAO,CAAK,CAAC,EACpB,CACR,CACF,CAAC,EAID,GAAM,CAAE,sBAAqB,mBAAoB,MAAM,EACrD,uBACA,SAAY,CACV,IAAM,EAAsB,GAC1B,EACA,EAAI,iBACJ,EAAO,IACT,EAMA,MAAO,CAAE,sBAAqB,gBAJ5B,EAAI,kBACH,EAAoB,OAAS,EAC1B,GAAsB,CAAE,OAAQ,CAAE,MAAO,CAAC,CAAE,EAAG,QAAS,EAAK,QAAQ,EAAO,IAAI,CAAE,CAAC,EACnF,IAAA,GACwC,CAChD,CACF,EAGA,GAAI,EAAI,YAAa,CACnB,IAAM,EAAc,EAAI,YACxB,MAAM,EAAS,iCAAkC,SAC/C,EAAY,kBAAkB,CAChC,CACF,EAGI,EAAI,iBAAiB,OAAS,GAAK,EAAoB,OAAS,IAClE,EAAO,QAAQ,EAIU,EAAkB,KAAM,GAAM,EAAE,iBAAmB,IACzD,IACnB,MAAM,EAAS,2BAA4B,SAAY,CACrD,MAAM,cAAc,iBAAiB,CACvC,CAAC,EACD,EAAO,QAAQ,GAIjB,MAAM,EAAS,yBAA0B,SAAY,CACnD,IAAK,IAAM,KAAmB,EAAI,iBAAkB,CAClD,IAAM,EAAY,EAAgB,UAClC,MAAM,EAAS,0BAA0B,IAAa,SAAY,CAChE,GAAI,CACF,MAAM,EAAgB,cAAc,EACpC,IAAM,EAA+C,CAAC,EACtD,EAAS,SAAS,GAAa,EAC/B,OAAO,QAAQ,EAAgB,SAAS,CAAC,CAAC,SAAS,CAAC,EAAG,KAAc,CACnE,EAAmB,EAAS,MAAQ,CACtC,CAAC,CACH,OAAS,EAAO,CAKd,MAJA,EAAO,MACL,gDAAgD,EAAO,KAAK,CAAS,GACvE,EACA,EAAO,MAAM,OAAO,CAAK,CAAC,EACpB,CACR,CACF,CAAC,CACH,CACF,CAAC,EAG0B,EAAkB,KAAM,GAAM,EAAE,iBAAmB,IACzD,IACnB,MAAM,EAAS,4BAA6B,SAAY,CACtD,MAAM,cAAc,iBAAiB,CACvC,CAAC,EACD,EAAO,QAAQ,GAIjB,MAAM,EAAS,yBAA0B,SAAY,CAC/C,IACF,MAAM,EAAgB,cAAc,EAEhC,EAAoB,OAAS,GAC/B,MAAM,EAAgB,wBAAwB,CAAC,GAAG,CAAmB,CAAC,GAI1E,IAAM,EAAe,GAAiB,WAAa,CAAC,EACpD,OAAO,QAAQ,CAAY,CAAC,CAAC,SAAS,CAAC,EAAK,KAAc,CACxD,EAAS,SAAS,GAAO,CAC3B,CAAC,CACH,CAAC,EAG0B,EAAkB,KAAM,GAAM,EAAE,iBAAmB,IACzD,IACnB,MAAM,EAAS,4BAA6B,SAAY,CACtD,MAAM,cAAc,iBAAiB,CACvC,CAAC,EACD,EAAO,QAAQ,EAEnB,CACF,CACF,CAOA,eAAsBC,WAAS,EAA2B,CACxD,OAAO,EAAS,WAAY,KAAO,IAAa,CAE9C,GAAM,CAAE,SAAQ,WAAY,MAAM,EAAS,sBAAuB,SACzD,WAAW,GAAS,UAAU,CACtC,EAGD,MAAM,EAAS,6BAA8B,SAC3C,kBAAkB,CAAE,SAAQ,WAAY,EAAO,IAAK,CAAC,CACvD,EAGA,IAAI,EACA,EAAQ,OAAS,IACnB,EAAgB,IAAI,GAAc,CAAO,GAI3C,IAAM,EAAc,GAAkB,CAAE,SAAQ,eAAc,CAAC,EAE/D,EAAS,aAAa,WAAY,EAAY,OAAO,IAAI,EAGzD,MADgB,wBAAwB,CAAE,cAAa,SAAQ,eAAc,CACjE,CAAC,CAAC,SAAS,CACzB,CAAC,CACH,CCxaA,SAAS,gBAAgB,EAAoC,CAE3D,OADA,EAAO,eAAe,EAAK,YAAY,EAChC,CACL,KAAM,EAAK,KACX,SAAU,EAAK,SACf,aAAc,EAAK,aACnB,UAAW,EAAK,UAAY,EAAc,EAAK,SAAS,EAAI,KAC5D,UAAW,EAAK,UAAY,EAAc,EAAK,SAAS,EAAI,KAC5D,WAAY,OAAO,YACjB,OAAO,QAAQ,EAAK,YAAY,CAAC,CAAC,KAAK,CAAC,EAAK,KAAW,CAAC,EAAK,GAAO,GAAa,CAAK,CAAC,CAAC,CAC3F,CACF,CACF,CAOA,eAAsB,iBACpB,EAC4B,CAE5B,GAAM,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,GAAS,QAClB,YAAa,GAAS,WACxB,CAAC,EAGK,CAAE,UAAW,MAAM,WAAW,GAAS,UAAU,EACjD,CAAE,eAAgB,MAAM,EAAO,eAAe,CAClD,cACA,gBAAiB,EAAO,IAC1B,CAAC,EACD,GAAI,CAAC,GAAa,cAChB,MAAM,EAAS,CACb,KAAM,uBACN,QAAS,eAAe,EAAO,KAAK,sCACtC,CAAC,EAGH,IAAM,EAAgB,gBAAgB,GAAS,KAAK,EAepD,OAAO,MAdoB,GACzB,MAAO,EAAW,IAAa,CAC7B,GAAM,CAAE,eAAc,iBAAkB,MAAM,EAAO,qBAAqB,CACxE,cACA,YACA,WACA,cAAe,EAAY,cAC3B,eACF,CAAC,EACD,MAAO,CAAC,EAAc,CAAa,CACrC,EACA,CAAE,MAAO,GAAS,KAAM,CAC1B,EAAA,CAEoB,IAAI,eAAe,CACzC,CAEA,MAAaC,GAAc,EAAiB,CAC1C,KAAM,OACN,YAAa,6CACb,KAAM,EAAE,aAAa,CACnB,GAAG,GACH,GAAG,eAAe,CACpB,CAAC,EACD,IAAK,KAAO,IAAS,CAEnB,IAAM,EAAe,MAAM,iBAAiB,CAC1C,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,WAAY,EAAK,OACjB,MAAO,EAAK,MACZ,MAAO,EAAK,KACd,CAAC,EAGD,EAAO,IAAI,EAAc,CAAE,QAAS,CAAE,UAAW,KAAM,UAAW,IAAK,CAAE,CAAC,CAC5E,CACF,CAAC,ECjFD,eAAe,4BACb,EAC+B,CAE/B,IAAM,EAAO,MAAM,oBAAoB,CACrC,YAAa,EAAQ,KACrB,kBAAmB,EAAQ,WAC3B,QAAS,EAAQ,OACnB,CAAC,EACD,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,wBACN,QAAS,4BACT,WACE,sKACF,QAAS,mBACX,CAAC,EAGH,GAAM,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAQ,QACjB,YAAa,EAAQ,WACvB,CAAC,EAGK,CAAE,UAAW,MAAM,WAAW,EAAQ,UAAU,EAChD,CAAE,eAAgB,MAAM,EAAO,eAAe,CAClD,cACA,gBAAiB,EAAO,IAC1B,CAAC,EACD,GAAI,CAAC,GAAa,cAChB,MAAM,EAAS,CACb,KAAM,uBACN,QAAS,eAAe,EAAO,KAAK,sCACtC,CAAC,EAIH,GAAM,CAAE,eAAgB,MAAM,EAAO,mBAAmB,CACtD,cACA,cAAe,EAAY,cAC3B,MACF,CAAC,EACD,GAAI,CAAC,EACH,MAAM,EAAS,CAAE,KAAM,yBAA0B,QAAS,gBAAgB,EAAK,YAAa,CAAC,EAI/F,IAAM,EAAO,MAAM,GACjB,EAAY,IACZ,EAAY,SACZ,EAAY,YACd,EACM,EAAY,IAAI,KAGtB,OAFA,EAAU,WAAW,EAAU,WAAW,EAAI,EAAK,UAAU,EAEtD,CACL,YAAa,EAAK,aAClB,UAAW,EAAK,WAChB,UAAW,EAAU,YAAY,CACnC,CACF,CAOA,eAAsB,oBACpB,EAC+B,CAC/B,OAAO,MAAM,4BAA4B,CAAO,CAClD,CAEA,MAAa,GAAe,EAAiB,CAC3C,KAAM,QACN,YAAa,0CACb,KAAM,EAAE,aAAa,CACnB,GAAG,GACH,KAAM,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CAC/B,WAAY,GACZ,YACE,qHACJ,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CAEnB,IAAM,EAAQ,MAAM,4BAA4B,CAC9C,KAAM,EAAK,KACX,WAAY,8BAA8B,EAAK,KAAM,QAAQ,KAAK,MAAM,CAAC,EAAG,CAC1E,gBAAiB,EAAK,OAAS,IAAA,EACjC,CAAC,EACD,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,WAAY,EAAK,MACnB,CAAC,EAIK,EAAY,CAChB,aAAc,EAAM,YACpB,WAAY,EAAM,UAClB,WAAY,EAAM,SACpB,EACA,EAAO,IAAI,CAAS,CACtB,CACF,CAAC,ECnIK,kBAAqB,GAAkD,CAC3E,OAAQ,EAAR,CACE,KAAK,GAA2B,mBAC9B,MAAO,qBACT,KAAK,GAA2B,cAC9B,MAAO,gBACT,QACE,MAAO,SACX,CACF,EA0BA,SAAgB,mBAAmB,EAA4C,CAC7E,MAAO,CACL,KAAM,EAAO,KACb,YAAa,EAAO,YACpB,SAAU,EAAO,SACjB,WAAY,EAAO,WAAW,IAAI,iBAAiB,EACnD,aAAc,EAAO,aACrB,UAAW,EAAO,UAAY,EAAc,EAAO,SAAS,EAAI,IAClE,CACF,CAOA,SAAgB,0BAA0B,EAAmD,CAE3F,OADA,EAAO,eAAe,EAAO,YAAY,EAClC,CACL,KAAM,EAAO,KACb,YAAa,EAAO,YACpB,SAAU,EAAO,SACjB,aAAc,EAAO,aACrB,WAAY,EAAO,WAAW,IAAI,iBAAiB,EACnD,aAAc,EAAO,aACrB,UAAW,EAAO,UAAY,EAAc,EAAO,SAAS,EAAI,IAClE,CACF,CC7CA,eAAsB,gBACpB,EACkC,CAClC,GAAM,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAQ,QACjB,YAAa,EAAQ,WACvB,CAAC,EAEK,CAAE,UAAW,MAAM,WAAW,EAAQ,UAAU,EAChD,CAAE,eAAgB,MAAM,EAAO,eAAe,CAClD,cACA,gBAAiB,EAAO,IAC1B,CAAC,EACD,GAAI,CAAC,GAAa,cAChB,MAAM,EAAS,CACb,KAAM,uBACN,QAAS,eAAe,EAAO,KAAK,sCACtC,CAAC,EAGH,GAAI,CACF,GAAM,CAAE,gBAAiB,MAAM,EAAO,oBAAoB,CACxD,cACA,cAAe,EAAY,cAC3B,KAAM,EAAQ,IAChB,CAAC,EAED,OAAO,0BACL,EAAc,EAAc,kCAAkC,CAChE,CACF,OAAS,EAAO,CAQd,MAPI,aAAiB,GAAgB,EAAM,OAAS,EAAK,SACjD,EAAS,CACb,KAAM,0BACN,QAAS,kBAAkB,EAAQ,KAAK,cACxC,MAAO,CACT,CAAC,EAEG,CACR,CACF,CAEA,MAAaC,GAAa,EAAiB,CACzC,KAAM,MACN,YAAa,2DACb,KAAM,EAAE,aAAa,CACnB,GAAG,GACH,KAAM,EAAI,EAAE,OAAO,EAAG,CACpB,WAAY,GACZ,YAAa,oBACf,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAc,MAAM,gBAAgB,CACxC,KAAM,EAAK,KACX,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,WAAY,EAAK,MACnB,CAAC,EAED,EAAO,IAAI,CAAW,CACxB,CACF,CAAC,EC/DD,eAAsB,kBACpB,EAC6B,CAC7B,GAAM,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,GAAS,QAClB,YAAa,GAAS,WACxB,CAAC,EAEK,CAAE,UAAW,MAAM,WAAW,GAAS,UAAU,EACjD,CAAE,eAAgB,MAAM,EAAO,eAAe,CAClD,cACA,gBAAiB,EAAO,IAC1B,CAAC,EACD,GAAI,CAAC,GAAa,cAChB,MAAM,EAAS,CACb,KAAM,uBACN,QAAS,eAAe,EAAO,KAAK,sCACtC,CAAC,EAGH,IAAM,EAAgB,gBAAgB,GAAS,KAAK,EAepD,OAAO,MAdqB,GAC1B,MAAO,EAAW,IAAa,CAC7B,GAAM,CAAE,gBAAe,iBAAkB,MAAM,EAAO,sBAAsB,CAC1E,cACA,YACA,WACA,cAAe,EAAY,cAC3B,eACF,CAAC,EACD,MAAO,CAAC,EAAe,CAAa,CACtC,EACA,CAAE,MAAO,GAAS,KAAM,CAC1B,EAAA,CAEqB,IAAI,kBAAkB,CAC7C,CAEA,MAAaC,GAAc,EAAiB,CAC1C,KAAM,OACN,YAAa,8CACb,KAAM,EAAE,aAAa,CACnB,GAAG,GACH,GAAG,eAAe,CACpB,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAgB,MAAM,kBAAkB,CAC5C,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,WAAY,EAAK,OACjB,MAAO,EAAK,MACZ,MAAO,EAAK,KACd,CAAC,EAED,EAAO,IAAI,CAAa,CAC1B,CACF,CAAC,EC/CY,qBACX,IAC0B,CAC1B,eAAgB,EAAI,eACpB,iBAAkB,EAAI,iBACtB,aAAc,EAAI,aAClB,eAAgB,EAAI,eACpB,YAAa,EAAI,WACnB,GAEa,iBAAoB,IAAyC,CACxE,GAAI,EAAI,GACR,KAAM,EAAI,KACV,UAAW,gBAAgB,EAAI,UAAU,EACzC,UAAW,gBAAgB,EAAI,UAAU,CAC3C,GAEa,eAAkB,IAAoC,CACjE,GAAI,EAAO,GACX,KAAM,EAAO,KACb,eAAgB,EAAO,eACvB,eAAgB,EAAO,eACvB,YAAa,EAAO,YACpB,UAAW,gBAAgB,EAAO,UAAU,CAC9C,GAEa,WAAc,IAAgC,CACzD,GAAG,eAAe,CAAM,EACxB,UAAW,gBAAgB,EAAO,UAAU,CAC9C,GChDM,GAA4B,EAAE,OAAO,CACzC,eAAgB,EAAE,KAAK,CAAE,QAAS,sCAAuC,CAAC,EAC1E,eAAgB,EAAE,OAAO,CAAC,CAAC,SAAS,EACpC,KAAM,EAAE,OAAO,CAAC,CAAC,IAAI,EAAG,wBAAwB,CAClD,CAAC,EASD,eAAsB,aAAa,EAAmD,CACpF,IAAM,EAAY,aAAa,GAA2B,CAAO,EAE3D,EAAc,MAAM,gBAAgB,EAGpC,EAAW,MAAM,MAFF,EAAmB,CAAW,EAAA,CAErB,yBAAyB,CACrD,eAAgB,EAAU,eAC1B,eAAgB,EAAU,gBAAkB,GAC5C,WAAY,EAAU,IACxB,CAAC,EAED,GAAI,CAAC,EAAS,OACZ,MAAM,EAAc,0BAA0B,EAGhD,OAAO,WAAW,EAAS,MAAM,CACnC,CAEA,MAAa,GAAgB,EAAiB,CAC5C,KAAM,SACN,YAAa,0CACb,KAAM,EAAE,aAAa,CACnB,GAAG,GACH,mBAAoB,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CAC7C,YAAa,kBACf,CAAC,EACD,KAAM,EAAI,EAAE,OAAO,EAAG,CACpB,MAAO,IACP,YAAa,aACf,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,MAAM,eAAe,EACrB,IAAM,EAAS,MAAM,aAAa,CAChC,eAAgB,EAAK,mBACrB,eAAgB,EAAK,oBACrB,KAAM,EAAK,IACb,CAAC,EAEI,EAAK,MACR,EAAO,QAAQ,WAAW,EAAO,KAAK,wBAAwB,EAGhE,EAAO,IAAI,CAAM,CACnB,CACF,CAAC,EC3DK,GAA4B,EAAE,OAAO,CACzC,eAAgB,EAAE,KAAK,CAAE,QAAS,sCAAuC,CAAC,EAC1E,SAAU,EAAE,KAAK,CAAE,QAAS,gCAAiC,CAAC,CAChE,CAAC,EASD,eAAsB,aAAa,EAA6C,CAC9E,IAAM,EAAY,aAAa,GAA2B,CAAO,EAE3D,EAAc,MAAM,gBAAgB,EAG1C,MAAM,MAFe,EAAmB,CAAW,EAAA,CAEtC,yBAAyB,CACpC,eAAgB,EAAU,eAC1B,SAAU,EAAU,QACtB,CAAC,CACH,CAEA,MAAaC,GAAgB,EAAiB,CAC5C,KAAM,SACN,YAAa,wCACb,KAAM,EAAE,aAAa,CACnB,GAAG,GACH,GAAG,GACH,GAAG,EACL,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,MAAM,eAAe,EACrB,IAAM,EAAc,MAAM,gBAAgB,EACpC,EAAS,MAAM,EAAmB,CAAW,EAG/C,EACJ,GAAI,CACF,EAAW,MAAM,EAAO,sBAAsB,CAC5C,eAAgB,EAAK,mBACrB,SAAU,EAAK,YACjB,CAAC,CACH,OAAS,EAAO,CAQd,MAPI,aAAiB,GAAgB,EAAM,OAAS,EAAK,SACjD,EAAS,CACb,KAAM,mBACN,QAAS,WAAW,EAAK,aAAa,cACtC,MAAO,CACT,CAAC,EAEG,CACR,CACA,GAAI,CAAC,EAAS,OACZ,MAAM,EAAS,CACb,KAAM,mBACN,QAAS,WAAW,EAAK,aAAa,aACxC,CAAC,EAEH,IAAM,EAAa,EAAS,OAAO,KAGnC,GAAI,CAAC,EAAK,KAIJ,CAAC,MAHmB,EAAO,QAAQ,CACrC,QAAS,2CAA2C,EAAW,GACjE,CAAC,EACe,CACd,EAAO,KAAK,4BAA4B,EACxC,MACF,CAGF,MAAM,EAAO,yBAAyB,CACpC,eAAgB,EAAK,mBACrB,SAAU,EAAK,YACjB,CAAC,EAED,EAAO,QAAQ,WAAW,EAAW,wBAAwB,CAC/D,CACF,CAAC,ECjFK,GAAyB,EAAE,OAAO,CACtC,eAAgB,EAAE,KAAK,CAAE,QAAS,sCAAuC,CAAC,EAC1E,SAAU,EAAE,KAAK,CAAE,QAAS,gCAAiC,CAAC,CAChE,CAAC,EASD,eAAsB,UAAU,EAAgD,CAC9E,IAAM,EAAY,aAAa,GAAwB,CAAO,EAExD,EAAc,MAAM,gBAAgB,EAGpC,EAAW,MAAM,MAFF,EAAmB,CAAW,EAAA,CAErB,sBAAsB,CAClD,eAAgB,EAAU,eAC1B,SAAU,EAAU,QACtB,CAAC,EAED,GAAI,CAAC,EAAS,OACZ,MAAM,EAAS,CACb,KAAM,mBACN,QAAS,WAAW,EAAU,SAAS,aACzC,CAAC,EAGH,OAAO,WAAW,EAAS,MAAM,CACnC,CAEA,MAAaC,GAAa,EAAiB,CACzC,KAAM,MACN,YAAa,4CACb,KAAM,EAAE,aAAa,CACnB,GAAG,GACH,GAAG,EACL,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAS,MAAM,UAAU,CAC7B,eAAgB,EAAK,mBACrB,SAAU,EAAK,YACjB,CAAC,EAEK,EAAkB,EAAK,KACzB,EACA,CACE,GAAG,EACH,UAAW,qBAAqB,EAAO,SAAS,EAChD,UAAW,qBAAqB,EAAO,SAAS,CAClD,EAEJ,EAAO,IAAI,CAAe,CAC5B,CACF,CAAC,ECzDK,GAA2B,EAAE,OAAO,CACxC,eAAgB,EAAE,KAAK,CAAE,QAAS,sCAAuC,CAAC,EAC1E,eAAgB,EAAE,OAAO,CAAC,CAAC,SAAS,EACpC,MAAO,GAAS,SAAS,EACzB,MAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,SAAS,CACjD,CAAC,EASD,eAAsB,YAAY,EAAwD,CAGxF,GAAM,CAAE,iBAAgB,iBAAgB,QAAO,SAF7B,aAAa,GAA0B,CAEQ,EAE3D,EAAc,MAAM,gBAAgB,EACpC,EAAS,MAAM,EAAmB,CAAW,EAE7C,EAAgB,gBAAgB,CAAK,EAe3C,OAAO,MAde,GACpB,MAAO,EAAW,IAAa,CAC7B,IAAM,EAAW,MAAM,EAAO,wBAAwB,CACpD,iBACA,GAAI,EAAiB,CAAE,gBAAe,EAAI,CAAC,EAC3C,YACA,WACA,eACF,CAAC,EACD,MAAO,CAAC,EAAS,QAAS,EAAS,aAAa,CAClD,EACA,CAAE,OAAM,CACV,EAAA,CAEe,IAAI,cAAc,CACnC,CAEA,MAAaC,GAAc,EAAiB,CAC1C,KAAM,OACN,YAAa,mCACb,KAAM,EAAE,aAAa,CACnB,GAAG,GACH,mBAAoB,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CAC7C,YAAa,sCACf,CAAC,EACD,GAAG,eAAe,CACpB,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAU,MAAM,YAAY,CAChC,eAAgB,EAAK,mBACrB,eAAgB,EAAK,oBACrB,MAAO,EAAK,MACZ,MAAO,EAAK,KACd,CAAC,EACD,EAAO,IAAI,EAAS,CAAE,QAAS,CAAE,UAAW,IAAK,CAAE,CAAC,CACtD,CACF,CAAC,ECzDK,GAA4B,EAAE,OAAO,CACzC,eAAgB,EAAE,KAAK,CAAE,QAAS,sCAAuC,CAAC,EAC1E,SAAU,EAAE,KAAK,CAAE,QAAS,gCAAiC,CAAC,EAC9D,KAAM,EAAE,OAAO,CAAC,CAAC,IAAI,EAAG,wBAAwB,CAClD,CAAC,EASD,eAAsB,aAAa,EAAmD,CACpF,IAAM,EAAY,aAAa,GAA2B,CAAO,EAE3D,EAAc,MAAM,gBAAgB,EAGpC,EAAW,MAAM,MAFF,EAAmB,CAAW,EAAA,CAErB,yBAAyB,CACrD,eAAgB,EAAU,eAC1B,SAAU,EAAU,SACpB,WAAY,EAAU,IACxB,CAAC,EAED,GAAI,CAAC,EAAS,OACZ,MAAM,EAAc,4BAA4B,EAAU,SAAS,GAAG,EAGxE,OAAO,WAAW,EAAS,MAAM,CACnC,CAEA,MAAaC,GAAgB,EAAiB,CAC5C,KAAM,SACN,YAAa,0BACb,KAAM,EAAE,aAAa,CACnB,GAAG,GACH,GAAG,GACH,KAAM,EAAI,EAAE,OAAO,EAAG,CACpB,MAAO,IACP,YAAa,iBACf,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,MAAM,eAAe,EACrB,IAAM,EAAS,MAAM,aAAa,CAChC,eAAgB,EAAK,mBACrB,SAAU,EAAK,aACf,KAAM,EAAK,IACb,CAAC,EAEI,EAAK,MACR,EAAO,QAAQ,WAAW,EAAO,KAAK,wBAAwB,EAGhE,EAAO,IAAI,CAAM,CACnB,CACF,CAAC,EC1DK,GAA+B,EAAE,OAAO,CAC5C,eAAgB,EAAE,KAAK,CAAE,QAAS,sCAAuC,CAAC,CAC5E,CAAC,EASD,eAAsB,gBAAgB,EAA4D,CAChG,IAAM,EAAY,aAAa,GAA8B,CAAO,EAE9D,EAAc,MAAM,gBAAgB,EAGpC,EAAW,MAAM,MAFF,EAAmB,CAAW,EAAA,CAErB,gBAAgB,CAC5C,eAAgB,EAAU,cAC5B,CAAC,EAED,GAAI,CAAC,EAAS,aACZ,MAAM,EAAS,CACb,KAAM,yBACN,QAAS,iBAAiB,EAAU,eAAe,aACrD,CAAC,EAGH,OAAO,iBAAiB,EAAS,YAAY,CAC/C,CAEA,MAAaC,GAAa,EAAiB,CACzC,KAAM,MACN,YAAa,mDACb,KAAM,EAAE,aAAa,CACnB,GAAG,EACL,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAe,MAAM,gBAAgB,CACzC,eAAgB,EAAK,kBACvB,CAAC,EAEK,EAAwB,EAAK,KAC/B,EACA,CACE,GAAG,EACH,UAAW,qBAAqB,EAAa,SAAS,EACtD,UAAW,qBAAqB,EAAa,SAAS,CACxD,EAEJ,EAAO,IAAI,CAAqB,CAClC,CACF,CAAC,EC9CD,eAAsB,kBACpB,EACiC,CACjC,IAAM,EAAQ,GAAS,MACjB,EAAc,MAAM,gBAAgB,EAGpC,CAAE,qBAAsB,MAAM,MAFf,EAAmB,CAAW,EAAA,CAER,sBAAsB,CAAC,CAAC,EAC7D,EAAU,EAAkB,IAAI,oBAAoB,EAK1D,OAHI,IAAU,IAAA,GAGP,EAFE,EAAQ,MAAM,EAAG,CAAK,CAGjC,CAEA,MAAaC,GAAc,EAAiB,CAC1C,KAAM,OACN,YAAa,oCACb,KAAM,EAAE,aAAa,CACnB,MAAO,EAAI,GAAe,SAAS,EAAG,CACpC,MAAO,IACP,YAAa,yCACf,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAgB,MAAM,kBAAkB,CAAE,MAAO,EAAK,KAAM,CAAC,EACnE,EAAO,IAAI,CAAa,CAC1B,CACF,CAAC,ECdD,eAAe,kBACb,EACA,EACA,EACA,EACA,EACqB,CACrB,GAAI,IAAa,IAAA,IAAa,GAAgB,EAC5C,MAAO,CAAC,EAGV,IAAM,EAAU,MAAM,GAAS,MAAO,EAAW,IAAgB,CAC/D,IAAM,EAAW,MAAM,EAAO,wBAAwB,CACpD,iBACA,iBACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAS,QAAS,EAAS,aAAa,CAClD,CAAC,EAEK,EAAoB,CAAC,EAC3B,IAAK,IAAM,KAAU,EAAS,CAC5B,IAAM,EAAW,EAAO,YACpB,MAAM,kBAAkB,EAAQ,EAAgB,EAAO,GAAI,EAAe,EAAG,CAAQ,EACrF,CAAC,EACL,EAAM,KAAK,CAAE,KAAM,EAAO,KAAM,UAAS,CAAC,CAC5C,CACA,OAAO,CACT,CAEA,eAAe,oBACb,EACA,EACA,EACA,EACA,EAC2B,CAC3B,GAAI,IAAa,IAAA,IAAa,GAAgB,EAC5C,MAAO,CAAC,EAGV,IAAM,EAAU,MAAM,GAAS,MAAO,EAAW,IAAgB,CAC/D,IAAM,EAAW,MAAM,EAAO,wBAAwB,CACpD,iBACA,iBACA,YACA,SAAU,CACZ,CAAC,EACD,MAAO,CAAC,EAAS,QAAS,EAAS,aAAa,CAClD,CAAC,EAEK,EAA2B,CAAC,EAClC,IAAK,IAAM,KAAU,EAAS,CAC5B,IAAM,EAAW,EAAO,YACpB,MAAM,oBAAoB,EAAQ,EAAgB,EAAO,GAAI,EAAe,EAAG,CAAQ,EACvF,CAAC,EACL,EAAO,KAAK,CAAE,GAAI,EAAO,GAAI,KAAM,EAAO,KAAM,UAAS,CAAC,CAC5D,CACA,OAAO,CACT,CAEA,SAAS,WAAW,EAAmB,EAAwB,CAC7D,IAAI,EAAS,GACb,IAAK,GAAM,CAAC,EAAG,KAAS,EAAM,QAAQ,EAAG,CACvC,IAAM,EAAS,IAAM,EAAM,OAAS,EAC9B,EAAY,EAAS,OAAwB,OAC7C,EAAc,EAAS,OAAS,OACtC,GAAU,GAAG,IAAS,IAAY,EAAK,KAAK,IACxC,EAAK,SAAS,OAAS,IACzB,GAAU,WAAW,EAAK,SAAU,EAAS,CAAW,EAE5D,CACA,OAAO,CACT,CAEA,eAAe,aACb,EACA,EACA,EACiB,CACjB,IAAM,EAAW,MAAM,kBAAkB,EAAQ,EAAI,eAAgB,EAAI,aAAc,EAAG,CAAK,EAC3F,EAAS,GAAG,EAAI,iBAAiB,IAErC,MADA,IAAU,WAAW,EAAU,EAAE,EAC1B,CACT,CAOA,eAAsB,iBACpB,EACiC,CACjC,IAAM,EAAc,MAAM,gBAAgB,EACpC,EAAS,MAAM,EAAmB,CAAW,EAE/C,EACJ,GAAI,GAAS,eAEX,IADA,GAAQ,MAAM,kBAAkB,EAAA,CAAG,OAAQ,GAAM,EAAE,iBAAmB,EAAQ,cAAc,EACxF,EAAK,SAAW,EAClB,MAAM,EAAS,CACb,KAAM,yBACN,QAAS,iBAAiB,EAAQ,eAAe,aACnD,CAAC,CAAA,KAGH,GAAO,MAAM,kBAAkB,EAGjC,IAAM,EAAQ,GAAS,MAEjB,EAAqC,CAAC,EAC5C,IAAK,IAAM,KAAO,EAAM,CACtB,IAAM,EAAU,MAAM,oBACpB,EACA,EAAI,eACJ,EAAI,aACJ,EACA,CACF,EACA,EAAW,KAAK,CACd,eAAgB,EAAI,eACpB,iBAAkB,EAAI,iBACtB,SACF,CAAC,CACH,CAEA,OAAO,CACT,CAEA,MAAa,GAAc,EAAiB,CAC1C,KAAM,OACN,YAAa,mDACb,KAAM,EAAE,aAAa,CACnB,kBAAmB,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CAC5C,MAAO,IACP,YAAa,wCACb,IAAK,iCACP,CAAC,EACD,MAAO,EAAI,GAAe,SAAS,EAAG,CACpC,MAAO,IACP,YAAa,iCACf,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAc,MAAM,gBAAgB,EACpC,EAAS,MAAM,EAAmB,CAAW,EAE/C,EACJ,GAAI,EAAK,mBAIP,IAHA,GAAQ,MAAM,kBAAkB,EAAA,CAAG,OAChC,GAAM,EAAE,iBAAmB,EAAK,kBACnC,EACI,EAAK,SAAW,EAClB,MAAM,EAAS,CACb,KAAM,yBACN,QAAS,iBAAiB,EAAK,mBAAmB,aACpD,CAAC,CAAA,KAGH,GAAO,MAAM,kBAAkB,EAGjC,GAAI,EAAK,KAAM,CACb,IAAM,EAAqC,CAAC,EAC5C,IAAK,IAAM,KAAO,EAAM,CACtB,IAAM,EAAU,MAAM,oBACpB,EACA,EAAI,eACJ,EAAI,aACJ,EACA,EAAK,KACP,EACA,EAAW,KAAK,CACd,eAAgB,EAAI,eACpB,iBAAkB,EAAI,iBACtB,SACF,CAAC,CACH,CACA,EAAO,IAAI,CAAU,EACrB,MACF,CAEA,IAAM,EAAkB,CAAC,EACzB,IAAK,IAAM,KAAO,EAChB,EAAM,KAAK,MAAM,aAAa,EAAQ,EAAK,EAAK,KAAK,CAAC,EAGxD,EAAO,IAAI,EAAM,KAAK;CAAI,CAAC,CAC7B,CACF,CAAC,ECpNK,GAAkC,EAAE,OAAO,CAC/C,eAAgB,EAAE,KAAK,CAAE,QAAS,sCAAuC,CAAC,EAC1E,KAAM,EAAE,OAAO,CAAC,CAAC,IAAI,EAAG,wBAAwB,CAClD,CAAC,EASD,eAAsB,mBACpB,EAC2B,CAC3B,IAAM,EAAY,aAAa,GAAiC,CAAO,EAEjE,EAAc,MAAM,gBAAgB,EAGpC,EAAW,MAAM,MAFF,EAAmB,CAAW,EAAA,CAErB,mBAAmB,CAC/C,eAAgB,EAAU,eAC1B,iBAAkB,EAAU,IAC9B,CAAC,EAED,GAAI,CAAC,EAAS,aACZ,MAAM,EAAc,kCAAkC,EAAU,eAAe,GAAG,EAGpF,OAAO,iBAAiB,EAAS,YAAY,CAC/C,CAEA,MAAaC,GAAgB,EAAiB,CAC5C,KAAM,SACN,YAAa,iCACb,KAAM,EAAE,aAAa,CACnB,GAAG,GACH,KAAM,EAAI,EAAE,OAAO,EAAG,CACpB,MAAO,IACP,YAAa,uBACf,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,MAAM,eAAe,EACrB,IAAM,EAAe,MAAM,mBAAmB,CAC5C,eAAgB,EAAK,mBACrB,KAAM,EAAK,IACb,CAAC,EAEI,EAAK,MACR,EAAO,QAAQ,iBAAiB,EAAa,KAAK,wBAAwB,EAG5E,EAAO,IAAI,CAAY,CACzB,CACF,CAAC,ECzBD,eAAe,sBAAsB,EAA6C,CAChF,IAAM,EAAO,cAAc,EAAO,IAAI,EACtC,GAAI,IAAS,KAEX,OADA,iBAAiB,EAAO,EAAE,EACnB,EAET,IAAM,EAAO,MAAM,oBAAoB,CACrC,OACA,KAAM,OACN,QAAS,CAAC,CAAE,WAAY,EAAO,KAAM,SAAU,EAAO,EAAG,CAAC,CAC5D,CAAC,EACD,MAAO,CAAE,GAAG,EAAQ,GAAI,EAAK,QAAQ,EAAE,EAAE,EAAG,CAC9C,CAEA,eAAeC,eAAY,EAAyB,CAClD,GAAM,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,GAAS,QAClB,YAAa,GAAS,WACxB,CAAC,EACK,CAAE,OAAQ,GAAiB,MAAM,WAAW,GAAS,UAAU,EAC/D,EAAS,MAAM,sBAAsB,CAAY,EAEvD,MAAO,CACL,SACA,cACA,YAJkB,GAAkB,CAAE,QAAO,CAInC,EACV,QACF,CACF,CAEA,eAAe,WACb,EACA,EACA,EACA,EACA,EACA,CAEA,IAAM,EAAmB,CACvB,SACA,cACA,cACA,WAAY,GACZ,QACF,EAGM,EAAQ,CACZ,SAAU,MAAM,aAAa,CAAG,EAChC,cAAe,MAAM,kBAAkB,CAAG,EAC1C,UAAW,MAAM,cAAc,CAAG,EAClC,IAAK,MAAM,QAAQ,CAAG,EACtB,KAAM,MAAM,SAAS,CAAG,EACxB,SAAU,MAAM,aAAa,CAAG,EAChC,IAAK,MAAM,gBAAgB,CAAG,EAC9B,SAAU,MAAM,aAAa,CAAG,EAChC,SAAU,MAAM,aAAa,EAAQ,EAAa,EAAY,KAAM,EAAY,GAAI,CAAC,EAAG,CAAC,CAAC,EAC1F,wBAAyB,MAAM,uCAC7B,EACA,EACA,EAAY,KACZ,EAAY,GACZ,CAAC,CACH,EACA,iBAAkB,MAAM,qBACtB,EACA,EACA,EAAY,KACZ,EAAY,GACZ,CAAC,CACH,EACA,cAAe,MAAM,kBAAkB,CAAG,CAC5C,EAKM,EAAa,OAAO,OAAO,CAAK,CAAC,CAAC,KACrC,GAAS,mBAAoB,GAAQ,EAAK,eAAe,IAAI,EAAY,IAAI,CAChF,EAGM,EAAc,CAClB,GAAG,EAAM,iBAAiB,UAAU,MAAM,EAC1C,GAAG,EAAM,cAAc,UAAU,MAAM,EACvC,GAAG,EAAM,UAAU,UAAU,MAAM,EACnC,GAAG,EAAM,IAAI,MAAM,EACnB,GAAG,EAAM,SAAS,UAAU,QAAQ,MAAM,EAC1C,GAAG,EAAM,SAAS,UAAU,KAAK,MAAM,EACvC,GAAG,EAAM,SAAS,UAAU,cAAc,MAAM,EAChD,GAAG,EAAM,SAAS,UAAU,QAAQ,MAAM,EAC1C,GAAG,EAAM,SAAS,UAAU,SAAS,MAAM,EAC3C,GAAG,EAAM,SAAS,UAAU,MAAM,EAClC,GAAG,EAAM,SAAS,UAAU,MAAM,EAClC,GAAG,EAAM,wBAAwB,UAAU,MAAM,EACjD,GAAG,EAAM,IAAI,UAAU,QAAQ,MAAM,EACrC,GAAG,EAAM,IAAI,UAAU,OAAO,MAAM,EACpC,GAAG,EAAM,KAAK,UAAU,QAAQ,MAAM,EACtC,GAAG,EAAM,KAAK,UAAU,UAAU,MAAM,EACxC,GAAG,EAAM,KAAK,UAAU,kBAAkB,MAAM,EAChD,GAAG,EAAM,KAAK,UAAU,aAAa,MAAM,EAC3C,GAAG,EAAM,KAAK,UAAU,YAAY,MAAM,EAC1C,GAAG,EAAM,KAAK,UAAU,aAAa,MAAM,EAC3C,GAAG,EAAM,KAAK,UAAU,SAAS,MAAM,EACvC,GAAG,EAAM,KAAK,UAAU,KAAK,MAAM,EACnC,GAAG,EAAM,KAAK,UAAU,aAAa,MAAM,EAC3C,GAAG,EAAM,KAAK,UAAU,WAAW,MAAM,EACzC,GAAG,EAAM,cAAc,eAAe,MAAM,EAC5C,GAAG,EAAM,cAAc,gBAAgB,MAAM,CAC/C,EA4CA,OA3CI,EAAY,OAAS,GAAG,EAAO,IAAI,EAAY,KAAK;CAAI,CAAC,EAG3D,EAAM,SAAS,UAAU,QAAQ,QAAQ,SAAW,GACpD,EAAM,cAAc,UAAU,QAAQ,SAAW,GACjD,EAAM,UAAU,UAAU,QAAQ,SAAW,GAC7C,EAAM,IAAI,UAAU,QAAQ,QAAQ,SAAW,GAC/C,EAAM,KAAK,UAAU,QAAQ,QAAQ,SAAW,GAChD,EAAM,SAAS,UAAU,QAAQ,QAAQ,SAAW,GACpD,EAAM,IAAI,QAAQ,SAAW,GAC7B,EAAM,SAAS,UAAU,QAAQ,SAAW,GAC5C,EAAM,SAAS,UAAU,QAAQ,SAAW,GAC5C,EAAM,wBAAwB,UAAU,QAAQ,SAAW,GAC3D,EAAM,iBAAiB,UAAU,QAAQ,SAAW,GACpD,EAAM,cAAc,eAAe,QAAQ,SAAW,GACtD,EAAM,cAAc,gBAAgB,QAAQ,SAAW,EAEhD,CAAE,YAAW,GAIlB,GACF,MAAM,EAAQ,EAIhB,MAAM,cAAc,EAAQ,EAAM,SAAU,QAAQ,EACpD,MAAM,wCAAwC,EAAQ,EAAM,wBAAyB,QAAQ,EAC7F,MAAM,cAAc,EAAQ,EAAM,SAAU,QAAQ,EACpD,MAAM,mBAAmB,EAAQ,EAAM,cAAe,QAAQ,EAC9D,MAAM,eAAe,EAAQ,EAAM,UAAW,QAAQ,EACtD,MAAM,iBAAiB,EAAQ,EAAM,IAAK,QAAQ,EAClD,MAAM,cAAc,EAAQ,EAAM,SAAU,kBAAkB,EAC9D,MAAM,cAAc,EAAQ,EAAM,SAAU,iBAAiB,EAC7D,MAAM,UAAU,EAAQ,EAAM,KAAM,kBAAkB,EACtD,MAAM,UAAU,EAAQ,EAAM,KAAM,iBAAiB,EACrD,MAAM,SAAS,EAAQ,EAAM,IAAK,kBAAkB,EACpD,MAAM,SAAS,EAAQ,EAAM,IAAK,iBAAiB,EACnD,MAAM,cAAc,EAAQ,EAAM,SAAU,kBAAkB,EAC9D,MAAM,cAAc,EAAQ,EAAM,SAAU,iBAAiB,EAC7D,MAAM,sBAAsB,EAAQ,EAAa,EAAM,iBAAkB,QAAQ,EACjF,MAAM,mBAAmB,EAAQ,EAAM,cAAe,QAAQ,EAEvD,CAAE,YAAW,EACtB,CAOA,eAAsB,OAAO,EAAwC,CACnE,GAAM,CAAE,SAAQ,cAAa,cAAa,UAAW,MAAMA,eAAY,CAAO,EAC9E,MAAM,WAAW,EAAQ,EAAa,EAAa,CAAM,CAC3D,CAEA,MAAaC,GAAgB,EAAiB,CAC5C,KAAM,SACN,YAAa,sEACb,KAAM,EAAE,aAAa,CACnB,GAAG,GACH,GAAG,EACL,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,MAAM,eAAe,CAAE,QAAS,EAAK,OAAQ,CAAC,EAC9C,GAAM,CAAE,SAAQ,cAAa,cAAa,UAAW,MAAMD,eAAY,CACrE,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,WAAY,EAAK,MACnB,CAAC,EAED,EAAO,KAAK,6CAA6C,EAAY,KAAK,KAAK,EAC/E,EAAO,QAAQ,EAEf,GAAM,CAAE,cAAe,MAAM,WAAW,EAAQ,EAAa,EAAa,EAAQ,SAAY,CAC5F,GAAK,EAAK,IAeR,EAAO,QAAQ,kDAAkD,OAV7D,GAAA,CAAC,MAJmB,EAAO,QAAQ,CACrC,QAAS,iDACT,QAAS,EACX,CAAC,EAEC,MAAM,EAAS,CACb,KAAM,mBACN,QAAS,CAAE;;;OAIb,CAAC,CAKP,CAAC,EAED,GAAI,EAAY,CACd,EAAO,KAAK,CAAE;iCACa,EAAY,KAAK;;OAE3C,EACD,MACF,CACA,EAAO,QAAQ,kDAAkD,EAAY,KAAK,GAAG,CACvF,CACF,CAAC,ECjND,SAAS,gBAAgB,EAAmC,CAC1D,MAAO,CACL,KAAM,EAAI,KACV,OAAQ,EAAI,OACZ,IAAK,EAAI,IACT,KAAM,EAAI,cACV,KAAM,EAAI,KACV,mBAAoB,EAAI,mBACxB,qBAAsB,EAAI,qBAC1B,UAAW,EAAI,WAAa,EAAc,EAAI,UAAU,EAAI,KAC5D,UAAW,EAAI,WAAa,EAAc,EAAI,UAAU,EAAI,IAC9D,CACF,CAEA,eAAe,gBACb,EACA,EACA,EAC0B,CAc1B,OAAO,MAbgB,QAAQ,IAC7B,EAAM,IAAI,KAAO,IAAS,CACxB,GAAI,CACF,GAAM,CAAE,aAAc,MAAM,EAAO,aAAa,CAAE,cAAa,cAAe,CAAK,CAAC,EACpF,OAAO,EAAY,CAAE,KAAM,EAAU,KAAM,IAAK,EAAU,GAAI,EAAI,IAAA,EACpE,OAAS,EAAO,CACd,GAAI,aAAiB,GAAgB,EAAM,OAAS,EAAK,SACvD,OAEF,MAAM,CACR,CACF,CAAC,CACH,EAAA,CACgB,OAAQ,GAAsC,IAAY,IAAA,EAAS,CACrF,CAOA,eAAsB,KAAK,EAA0C,CAEnE,GAAM,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,GAAS,QAClB,YAAa,GAAS,WACxB,CAAC,EAEK,CAAE,UAAW,MAAM,WAAW,GAAS,UAAU,EACjD,EAAiB,EAAO,YAAY,OACtC,CAAC,GAAG,IAAI,IAAI,EAAO,WAAW,IAAK,GAAY,EAAQ,IAAI,CAAC,CAAC,EAC7D,CAAC,EACC,CAAC,EAAe,EAAM,GAAc,MAAM,QAAQ,IAAI,CAC1D,EAAO,aAAa,CAClB,aACF,CAAC,EACD,EAAO,eAAe,CACpB,cACA,gBAAiB,EAAO,IAC1B,CAAC,EACD,gBAAgB,EAAQ,EAAa,CAAc,CACrD,CAAC,EACK,CAAE,OAAM,GAAG,GAAY,gBAC3B,EAAc,EAAK,YAAa,gBAAgB,EAAO,KAAK,yBAAyB,CACvF,EACM,EAAY,EAAc,UAC1B,EAAsB,EAAY,MAAM,2BAA2B,EAAQ,CAAS,EAAI,GAE9F,MAAO,CACL,OACA,cACA,cAAe,GAAW,MAAQ,GAClC,GAAI,EAAsB,CAAE,qBAAoB,EAAI,CAAC,EACrD,gBAAiB,GAAW,QAAU,GACtC,GAAG,EACH,YACF,CACF,CAEA,MAAM,GAA+B,+BACnC,gBACA,qBACF,EAEa,GAAc,EAAiB,CAC1C,KAAM,OACN,YAAa,mDACb,KAAM,EAAE,aAAa,CACnB,GAAG,EACL,CAAC,EACD,IAAK,KAAO,IAAS,CAEnB,IAAM,EAAU,MAAM,KAAK,CACzB,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,WAAY,EAAK,MACnB,CAAC,EAED,EAAO,IAAI,EAAS,CAClB,QAAS,CAAE,cAAe,GAA8B,oBAAqB,IAAK,CACpF,CAAC,CACH,CACF,CAAC,EC5ID,SAAgB,eAAe,EAAe,EAAe,CAC3D,IAAI,EAAU,EAYd,MAAO,CAAE,WAVY,CACnB,GAAW,EACX,IAAM,EAAU,KAAK,MAAO,EAAU,EAAS,GAAG,EAClD,QAAQ,OAAO,MAAM,KAAK,EAAM,GAAG,EAAQ,GAAG,EAAM,IAAI,EAAQ,GAAG,CACrE,EAMiB,WAJI,CACnB,QAAQ,OAAO,MAAM;CAAI,CAC3B,CAEwB,CAC1B,CAUA,eAAsB,YAAe,EAAe,EAAY,EAA6B,CAC3F,IAAM,EAAoB,IAAI,gBAC9B,GAAI,CACF,OAAO,MAAM,QAAQ,KAAK,CACxB,EACAE,GAAW,EAAI,IAAA,GAAW,CAAE,OAAQ,EAAkB,MAAO,CAAC,CAAC,CAAC,SAAW,CACzE,MAAU,MAAM,CAAO,CACzB,CAAC,CACH,CAAC,CACH,QAAU,CACR,EAAkB,MAAM,CAC1B,CACF,CC1BA,MACM,GAAgB,IAAI,IAAI,CAAC,YAAa,YAAa,aAAa,CAAC,EACvE,SAAS,iBAAiB,EAAkB,CAC1C,IAAM,EAAW,EAAK,SAAS,CAAQ,CAAC,CAAC,YAAY,EACrD,OAAO,GAAc,IAAI,CAAQ,CACnC,CAgBA,eAAsB,oBACpB,EACA,EACA,EACA,EACA,EAAwB,GACD,CACvB,GAAM,CAAE,gBAAiB,MAAM,EAAO,iBAAiB,CACrD,cACA,MACF,CAAC,EAED,GAAI,CAAC,EACH,MAAM,EAAc,8CAA8C,EAGpE,IAAM,EAAe,MAAM,gBACzB,EACA,EACA,EACA,EACA,CACF,EAEM,CAAE,OAAQ,MAAM,EAAO,kBAAkB,CAC7C,cACA,cACF,CAAC,EAED,GAAI,CAAC,EACH,MAAM,EAAc,sCAAsC,EAG5D,MAAO,CAAE,MAAK,cAAa,CAC7B,CAEA,eAAe,gBACb,EACA,EACA,EACA,EACA,EACmB,CACnB,IAAM,EAAQ,MAAM,aAAa,CAAO,EACxC,GAAI,EAAM,SAAW,EAEnB,OADA,EAAO,KAAK,wBAAwB,GAAS,EACtC,CAAC,EAIV,IAAM,EAAQ,GAAO,CAAW,EAE1B,EAAQ,EAAM,OACd,EAAW,EAAe,eAAe,kBAAmB,CAAK,EAAI,IAAA,GACrE,EAAyB,CAAC,EAwBhC,OAtBA,MAAM,QAAQ,IACZ,EAAM,IAAK,GACT,EAAM,SAAY,CAChB,MAAM,iBACJ,EACA,EACA,EACA,EACA,EACA,CACF,EACI,GACF,EAAS,OAAO,CAEpB,CAAC,CACH,CACF,EAEI,GACF,EAAS,OAAO,EAGX,CACT,CAQA,eAAe,aAAa,EAAiB,EAAa,GAAuB,CAC/E,IAAM,EAAU,EAAK,KAAK,EAAS,CAAU,EAEvC,EAAU,MAAMC,GAAG,SAAS,QAAQ,EAAS,CACjD,cAAe,EACjB,CAAC,EACK,EAAkB,CAAC,EAEzB,IAAK,IAAM,KAAS,EAAS,CAC3B,IAAM,EAAM,EAAK,KAAK,EAAY,EAAM,IAAI,EAC5C,GAAI,EAAM,YAAY,EAAG,CACvB,IAAM,EAAM,MAAM,aAAa,EAAS,CAAG,EAC3C,EAAM,KAAK,GAAG,CAAG,CACnB,MAAW,EAAM,OAAO,GAAK,CAAC,EAAM,eAAe,GAAK,CAAC,iBAAiB,CAAG,GAC3E,EAAM,KAAK,CAAG,CAElB,CAEA,OAAO,CACT,CAEA,eAAe,iBACb,EACA,EACA,EACA,EACA,EACA,EACe,CACf,IAAM,EAAU,EAAK,KAAK,EAAS,CAAQ,EAErC,EAAOC,GAAW,CAAQ,EAEhC,GAAI,CAAC,EAAM,CACT,EAAa,KAAK,GAAG,EAAS,mDAAmD,EACjF,MACF,CAEA,IAAM,EAAc,EAEd,EAAaD,GAAG,iBAAiB,EAAS,CAC9C,cAAe,KACjB,CAAC,EAED,eAAgB,eAAiF,CAC/F,KAAM,CACJ,QAAS,CACP,KAAM,kBACN,MAAO,CACL,cACA,eACA,WACA,aACF,CACF,CACF,EACA,UAAW,IAAM,KAAS,EACxB,KAAM,CACJ,QAAS,CACP,KAAM,YACN,MAAO,CACT,CACF,CAEJ,CAEA,eAAe,mBAAoB,CACjC,GAAI,CACF,MAAM,EAAO,WAAW,cAAc,CAAC,CACzC,OAAS,EAAO,CACd,GAAI,aAAiB,GAAgB,EAAM,OAAS,EAAK,gBAAiB,CACxE,EAAa,KAAK,GAAG,EAAS,qCAAqC,EAAM,QAAQ,EAAE,EACnF,MACF,CAEA,MAAM,CACR,CACF,CAEA,MAAM,YACJ,kBAAkB,EAElB,KACA,yBAAyB,EAAS,EACpC,CACF,CAMA,SAAS,gBAAgB,EAAwB,CAC3C,KAAa,SAAW,EAG5B,GAAO,KACL,iKACF,EACA,IAAK,IAAM,KAAQ,EACjB,EAAO,IAAI,OAAO,GAAM,CAF1B,CAIF,CAEA,MAAa,GAAgB,EAAiB,CAC5C,KAAM,SACN,YAAa,wDACb,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,KAAM,EAAI,EAAE,OAAO,EAAG,CACpB,MAAO,IACP,YAAa,qBACf,CAAC,EACD,IAAK,EAAI,EAAE,OAAO,EAAG,CACnB,MAAO,IACP,YAAa,mCACb,WAAY,CAAE,KAAM,WAAY,CAClC,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,MAAM,eAAe,CAAE,QAAS,EAAK,OAAQ,CAAC,EAC9C,EAAO,KAAK,6BAA6B,EAAK,KAAK,oBAAoB,EAAK,KAAK,EACjF,IAAM,EAAc,MAAM,gBAAgB,CACxC,QAAS,EAAK,OAChB,CAAC,EACK,EAAS,MAAM,EAAmB,CAAW,EAE7C,EAAO,EAAK,KACZ,EAAM,EAAK,QAAQ,QAAQ,IAAI,EAAG,EAAK,GAAG,EAC1C,EAAc,MAAM,gBAAgB,CACxC,YAAa,EAAK,gBAClB,QAAS,EAAK,OAChB,CAAC,EAED,GAAI,CAACA,GAAG,WAAW,CAAG,GAAK,CAACA,GAAG,SAAS,CAAG,CAAC,CAAC,YAAY,EACvD,MAAM,EAAS,CACb,KAAM,sBACN,QAAS,2CAA2C,GACtD,CAAC,EAGH,GAAM,CAAE,MAAK,gBAAiB,MAAM,YAClC,oBAAoB,EAAQ,EAAa,EAAM,EAAK,CAAC,EAAK,IAAI,EAE9D,IACA,wCACF,EAEI,EAAK,KACP,EAAO,IAAI,CAAE,OAAM,cAAa,MAAK,cAAa,CAAC,GAEnD,EAAO,QAAQ,mBAAmB,EAAK,gCAAgC,GAAK,EAC5E,gBAAgB,CAAY,EAEhC,CACF,CAAC,EClRD,SAAgB,eAAe,EAA2B,CACxD,EAAO,KACL,QAAQ,EAAY,mFACtB,EACA,EAAO,QAAQ,CACjB,CCPA,SAAS,uBAAuB,EAAgD,CAC9E,IAAM,EAAa,GAAQ,KAAK,EAChC,OAAO,GAAc,EAAW,OAAS,EAAI,EAAa,IAAA,EAC5D,CAMA,SAAgB,4BAAiD,CAC/D,OAAO,uBAAuB,QAAQ,IAAI,MAAM,GAAK,uBAAuB,QAAQ,IAAI,MAAM,CAChG,CAMA,SAAgB,kBAA2B,CACzC,OAAO,2BAA2B,GAAK,QACzC,CAEA,SAAS,mBAAmB,EAG1B,CACA,GAAM,CAAC,EAAS,GAAG,GAAQ,EAAO,KAAK,CAAC,CAAC,MAAM,KAAK,EAEpD,GAAI,CAAC,EACH,MAAU,MAAM,0BAA0B,EAG5C,MAAO,CACL,UACA,MACF,CACF,CAQA,eAAsB,aACpB,EACA,EAAS,iBAAiB,EACR,CAClB,GAAM,CAAE,UAAS,QAAS,mBAAmB,CAAM,EAkBnD,OAhBA,MAAM,IAAI,SAAe,EAAS,IAAW,CAC3C,IAAM,EAAQ,GAAM,EAAS,CAAC,GAAG,EAAM,CAAQ,EAAG,CAChD,MAAO,UACP,SAAU,EACZ,CAAC,EAED,EAAM,KAAK,QAAU,GAAU,EAAO,CAAK,CAAC,EAC5C,EAAM,KAAK,QAAU,GAAS,CAC5B,GAAI,GAAQ,MAAQ,IAAS,EAAG,CAC9B,EAAQ,EACR,MACF,CACA,EAAW,MAAM,2BAA2B,EAAK,EAAE,CAAC,CACtD,CAAC,CACH,CAAC,EAEM,EACT,CAOA,eAAsB,uBAAuB,EAAoC,CAC/E,IAAM,EAAS,2BAA2B,EAK1C,OAJK,EAIE,MAAM,aAAa,EAAU,CAAM,EAHjC,EAIX,CCpCA,SAAgB,SAAS,EAAmB,EAA2B,CACrE,MAAO,GAAG,EAAU,GAAG,GACzB,CAYA,SAAgB,mBAAmB,EAAmB,EAAoC,CACxF,IAAM,EAAO,GAAG,WAChB,IAAK,IAAI,EAAU,EAAG,GAAW,EAAM,KAAO,EAAG,IAAW,CAC1D,IAAM,EAAY,IAAY,EAAI,EAAO,GAAG,IAAO,IACnD,GAAI,EAAU,OAAS,GAAuB,MAC9C,GAAI,CAAC,EAAM,IAAI,CAAS,EAAG,OAAO,CACpC,CACA,MAAM,EAAS,CACb,KAAM,6CACN,QAAS,6CAA6C,EAAU,sDAClE,CAAC,CACH,CAwBA,SAAgB,0BACd,EACyC,CACzC,OACE,EAAO,OAAS,uBACf,EAAO,OAAS,kBAAoB,oBAAoB,EAAO,OAAQ,EAAO,KAAK,CAExF,CAUA,SAAgB,gBAAgB,EAA0C,CACxE,OAAO,6BAA6B,CAAO,CAAC,CAAC,QAC/C,CAUA,SAAgB,6BACd,EAC2B,CAC3B,GAAM,CAAE,WAAU,UAAS,YAAW,aAAc,EAC9C,EAAS,EAAS,OAAO,EAAU,EAAE,OAAO,GAC5C,EAAQ,EAAQ,OAAO,EAAU,EAAE,OAAO,GAChD,GAAI,CAAC,GAAU,CAAC,EACd,MAAO,CAAE,SAAU,GAAO,OAAQ,0CAA2C,EAE/E,IAAM,EAAmB,wCAAwC,EAAQ,CAAK,EAQ9E,OAPK,EAAiB,SAEpB,kBAAkB,EAAS,OAAO,GAAY,CAAS,GACvD,kBAAkB,EAAQ,OAAO,GAAY,CAAS,EAE/C,CAAE,SAAU,GAAO,OAAQ,6CAA8C,EAE3E,CAAE,SAAU,EAAK,EAPe,CAQzC,CAeA,SAAS,gBAAgB,EAAkD,CAEzE,OADK,EACE,CACL,GAAG,OAAO,KAAK,EAAK,MAAM,EAC1B,GAAG,OAAO,KAAK,EAAK,OAAS,CAAC,CAAC,EAC/B,GAAG,OAAO,KAAK,EAAK,sBAAwB,CAAC,CAAC,EAC9C,GAAG,OAAO,KAAK,EAAK,uBAAyB,CAAC,CAAC,CACjD,EANkB,CAAC,CAOrB,CAEA,SAAS,mBAAmB,EAAkB,EAAuC,CACnF,GAAI,CAAC,GAAY,EAAI,OAAS,aAAc,OAAO,EAAI,KACvD,GAAI,EAAI,OAAS,WAAa,OAAO,EAAI,OAAU,SAAU,OAAO,EAAI,MACxE,GAAI,EAAI,OAAS,mBAAqB,EAAI,YAAY,SAAW,EAC/D,OAAO,EAAI,OAAO,EAAE,EAAE,MAAM,QAAU,IAAA,EAG1C,CAEA,MAAM,GAA2B,IAAI,IAAI,CAAC,QAAS,YAAa,YAAa,UAAW,KAAK,CAAC,EAE9F,SAAS,cACP,EACA,EACA,EAA6B,CAAC,EACxB,CACN,GAAI,CAAC,EAAM,OACX,EAAM,EAAM,CAAS,EACrB,IAAM,EAAkB,CAAC,GAAG,EAAW,CAAI,EACrC,EAAS,EACf,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAM,EAC1C,OAAQ,QAAU,IAAQ,SAC9B,IAAI,MAAM,QAAQ,CAAK,EAChB,IAAA,IAAM,KAAQ,EACb,GAAQ,OAAO,GAAS,UAAY,SAAU,GAChD,cAAc,EAAc,EAAO,CAAe,OAG7C,GAAS,OAAO,GAAU,UAAY,SAAU,GACzD,cAAc,EAAe,EAAO,CAAe,CAAA,CAGzD,CAEA,SAAS,eAAe,EAAkB,CACxC,OAAO,EAAK,OAAS,0BAA4B,eAAe,EAAK,UAAU,EAAI,CACrF,CAEA,SAAS,qBAAqB,EAA4B,CACxD,IAAM,EAAgB,IAAI,IAAI,CAAC,UAAU,CAAC,EAC1C,cAAc,EAAU,GAAS,CAC/B,GAAI,EAAK,OAAS,iBAAkB,OACpC,IAAM,EAAS,eAAe,EAAK,MAAM,EACzC,GACG,EAAO,OAAS,2BAA6B,EAAO,OAAS,sBAC9D,EAAK,UAAU,EAAE,EAAE,OAAS,cAC5B,EAAK,UAAU,EAAE,CAAC,OAAS,WAE3B,OAEF,IAAM,EAAiB,EAAO,OAAO,GACjC,GAAgB,OAAS,cAAc,EAAc,IAAI,EAAe,IAAI,CAClF,CAAC,EAED,IAAI,EACJ,EAAG,CACD,IAAM,EAAe,EAAc,KACnC,cAAc,EAAU,GAAS,CAE7B,EAAK,OAAS,sBACd,EAAK,GAAG,OAAS,cACjB,EAAK,MAAM,OAAS,cACpB,EAAc,IAAI,EAAK,KAAK,IAAI,GAEhC,EAAc,IAAI,EAAK,GAAG,IAAI,CAElC,CAAC,EACD,EAAe,EAAc,KAAO,CACtC,OAAS,GACT,OAAO,CACT,CAEA,SAAS,0BAA0B,EAAY,EAAqC,CAClF,GAAI,EAAK,OAAS,WAAY,MAAO,GACrC,IAAM,EAAe,mBAAmB,EAAK,IAAK,EAAK,QAAQ,EAC/D,GAAI,CAAC,GAAgB,CAAC,GAAyB,IAAI,CAAY,EAAG,MAAO,GACzE,IAAM,EAAS,EAAU,GAAG,EAAE,EACxB,EAAO,EAAU,GAAG,EAAE,EAE5B,OADI,GAAQ,OAAS,oBAAsB,GAAM,OAAS,iBAAyB,GAEjF,EAAK,UAAU,KAAO,GACtB,CAAC,0BAA2B,oBAAoB,CAAC,CAAC,SAAS,eAAe,EAAK,MAAM,CAAC,CAAC,IAAI,CAE/F,CAEA,SAAS,2BAA2B,EAAY,EAAqC,CACnF,GAAI,EAAK,OAAS,WAAY,MAAO,GACrC,IAAM,EAAe,mBAAmB,EAAK,IAAK,EAAK,QAAQ,EAC/D,GAAI,CAAC,GAAgB,CAAC,GAAyB,IAAI,CAAY,EAAG,MAAO,GACzE,IAAM,EAAU,EAAU,GAAG,EAAE,EAC/B,GAAI,GAAS,OAAS,gBAAiB,MAAO,GAE9C,IAAK,IAAI,EAAQ,EAAU,OAAS,EAAG,GAAS,EAAG,IAAS,CAC1D,IAAM,EAAY,EAAU,GAC5B,GACE,IACC,EAAU,OAAS,2BAA6B,EAAU,OAAS,uBACpE,EAAU,OAAO,KAAO,EAExB,OAAO,EACJ,MAAM,EAAG,CAAK,CAAC,CACf,KACE,GACC,EAAS,OAAS,kBAClB,eAAe,EAAS,MAAM,IAAM,GACpC,EAAS,UAAU,EAAE,EAAE,OAAS,oBAChC,EAAS,UAAU,EAAE,CAAC,WAAW,KAC9B,GACC,EAAS,OAAS,YAClB,mBAAmB,EAAS,IAAK,EAAS,QAAQ,IAAM,CAC5D,CACJ,CAEN,CACA,MAAO,EACT,CAEA,SAAS,eACP,EACA,EACA,EACS,CACT,IAAM,EAAO,EAAU,GAAG,EAAE,EAC5B,OACE,GAAM,OAAS,kBACf,EAAK,OAAO,OAAS,cACrB,EAAc,IAAI,EAAK,OAAO,IAAI,GAClC,EAAK,UAAU,UAAW,GAAa,IAAa,CAAI,EAAI,CAEhE,CAEA,SAAS,sBAAsB,EAAgB,EAA4B,CACzE,GAAI,CACF,GAAM,CAAE,UAAS,UAAW,GAAU,+BAAgC,EAAQ,CAC5E,WAAY,QACd,CAAC,EACD,GAAI,EAAO,OAAS,EAAG,MAAO,GAE9B,IAAM,EAAgB,qBAAqB,CAAO,EAE9C,EAAa,GAmCjB,OAlCA,cAAc,GAAU,EAAM,IAAc,CACtC,IAEF,EAAK,OAAS,qBACb,mBAAmB,EAAK,SAAU,EAAK,QAAQ,IAAM,GACnD,EAAK,UAAY,mBAAmB,EAAK,SAAU,EAAI,IAAM,IAAA,KAIhE,EAAK,OAAS,aACb,mBAAmB,EAAK,IAAK,EAAK,QAAQ,IAAM,GAC9C,EAAK,UAAY,mBAAmB,EAAK,IAAK,EAAI,IAAM,IAAA,MAC1D,EAAK,UACH,CAAC,0BAA0B,EAAM,CAAS,GACzC,CAAC,2BAA2B,EAAM,CAAS,IAI/C,EAAK,OAAS,kBACd,EAAK,OAAO,OAAS,cACrB,EAAc,IAAI,EAAK,OAAO,IAAI,GAClC,EAAK,UAAU,KAAO,IAAA,IACtB,EAAK,UAAU,EAAE,CAAC,OAAS,iBAC3B,mBAAmB,EAAK,UAAU,GAAI,EAAI,IAAM,IAI/C,EAAK,OAAS,WAAa,EAAK,OAAS,oBAC1C,mBAAmB,EAAM,EAAI,IAAM,GACnC,CAAC,eAAe,EAAM,EAAW,CAAa,KAtB9C,EAAa,GA0BjB,CAAC,EACM,CACT,MAAQ,CACN,MAAO,EACT,CACF,CAEA,SAAS,0BACP,EACA,EACS,CAMT,OALK,EAKE,CADW,GAHK,EAAY,OAC/B,OAAO,OAAO,EAAY,MAAM,CAAC,CAAC,QAAS,GAAa,CAAQ,EAChE,CAAC,EACgC,GAAI,EAAY,KAAO,CAAC,CAC/C,CAAC,CAAC,KAAM,GACpB,EAAO,WAAW,KAAM,GAA2C,CACjE,GAAM,CAAC,GAAQ,GAAS,EACxB,MAAO,CAAC,EAAM,CAAK,CAAC,CAAC,KAClB,GACC,0BAA0B,CAAO,IAC/B,WAAY,GAAW,EAAQ,SAAW,GACzC,cAAe,GAAW,EAAQ,YAAc,GAChD,cAAe,GAAW,EAAQ,YAAc,EACvD,CACF,CAAC,CACH,EAhByB,EAiB3B,CAYA,SAAS,kBAAkB,EAAwC,EAA4B,CAe7F,OAdK,EACW,OAAO,OAAO,EAAK,SAAW,CAAC,CAAC,CAAC,CAAC,KAAM,GACtD,EAAM,OAAO,SAAS,CAAS,CAEvB,GACM,CACd,GAAG,OAAO,OAAO,EAAK,sBAAwB,CAAC,CAAC,EAChD,GAAG,OAAO,OAAO,EAAK,uBAAyB,CAAC,CAAC,CACnD,CAAC,CAAC,KACC,GACC,EAAa,cAAgB,GAAa,EAAa,cAAgB,CAEjE,GACN,0BAA0B,EAAK,YAAa,CAAS,EAAU,GAC5D,CAAC,EAAK,cAAc,OAAQ,EAAK,cAAc,OAAQ,EAAK,gBAAgB,CAAC,CACjF,OAAQ,GAA6B,IAAW,IAAA,EAAS,CAAC,CAC1D,KAAM,GAAW,sBAAsB,EAAQ,CAAS,CAAC,EAhB1C,EAiBpB,CAQA,SAAgB,mBAAmB,EAA4D,CAC7F,GAAM,CAAE,WAAU,UAAS,OAAM,aAAc,EACzC,EAA8B,CAAC,EAC/B,EAAU,IAAI,IAEpB,IAAK,IAAM,KAAU,EAAK,QAAS,CACjC,GAAI,CAAC,0BAA0B,CAAM,EAAG,SACxC,IAAM,EAAM,SAAS,EAAO,UAAW,EAAO,SAAS,EAEvD,GADI,CAAC,EAAU,IAAI,CAAG,GAEpB,CAAC,gBAAgB,CACf,WACA,UACA,UAAW,EAAO,UAClB,UAAW,EAAO,SACpB,CAAC,EAED,SAKF,IAAM,EAAQ,IAAI,IAAI,CACpB,GAAG,gBAAgB,EAAS,OAAO,EAAO,UAAU,EACpD,GAAG,gBAAgB,EAAQ,OAAO,EAAO,UAAU,EACnD,GAAG,EACA,OAAQ,GAAS,EAAK,YAAc,EAAO,SAAS,CAAC,CACrD,IAAK,GAAS,EAAK,aAAa,CACrC,CAAC,EACD,EAAM,KAAK,CACT,UAAW,EAAO,UAClB,UAAW,EAAO,UAClB,cAAe,mBAAmB,EAAO,UAAW,CAAK,EACzD,OAAQ,EAAO,OACf,MAAO,EAAO,KAChB,CAAC,EACD,EAAQ,IAAI,CAAG,CACjB,CAQA,MAAO,CAAE,QAAO,QANA,EAAK,gBAAgB,OAClC,GACC,EAAO,aACP,EAAE,EAAO,WAAa,EAAQ,IAAI,SAAS,EAAO,UAAW,EAAO,SAAS,CAAC,EAG5D,CAAE,CAC1B,CCjZA,SAAS,4BAA4B,EAA8C,CACjF,IAAM,EAAqB,IAAI,IACzB,EAAsB,IAAI,IAC1B,EAAmB,IAAI,IACvB,EAAgB,IAAI,IACpB,EAAe,IAAI,IAEzB,IAAK,IAAM,KAAU,EAAK,QACxB,GAAI,EAAO,OAAS,kBAAoB,EAAO,OAAS,sBAAuB,CAC7E,GAAM,CAAE,SAAQ,SAAU,EAe1B,GAZI,CAAC,EAAO,UAAY,EAAM,WACvB,EAAmB,IAAI,EAAO,SAAS,GAC1C,EAAmB,IAAI,EAAO,UAAW,IAAI,GAAK,EAEpD,EACE,EAAmB,IAAI,EAAO,SAAS,EACvC,kCACF,CAAC,CAAC,IAAI,EAAO,SAAS,GAKpB,EAAO,OAAS,QAAU,EAAM,OAAS,OAAQ,CAEnD,IAAM,GAAgB,EAAO,eAAiB,CAAC,EAAA,CAAG,IAAK,GAAM,EAAE,KAAK,EAC9D,GAAe,EAAM,eAAiB,CAAC,EAAA,CAAG,IAAK,GAAM,EAAE,KAAK,EAC5D,EAAY,IAAI,IAAI,CAAY,EAChC,EAAW,IAAI,IAAI,CAAW,GAElC,EAAa,KAAM,GAAM,CAAC,EAAS,IAAI,CAAC,CAAC,GAAK,EAAY,KAAM,GAAM,CAAC,EAAU,IAAI,CAAC,CAAC,KAGlF,EAAiB,IAAI,EAAO,SAAS,GACxC,EAAiB,IAAI,EAAO,UAAW,IAAI,GAAK,EAElD,EACE,EAAiB,IAAI,EAAO,SAAS,EACrC,gCACF,CAAC,CAAC,IAAI,EAAO,UAAW,CACtB,eACA,cACA,cAAe,EAAM,QACvB,CAAC,EAEL,CACF,MAAO,GAAI,EAAO,OAAS,cAAe,CACxC,GAAM,CAAE,SAAU,EAId,EAAM,WACH,EAAoB,IAAI,EAAO,SAAS,GAC3C,EAAoB,IAAI,EAAO,UAAW,IAAI,GAAK,EAErD,EACE,EAAoB,IAAI,EAAO,SAAS,EACxC,mCACF,CAAC,CAAC,IAAI,EAAO,UAAW,CAAK,EAEjC,MAAW,EAAO,OAAS,iBAGpB,EAAc,IAAI,EAAO,SAAS,GACrC,EAAc,IAAI,EAAO,UAAW,IAAI,GAAK,EAE/C,EAAc,EAAc,IAAI,EAAO,SAAS,EAAG,6BAA6B,CAAC,CAAC,IAChF,EAAO,UACP,EAAO,KACT,GACS,EAAO,OAAS,iBAGzB,EAAa,IAAI,EAAO,UAAW,EAAO,KAAK,EAInD,MAAO,CACL,qBACA,sBACA,mBACA,gBACA,cAAe,IAAI,IACnB,cACF,CACF,CASA,SAAS,4BACP,EACA,EACA,EAA6C,CAAC,EACtC,CAER,IAAM,EAAuB,EACzB,4BAA4B,CAAI,EAChC,CACE,mBAAoB,IAAI,IACxB,oBAAqB,IAAI,IACzB,iBAAkB,IAAI,IACtB,cAAe,IAAI,IACnB,cAAe,IAAI,IACnB,aAAc,IAAI,GACpB,EAIJ,IAAK,IAAM,KAAQ,EAAa,CAC9B,IAAM,EACJ,EAAqB,cAAc,IAAI,EAAK,SAAS,GACrD,IAAI,IACN,EAAS,IAAI,EAAK,cAAe,CAAE,GAAG,EAAK,MAAO,SAAU,GAAO,OAAQ,EAAM,CAAC,EAClF,EAAqB,cAAc,IAAI,EAAK,UAAW,CAAQ,EAE/D,IAAM,EAAU,EAAqB,cAAc,IAAI,EAAK,SAAS,GAAK,IAAI,IAC9E,EAAQ,IAAI,EAAK,SAAS,EAC1B,EAAqB,cAAc,IAAI,EAAK,UAAW,CAAO,CAChE,CAEA,IAAM,EAAS,CAAC,GAAG,OAAO,OAAO,EAAS,MAAM,EAAG,GAAG,EAAqB,aAAa,OAAO,CAAC,EAChG,GAAI,EAAO,SAAW,EACpB,OAAO,qBAAqB,EAAS,SAAS,EAIhD,IAAM,EAAmB,IAAI,IACzB,EAAsB,GAGpB,EAA4B,CAAC,EACnC,IAAK,IAAM,KAAQ,EAAQ,CACzB,IAAM,EAAS,kBAAkB,EAAM,CAAoB,EACvD,EAAO,eAAe,EAAiB,IAAI,WAAW,EAC1D,IAA6C,EAAO,oBACpD,EAAgB,KAAK,EAAO,OAAO,CACrC,CAIA,IAAM,EAAoB,CAAC,kBAAmB,uCAAuC,EACjF,GACF,EAAQ,KAAK,sBAAsB,EAIrC,IAAM,EAAoC,CAAC,EAuC3C,OAtCI,EAAiB,IAAI,WAAW,GAClC,EAAwB,KACtB,kEACF,EAEF,EAAwB,KACtB;;qCACF,EACI,EAAiB,IAAI,QAAQ,GAC/B,EAAwB,KAAK,iEAAiE,EA6BzF,CAxBL,MACA,uDACA,4EACA,KACA,wEACA,MACA,GACA,YAAY,EAAQ,KAAK,IAAI,EAAE,wCAC/B,mDACA,GACA,GAAG,EACH,GACA,8BACA,GAAG,EACH,IACA,GACA,yDACA,GACA,mFACA,mCACA,oFACA,IAGS,CAAC,CAAC,KAAK;CAAI,EAAI;CAC5B,CAOA,SAAS,qBAAqB,EAA2B,CACvD,MACE,CACE,MACA,uDACA,iBAAiB,IACjB,KACA,wEACA,MACA,GACA,uFACA,mDACA,GACA,sEACA,+BACA,GACA,yDACA,GACA,mFACA,mCACA,oFACA,IACF,CAAC,CAAC,KAAK;CAAI,EAAI;CAEnB,CAQA,SAAS,kBACP,EACA,EAMA,CACA,IAAM,EAAuB,CAAC,EAC1B,EAAgB,GAChB,EAAiB,GACjB,EAAsB,GAG1B,EAAW,KAAK,4BAA4B,EAG5C,IAAM,EACJ,EAAqB,mBAAmB,IAAI,EAAK,IAAI,GAAK,IAAI,IAG1D,EAAsB,EAAqB,oBAAoB,IAAI,EAAK,IAAI,GAAK,IAAI,IAGrF,EAA0B,EAAqB,iBAAiB,IAAI,EAAK,IAAI,GAAK,IAAI,IAGtF,EACJ,EAAqB,cAAc,IAAI,EAAK,IAAI,GAAK,IAAI,IAE3D,IAAK,GAAM,CAAC,EAAW,KAAgB,OAAO,QAAQ,EAAK,MAAM,EAAG,CAClE,GAAI,IAAc,KAAM,SAIxB,IAAM,EAAS,kBAAkB,EAFJ,EAAyB,IAAI,CAEO,EADzC,EAAwB,IAAI,CAC8B,CAAC,EAG7E,EAAY,EAAqB,IAAI,CAAS,EAC9C,EAAU,EAAY,2BAA2B,CAAW,EAAI,EACtE,EAAW,KAAK,OAAO,EAAU,IAAI,EAAQ,KAAK,EAAE,EACpD,IAAiC,EAAQ,cACzC,EAAiB,GAAkB,EAAO,gBAAkB,EAC5D,IAA8C,CAAC,GAAa,EAAO,mBACrE,CAIA,IAAK,GAAM,CAAC,EAAW,KAAgB,EAAqB,CAE1D,IAAM,EAAS,kBAAkB,EAAa,GAAM,IAAA,EAAS,EAC7D,EAAW,KAAK,OAAO,EAAU,IAAI,EAAO,KAAK,EAAE,EACnD,IAAiC,EAAO,cACxC,IAAmC,EAAO,eAC1C,IAA6C,EAAO,mBACtD,CAKA,IAAM,EAAuB,EAAqB,cAAc,IAAI,EAAK,IAAI,GAAK,IAAI,IACtF,IAAK,GAAM,CAAC,EAAW,KAAgB,EAAsB,CAC3D,IAAM,EAAS,kBAAkB,EAAa,EAAY,SAAU,IAAA,EAAS,EAC7E,EAAW,KAAK,OAAO,EAAU,IAAI,EAAO,KAAK,EAAE,EACnD,IAAiC,EAAO,cACxC,IAAmC,EAAO,eAC1C,IAA6C,EAAO,mBACtD,CAIA,MAAO,CAAE,QAAA,KAFY,EAAK,KAAK,OAAO,EAAW,KAAK;CAAI,EAAE,OAE1C,gBAAe,iBAAgB,qBAAoB,CACvE,CAEA,SAAS,YACP,EACA,EAIA,CACA,GAAI,IAAc,SAChB,MAAO,CAAE,KAAM,0BAA2B,cAAe,EAAM,EAEjE,GAAI,IAAc,QAAU,GAAiB,EAAc,OAAS,EAClE,MAAO,CACL,KAAM,IAAI,gBAAgB,EAAc,IAAK,GAAM,EAAE,KAAK,CAAC,EAAE,GAC7D,cAAe,EACjB,EAEF,GAAI,IAAc,OAChB,MAAO,CAAE,KAAM,SAAU,cAAe,EAAM,EAEhD,IAAM,EAAO,GAAyB,CAAS,EAC/C,MAAO,CAAE,OAAM,cAAe,IAAS,WAAY,CACrD,CAEA,SAAS,gBAAgB,EAA0B,CACjD,OAAO,EAAO,IAAK,GAAM,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,CAC/C,CAEA,SAAS,eAAe,EAAkB,EAAgB,EAA2B,CACnF,GAAI,EAAO,SAAW,EAEpB,OADK,EACE,EAAW,iBAAmB,UADlB,EAAW,OAAS,QAGzC,IAAM,EAAQ,gBAAgB,CAAM,EAEpC,OADI,EAAc,EAAW,IAAI,EAAM,YAAc,IAAI,EAAM,KACxD,EAAW,IAAI,EAAM,UAAY,CAC1C,CAYA,SAAS,6BACP,EACA,EACQ,CACR,IAAM,EAAQ,EAAO,OAAS,GACxB,EAAY,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAgB,aAAc,GAAG,EAAgB,WAAW,CAAC,CAAC,EAC1F,EAAgB,CAAC,EAAgB,cACjC,EAAa,eAAe,EAAW,EAAO,CAAC,EAAO,UAAY,CAAa,EAC/E,EAAY,eAAe,EAAgB,YAAa,EAAO,CAAa,EAClF,MAAO,cAAc,EAAW,IAAI,EAAU,IAAI,EAAU,EAC9D,CAUA,SAAS,2BAA2B,EAGlC,CACA,GAAM,CAAE,QAAS,YAAY,EAAO,KAAM,EAAO,aAAa,EAGxD,EAAQ,GAAoB,IAAI,CAAI,EAC1C,GAAI,EAAO,CACT,IAAM,EAAS,EAAO,MAAQ,GAAG,EAAM,OAAO,IAAM,EAAM,OACpD,EAAQ,EAAO,MAAQ,IAAI,EAAM,MAAM,KAAO,EAAM,MAC1D,MAAO,CACL,KAAM,cAAc,EAAO,WAAW,EAAM,WAAW,EAAM,UAC7D,cAAe,EACjB,CACF,CACA,IAAM,EAAO,EAAO,MAAQ,GAAG,EAAK,IAAM,EAC1C,MAAO,CACL,KAAM,cAAc,EAAK,WAAW,EAAK,WAAW,EAAK,UACzD,cAAe,EACjB,CACF,CAEA,SAAS,yCAAyC,EAA4C,CAC5F,GAAI,EAAO,OAAS,QAAU,EAAO,OAAS,WAAY,OAAO,KAIjE,IAAM,EAAQ,GAAoB,IAAI,GAAyB,EAAO,IAAI,CAAC,EAC3E,GAAI,CAAC,EAAO,OAAO,KACnB,IAAM,EAAS,EAAO,MAAQ,GAAG,EAAM,OAAO,IAAM,EAAM,OACpD,EAAQ,EAAO,MAAQ,IAAI,EAAM,MAAM,KAAO,EAAM,MAE1D,MAAO,cAAc,EAAO,WAAW,EAAM,IAAI,EAAM,EACzD,CASA,SAAS,kBACP,EACA,EACA,EAMA,CAEA,GAAI,EACF,MAAO,CACL,KAAM,6BAA6B,EAAiB,CAAM,EAC1D,cAAe,GACf,eAAgB,GAChB,oBAAqB,EACvB,EAIF,IAAI,EACA,EAAgB,GAEpB,GAAI,EAAO,OAAS,OAAQ,CAC1B,IAAM,EAAa,EAAO,eAAe,IAAK,GAAM,EAAE,KAAK,GAAK,CAAC,EACjE,EAAW,EAAW,OAAS,EAAI,gBAAgB,CAAU,EAAI,QACnE,KAAO,CACL,IAAM,EAAS,YAAY,EAAO,IAAI,EACtC,EAAW,EAAO,KAClB,EAAgB,EAAO,aACzB,CAEA,GAAI,EAAsB,CACxB,IAAM,EAAiB,yCAAyC,CAAM,EACtE,GAAI,EACF,MAAO,CACL,KAAM,EACN,cAAe,GACf,eAAgB,GAChB,oBAAqB,EACvB,CAEJ,CAKA,IAAI,EAAO,EACX,GAAI,EAAO,MAAO,CAChB,GAAI,GAAoB,IAAI,CAAQ,EAAG,CACrC,IAAM,EAAY,mBAAmB,EAAS,GAC9C,MAAO,CACL,KAAM,EAAO,SAAW,EAAY,GAAG,EAAU,SACjD,gBACA,eAAgB,GAChB,oBAAqB,EACvB,CACF,CAGA,EADE,EAAO,OAAS,QAAU,EAAO,eAAiB,EAAO,cAAc,OAAS,EAC7D,IAAI,EAAS,KAAO,GAAG,EAAS,GACvD,CAmBA,OAhBI,EAIK,CACL,KAAM,cAAc,EAAK,WAAW,EAAK,IAAI,EAAK,GAClD,gBACA,eAAgB,GAChB,oBAAqB,EACvB,GAGG,EAAO,WACV,EAAO,GAAG,EAAK,UAGV,CAAE,OAAM,gBAAe,eAAgB,GAAO,oBAAqB,EAAM,EAClF,CAWA,eAAsB,iBACpB,EACA,EACA,EACA,EACA,EAA6C,CAAC,EAC7B,CACjB,IAAM,EAAU,4BAA4B,EAAU,EAAM,CAAW,EACjE,EAAW,qBAAqB,EAAe,EAAiB,IAAI,EAE1E,OADA,MAAM,EAAG,UAAU,EAAU,CAAO,EAC7B,CACT,CCziBA,SAAS,WAAW,EAA6C,CAC/D,MAAO,CAAE,KAAM,EAAM,KAAM,OAAQ,EAAM,OAAQ,QAAS,EAAM,OAAQ,CAC1E,CAUA,SAAgB,wBACd,EACA,EACkB,CAClB,IAAM,EAAS,oBAAoB,EAAkB,CAAI,EACnD,EAAe,qCAAqC,CAAC,CAAI,CAAC,EAC1D,EAAe,0CAA0C,CAAC,CAAI,CAAC,EAE/D,EAA2B,OAAO,OAAO,EAAO,MAAM,CAAC,CAAC,IAAK,GAAU,CAC3E,IAAM,EAAS,mBAAmB,EAAM,MAAM,EACxC,EAAc,EAAa,IAAI,EAAM,IAAI,EAC3C,GAAa,4CAA4C,EAAQ,CAAW,EAChF,IAAM,EAAU,mBAAmB,EAAM,OAAO,EAC1C,EAAmB,EAAa,IAAI,EAAM,IAAI,EAEpD,OADI,GAAkB,4CAA4C,EAAS,CAAgB,EACpF,CAAE,KAAM,EAAM,KAAM,SAAQ,SAAQ,CAC7C,CAAC,EAED,IAAK,IAAM,KAAU,EAAK,SACpB,EAAO,OAAS,iBAAmB,EAAO,OAAS,kBACrD,EAAO,KAAK,WAAW,EAAO,MAAM,CAAC,EAGzC,OAAO,CACT,CAQA,SAAgB,8BACd,EACA,EACQ,CACR,OAAO,GACL,CACE,CACE,UAAW,EAAiB,UAC5B,OAAQ,wBAAwB,EAAkB,CAAI,CACxD,CACF,EACA,CAAE,YAAa,sBAAuB,CACxC,CACF,CAUA,eAAsB,sBACpB,EACA,EACA,EACA,EACiB,CACjB,IAAM,EAAW,qBAAqB,EAAe,EAAiB,cAAc,EAEpF,OADA,MAAM,EAAG,UAAU,EAAU,8BAA8B,EAAkB,CAAI,CAAC,EAC3E,CACT,CAqCA,eAAsB,yBACpB,EACA,EACA,EACA,EACiC,CACjC,GAAI,CACF,MAAO,CACL,iBAAkB,MAAM,sBACtB,EACA,EACA,EACA,CACF,CACF,CACF,OAAS,EAAO,CACd,MAAO,CAAE,kBAAmB,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAAE,CACrF,CACF,CAOA,eAAsB,wBACpB,EACwC,CACxC,GAAM,CAAE,mBAAkB,OAAM,gBAAe,kBAAiB,cAAc,CAAC,GAAM,EAQrF,MAAO,CACL,YAAA,MARwB,iBACxB,EACA,EACA,EACA,EACA,CACF,EAGE,GAAI,MAAM,yBAAyB,EAAkB,EAAM,EAAe,CAAe,CAC3F,CACF,CC7IA,MAAa,GAAmC,gCAOhD,eAAe,WAAW,EAAoC,CAC5D,GAAI,CAEF,OADA,MAAM,EAAG,OAAO,CAAQ,EACjB,EACT,MAAQ,CACN,MAAO,EACT,CACF,CAOA,eAAe,oBAAoB,EAAiC,CAClE,GAAI,MAAM,WAAW,CAAQ,EAC3B,MAAM,EAAS,CACb,KAAM,wBACN,QAAS,kCAAkC,GAC7C,CAAC,CAEL,CAyBA,eAAsB,mBACpB,EACA,EACA,EAC+B,CAE/B,IAAM,EAAe,oBAAoB,EAAe,CAAe,EACvE,MAAM,EAAG,MAAM,EAAc,CAAE,UAAW,EAAK,CAAC,EAEhD,IAAM,EAAW,qBAAqB,EAAe,EAAiB,QAAQ,EAO9E,OAJA,MAAM,oBAAoB,CAAQ,EAElC,MAAM,EAAG,UAAU,EAAU,KAAK,UAAU,EAAU,KAAM,CAAC,CAAC,EAEvD,CACL,WACA,iBACF,CACF,CAYA,eAAsB,kBACpB,EACA,EACA,EACA,EACA,EACA,EAA6C,CAAC,EACjB,CAE7B,IAAM,EAAe,oBAAoB,EAAe,CAAe,EACvE,MAAM,EAAG,MAAM,EAAc,CAAE,UAAW,EAAK,CAAC,EAGhD,IAAM,EAAe,qBAAqB,EAAe,EAAiB,MAAM,EAC1E,EAAkB,qBAAqB,EAAe,EAAiB,SAAS,EAChF,EAAkB,qBAAqB,EAAe,EAAiB,IAAI,EAC3E,EAAuB,qBAAqB,EAAe,EAAiB,cAAc,EAE1F,EAAc,EAAK,wBAGzB,MAAM,oBAAoB,CAAY,EAClC,IACF,MAAM,oBAAoB,CAAe,EACzC,MAAM,oBAAoB,CAAe,EACzC,MAAM,oBAAoB,CAAoB,GAIhD,IAAM,EAAsB,EAAc,CAAE,GAAG,EAAM,aAAY,EAAI,EAGrE,MAAM,EAAG,UAAU,EAAc,KAAK,UAAU,EAAqB,KAAM,CAAC,CAAC,EAE7E,IAAM,EAA6B,CACjC,eACA,iBACF,EAEA,GAAI,EAAa,CACf,IAAM,EAAgB,wBAAwB,EAAqB,CAAW,EAC9E,MAAM,EAAG,UAAU,EAAiB,CAAa,EACjD,EAAO,gBAAkB,EAKzB,IAAM,EAAY,MAAM,wBAAwB,CAC9C,mBACA,KAAM,EACN,gBACA,kBACA,aACF,CAAC,EACD,EAAO,gBAAkB,EAAU,YACnC,EAAO,qBAAuB,EAAU,iBACxC,EAAO,kBAAoB,EAAU,iBACvC,CAEA,OAAO,CACT,CA+BA,eAAsB,+BACpB,EACsC,CACtC,GAAM,CAAE,gBAAe,kBAAiB,WAAU,eAAgB,EAC5D,EAAe,oBAAoB,EAAe,CAAe,EACvE,MAAM,EAAG,MAAM,EAAc,CAAE,UAAW,EAAK,CAAC,EAEhD,IAAM,EAAe,qBAAqB,EAAe,EAAiB,MAAM,EAC1E,EAAkB,qBAAqB,EAAe,EAAiB,SAAS,EAChF,EAAkB,qBAAqB,EAAe,EAAiB,IAAI,EAEjF,MAAM,oBAAoB,CAAY,EACtC,MAAM,oBAAoB,CAAe,EACzC,MAAM,oBAAoB,CAAe,EACzC,MAAM,oBAAoB,qBAAqB,EAAe,EAAiB,cAAc,CAAC,EAE9F,IAAM,EAAO,EAAc,CAAE,GAAG,EAAQ,KAAM,aAAY,EAAI,EAAQ,KACtE,MAAM,EAAG,UAAU,EAAc,KAAK,UAAU,EAAM,KAAM,CAAC,CAAC,EAC9D,MAAM,EAAG,UAAU,EAAiB,gCAAgC,EAAK,SAAS,CAAC,EACnF,IAAM,EAAY,MAAM,wBAAwB,CAC9C,iBAAkB,EAClB,OACA,gBACA,iBACF,CAAC,EAED,MAAO,CACL,eACA,kBACA,kBACA,qBAAsB,EAAU,iBAChC,kBAAmB,EAAU,kBAC7B,iBACF,CACF,CAOA,SAAS,gCAAgC,EAA2B,CAClE,MAAO;oCAC2B,EAAU;;;;;;;;;;;;;;CAe9C,CAQA,SAAgB,wBACd,EACA,EAA6C,CAAC,EACtC,CACR,IAAM,EAAoB,CAAC,EACrB,EAAoB,IAAI,IAC5B,EAAK,QACF,OAAQ,GAAyC,EAAO,OAAS,eAAe,CAAC,CACjF,IAAK,GAAW,CAAC,EAAO,kBAAmB,EAAO,SAAS,CAAC,CACjE,EAEA,IAAK,IAAM,KAAQ,EACjB,EAAQ,KAAK,+BAA+B,CAAI,CAAC,EAGnD,IAAK,IAAM,KAAU,EAAK,QAAS,CACjC,IAAM,EAAqB,iCAAiC,CAAM,EAElE,GADA,EAAQ,KAAK,GAAG,sBAAsB,EAAQ,IAAuB,KAAM,CAAiB,CAAC,EACzF,EAAoB,CACtB,EAAQ,KAAK,CAAkB,EAE/B,IAAM,EAAyB,+BAA+B,CAAM,EAChE,GACF,EAAQ,KAAK,CAAsB,CAEvC,CACF,CAEI,EAAQ,SAAW,GACrB,EAAQ,KAAK;iDACgC,EAG/C,IAAM,EAAU,EAAK,QAAQ,KAC1B,GAAW,EAAO,OAAS,kBAAoB,EAAO,eAAe,MACxE,EACI,KAAK,KACL,GAEJ,MAAO;0BACiB,EAAK,UAAU;;;;;;;;;;;;;EAavC,EAAQ;;EAER,EAAQ,KAAK;;CAAM,EAAE;;CAGvB,CAOA,SAAgB,4BAA4B,EAA6B,CACvE,MAAO;uBACc,EAAK,UAAU;;;;;;;;;;;;;WAa3B,KAAK,UAAU,GAAG,EAAK,UAAU,WAAW,EAAE;;;;;;;;;;;;;;;;;;CAmBzD,CAOA,SAAgB,kCAAkC,EAA6B,CAC7E,IAAM,EAAS,qBAAqB,KAAK,EAAK,SAAS,EACnD,gBAAgB,EAAK,YACrB,gBAAgB,KAAK,UAAU,EAAK,SAAS,EAAE,GACnD,MAAO;yBACgB,EAAK,UAAU;;;;;;;;;;;;;;;;;;;sBAmBlB,EAAO;;;;;;;WAOlB,KAAK,UAAU,GAAG,EAAK,UAAU,oBAAoB,EAAE;;;;;;;;;;;;CAalE,CASA,SAAS,sBACP,EACA,EAAwB,GACxB,EACU,CACV,GAAI,EAAO,OAAS,eAAiB,EAAO,OAAS,iBAAkB,CACrE,IAAM,EAAS,EAAO,OAAS,iBAAmB,EAAO,OAAS,IAAA,GAClE,GAAI,CAAC,sBAAsB,EAAO,UAAW,EAAO,UAAW,EAAQ,EAAO,KAAK,EACjF,MAAO,CAAC,EAEV,IAAM,EAAS,EAAO,MAAM,OACtB,EAAY,EAAO,IAAK,GAAM,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,EACjD,EAAe,EAAO,IAAK,GAAM,WAAW,EAAE,cAAc,EAAE,EAAE,CAAC,CAAC,KAAK;SAAY,EACzF,MAAO,CACL,2BAA2B,EAAO,KAAK,IAAI,EAAE,sCAAsC,EAAO,UAAU;;;qBAGrF,EAAO,UAAU;iBACrB,EAAU;kBACT,EAAU;;;;;uBAKL,EAAO,UAAU;;UAE9B,EAAa;;;;;0BAKG,EAAO,UAAU;mBACxB,EAAO,GAAG;;;;;IAMzB,CACF,CAEA,GAAI,EAAO,OAAS,cAalB,OAZc,EAAO,MACX,SACD,CACL,iBAAiB,EAAO,UAAU,gBAAgB,EAAO,UAAU;;oBAEvD,EAAO,UAAU;;QAE7B,EAAO,UAAU;;gBAGnB,EAEK,CAAC,EAGV,GAAI,EAAO,OAAS,gBAAiB,CACnC,IAAM,EAAU,CAAC,8BAA8B,CAAM,CAAC,EAYtD,OALG,EAAO,MAAM,QAAU,MACvB,EAAE,EAAO,OAAO,QAAU,KAAU,4BAA4B,CAAM,IAEvE,EAAQ,KAAK,2BAA2B,EAAO,UAAW,EAAO,UAAW,QAAQ,CAAC,EAEhF,CACT,CAEA,GAAI,EAAO,OAAS,gBAClB,MAAO,CAAC,6BAA6B,CAAM,CAAC,EAG9C,GAAI,EAAO,OAAS,kBAAoB,EAAO,OAAS,sBAEtD,MAAO,CAAC,EAGV,GAAM,CAAE,SAAQ,SAAU,EACpB,EAAoB,CAAC,EA0B3B,GAxBI,EAAO,OAAS,uBAClB,EAAQ,KAAK,8BAA8B,CAAM,CAAC,EAGhD,EAAO,OAAS,kBAAoB,EAAO,eAAe,QAC5D,EAAQ,KAAK,qCAAqC,CAAM,CAAC,EAIvD,CAAC,EAAO,UAAY,EAAM,UAC5B,EAAQ,KAAK,YAAY,EAAO,UAAU,OAAO,EAAO,UAAU;;oBAElD,EAAO,UAAU;;QAE7B,EAAO,UAAU;;cAEX,EAAO,UAAU;gBACf,EAOV,CAAC,EAAuB,CAC1B,IAAM,EAAyB,+BAA+B,CAAM,EAChE,GACF,EAAQ,KAAK,CAAsB,CAEvC,CAGA,GAAI,EAAO,OAAS,QAAU,EAAM,OAAS,OAAQ,CACnD,IAAM,GAAgB,EAAO,eAAiB,CAAC,EAAA,CAAG,IAAK,GAAM,EAAE,KAAK,EAC9D,GAAe,EAAM,eAAiB,CAAC,EAAA,CAAG,IAAK,GAAM,EAAE,KAAK,EAC5D,EAAgB,EAAa,OAAQ,GAAM,CAAC,EAAY,SAAS,CAAC,CAAC,EACzE,GAAI,EAAc,OAAS,EAAG,CAC5B,GAAM,CAAC,GAAc,EACf,EACJ,IAAe,IAAA,GAEX,EAAM,SACJ,cACA,OAHF,KAAK,UAAU,CAAU,EAI/B,EAAQ,KAAK,kDAAkD,EAAc,KAAK,IAAI,EAAE;;oBAE1E,EAAO,UAAU;aACxB,EAAO,UAAU,IAAI,EAAY;cAChC,EAAO,UAAU,YAAY,EAAc,IAAK,GAAM,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE;gBAClF,CACZ,CACF,CAyBA,OArBI,6BAA6B,EAAQ,EAAO,CAAiB,GAC/D,EAAQ,KAAK,gBAAgB,EAAO,UAAU,mBAAmB,EAAO,eAAe,MAAM,EAAM,eAAe;;;;qBAIjG,EAAO,UAAU;mBACnB,EAAM,eAAe,MAAM,EAAO,UAAU,GAAG,EAAO,UAAU,MAAM,EAAM,eAAe;kBAC5F,EAAO,UAAU,SAAS,EAAO,UAAU,GAAG,EAAO,UAAU;gBACjE,EAAM,eAAe;gBACrB,EAAO,UAAU,GAAG,EAAO,UAAU;;;;wBAI7B,EAAO,UAAU;iBACxB,EAAO,UAAU;;;;IAI9B,EAGK,CACT,CAEA,SAAS,4BAA4B,EAAqC,CACxE,GAAM,CAAE,SAAQ,SAAU,EAE1B,OADI,EAAO,OAAS,WAAa,EAAM,OAAS,UAAkB,IAC1D,EAAM,OAAA,IAAmC,EAAO,OAAA,EAC1D,CAEA,SAAS,8BAA8B,EAAoC,CACzE,GAAM,CAAE,YAAW,YAAW,oBAAmB,SAAQ,SAAU,EAcnE,MAAO,aAAa,EAAU,GAAG,EAAkB,QAAQ,EAAU;;oEAEH,EAAU,GAd1E,CAAC,EAAO,UAAY,EAAM,SACtB;aACK,EAAkB,mBAAmB,EAAU;kEAEpD,KACkB,4BAA4B,CAAM,EACtD;gBACU,EAAU,oCAAoC,EAAkB;;kCAG1E,GAI0G;;oBAE5F,EAAU;sBACR,EAAU,YAAY,EAAkB;gBAE9D,CAEA,SAAS,qCAAqC,EAAqC,CACjF,GAAM,CAAE,YAAW,aAAc,EAC3B,EAAU,EAAO,eAAiB,CAAC,EACnC,EAAU,EACb,IAAK,GAAW,GAAG,EAAO,aAAa,KAAK,GAAG,EAAE,KAAK,EAAO,KAAK,KAAK,GAAG,GAAG,CAAC,CAC9E,KAAK,IAAI,EAEN,EAAQ,EACX,IACE,GACC,8CAA8C,EAAO,aAAa,IAAK,GAAY,KAAK,UAAU,CAAO,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,KAAK,KAAK,UAAU,EAAO,KAAK,EAAO,KAAK,OAAS,EAAE,EAAE,GACpL,CAAC,CACA,KAAK;CAAI,EACN,EAAS,KAAK,UAAU,CAAS,EAEvC,MAAO,oCAAoC,EAAU,GAAG,EAAU,IAAI,EAAQ;;;;;;;uBAOzD,EAAU;yBACR,EAAO;;;;;;;;;;mCAUG,EAAO;EACxC,EAAM;;0BAEkB,EAAU;oBAChB,EAAO;;;;;;IAO3B,CAIA,MAAM,GAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqCpC,SAAS,6BAA6B,EAAoC,CACxE,GAAM,CAAE,YAAW,qBAAsB,EAEnC,EAAa,CADF,KAAM,GAAG,OAAO,KAAK,EAAO,OAAO,MAAM,CAAC,CAAC,OAAQ,GAAS,IAAS,IAAI,CACjE,CAAC,CAAC,IAAK,GAAS,KAAK,UAAU,CAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAGlE,EAAiB,OAAO,QAAQ,EAAO,MAAM,MAAM,CAAC,CACvD,QAAQ,EAAG,KAAW,EAAM,iBAAmB,CAAS,CAAC,CACzD,KAAK,CAAC,KAAU,CAAI,EAyBvB,MAAO,mBAAmB,EAAkB,YAAY,EAAU;mDACjB,EAAkB;;;;;;uBAM9C,EAAkB;mBACtB,EAAW;;;;;;;;;8BASA,EAAU,YAxCpC,EAAe,OAAS,EACpB,gCAAgC,EAAe,IAAK,GAAS,GAAG,EAAK,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,MACzF,OAsCyD;;;KApC7D,EAAe,OAAS,EACpB;;;;oBAIY,EAAU;;EAE5B,EACC,IACE,GAAS,SAAS,EAAK;uBACL,EAAkB;mBACtB,EAAkB,GAAG,EAAK;qBACxB,EAAkB,cAAc,EAAU,OAC7D,CAAC,CACA,KAAK;CAAI,EAAE;;iBAGN,IAuBR,CAEA,SAAS,8BACP,EACQ,CACR,MAAO,kBAAkB,EAAO,UAAU,GAAG,EAAO,UAAU,QAAQ,EAAO,OAAO,KAAK,MAAM,EAAO,MAAM,KAAK;;;;;uBAK5F,EAAO,UAAU;0BACd,EAAO,UAAU;kBACzB,EAAO,UAAU;;;;;;;;;;aAUtB,GAAiC;mDACK,EAAO,OAAO,KAAK,wBAAwB,EAAO,MAAM,KAAK;kCAC9E,EAAO,UAAU;;;;;0BAKzB,EAAO,UAAU;oBACvB,KAAK,UAAU,EAAO,SAAS,EAAE;;;;;;IAOrD,CASA,SAAS,8BAA8B,EAAkC,CACvE,GAAI,2BAA2B,EAAK,OAAQ,EAAK,KAAK,EACpD,MAAO,wBAAwB,EAAK,OAAO,KAAK,oCAAoC,iBAAiB,EAAK,KAAK,EAAE;kCACnF,EAAK,UAAU;;+CAI/C,IAAM,EAAS,EAAK,MAAM,MACtB,qBAAqB,iBAAiB,EAAK,KAAK,EAAE,QAClD,OAAO,EAAK,MAAM,KAAK,OAC3B,MAAO,cAAc,GAAiC;yCACf,EAAO,mBAAmB,EAAK,OAAO,KAAK;kCAClD,EAAK,UAAU;mDAEjD,CAEA,SAAS,+BAA+B,EAAkC,CACxE,IAAM,GACH,EAAK,MAAM,OAAS,KAAU,CAAC,2BAA2B,EAAK,OAAQ,EAAK,KAAK,EACpF,MAAO,gBAAgB,EAAK,UAAU,GAAG,EAAK,UAAU,QAAQ,EAAK,cAAc,6CAA6C,EAAK,UAAU;;;;;uBAK1H,EAAK,UAAU;0BACZ,EAAK,UAAU;kBACvB,EAAK,UAAU;;;;;;;;;;EAU/B,8BAA8B,CAAI,EAAE;sBAChB,EAAK,UAAU;;0BAEX,EAAK,UAAU;;eAE1B,KAAK,UAAU,EAAK,aAAa,EAAE,KAAK,EAAe,mBAAqB,iBAAiB;eAC7F,KAAK,UAAU,EAAK,SAAS,EAAE;;;;;;;IAQ9C,CAEA,SAAS,+BAA+B,EAAmC,CACzE,GAAI,EAAO,OAAS,kBAAoB,EAAO,OAAS,sBAAuB,OAAO,KAEtF,GAAM,CAAE,SAAQ,SAAU,EAG1B,OAFK,EAAO,QAAU,KAAU,EAAE,EAAM,QAAU,IAAe,KAE1D,2BACL,EAAO,UACP,EAAO,UACP,EAAO,OAAS,sBAAwB,QAAU,QACpD,CACF,CAEA,SAAS,2BACP,EACA,EACA,EACQ,CAiBR,MAAO,eAAe,EAAU;;;qBAGb,EAAU;kBACb,EAAU;kBACV,EAAU;;;;;;uBAML,EAAU;0BACP,EAAU;kBAClB,EAAU,cAAc,EAAU;;EA5BhD,IAAe,QACX;;qCAE6B,EAAU,GAAG,EAAU;;SAGpD;;;0BAGkB,EAAU;mBACjB,EAAU,oBAAoB,EAAU;;;SAoBrC;;IAGtB,CAEA,SAAS,iCAAiC,EAAmC,CAC3E,GAAI,EAAO,OAAS,iBAAkB,OAAO,KAE7C,GAAM,CAAE,SAAQ,SAAU,EAC1B,GAAI,EAAO,OAAS,WAAa,EAAM,OAAS,WAAa,EAAO,QAAU,EAAM,MAClF,OAAO,KAET,IAAM,EACJ,CAAC,EAAO,UAAY,EAAM,SAAW,OAAO,EAAO,UAAU,GAAK,OAAO,EAAO,YAC5E,EAAc,EAAO,OAAA,EAErB,GADa,EAAM,OAAA,GAEV,EACT;;uDAGA,GAEN,MAAO,yBAAyB,EAAO,UAAU,WAAW,EAAO,UAAU;;;+EAGA,EAAgB;;;;;uBAKxE,EAAO,UAAU;0BACd,EAAO,UAAU;kBACzB,EAAO,UAAU;;;;;;;;;;;0BAWT,EAAO,UAAU;mBACxB,EAAO,UAAU,IAAI,EAAgB;;oBAEpC,EAAO,UAAU,UAAU,EAAgB;;;;;IAM/D,CC32BA,SAAgB,2BAA2B,EAAsD,CAC/F,GAAM,CAAE,gBAAe,kBAAiB,UAAW,EAC7C,EAAQ,sBAAsB,CAAe,EAC7C,EAAmB,EAAO,KAAK,EACrC,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,mCACN,QAAS,kDACT,QAAS,2BACX,CAAC,EAGH,IAAM,EAAW,qBAAqB,EAAe,EAAiB,MAAM,EAC5E,GAAI,CAACE,EAAG,WAAW,CAAQ,EACzB,MAAM,EAAS,CACb,KAAM,sBACN,QAAS,aAAa,EAAM,gBAAgB,EAAc,aAAa,EAAS,EAClF,CAAC,EAGH,IAAM,EAAO,SAAS,CAAQ,EAC9B,GAAI,CAAC,EAAK,yBAA2B,CAAC,EAAK,YACzC,MAAM,EAAS,CACb,KAAM,gCACN,QAAS,aAAa,EAAM,qFAC9B,CAAC,EAEH,GAAI,EAAK,cACP,MAAM,EAAS,CACb,KAAM,+BACN,QACE,aAAa,EAAM,uCACf,EAAK,cAAc,eAAe,IAAI,EAAK,cAAc,OAAO,GACxE,CAAC,EAGH,IAAM,EAAc,qBAAqB,EAAe,EAAiB,SAAS,EAClF,GAAIA,EAAG,WAAW,CAAW,EAC3B,MAAM,EAAS,CACb,KAAM,0BACN,QAAS,8BAA8B,EAAY,GACnD,WAAY,wEACd,CAAC,EAGH,IAAM,EAAmC,CACvC,OAAQ,EACR,eAAgB,IAAI,KAAK,CAAA,CAAE,YAAY,CACzC,EAGM,EAAM,KAAK,MAAMA,EAAG,aAAa,EAAU,OAAO,CAAC,EAIzD,MAHA,GAAI,cAAgB,EACpB,EAAG,cAAc,EAAU,KAAK,UAAU,EAAK,KAAM,CAAC,CAAC,EAEhD,CACT,CAMA,SAAgB,4BAA4B,EAAwB,CAClE,IAAM,EAAM,KAAK,MAAMA,EAAG,aAAa,EAAU,OAAO,CAAC,EACpD,OAAO,OAAO,EAAK,eAAe,IACvC,OAAO,EAAI,cACX,EAAG,cAAc,EAAU,KAAK,UAAU,EAAK,KAAM,CAAC,CAAC,EACzD,CAWA,eAAsB,wBACpB,EACwC,CACxC,GAAM,CAAE,gBAAe,kBAAiB,WAAW,GAAO,kBAAkB,IAAU,EAChF,EAAQ,sBAAsB,CAAe,EAE7C,EAAW,qBAAqB,EAAe,EAAiB,MAAM,EAC5E,GAAI,CAACA,EAAG,WAAW,CAAQ,EACzB,MAAM,EAAS,CACb,KAAM,sBACN,QAAS,aAAa,EAAM,gBAAgB,EAAc,aAAa,EAAS,EAClF,CAAC,EAGH,IAAM,EAAO,SAAS,CAAQ,EACxB,EAAc,qBAAqB,EAAe,EAAiB,SAAS,EAC5E,EAAgBA,EAAG,WAAW,CAAW,EACzC,EAAwC,CAAC,EAE/C,GAAI,GAAiB,EAAK,cAKxB,IAFA,4BAA4B,CAAQ,EACpC,EAAO,kBAAoB,GACvB,CAAC,EAAU,OAAO,CAAA,MACjB,GAAI,GAAiB,CAAC,EAC3B,MAAM,EAAS,CACb,KAAM,0BACN,QAAS,sCAAsC,EAAY,EAC7D,CAAC,EAGH,IAAM,EAAW,qBAAqB,EAAe,EAAiB,MAAM,EACtE,EAAiB,qBAAqB,EAAe,EAAiB,YAAY,EAClF,EAAmB,qBAAqB,EAAe,EAAiB,cAAc,EAEtF,EAAgB,GAAY,CAACA,EAAG,WAAW,CAAQ,EACnD,EAAsB,GAAY,GAAmB,CAACA,EAAG,WAAW,CAAc,EACxF,GAAI,GAAY,CAAC,GAAiB,CAAC,EACjC,MAAM,EAAS,CACb,KAAM,wBACN,QAAS,EACL,oCAAoC,EAAS,OAAO,EAAe,GACnE,oCAAoC,EAAS,EACnD,CAAC,EAGH,GAAI,GAAiB,EAAU,CAC7B,IAAM,EAAc,qBAAqB,EAAe,EAAiB,IAAI,EAC7E,GAAI,CAACA,EAAG,WAAW,CAAW,EAC5B,MAAM,EAAS,CACb,KAAM,4BACN,QAAS,gCAAgC,EAAY,GACrD,WACE,mFACJ,CAAC,CAEL,CAKA,IAAM,EAAwB,CAAC,GAAkB,GAAY,CAACA,EAAG,WAAW,CAAgB,EACtF,EAAmB,EACrB,kCAAkC,EAAe,EAAkB,CAAC,EACpE,KACJ,GAAI,GAAyB,CAAC,EAC5B,MAAM,EAAS,CACb,KAAM,4BACN,QAAS,uDAAuD,EAAM,GACtE,WAAY,+BACd,CAAC,EAGH,GAAI,CAAC,GAAiB,EAAkB,CACtC,MAAMC,EAAW,UAAU,EAAa,wBAAwB,CAAI,CAAC,EACrE,EAAO,YAAc,EACrB,IAAM,EAAY,MAAM,wBAAwB,CAC9C,mBACA,OACA,gBACA,iBACF,CAAC,EACD,EAAO,YAAc,EAAU,YAC/B,EAAO,iBAAmB,EAAU,iBACpC,EAAO,kBAAoB,EAAU,kBACrC,4BAA4B,CAAQ,CACtC,MAAW,GAAY,GAErB,OAAO,OACL,EACA,MAAM,yBAAyB,EAAkB,EAAM,EAAe,CAAe,CACvF,EAcF,OAXI,IACF,MAAMA,EAAW,UAAU,EAAU,4BAA4B,CAAI,CAAC,EACtE,EAAO,SAAW,GAEpB,EAAO,oBAAsB,EAEzB,GAAuBD,EAAG,WAAW,CAAgB,IACvD,MAAMC,EAAW,UAAU,EAAgB,kCAAkC,CAAI,CAAC,EAClF,EAAO,eAAiB,GAGnB,CACT,CAQA,SAAgB,kBAAkB,EAAgC,CAChE,IAAI,EAAM,EAAK,QAAQ,CAAa,EACpC,OAAS,CACP,GAAID,EAAG,WAAW,EAAK,KAAK,EAAK,eAAgB,gBAAiB,SAAU,cAAc,CAAC,EACzF,MAAO,GAET,IAAM,EAAS,EAAK,QAAQ,CAAG,EAC/B,GAAI,IAAW,EAAK,MAAO,GAC3B,EAAM,CACR,CACF,CAMA,eAAe,OAAO,EAAuC,CAC3D,eAAe,oBAAoB,EAEnC,IAAM,EAAkB,wBAAwB,EAAQ,MAAM,EAE9D,GAAI,IAAA,EACF,MAAM,EAAS,CACb,KAAM,+BACN,QAAS,aAAa,EAAQ,OAAO,oEACvC,CAAC,EAGH,GAAM,CAAE,UAAW,MAAM,WAAW,EAAQ,UAAU,EAGhD,EAA2B,4BAA4B,EAF3C,EAAK,QAAQ,EAAO,IAE+B,CAAS,EAC9E,GAAI,EAAyB,SAAW,EACtC,MAAM,6BAA6B,EAGrC,IAAM,EAAkB,uBAAuB,EAA0B,EAAQ,SAAS,EACpF,CAAE,iBAAkB,EACxB,EAAyB,KAAM,GAAO,EAAG,YAAc,CAAe,EACtE,qCACF,EAEA,GAAI,EAAQ,SAAU,CACpB,GAAI,EAAQ,SACV,MAAM,EAAS,CACb,KAAM,oCACN,QAAS,wDACT,QAAS,2BACX,CAAC,EAEH,IAAM,EAAS,EAAQ,QAAQ,KAAK,EACpC,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,mCACN,QAAS,yCACT,QAAS,2BACX,CAAC,EAEH,IAAM,EAAgB,2BAA2B,CAC/C,gBACA,kBACA,QACF,CAAC,EACD,EAAO,QACL,2BAA2B,EAAO,KAAK,EAAQ,MAAM,EAAE,gBAAgB,EAAO,KAAK,CAAe,EAAE,uCACtG,EACA,EAAO,KAAK,aAAa,EAAc,QAAQ,EAC/C,EAAO,KAAK,gBAAgB,qBAAqB,EAAe,EAAiB,MAAM,GAAG,EAC1F,MACF,CACA,GAAI,EAAQ,SAAW,IAAA,GACrB,MAAM,EAAS,CACb,KAAM,oCACN,QAAS,uDACT,QAAS,2BACX,CAAC,EAGH,IAAM,EAAkB,kBAAkB,CAAa,EACjD,EAAS,MAAM,wBAAwB,CAC3C,gBACA,kBACA,SAAU,EAAQ,SAClB,iBACF,CAAC,EAED,GAAI,EAAO,oBACT,EAAO,QACL,sDAAsD,EAAO,KAAK,EAAQ,MAAM,EAAE,gBAAgB,EAAO,KAAK,CAAe,GAC/H,EACI,CAAC,EAAO,UAAY,CAAC,EAAO,qBAAqB,CACnD,EAAO,KACL,uBAAuB,qBAAqB,EAAe,EAAiB,SAAS,GACvF,EACA,MACF,CAGF,IAAM,EAAY,CAAC,EAAO,SAAU,EAAO,cAAc,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,OACrE,EAAQ,CACZ,EAAO,aAAe,mBACtB,EAAY,IAAM,EAAY,EAAI,kBAAoB,iBACxD,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,OAAO,EACT,EAAS,iBAAiB,EAAO,KAAK,EAAQ,MAAM,EAAE,gBAAgB,EAAO,KAAK,CAAe,IACnG,EACF,EAAO,QAAQ,SAAS,EAAM,GAAG,GAAQ,EAEzC,EAAO,KAAK,kBAAkB,GAAQ,EAEpC,EAAO,cACT,EAAO,KAAK,uBAAuB,EAAO,aAAa,EACvD,EAAO,KAAK,eAAe,EAAO,aAAa,GAE7C,EAAO,kBACT,EAAO,KAAK,oBAAoB,EAAO,kBAAkB,EAEvD,EAAO,mBACT,EAAO,KAAK,4BAA4B,EAAO,mBAAmB,EAEhE,EAAO,UACT,EAAO,KAAK,qBAAqB,EAAO,UAAU,EAEhD,EAAO,eACT,EAAO,KAAK,kBAAkB,EAAO,gBAAgB,EAC5C,EAAO,UAAY,CAAC,EAC7B,EAAO,KACL,4GACF,EACS,EAAO,qBAAuB,EAAO,mBAC9C,EAAO,KAAK,+EAA+E,EAG7F,EAAO,QAAQ,EACX,EAAO,cACT,EAAO,IAAI,yDAAyD,EACpE,EAAO,IAAI,qEAAqE,GAE9E,EAAO,UACT,EAAO,IAAI,uEAAuE,EAGpF,IAAM,EAAa,EAAO,aAAe,EAAO,SAChD,GAAI,CAAC,EAAY,OAEjB,IAAM,EAAS,2BAA2B,EACrC,KAGL,CADA,EAAO,QAAQ,EACf,EAAO,KAAK,WAAW,EAAK,SAAS,CAAU,EAAE,MAAM,EAAO,IAAI,EAClE,GAAI,CACF,MAAM,uBAAuB,CAAU,CACzC,MAAQ,CACN,MACF,CALkE,CAMpE,CASA,SAAgB,uBACd,EACA,EACQ,CACR,GAAI,EAAW,CACb,GAAI,CAAC,EAAyB,KAAM,GAAO,EAAG,YAAc,CAAS,EACnE,MAAM,EAAS,CACb,KAAM,+BACN,QAAS,cAAc,EAAU,mDACnC,CAAC,EAEH,OAAO,CACT,CACA,GAAI,EAAyB,SAAW,EAAG,CACzC,GAAM,CAAC,GAAM,EACb,OAAO,EAAc,EAAI,mCAAmC,CAAC,CAAC,SAChE,CACA,MAAM,EAAS,CACb,KAAM,+BACN,QAAS,qFAAqF,EAAyB,IAAK,GAAO,EAAG,SAAS,CAAC,CAAC,KAAK,IAAI,IAC1J,QAAS,2BACX,CAAC,CACH,CAEA,MAAa,GAAgB,EAAiB,CAC5C,KAAM,SACN,YACE,uJACF,MAAO,+TACP,KAAM,EAAE,aAAa,CACnB,GAAG,GACH,OAAQ,EAAI,EAAE,OAAO,EAAG,CACtB,WAAY,GACZ,YAAa,uDACf,CAAC,EACD,UAAW,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CACpC,MAAO,IACP,YAAa,mEACf,CAAC,EACD,YAAa,EAAI,EAAE,QAAQ,CAAC,CAAC,SAAS,EAAG,CACvC,YACE,8FACJ,CAAC,EACD,OAAQ,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CACjC,YAAa,kEACf,CAAC,EACD,YAAa,EAAI,EAAE,QAAQ,CAAC,CAAC,SAAS,EAAG,CACvC,YAAa,mEACf,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,MAAM,OAAO,CACX,WAAY,EAAK,OACjB,OAAQ,EAAK,OACb,UAAW,EAAK,UAChB,SAAU,EAAK,aACf,OAAQ,EAAK,OACb,SAAU,EAAK,YACjB,CAAC,CACH,CACF,CAAC,EC3YD,SAAgB,kCAA6C,CAC3D,MAAO,CACL,2DACA,4EACA,2EACA,yFACA,kEACA,kEACA,sCACA,yEACA,uEACA,6FACF,CACF,CAQA,eAAe,iBACb,EACA,EACe,CAEf,IAAM,EAAe,EAAW,QAAQ,CAAE,mBAAoBE,EAAG,WAAW,CAAa,CAAC,EAE1F,GAAI,EAAa,SAAW,EAAG,CAC7B,EAAO,KAAK,0CAA0C,EACtD,MACF,CAGA,EAAO,QAAQ,EACf,EAAO,KAAK,gDAAgD,EAC5D,IAAK,GAAM,CAAE,YAAW,mBAAmB,EACzC,EAAO,IAAI,OAAO,EAAU,IAAI,GAAe,EAEjD,EAAO,QAAQ,EAGV,IAME,MALsB,EAAO,QAAQ,CACxC,QAAS,qEACT,QAAS,EACX,CAAC,IAGC,EAAO,KAAK,sBAAsB,EAClC,QAAQ,KAAK,CAAC,GAEhB,EAAO,QAAQ,GAIjB,IAAK,GAAM,CAAE,YAAW,mBAAmB,EACzC,GAAI,CACF,MAAMC,EAAW,GAAG,EAAe,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,EACnE,EAAO,QAAQ,mCAAmC,EAAO,KAAK,CAAS,GAAG,CAC5E,OAAS,EAAO,CAEd,MADA,EAAO,MAAM,oBAAoB,EAAc,IAAI,GAAO,EACpD,CACR,CAGF,EAAO,QAAQ,EACf,EAAO,KAAK,+DAA+D,EAC3E,EAAO,QAAQ,CACjB,CAOA,eAAsB,SAAS,EAAyC,CACtE,eAAe,oBAAoB,EAGnC,GAAM,CAAE,SAAQ,WAAY,MAAM,WAAW,EAAQ,UAAU,EAIzD,EAAsD,4BAC1D,EAJgB,EAAK,QAAQ,EAAO,IAKpC,CACF,EAEA,GAAI,EAAyB,SAAW,EAAG,CACzC,EAAO,KAAK,sDAAsD,EAClE,EAAO,KACL,4FACF,EACA,MACF,CAMA,IAAM,EAA4B,CAAC,EAC7B,EAAoC,CAAC,EACrC,EAA8C,CAAC,EACrD,IAAK,IAAM,KAAO,EAAQ,SAAW,CAAC,EAAG,CACvC,IAAM,EAAQ,YAAY,CAAG,EACzB,GAAS,EACX,EAAkB,KAAK,CAAE,MAAK,KAAM,8BAA8B,CAAG,CAAE,CAAC,EAC/D,IAAU,EACnB,EAAY,KAAK,CAAE,MAAK,KAAM,kBAAkB,CAAG,CAAE,CAAC,EAEtD,EAAgB,KAAK,CAAE,MAAK,KAAM,sBAAsB,CAAG,CAAE,CAAC,CAElE,CACA,IAAM,EAAwB,CAAC,EACzB,EAAgC,CAAC,EACjC,EAA0C,CAAC,EACjD,IAAK,IAAM,KAAO,EAAQ,OAAS,CAAC,EAAG,CACrC,IAAM,EAAQ,YAAY,CAAG,EACzB,GAAS,EACX,EAAgB,KAAK,CAAE,MAAK,KAAM,4BAA4B,CAAG,CAAE,CAAC,EAC3D,IAAU,EACnB,EAAU,KAAK,CAAE,MAAK,KAAM,gBAAgB,CAAG,CAAE,CAAC,EAElD,EAAc,KAAK,CAAE,MAAK,KAAM,oBAAoB,CAAG,CAAE,CAAC,CAE9D,CACA,IAAM,GAA6C,EAAQ,iBAAmB,CAAC,EAAA,CAAG,IAAK,IAAS,CAC9F,MACA,KAAM,0BAA0B,CAAG,CACrC,EAAE,EAGI,EACJ,EAAY,OAAS,GACrB,EAAgB,OAAS,GACzB,EAAkB,OAAS,GAC3B,EAAU,OAAS,GACnB,EAAc,OAAS,GACvB,EAAgB,OAAS,EAC3B,GAAI,EAAQ,OAAS,GAAwB,EAAoB,OAAS,GACxE,MAAM,EAAS,CACb,KAAM,sCACN,QAAS,+EACT,QAAS,6BACX,CAAC,EAEH,IAAM,EAAmB,IAAI,IAC3B,EAAU,KAAK,CAAE,UAAW,GAAG,EAAK,UAAU,GAAG,EAAK,WAAW,CACnE,EACM,EAAmB,EAAY,QAAQ,CAAE,UAC7C,EAAiB,IAAI,GAAG,EAAK,UAAU,GAAG,EAAK,mBAAmB,CACpE,EACA,GAAI,EAAiB,OAAS,EAC5B,MAAM,EAAS,CACb,KAAM,iCACN,QAAS,qCAAqC,EAC3C,KAAK,CAAE,UAAW,GAAG,EAAK,UAAU,GAAG,EAAK,mBAAmB,CAAC,CAChE,KAAK,IAAI,IACZ,QAAS,6BACX,CAAC,EAEH,IAAM,EAAoB,IAAI,IAAI,EAAgB,KAAK,CAAE,UAAW,gBAAgB,CAAI,CAAC,CAAC,EACpF,EAAyB,EAAkB,QAAQ,CAAE,UACzD,EAAkB,IAAI,gBAAgB,CAAE,GAAG,EAAM,KAAM,EAAK,YAAa,CAAC,CAAC,CAC7E,EACA,GAAI,EAAuB,OAAS,EAClC,MAAM,EAAS,CACb,KAAM,iCACN,QAAS,qCAAqC,EAC3C,KAAK,CAAE,UAAW,gBAAgB,CAAE,GAAG,EAAM,KAAM,EAAK,YAAa,CAAC,CAAC,CAAC,CACxE,KAAK,IAAI,IACZ,QAAS,6BACX,CAAC,EAEH,IAAM,EAAmB,IAAI,IAAI,EAAc,KAAK,CAAE,UAAW,EAAK,SAAS,CAAC,EAC1E,EAAuB,EAAgB,QAAQ,CAAE,UACrD,EAAiB,IAAI,EAAK,iBAAiB,CAC7C,EACA,GAAI,EAAqB,OAAS,EAChC,MAAM,EAAS,CACb,KAAM,iCACN,QAAS,qCAAqC,EAC3C,KAAK,CAAE,UAAW,EAAK,iBAAiB,CAAC,CACzC,KAAK,IAAI,IACZ,QAAS,6BACX,CAAC,EAEH,GAAI,EAAQ,YAAc,IAAA,IAAa,CAAC,EAAQ,SAC9C,MAAM,EAAS,CACb,KAAM,sCACN,QAAS,0DACT,QAAS,6BACX,CAAC,EAIH,GACE,EAAQ,WACP,EAAQ,MAAQ,GAAwB,EAAoB,OAAS,GAEtE,MAAM,EAAS,CACb,KAAM,sCACN,QACE,4FACF,QAAS,6BACX,CAAC,EAGH,IAAM,EAA0B,EAAQ,SACpC,uBAAuB,EAA0B,EAAQ,SAAS,EAClE,IAAA,GACE,EACJ,IAA4B,IAAA,GACxB,EACA,EAAyB,QAAQ,CAAE,eAAgB,IAAc,CAAuB,EAG1F,EAAQ,MACV,MAAM,iBAAiB,EAA0B,EAAQ,GAAG,EAI9D,IAAI,EACA,EAAQ,OAAS,IACnB,EAAgB,IAAI,GAAc,CAAO,GAI3C,GAAM,CAAE,qBAAsB,MAAM,OAAO,8BACrC,EAAc,EAAkB,CAAE,SAAQ,eAAc,CAAC,EAIzD,EAAqC,CAAC,EAC5C,IAAK,GAAM,CAAE,YAAW,mBAAmB,EAAkB,CAC3D,EAAO,KAAK,yBAAyB,EAAO,KAAK,CAAS,GAAG,EAG7D,0BAA0B,EAAe,CAAS,EAGlD,IAAM,EAAkB,EAAY,iBAAiB,KAAM,GAAM,EAAE,YAAc,CAAS,EAC1F,GAAI,CAAC,EAAiB,CACpB,EAAO,KAAK,4CAA4C,EAAU,EAAE,EACpE,QACF,CAGA,MAAM,EAAgB,UAAU,EAChC,MAAM,EAAgB,wBAAwB,EAE9C,IAAM,EAAgB,EAAgB,MAEtC,EAAY,KAAK,CACf,YACA,gBAEA,gBAAiB,6BAA6B,EAAe,CAAS,EAGtE,iBAAkB,kCAAkC,CAAa,CACnE,CAAC,CACH,CAEA,GAAI,IAA4B,IAAA,GAAW,CACzC,MAAM,0BAA0B,EAAa,EAAyB,CAAO,EAC7E,MACF,CAKA,IAAM,EAAyB,uBAC7B,EACA,EACA,kBACA,sDACF,EACM,GAA6B,uBACjC,EACA,EACA,sBACA,sDACF,EACM,GAAuB,uBAC3B,EACA,EACA,gBACA,uCACF,EACM,GAA2B,uBAC/B,EACA,EACA,oBACA,uCACF,EACM,GAA+B,uBACnC,EACA,EACA,8BACA,8DACF,EACM,GAA6B,uBACjC,EACA,EACA,4BACA,+CACF,EAEM,GAAgC,IAAI,IACpC,GAA6B,IAAI,IACjC,GAAsC,CAAC,EAC7C,IAAK,GAAM,CAAE,YAAW,mBAAkB,qBAAqB,EAAa,CAC1E,GAAI,CAAC,EAAkB,SACvB,IAAM,EAAmC,CAAC,EAC1C,IAAK,IAAM,KAAQ,EAAqB,CACtC,GAAM,CAAE,QAAS,EACX,EAAS,EAAiB,OAAO,EAAK,UAAU,EAAE,OAAO,EAAK,WAC9D,EAAQ,EAAgB,OAAO,EAAK,UAAU,EAAE,OAAO,EAAK,WAClE,GAAI,CAAC,GAAU,CAAC,GAAS,CAAC,oBAAoB,EAAQ,CAAK,EAAG,SAC9D,GAA2B,IAAI,CAAI,EACnC,IAAM,EAAc,6BAA6B,CAC/C,SAAU,EACV,QAAS,EACT,UAAW,EAAK,UAChB,UAAW,EAAK,SAClB,CAAC,EACD,GAAI,CAAC,EAAY,SAAU,CACzB,GAA0B,KACxB,oCAAoC,EAAK,IAAI,eAAe,EAAU,KAAK,EAAY,QACzF,EACA,QACF,CACA,EAAW,KAAK,CAAI,CACtB,CACA,GAA8B,IAC5B,EACA,IAAI,IAAI,EAAW,KAAK,CAAE,UAAW,SAAS,EAAK,UAAW,EAAK,SAAS,CAAC,CAAC,CAChF,CACF,CACA,IAAM,GAAwB,EAAoB,OAC/C,GAAS,CAAC,GAA2B,IAAI,CAAI,CAChD,EACA,GAAI,GAAsB,OAAS,EACjC,MAAM,EAAS,CACb,KAAM,sCACN,QAAS,8EAA8E,GACpF,IAAK,GAAS,EAAK,GAAG,CAAC,CACvB,KAAK,IAAI,IACZ,QAAS,6BACX,CAAC,EAEH,GAAI,GAA0B,OAAS,EACrC,MAAM,EAAS,CACb,KAAM,uCACN,QAAS,GAA0B,KAAK;CAAI,CAC9C,CAAC,EAOH,IAAM,GAAoD,CAAC,EAC3D,IAAK,IAAM,KAAc,EAAa,CACpC,GAAM,CAAE,YAAW,mBAAkB,mBAAoB,EACzD,GAAI,CAAC,EAAkB,SACvB,IAAM,EAAO,iBAAiB,EAAkB,CAAe,EAC/D,GAAI,CAAC,WAAW,CAAI,EAAG,CACrB,EAAW,KAAO,EAClB,QACF,CACA,IAAM,EAAa,MAAM,eAAe,EAAkB,EAAiB,EAAM,EAAS,CACxF,aAAc,EAAuB,IAAI,CAAS,GAAK,CAAC,EACxD,YAAa,GAA2B,IAAI,CAAS,GAAK,CAAC,EAC3D,WAAY,GAAqB,IAAI,CAAS,GAAK,CAAC,EACpD,UAAW,GAAyB,IAAI,CAAS,GAAK,CAAC,EACvD,oBAAqB,GAA6B,IAAI,CAAS,GAAK,CAAC,EACrE,kBAAmB,GAA2B,IAAI,CAAS,GAAK,CAAC,CACnE,CAAC,EACD,EAAW,KAAO,EAAW,KAC7B,GAAqB,KAAK,GAAG,EAAW,UAAU,EAClD,EAAW,YAAc,MAAM,2BAA2B,CACxD,mBACA,kBACA,KAAM,EAAW,KACjB,UACA,cAAe,GAA8B,IAAI,CAAS,GAAK,IAAI,GACrE,CAAC,CACH,CAKA,GAAI,GAAqB,OAAS,EAAG,CACnC,IAAM,EAAU,GACb,KACE,CAAE,YAAW,QAAO,aACnB,OAAO,EAAM,KAAK,EAAQ,KAAK,IAAI,EAAE,gBAAgB,EAAU,EACnE,CAAC,CACA,KAAK;CAAI,EACZ,MAAM,EAAS,CACb,KAAM,8BACN,QAAS,iCAAiC,IAC1C,WACE,iTACF,QAAS,6BACX,CAAC,CACH,CAEA,IAAK,GAAM,CACT,gBACA,kBACA,mBACA,OACA,iBACG,EACE,EAIH,MAAM,yBACJ,EACA,EAAc,EAAM,kDAAkD,EACtE,EACA,EACA,EACA,GAAe,CAAC,CAClB,EATA,MAAM,wBAAwB,EAAiB,CAAa,CAYlE,CAUA,eAAe,0BACb,EACA,EACA,EACe,CACf,IAAM,EAAa,EAAY,KAAM,GAAM,EAAE,YAAc,CAAS,EACpE,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,+BACN,QAAS,4CAA4C,EAAU,EACjE,CAAC,EAEH,GAAM,CAAE,gBAAe,mBAAkB,mBAAoB,EAC7D,GAAI,CAAC,EACH,MAAM,EAAS,CACb,KAAM,+BACN,QAAS,cAAc,EAAU,8BACjC,WAAY,2CACd,CAAC,EAGH,IAAM,EAAO,iBAAiB,EAAkB,CAAe,EAC/D,GAAI,WAAW,CAAI,EAIjB,MAHA,EAAO,QAAQ,EACf,EAAO,IAAI,oBAAoB,CAAI,CAAC,EACpC,EAAO,QAAQ,EACT,EAAS,CACb,KAAM,mCACN,QAAS,cAAc,EAAU,uDACjC,WAAY,qEACd,CAAC,EAGH,IAAM,EAAkB,uBAAuB,CAAa,EACtD,EAAS,MAAM,+BAA+B,CAClD,KAAM,CAAE,GAAG,EAAM,wBAAyB,EAAK,EAC/C,gBACA,kBACA,SAAU,EACV,YAAa,EAAQ,IACvB,CAAC,EAED,EAAO,QACL,iCAAiC,EAAO,KAAK,sBAAsB,EAAO,eAAe,CAAC,GAC5F,EACA,EAAO,KAAK,gBAAgB,EAAO,cAAc,EACjD,EAAO,KAAK,uBAAuB,EAAO,iBAAiB,EAC3D,EAAO,KAAK,eAAe,EAAO,iBAAiB,EACnD,sBAAsB,CAAM,EAC5B,EAAO,QAAQ,EACf,EAAO,IAAI,2CAA2C,EACtD,EAAO,IACL,sFACF,EAEA,MAAM,4BAA4B,EAAO,eAAe,CAC1D,CAMA,SAAS,sBAAsB,EAGtB,CACH,EAAO,sBACT,EAAO,KAAK,oBAAoB,EAAO,sBAAsB,EAE3D,EAAO,mBACT,EAAO,KAAK,4BAA4B,EAAO,mBAAmB,CAEtE,CAQA,eAAe,4BAA4B,EAAwC,CACjF,IAAM,EAAS,2BAA2B,EACrC,KAIL,IAAI,CACF,MAAMA,EAAW,OAAO,CAAe,CACzC,MAAQ,CACN,MACF,CAEA,EAAO,QAAQ,EACf,EAAO,KAAK,WAAW,EAAK,SAAS,CAAe,EAAE,MAAM,EAAO,IAAI,EAEvE,GAAI,CACF,MAAM,uBAAuB,CAAe,CAC9C,MAAQ,CACN,MACF,CATA,CAUF,CAiBA,eAAe,2BACb,EAC+B,CAC/B,GAAM,CAAE,mBAAkB,kBAAiB,OAAM,UAAS,iBAAkB,EACtE,EAAY,IAAI,IAAI,CAAa,EAEvC,GAAI,CAAC,EAAQ,KAAO,UAAU,EAC5B,IAAK,IAAM,KAAU,EAAK,QAAS,CACjC,GAAI,CAAC,0BAA0B,CAAM,EAAG,SACxC,IAAM,EAAM,SAAS,EAAO,UAAW,EAAO,SAAS,EACnD,EAAU,IAAI,CAAG,GAElB,gBAAgB,CACf,SAAU,EACV,QAAS,EACT,UAAW,EAAO,UAClB,UAAW,EAAO,SACpB,CAAC,IAKH,EAAO,QAAQ,EACf,EAAO,KACL,GAAG,EAAO,UAAU,GAAG,EAAO,UAAU,gBAAgB,iBAAiB,EAAO,MAAM,EAAE,MAAM,iBAAiB,EAAO,KAAK,EAAE,uCAC/H,EAKI,MAJmB,EAAO,QAAQ,CACpC,QAAS,sCAAsC,EAAO,UAAU,GAAG,EAAO,UAAU,6BACpF,QAAS,EACX,CAAC,GACa,EAAU,IAAI,CAAG,EACjC,CAGF,OAAO,mBAAmB,CACxB,SAAU,EACV,QAAS,EACT,OACA,WACF,CAAC,CAAC,CAAC,KACL,CAQA,eAAe,wBACb,EACA,EACe,CACf,IAAM,EAAS,MAAM,mBAAmB,EAAU,EAAA,CAAoC,EAEtF,EAAO,QAAQ,mCAAmC,EAClD,EAAO,KAAK,WAAW,EAAO,UAAU,EACxC,EAAO,KAAK,aAAa,OAAO,KAAK,EAAS,MAAM,CAAC,CAAC,QAAQ,EAE9D,EAAO,IAAI;sEAAyE,CACtF,CA0BA,SAAS,YAAY,EAAqB,CACxC,OAAQ,EAAI,MAAM,GAAG,CAAC,CAAC,IAAM,GAAA,CAAI,MAAM,GAAG,CAAC,CAAC,OAAS,CACvD,CAgBA,SAAS,gBAAgB,EAAsC,CAC7D,MAAO,GAAG,EAAO,UAAU,GAAG,EAAO,UAAU,GAAG,EAAO,KAAK,KAAK,GAAG,GACxE,CAYA,SAAS,uBACP,EACA,EACA,EACA,EACkB,CAClB,IAAM,EAAmB,IAAI,IACvB,EAAU,IAAI,IACpB,IAAK,GAAM,CAAE,YAAW,mBAAkB,qBAAqB,EAAa,CAC1E,GAAI,CAAC,EAAkB,SACvB,IAAM,EAAa,EAAM,QAAQ,CAAE,UAAW,EAAQ,EAAM,EAAkB,CAAe,CAAC,EAC9F,IAAK,IAAM,KAAQ,EACjB,EAAQ,IAAI,CAAI,EAElB,EAAiB,IACf,EACA,EAAW,IAAK,GAAS,EAAK,IAAI,CACpC,CACF,CACA,IAAM,EAAS,EAAM,OAAQ,GAAS,CAAC,EAAQ,IAAI,CAAI,CAAC,EACxD,GAAI,EAAO,OAAS,EAClB,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,GAAG,EAAe,IAAI,EAAO,IAAK,GAAS,EAAK,GAAG,CAAC,CAAC,KAAK,IAAI,IACvE,QAAS,6BACX,CAAC,EAEH,OAAO,CACT,CA8DA,SAAS,mCACP,EACA,EACU,CACV,IAAM,EAAS,EAAU,aAAa,MAAM,EAAG,EAAE,EACjD,OAAO,EAAU,MAAM,OACpB,GAAS,CAAC,EAAe,IAAI,gBAAgB,CAAE,GAAG,EAAW,KAAM,CAAC,GAAG,EAAQ,CAAI,CAAE,CAAC,CAAC,CAC1F,CACF,CASA,eAAe,kCACb,EACA,EAC6B,CAC7B,IAAM,EAAW,gBAAgB,CAAE,GAAG,EAAW,KAAM,EAAU,YAAa,CAAC,EACzE,EAAU,EAAU,aAAa,EAAU,aAAa,OAAS,IAAM,GACvE,CAAC,GAAa,EAkBpB,OAjBI,EAAW,SAAW,GAAK,EAKtB,MAJgB,EAAO,QAAQ,CACpC,QAAS,GAAG,EAAS,mBAAmB,EAAU,uDAAuD,EAAU,GACnH,QAAS,EACX,CAAC,EACiB,EAAY,IAAA,GAYzB,MAVgB,EAAO,OAAO,CACnC,QAAS,GAAG,EAAS,6DACrB,QAAS,CACP,GAAG,EAAW,IAAK,IAAU,CAC3B,KAAM,mBAAmB,IACzB,MAAO,CACT,EAAE,EACF,CAAE,KAAM,OAAO,EAAQ,cAAe,MAAO,IAAK,CACpD,CACF,CAAC,GACkB,IAAA,EACrB,CAEA,SAAS,uBACP,EACA,EACU,CACV,OAAO,EAAU,MACd,OAAQ,GAAU,CAAC,EAAc,IAAI,GAAG,EAAU,UAAU,GAAG,EAAM,WAAW,CAAC,CAAC,CAClF,IAAK,GAAU,EAAM,SAAS,CACnC,CASA,eAAe,sBACb,EACA,EAC6B,CAC7B,IAAM,EAAW,GAAG,EAAU,UAAU,GAAG,EAAU,QAAQ,YACvD,CAAC,GAAkB,EAkBzB,OAjBI,EAAgB,SAAW,GAAK,EAK3B,MAJgB,EAAO,QAAQ,CACpC,QAAS,GAAG,EAAS,mBAAmB,EAAe,uDAAuD,EAAe,GAC7H,QAAS,EACX,CAAC,EACiB,EAAiB,IAAA,GAY9B,MAVgB,EAAO,OAAO,CACnC,QAAS,GAAG,EAAS,4DACrB,QAAS,CACP,GAAG,EAAgB,IAAK,IAAe,CACrC,KAAM,mBAAmB,IACzB,MAAO,CACT,EAAE,EACF,CAAE,KAAM,OAAO,EAAU,QAAQ,UAAU,cAAe,MAAO,IAAK,CACxE,CACF,CAAC,GACkB,IAAA,EACrB,CAEA,SAAS,2BACP,EACA,EACU,CACV,OAAO,EAAU,MACd,OAAQ,GAAU,CAAC,EAAa,IAAI,EAAM,SAAS,CAAC,CAAC,CACrD,IAAK,GAAU,EAAM,SAAS,CACnC,CASA,eAAe,0BACb,EACA,EAC6B,CAC7B,IAAM,EAAc,EAAU,QAAQ,UAChC,CAAC,GAAiB,EAkBxB,OAjBI,EAAe,SAAW,GAAK,EAK1B,MAJgB,EAAO,QAAQ,CACpC,QAAS,GAAG,EAAY,mBAAmB,EAAc,yDAAyD,EAAc,GAChI,QAAS,EACX,CAAC,EACiB,EAAgB,IAAA,GAY7B,MAVgB,EAAO,OAAO,CACnC,QAAS,GAAG,EAAY,4DACxB,QAAS,CACP,GAAG,EAAe,IAAK,IAAe,CACpC,KAAM,mBAAmB,IACzB,MAAO,CACT,EAAE,EACF,CAAE,KAAM,OAAO,EAAY,cAAe,MAAO,IAAK,CACxD,CACF,CAAC,GACkB,IAAA,EACrB,CAeA,eAAe,eACb,EACA,EACA,EACA,EACA,EAC2B,CAC3B,IAAM,EAA+B,CAAC,GAAG,EAAM,YAAY,EACrD,EAAgB,IAAI,IACxB,EAAU,QAAS,GAAS,CAC1B,GAAG,EAAK,UAAU,GAAG,EAAK,oBAC1B,GAAG,EAAK,UAAU,GAAG,EAAK,WAC5B,CAAC,CACH,EACM,EAAgB,IAAI,IACxB,EAAM,WAAW,IAAK,GAAS,GAAG,EAAK,UAAU,GAAG,EAAK,WAAW,CACtE,EACM,EAAmC,CAAC,GAAG,EAAM,WAAW,EACxD,EAAe,IAAI,IACvB,EAAe,QAAS,GAAS,CAAC,EAAK,kBAAmB,EAAK,SAAS,CAAC,CAC3E,EACM,EAAe,IAAI,IAAI,EAAM,UAAU,IAAK,GAAS,EAAK,SAAS,CAAC,EACpE,EAA4C,CAAC,GAAG,EAAM,mBAAmB,EACzE,EAAiB,IAAI,IACzB,EAAgB,QAAS,GAAS,CAChC,gBAAgB,CAAE,GAAG,EAAM,KAAM,EAAK,YAAa,CAAC,EACpD,gBAAgB,CAAI,CACtB,CAAC,CACH,EACM,EAAiB,IAAI,IAAI,EAAM,kBAAkB,IAAK,GAAS,gBAAgB,CAAI,CAAC,CAAC,EAErF,EAAiB,yBAAyB,CAAI,CAAC,CAAC,OACnD,GACC,CAAC,EAAa,IAAI,EAAU,QAAQ,SAAS,GAC7C,CAAC,EAAa,IAAI,EAAU,QAAQ,SAAS,GAC7C,2BAA2B,EAAW,CAAY,CAAC,CAAC,OAAS,CACjE,EACM,EAAa,qBAAqB,CAAI,CAAC,CAAC,OAC3C,GACC,CAAC,EAAc,IAAI,GAAG,EAAU,UAAU,GAAG,EAAU,QAAQ,WAAW,GAC1E,CAAC,EAAc,IAAI,GAAG,EAAU,UAAU,GAAG,EAAU,QAAQ,WAAW,GAC1E,uBAAuB,EAAW,CAAa,CAAC,CAAC,OAAS,CAC9D,EACM,EAAmB,iCAAiC,CAAI,CAAC,CAAC,OAAQ,GAAc,CACpF,IAAM,EAAM,gBAAgB,CAAE,GAAG,EAAW,KAAM,EAAU,YAAa,CAAC,EAC1E,MACE,CAAC,EAAe,IAAI,CAAG,GACvB,CAAC,EAAe,IAAI,CAAG,GACvB,mCAAmC,EAAW,CAAc,CAAC,CAAC,OAAS,CAE3E,CAAC,EAEK,EAA0C,CAAC,EACjD,GAAI,EAAQ,KAAO,CAAC,UAAU,EAAG,CAC/B,IAAK,IAAM,KAAa,EACtB,EAAW,KAAK,CACd,UAAW,EAAK,UAChB,MAAO,EAAU,QAAQ,UACzB,QAAS,2BAA2B,EAAW,CAAY,CAC7D,CAAC,EAEH,IAAK,IAAM,KAAa,EACtB,EAAW,KAAK,CACd,UAAW,EAAK,UAChB,MAAO,GAAG,EAAU,UAAU,GAAG,EAAU,QAAQ,YACnD,QAAS,uBAAuB,EAAW,CAAa,CAC1D,CAAC,EAEH,IAAK,IAAM,KAAa,EACtB,EAAW,KAAK,CACd,UAAW,EAAK,UAChB,MAAO,gBAAgB,CAAE,GAAG,EAAW,KAAM,EAAU,YAAa,CAAC,EACrE,QAAS,mCAAmC,EAAW,CAAc,CACvE,CAAC,CAEL,KAAO,CACL,IAAK,IAAM,KAAa,EAAgB,CACtC,IAAM,EAAiB,2BAA2B,EAAW,CAAY,EACzE,GAAI,EAAe,SAAW,EAAG,SACjC,IAAM,EAAc,MAAM,0BAA0B,EAAW,CAAc,EACzE,IACF,EAAe,KAAK,CAClB,kBAAmB,EAAU,QAAQ,UACrC,UAAW,CACb,CAAC,EACD,EAAa,IAAI,EAAU,QAAQ,SAAS,EAC5C,EAAa,IAAI,CAAW,EAEhC,CACA,IAAK,IAAM,KAAa,EAAY,CAClC,IAAM,EAAkB,uBAAuB,EAAW,CAAa,EACvE,GAAI,EAAgB,SAAW,EAAG,SAClC,IAAM,EAAe,MAAM,sBAAsB,EAAW,CAAe,EACvE,IACF,EAAU,KAAK,CACb,UAAW,EAAU,UACrB,kBAAmB,EAAU,QAAQ,UACrC,UAAW,CACb,CAAC,EACD,EAAc,IAAI,GAAG,EAAU,UAAU,GAAG,EAAU,QAAQ,WAAW,EACzE,EAAc,IAAI,GAAG,EAAU,UAAU,GAAG,GAAc,EAE9D,CACA,IAAK,IAAM,KAAa,EAAkB,CACxC,IAAM,EAAa,mCAAmC,EAAW,CAAc,EAC/E,GAAI,EAAW,SAAW,EAAG,SAC7B,IAAM,EAAU,MAAM,kCAAkC,EAAW,CAAU,EAC7E,GAAI,EAAS,CACX,IAAM,EAA+B,CACnC,UAAW,EAAU,UACrB,UAAW,EAAU,UACrB,aAAc,EAAU,aACxB,KAAM,CAAC,GAAG,EAAU,aAAa,MAAM,EAAG,EAAE,EAAG,CAAO,CACxD,EACA,EAAgB,KAAK,CAAI,EACzB,EAAe,IAAI,gBAAgB,CAAE,GAAG,EAAM,KAAM,EAAK,YAAa,CAAC,CAAC,EACxE,EAAe,IAAI,gBAAgB,CAAI,CAAC,CAC1C,CACF,CACF,CAKA,OAHI,EAAU,SAAW,GAAK,EAAe,SAAW,GAAK,EAAgB,SAAW,EAC/E,CAAE,OAAM,YAAW,EAErB,CACL,KAAM,iBAAiB,EAAkB,EAAiB,CACxD,aAAc,EACd,YAAa,EACb,oBAAqB,CACvB,CAAC,EACD,YACF,CACF,CAYA,eAAe,yBACb,EACA,EACA,EACA,EACA,EACA,EAA6C,CAAC,EAC/B,CACf,GAAI,CAAC,WAAW,CAAI,EAAG,CACrB,EAAO,KAAK,iCAAiC,EAC7C,MACF,CAGA,EAAO,QAAQ,EACf,EAAO,IAAI,oBAAoB,CAAI,CAAC,EACpC,EAAO,QAAQ,EACf,EAAO,KAAK,YAAY,kBAAkB,CAAI,GAAG,EAEjD,IAAM,EAAc,IAAI,IAAI,EAAY,IAAK,GAAS,SAAS,EAAK,UAAW,EAAK,SAAS,CAAC,CAAC,EACzF,EAAqB,EAAK,gBAAgB,OAC7C,GACC,EAAO,aACP,EAAE,EAAO,WAAa,EAAY,IAAI,SAAS,EAAO,UAAW,EAAO,SAAS,CAAC,EACtF,EACA,GAAI,EAAmB,OAAS,EAAG,CACjC,IAAK,IAAM,KAAU,EACnB,EAAO,QAAQ,EACf,EAAO,MAAM,uBAAuB,EAAO,UAAU,GAAG,EAAO,WAAW,EAC1E,EAAO,MAAM,KAAK,EAAO,QAAQ,EAInC,IAAM,EAAc,IAAI,IACxB,IAAK,GAAM,CAAE,YAAW,eAAe,EAEnC,IAAc,IAAA,IACd,gBAAgB,CACd,SAAU,EACV,QAAS,EACT,YACA,WACF,CAAC,GAED,EAAY,IAAI,SAAS,EAAW,CAAS,CAAC,EAGlD,GAAI,EAAY,KAAO,EAAG,CACxB,EAAO,QAAQ,EACf,EAAO,KAAK,sDAAsD,EAClE,IAAK,IAAM,KAAO,EAChB,EAAO,KAAK,wBAAwB,EAAI,EAAE,CAE9C,CAGA,GAAI,EAAmB,KAAM,GAAW,EAAO,iBAAiB,EAAG,CACjE,EAAO,QAAQ,EACf,IAAK,IAAM,KAAQ,iCAAiC,EAClD,EAAO,KAAK,CAAI,CAEpB,CAEA,IAAM,EAAU,EACb,IAAK,GAAM,OAAO,EAAE,UAAU,GAAG,EAAE,UAAU,IAAI,EAAE,QAAQ,CAAC,CAC5D,KAAK;CAAI,EACZ,MAAM,EAAS,CACb,KAAM,sCACN,QAAS,yCAAyC,GACpD,CAAC,CACH,CAGA,GAAI,EAAK,qBACP,EAAO,QAAQ,EACf,EAAO,KAAK,sBAAsB,EAAK,eAAe,CAAC,EAEnD,CAAC,EAAQ,KAAK,CAMhB,GAAI,CAAC,MALsB,EAAO,QAAQ,CACxC,QAAS,iCACT,QAAS,EACX,CAAC,EAEkB,CACjB,EAAO,KAAK,iCAAiC,EAC7C,MACF,CACA,EAAO,QAAQ,CACjB,CASF,GALI,EAAK,cACP,EAAO,QAAQ,EACf,EAAO,KAAK,eAAe,EAAK,QAAQ,CAAC,GAGvC,EAAY,OAAS,EAAG,CAC1B,MAAM,iCAAiC,CACrC,mBACA,kBACA,aAAc,EACd,MAAO,EACP,gBACA,YAAa,EAAQ,IACvB,CAAC,EACD,MACF,CAMA,IAAM,EAAS,MAAM,kBACnB,EACA,EALsB,uBAAuB,CAM7C,EACA,EACA,EAAQ,IACV,EAEA,EAAO,QACL,uBAAuB,EAAO,KAAK,sBAAsB,EAAO,eAAe,CAAC,GAClF,EACA,EAAO,KAAK,gBAAgB,EAAO,cAAc,EAE7C,EAAO,iBACT,EAAO,KAAK,uBAAuB,EAAO,iBAAiB,EACvD,EAAO,kBACT,EAAO,KAAK,eAAe,EAAO,iBAAiB,EACnD,sBAAsB,CAAM,GAE9B,EAAO,QAAQ,EACf,EAAO,IAAI,wDAAwD,EACnE,EAAO,IAAI,mEAAmE,EAE9E,MAAM,4BAA4B,EAAO,eAAe,GAC/C,EAAK,aACd,MAAM,oBAAoB,CACxB,UAAW,EAAK,UAChB,gBACA,gBAAiB,EAAO,gBACxB,WAAY,EAAQ,IACpB,WAAY,EAAQ,UACtB,CAAC,CAEL,CAkBA,eAAe,iCACb,EACe,CACf,GAAM,CAAE,mBAAkB,kBAAiB,eAAc,QAAO,gBAAe,eAC7E,EACI,EAAuB,0BAA0B,EAAkB,CAAK,EAGxE,EAAa,gBAAgB,EAAkB,EAAsB,CAAK,EAC1E,EAA2C,EAAa,QAC3D,OAAQ,GAAW,EAAO,OAAS,eAAe,CAAC,CACnD,KAAK,CAAE,YAAW,oBAAmB,gBAAiB,CACrD,YACA,oBACA,WACF,EAAE,EACE,EAAyC,EAAa,QACzD,OAAQ,GAAW,EAAO,OAAS,eAAe,CAAC,CACnD,KAAK,CAAE,oBAAmB,gBAAiB,CAAE,oBAAmB,WAAU,EAAE,EAUzE,EAAe,iBAAiB,EAAsB,EAAiB,CAC3E,oBAVuD,EAAa,QAAQ,QAAS,GACrF,EAAO,OAAS,kBACX,EAAO,eAAiB,CAAC,EAAA,CAAG,IAAK,IAAY,CAC5C,UAAW,EAAO,UAClB,UAAW,EAAO,UAClB,GAAG,CACL,EAAE,EACF,CAAC,CAGgB,EACrB,aAAc,CACZ,GAAG,EACH,GAAG,EAAM,IAAK,IAAU,CACtB,UAAW,EAAK,UAChB,kBAAmB,EAAK,cACxB,UAAW,EAAK,SAClB,EAAE,CACJ,EACA,YAAa,CACf,CAAC,EAEK,EAAe,uBAAuB,CAAa,EACzD,GAAI,EAAe,EAAA,KACjB,MAAM,EAAS,CACb,KAAM,6BACN,QAAS,4DAA4D,sBAAsB,IAAoB,EAAE,6BACjH,WAAY,0CACd,CAAC,EAEH,IAAM,EAAS,MAAM,kBACnB,EACA,EACA,EACA,EACA,EACA,CACF,EACM,EAAW,MAAM,kBACrB,EACA,EACA,EAAe,EACf,EACA,CACF,EAEM,EAAS,EAAM,IAAK,GAAS,GAAG,EAAK,UAAU,GAAG,EAAK,WAAW,CAAC,CAAC,KAAK,IAAI,EACnF,EAAO,QACL,wBAAwB,EAAO,KAAK,sBAAsB,EAAO,eAAe,CAAC,EAAE,OAAO,EAAO,KAC/F,sBAAsB,EAAS,eAAe,CAChD,EAAE,cAAc,GAClB,EACA,EAAO,KAAK,iBAAiB,EAAO,aAAa,IAAI,EAAS,cAAc,EACxE,EAAO,iBACT,EAAO,KAAK,wBAAwB,EAAO,iBAAiB,EAE1D,EAAS,iBACX,EAAO,KAAK,kBAAkB,EAAS,iBAAiB,EAE1D,EAAO,QAAQ,EACf,EAAO,KACL,0BAA0B,sBAAsB,EAAO,eAAe,EAAE,wCAAwC,sBAC9G,EAAS,eACX,EAAE,gFACF,CAAE,KAAM,OAAQ,CAClB,EACA,EAAO,KAAK,kDAAmD,CAAE,KAAM,OAAQ,CAAC,CAClF,CAeA,eAAe,oBAAoB,EAAoD,CACrF,GAAM,CAAE,YAAW,gBAAe,kBAAiB,aAAY,cAAe,EACxE,EAAQ,sBAAsB,CAAe,EAKnD,GAHA,EAAO,QAAQ,EACf,EAAO,IAAI,uEAAuE,EAE9E,CAAC,GAAc,UAAU,GAKvB,MAJiB,EAAO,QAAQ,CAClC,QAAS,iFACT,QAAS,EACX,CAAC,EACW,CAKV,IAAM,EAAgB,2BAA2B,CAAE,gBAAe,kBAAiB,aAJ9D,EAAO,KAAK,CAC/B,QAAS,UACT,SAAW,GAAU,EAAM,KAAK,IAAM,IAAM,2BAC9C,CAAC,CACyF,CAAC,EAC3F,EAAO,QACL,2BAA2B,EAAO,KAAK,CAAK,EAAE,uCAChD,EACA,EAAO,KAAK,aAAa,EAAc,QAAQ,EAC/C,MACF,CAGF,IAAM,EAAiB,CAAE,kBAAiB,YAAW,YAAW,EAChE,EAAO,IAAI,kCAAkC,EAC7C,EAAO,IAAI,KAAK,EAAO,KAAK,6BAA6B,CAAc,CAAC,GAAG,EAC3E,EAAO,IAAI,iEAAiE,EAC5E,EAAO,IACL,KAAK,EAAO,KAAK,6BAA6B,CAAE,GAAG,EAAgB,SAAU,EAAK,CAAC,CAAC,GACtF,CACF,CAKA,MAAa,GAAkB,EAAiB,CAC9C,KAAM,WACN,YACE,6HACF,KAAM,EAAE,aAAa,CACnB,GAAG,GACH,GAAG,GACH,KAAM,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CAC/B,MAAO,IACP,YAAa,wCACf,CAAC,EACD,KAAM,EAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAK,EAAG,CACpC,YAAa,4CACf,CAAC,EACD,YAAa,EAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAK,EAAG,CAC3C,YACE,wGACJ,CAAC,EACD,UAAW,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CACpC,YACE,mFACJ,CAAC,EACD,OAAQ,EAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,EAAG,CAC1C,YACE,6OACJ,CAAC,EACD,KAAM,EAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,EAAG,CACxC,YACE,wOACJ,CAAC,EACD,kBAAmB,EAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,EAAG,CACrD,YACE,iJACJ,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,MAAM,SAAS,CACb,WAAY,EAAK,OACjB,KAAM,EAAK,KACX,IAAK,EAAK,IACV,KAAM,EAAK,KACX,SAAU,EAAK,aACf,UAAW,EAAK,UAChB,QAAS,EAAK,OACd,MAAO,EAAK,KACZ,gBAAiB,EAAK,kBACxB,CAAC,CACH,CACF,CAAC,ECv8CD,SAAS,0BAA0B,EAA2B,CAC5D,MAAO,EAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BA8HK,EAAU;;;;;;2BAMT,MAAmB;;;;;;2BAMnB,EAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAyChB,EAAU;;;;;;;;;;uBAUR,EAAU;;;;;;;;;;;;;;;;;;;;mBAoBd,EAAU;;;;;;6BAMA,EAAU;;;;;;;;;;GAWvC,CAOA,SAAS,8BAA8B,EAA2B,CAChE,MAAO,EAAY;;;;;;;;;;;;;;;;;;;;;;;;0BAwBK,EAAU;;;;;;;;;;;;;;;;;;;;;yBAqBX,EAAU;;;;;2BAKR,EAAU;;;;;;GAOrC,CAeA,eAAsB,iBACpB,EACA,EACA,EAAkB,QAAQ,IAAI,EACH,CAO3B,MAAO,CACL,YACA,YAAA,MARwB,qBAAqB,CAC7C,cAAe,QAAQ,EAAU,WACjC,aAAc,0BAA0B,CAAS,EACjD,SACF,CAAC,EAKC,cAAe,CACjB,CACF,CAYA,eAAsB,qBACpB,EACA,EAAkB,QAAQ,IAAI,EACC,CAO/B,MAAO,CAAE,YAAW,YAAA,MANM,qBAAqB,CAC7C,cAAe,aAAa,EAAU,WACtC,aAAc,8BAA8B,CAAS,EACrD,SACF,CAAC,CAE+B,CAClC,CAgBA,eAAe,qBAAqB,EAAqD,CACvF,GAAM,CAAE,gBAAe,eAAc,WAAY,EAG3C,EAAY,EAAK,QAAQ,GAAW,EAAG,MAAM,EACnD,EAAG,UAAU,EAAW,CAAE,UAAW,EAAK,CAAC,EAE3C,IAAM,EAAY,EAAK,KAAK,EAAW,CAAa,EACpD,EAAG,cAAc,EAAW,CAAY,EAExC,IAAI,EACJ,GAAI,CACF,EAAW,MAAM,GAAgB,CAAO,CAC1C,MAAQ,CACN,EAAW,IAAA,EACb,CAGA,IAAM,EAAY,GAAgB,CAAE,UAAS,CAAC,EACxC,EAAS,MAAM,GAAS,MAAM,CAClC,QAAS,CACP,GAAmC,EAAW,CAAO,EACrD,GAA0B,EAC1B,EACF,EACA,MAAO,EACP,MAAO,GACP,OAAQ,CACN,OAAQ,MACR,UAAW,GACX,OAAQ,GACR,cAAe,GACf,QAAS,CACP,SAAU,UACZ,CACF,EACA,SAAU,CAAC,UAAU,EACrB,QAAS,CACP,eAAgB,CAAC,OAAQ,QAAQ,CACnC,EACA,WACA,UAAW,CACT,kBAAmB,GACnB,YAAa,GACb,yBAA0B,EAC5B,EACA,GAAG,EAAU,OACf,CAA0B,EAG1B,OAFA,EAAU,kBAAkB,EAErB,EAAO,OAAO,EAAE,CAAC,IAC1B,CCxYA,SAAgB,cAAc,EAA4C,CACxE,GAAM,CAAE,OAAM,QAAO,eAAc,iBAAiB,SAA6B,EAE3E,EAAY,EAAiB,EAAe,KAClD,GAAI,GAAa,EACf,MAAU,MACR,cAAc,EAAa,0CAA0C,EAAe,sCAEtF,EAIF,IAAM,EAAgB,EAAM,OAAQ,IAAU,EAAK,EAAK,EAAE,QAAU,GAAK,CAAC,EAE1E,GAAI,EAAc,SAAW,EAC3B,MAAO,CAAC,EAKV,GAAI,SADY,KAAK,UAAU,CAAE,OAAM,OAAM,CAC1B,CAAC,GAAK,EACvB,MAAO,CAAC,CAAE,OAAM,QAAO,MAAO,EAAG,MAAO,CAAE,CAAC,EAI7C,IAAM,EAAqC,CAAC,EACxC,EAAwB,CAAC,EACzB,EAAyB,CAAC,EAE9B,IAAK,IAAM,KAAQ,EAAe,CAChC,IAAM,EAAc,EAAc,EAAK,GAAO,+BAA+B,GAAM,EAGnF,GAAI,EAAa,OAAS,EAAG,CAC3B,IAAM,EAAW,CAAE,GAAG,GAAc,GAAO,CAAY,EACjD,EAAY,CAAC,GAAG,EAAc,CAAI,EACpC,SAAS,KAAK,UAAU,CAAE,KAAM,EAAU,MAAO,CAAU,CAAC,CAAC,EAAI,IAEnE,EAAO,KAAK,CAAE,KAAM,EAAa,MAAO,EAAc,MAAO,EAAO,MAAO,CAAC,EAC5E,EAAc,CAAC,EACf,EAAe,CAAC,EAEpB,CAGA,GAAI,SAAS,KAAK,UAAU,CAAE,KAAM,EAAG,GAAO,CAAY,EAAG,MAAO,CAAC,CAAI,CAAE,CAAC,CAAC,GAAK,EAAW,CAC3F,EAAY,GAAQ,EACpB,EAAa,KAAK,CAAI,EACtB,QACF,CAGI,EAAa,OAAS,IACxB,EAAO,KAAK,CAAE,KAAM,EAAa,MAAO,EAAc,MAAO,EAAO,MAAO,CAAC,EAC5E,EAAc,CAAC,EACf,EAAe,CAAC,GAGlB,IAAI,EAA4B,CAAC,EACjC,IAAK,IAAM,KAAU,EAAa,CAChC,GAAI,SAAS,KAAK,UAAU,CAAE,KAAM,EAAG,GAAO,CAAC,CAAM,CAAE,EAAG,MAAO,CAAC,CAAI,CAAE,CAAC,CAAC,EAAI,EAAW,CACvF,IAAM,EAAmB,SAAS,KAAK,UAAU,CAAM,CAAC,EACxD,MAAU,MACR,6BAA6B,EAAK,KAAK,EAAiB,2CAClD,EAAU,yEAClB,CACF,CAEA,IAAM,EAAY,CAAC,GAAG,EAAa,CAAM,EACnC,EAAW,CAAE,GAAG,GAAc,GAAO,CAAU,EAC/C,EAAY,EAAa,SAAS,CAAI,EAAI,EAAe,CAAC,GAAG,EAAc,CAAI,EACpE,SAAS,KAAK,UAAU,CAAE,KAAM,EAAU,MAAO,CAAU,CAAC,CAElE,EAAI,GAAa,EAAY,OAAS,GAE/C,EAAY,GAAQ,EACf,EAAa,SAAS,CAAI,GAC7B,EAAa,KAAK,CAAI,EAExB,EAAO,KAAK,CAAE,KAAM,EAAa,MAAO,EAAc,MAAO,EAAO,MAAO,CAAC,EAC5E,EAAc,CAAC,EACf,EAAe,CAAC,EAChB,EAAc,CAAC,CAAM,GAErB,EAAc,CAElB,CAGI,EAAY,OAAS,IACvB,EAAY,GAAQ,EACf,EAAa,SAAS,CAAI,GAC7B,EAAa,KAAK,CAAI,EAG5B,CAGI,EAAa,OAAS,GACxB,EAAO,KAAK,CAAE,KAAM,EAAa,MAAO,EAAc,MAAO,EAAO,MAAO,CAAC,EAG9E,IAAM,EAAQ,EAAO,OACrB,OAAO,EAAO,IAAK,IAAW,CAAE,GAAG,EAAO,OAAM,EAAE,CACpD,CAEA,SAAS,SAAS,EAAqB,CACrC,OAAO,IAAI,YAAY,CAAC,CAAC,OAAO,CAAG,CAAC,CAAC,MACvC,CC3JA,SAAS,oBAAoB,EAAoB,EAAiC,CAEhF,IAAM,EAA4B,IAAI,IAChC,EAA0B,CAAC,EAK3B,EAAsC,OAAO,OAAO,IAAI,EAE9D,IAAK,GAAM,CAAC,EAAW,KAAU,OAAO,QAAQ,EAAK,MAAM,EAAG,CAC5D,IAAM,EAAa,EAAM,UAAU,YAAc,EAAM,OAAO,eACzD,IAED,IAAe,EAAK,MACtB,EAAc,KAAK,CAAS,EAI5B,EAAY,GAAa,EAAM,UAAU,KAAO,EAAM,OAAO,iBAAmB,MAEhF,EAAa,IAAI,CAAU,EAE/B,CAEA,MAAO,CACL,KAAM,EAAK,KACX,YACA,aAAc,MAAM,KAAK,CAAY,EACrC,gBACA,cACA,SAAU,QAAQ,EAAK,KAAK,OAC9B,CACF,CA8CA,SAAS,0BAA0B,EAA6D,CAC9F,IAAM,EAAmB,IAAI,IAC7B,IAAK,IAAM,KAAM,EACf,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAG,MAAM,EACxC,IAAK,IAAM,KAAS,OAAO,OAAO,EAAK,MAAM,EAAG,CAC9C,IAAM,EAAa,EAAM,UAAU,YAAc,EAAM,OAAO,eACxD,EAAM,EAAM,UAAU,KAAO,EAAM,OAAO,gBAChD,GAAI,CAAC,GAAc,CAAC,EAAK,SACzB,IAAM,EAAO,EAAiB,IAAI,CAAU,GAAK,IAAI,IACrD,EAAK,IAAI,CAAG,EACZ,EAAiB,IAAI,EAAY,CAAI,CACvC,CAGJ,OAAO,CACT,CAOA,SAAgB,0BACd,EACuB,CACvB,IAAM,EAAqB,0BAA0B,CAAQ,EAE7D,OAAO,EAAS,IAAK,GAAO,CAC1B,IAAM,EAAkB,CAAC,EACnB,EAAyC,CAAC,EAC1C,EAAyB,CAAC,EAC1B,EAA0C,CAAC,EAC3C,EAAsD,CAAC,EACvD,EAA2C,CAAC,EAC5C,EAAuC,CAAC,EAE9C,IAAK,GAAM,CAAC,EAAW,KAAS,OAAO,QAAQ,EAAG,MAAM,EAAG,CACzD,IAAM,EAAW,oBAAoB,EAAM,EAAG,SAAS,EACvD,EAAM,KAAK,EAAS,IAAI,EACxB,EAAa,EAAS,MAAQ,EAAS,aACvC,EAAc,EAAS,MAAQ,EAAS,cACxC,EAAY,EAAS,MAAQ,EAAS,YAClC,EAAS,cAAc,OAAS,GAClC,EAAa,KAAK,EAAS,IAAI,EAGjC,IAAM,EAAS,EACb,EAAG,WAAW,IAAI,CAAS,EAC3B,kCAAkC,GACpC,EACM,EAAU,GAAe,EAAM,CAAM,EACrC,EAAmB,EAAmB,IAAI,EAAS,IAAI,EAC7D,EAAW,EAAS,MAAQ,EACxB,EAAQ,WAAW,OAAQ,GAAc,CAAC,EAAiB,IAAI,CAAS,CAAC,EACzE,EAAQ,WACZ,EAAe,EAAS,MAAQ,OAAO,QAAQ,EAAK,MAAM,CAAC,CACxD,QACE,CAAC,EAAW,KACX,EAAM,OAAO,WAAa,IAC1B,CAAC,EAAQ,eAAe,SAAS,CAAS,GAC1C,CAAC,EAAQ,WAAW,SAAS,CAAS,CAC1C,CAAC,CACA,KAAK,CAAC,KAAe,CAAS,CACnC,CAEA,MAAO,CACL,UAAW,EAAG,UACd,QACA,eACA,eACA,gBACA,cACA,iBACA,YACF,CACF,CAAC,CACH,CCnGA,eAAsB,gBAAgB,EAAkC,CAAC,EAAyB,CAChG,GAAM,CAAE,SAAQ,UAAS,cAAa,cAAe,MAAM,0BAA0B,CACnF,WAAY,EAAQ,UACtB,CAAC,EAID,GAAmC,CAAE,iBAAkB,EAAY,gBAAiB,CAAC,EAErF,IAAM,EAAgB,oBAAoB,EAAS,EAAe,EAClE,GAAI,CAAC,EACH,MAAU,MACR,mCAAmC,EAAO,KAAK,qGAEjD,EAEF,GAAI,OAAO,EAAc,UAAa,UAAY,EAAc,WAAa,GAC3E,MAAU,MACR,iBAAiB,EAAO,KAAK,8FAE/B,EAKF,MAAM,EAAY,aAAa,kBAAkB,EACjD,IAAM,EAAY,aAAa,CAAW,EACpC,EAAc,EAAY,GAAe,CAAS,EAAI,IAAA,GACtD,EAAqC,EACvC,CACE,aAAc,EAAY,aAC1B,eAAgB,GAA0B,EAAY,YAAY,EAClE,eAAgB,GAA+B,EAAY,YAAY,EACvE,mBAAoB,GAA8B,EAAY,YAAY,CAC5E,EACA,KAEJ,MAAO,CACL,SACA,SAAU,EAAK,QAAQ,EAAc,QAAQ,EAC7C,gBAAiB,EAAc,gBAC/B,WAAY,0BAA0B,CAAU,EAChD,SACF,CACF,CC9FA,eAAsB,uBACpB,EAC8B,CAC9B,IAAM,EAA6B,IAAI,IACvC,IAAK,IAAM,KAAa,EAAK,WAAY,CACvC,IAAM,EAAM,EAAU,YAAY,EAC5B,EAAW,EAA2B,IAAI,CAAG,EACnD,GAAI,EAAU,CACZ,EAAS,KAAK,CAAS,EACvB,QACF,CACA,EAA2B,IAAI,EAAK,CAAC,CAAS,CAAC,CACjD,CAEA,IAAM,EAAmB,IAAI,IAAI,EAAK,UAAU,EAC1C,EAAoB,IAAI,IAE9B,IAAK,IAAM,KAAa,EAAK,WAAY,CACvC,GAAI,EAAiB,OAAS,EAC5B,MAGF,GAAI,CACF,GAAM,CAAE,iBAAkB,MAAM,EAAK,OAAO,kBAAkB,CAC5D,YAAa,EAAK,YAClB,cAAe,CACjB,CAAC,EAED,IAAK,IAAM,KAAQ,EAAe,CAChC,IAAM,EAAwB,EAA2B,IAAI,EAAK,KAAK,YAAY,CAAC,EAC/E,KAIL,IAAK,IAAM,KAAsB,EAC3B,EAAkB,IAAI,CAAkB,IAG5C,EAAkB,IAAI,EAAoB,CAAS,EACnD,EAAiB,OAAO,CAAkB,EAE9C,CACF,MAAQ,CACN,QACF,CACF,CAEA,OAAO,CACT,CChCA,eAAe,mBACb,EACA,EACe,CACf,MAAM,EAAO,qBAAqB,CAChC,YAAa,EAAQ,YACrB,cAAe,EAAQ,cACvB,iBAAkB,EAAQ,SAC5B,CAAC,EAED,EAAO,QAAQ,oBAAoB,EAAQ,UAAU,kBAAkB,EAAQ,cAAc,EAAE,CACjG,CAEA,eAAe,kBACb,EACA,EACA,EACe,CACf,MAAM,EAAO,sBAAsB,CACjC,cACA,eACF,CAAC,EAED,EAAO,QAAQ,sCAAsC,EAAc,EAAE,CACvE,CAOA,eAAsB,SAAS,EAA0C,CACvE,OAAO,MAAM,UAAU,CAAE,GAAG,EAAS,IAAK,EAAK,CAAC,CAClD,CAEA,eAAe,UAAU,EAAmC,CAAC,EAAkB,CAE7E,GAAM,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAQ,QACjB,YAAa,EAAQ,WACvB,CAAC,EAGK,EAAY,EAAQ,QAAU,EAAQ,OAAO,OAAS,EACtD,EAAe,CAAC,CAAC,EAAQ,UACzB,EAAS,CAAC,CAAC,EAAQ,IAGnB,EAAc,CAAC,EAAQ,EAAc,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,OACtE,GAAI,IAAgB,EAClB,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,mEACT,QAAS,mBACX,CAAC,EAEH,GAAI,EAAc,EAChB,MAAM,EAAS,CACb,KAAM,4BACN,QACE,+FACF,QAAS,mBACX,CAAC,EAIH,GAAM,CAAE,UAAW,MAAM,WAAW,EAAQ,UAAU,EAChD,EAAa,uBAAuB,CAAM,EAGhD,GAAI,EAAQ,CACV,GAAI,EAAW,SAAW,EAAG,CAC3B,EAAO,KAAK,qCAAqC,EACjD,MACF,CAEA,GAAI,CAAC,EAAQ,IAAK,CAChB,IAAM,EAAgB,EAAW,KAAK,IAAI,EAK1C,GAAI,CAAC,MAJsB,EAAO,QAAQ,CACxC,QAAS,uGAAuG,EAAc,aAC9H,QAAS,EACX,CAAC,EACkB,CACjB,EAAO,KAAK,qBAAqB,EACjC,MACF,CACF,CAEA,IAAK,IAAM,KAAa,EACtB,MAAM,kBAAkB,EAAa,EAAW,CAAM,EAExD,EAAO,QAAQ,8CAA8C,EAC7D,MACF,CAGA,GAAI,EAAc,CAChB,IAAM,EAAY,EAAc,EAAQ,UAAW,0BAA0B,EAG7E,GAAI,CAAC,EAAW,SAAS,CAAS,EAAG,CACnC,IAAM,EAAW,EAAO,KAAK,GAQ7B,MAPI,GAAY,aAAc,EACtB,EAAS,CACb,KAAM,8BACN,QAAS,cAAc,EAAU,mFACjC,WAAY,oDACd,CAAC,EAEG,EAAS,CACb,KAAM,+BACN,QAAS,cAAc,EAAU,wFAAwF,EAAW,KAAK,IAAI,GAC/I,CAAC,CACH,CAEA,GAAI,CAAC,EAAQ,KAKP,CAAC,MAJsB,EAAO,QAAQ,CACxC,QAAS,+CAA+C,EAAU,cAClE,QAAS,EACX,CAAC,EACkB,CACjB,EAAO,KAAK,qBAAqB,EACjC,MACF,CAGF,MAAM,kBAAkB,EAAa,EAAW,CAAM,EACtD,MACF,CAGA,GAAI,EAAW,CACb,IAAM,EAAa,EAAc,EAAQ,OAAQ,uBAAuB,EAGlE,EAAoB,MAAM,uBAAuB,CACrD,cACA,aACA,aACA,QACF,CAAC,EACK,EAAiB,EAAW,OAAQ,GAAc,CAAC,EAAkB,IAAI,CAAS,CAAC,EAEzF,GAAI,EAAe,OAAS,EAC1B,MAAM,EAAS,CACb,KAAM,2BACN,QAAS,yDAAyD,EAAe,KAAK,IAAI,GAC5F,CAAC,EAGH,GAAI,CAAC,EAAQ,IAAK,CAChB,IAAM,EAAY,EAAW,KAAK,IAAI,EAKtC,GAAI,CAAC,MAJsB,EAAO,QAAQ,CACxC,QAAS,4CAA4C,EAAU,aAC/D,QAAS,EACX,CAAC,EACkB,CACjB,EAAO,KAAK,qBAAqB,EACjC,MACF,CACF,CAEA,IAAK,IAAM,KAAa,EAAY,CAClC,IAAM,EAAY,EAAkB,IAAI,CAAS,EAC5C,GAIL,MAAM,mBACJ,CACE,cACA,cAAe,EACf,WACF,EACA,CACF,CACF,CACF,CACF,CAEA,MAAa,GAAkB,EAAiB,CAC9C,KAAM,WACN,YAAa,sDACb,KAAM,EAAE,aAAa,CACnB,GAAG,GACH,GAAG,GACH,OAAQ,EAAI,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,EAAG,CACzC,WAAY,GACZ,YAAa,yBACf,CAAC,EACD,IAAK,EAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAK,EAAG,CACnC,MAAO,IACP,YAAa,4EACf,CAAC,EACD,UAAW,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CACpC,MAAO,IACP,YAAa,4CACf,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,MAAM,eAAe,CAAE,QAAS,EAAK,OAAQ,CAAC,EAC9C,IAAM,EAAS,EAAK,QAAU,EAAK,OAAO,OAAS,EAAI,EAAK,OAAS,IAAA,GACrE,MAAM,UAAU,CACd,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,WAAY,EAAK,OACjB,IAAK,EAAK,IACV,UAAW,EAAK,UAChB,SACA,IAAK,EAAK,GACZ,CAAC,CACH,CACF,CAAC,EClOD,eAAsB,cAAc,EAA6D,CAC/F,GAAM,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,GAAS,QAClB,YAAa,GAAS,WACxB,CAAC,EAEK,EAAgB,gBAAgB,GAAS,KAAK,EAcpD,OAAO,MAbiB,GACtB,MAAO,EAAW,IAAa,CAC7B,GAAM,CAAE,YAAW,iBAAkB,MAAM,EAAO,cAAc,CAC9D,cACA,YACA,WACA,eACF,CAAC,EACD,MAAO,CAAC,EAAW,CAAa,CAClC,EACA,CAAE,MAAO,GAAS,KAAM,CAC1B,EAAA,CAEiB,IAAI,kBAAkB,CACzC,CAEA,MAAaC,GAAc,EAAiB,CAC1C,KAAM,OACN,YAAa,uCACb,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,GAAG,eAAe,CACpB,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAa,EAAO,SACpB,EAAY,MAAM,cAAc,CACpC,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,MAAO,EAAK,MACZ,MAAO,EAAK,KACd,CAAC,EAEG,EAAU,SAAW,IACvB,EAAO,KAAK,qBAAqB,EAC7B,CAAC,IAIP,EAAO,IAAI,CAAS,CACtB,CACF,CAAC,ECrCD,eAAsB,eACpB,EACuC,CACvC,GAAM,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAQ,QACjB,YAAa,EAAQ,WACvB,CAAC,EAED,GAAI,CACF,GAAM,CAAE,eAAgB,MAAM,EAAO,wBAAwB,CAC3D,cACA,YAAa,EAAQ,WACvB,CAAC,EAED,MAAO,CACL,cACA,KAAO,GACLC,yBAAiB,CACf,SACA,cACA,cACA,SAAU,EAAQ,UAAY,IAC9B,QAAS,GAAa,QACtB,MAAO,GAAa,MACpB,aAAc,GAAa,YAC7B,CAAC,CACL,CACF,OAAS,EAAO,CACd,GAAI,aAAiB,EAAc,CACjC,GAAI,EAAM,OAAS,EAAK,SACtB,MAAM,EAAS,CACb,KAAM,+BACN,QAAS,cAAc,EAAQ,YAAY,cAC3C,MAAO,CACT,CAAC,EAEH,GAAI,EAAM,OAAS,EAAK,mBACtB,MAAM,EAAS,CACb,KAAM,mCACN,QAAS,cAAc,EAAQ,YAAY,gCAC3C,MAAO,CACT,CAAC,CAEL,CACA,MAAM,CACR,CACF,CAEA,MAAa,GAAgB,EAAiB,CAC5C,KAAM,SACN,YAAa,iDACb,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,eAAgB,EAAI,EAAE,OAAO,EAAG,CAC9B,WAAY,GACZ,YAAa,qBACf,CAAC,EACD,GAAG,EACL,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAa,EAAO,UAAY,EAAK,KACrC,CAAE,cAAa,QAAS,MAAM,eAAe,CACjD,YAAa,EAAK,YAClB,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,SAAU,cAAc,EAAK,QAAQ,CACvC,CAAC,EAMD,GAJK,GACH,EAAO,KAAK,iBAAiB,IAAe,CAAE,KAAM,QAAS,CAAC,EAG5D,EAAK,KAAM,CACb,IAAM,EAAS,MAAM,EAAK,CACxB,aAAc,CAAC,EACf,QAAS,cAAc,EAAK,OAAO,EACnC,MAAO,EAAK,KACd,CAAC,EACD,GAAI,EAAK,MAAQ,CAAC,EAAY,CAC5B,GAAM,CAAE,aAAc,MAAM,qBAAqB,CAC/C,cACA,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,KAAM,EACR,CAAC,EACD,uBAAuB,CAAS,CAClC,MAAO,GAAI,EAAK,KAAM,CACpB,GAAM,CAAE,aAAc,MAAM,qBAAqB,CAC/C,cACA,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,KAAM,EACR,CAAC,EACD,EAAO,IAAI,CAAE,GAAG,EAAQ,WAAY,EAAU,UAAW,CAAC,CAC5D,MACE,EAAO,IAAI,CAAM,EAEnB,IAAM,EAAU,uBAAuB,EAAQ,EAAK,KAAK,EACzD,GAAI,EACF,MAAM,CAEV,MACE,EAAO,IAAI,CAAE,aAAY,CAAC,CAE9B,CACF,CAAC,EChHD,eAAsB,sBACpB,EAC6B,CAC7B,OAAO,MAAM,6BAA6B,CACxC,GAAG,EACH,aAAc,EAAQ,cAAgB,CAAC,EAAO,SAC9C,UAAW,EAAQ,WAAa,EAClC,CAAC,CACH,CAQA,eAAe,4BACb,EACA,EAC6B,CAC7B,GAAM,CAAE,aAAc,MAAM,qBAAqB,CAC/C,YAAa,EAAQ,YACrB,YAAa,EAAQ,YACrB,QAAS,EAAQ,QACjB,KAAM,EACR,CAAC,EAED,MAAO,CACL,GAAG,EACH,WAAY,EAAU,UACxB,CACF,CAEA,MAAa,GAAc,EAAiB,CAC1C,KAAM,OACN,YAAa,iCACb,SAAU,CACR,CACE,IAAK,oDACL,KAAM,2BACR,EACA,CACE,IAAK,4DACL,KAAM,gCACR,EACA,CACE,IAAK,gCACL,KAAM,0CACR,CACF,EACA,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,eAAgB,EAAI,EAAE,OAAO,EAAG,CAC9B,WAAY,GACZ,YAAa,cACf,CAAC,EACD,GAAG,EACL,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAa,EAAO,UAAY,EAAK,KACrC,EAAS,MAAM,sBAAsB,CACzC,YAAa,EAAK,YAClB,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,SAAU,cAAc,EAAK,QAAQ,EACrC,QAAS,cAAc,EAAK,OAAO,EACnC,MAAO,EAAK,MACZ,aAAc,CAAC,CACjB,CAAC,EAEK,EAA6B,EAAK,KACpC,MAAM,4BAA4B,EAAQ,CACxC,YAAa,EAAK,YAClB,YAAa,EAAK,gBAClB,QAAS,EAAK,OAChB,CAAC,EACD,EAEA,CAAC,GAAc,EAAO,WACxB,uBAAuB,CACrB,GAAI,EAAO,GACX,aAAc,EAAO,aACrB,OAAQ,EAAO,OACf,cAAe,EAAO,cACtB,UAAW,EAAO,UAClB,WAAY,EAAO,WACnB,WAAY,EAAO,UACrB,CAAC,EAED,EAAO,IAAI,CAAM,EAGnB,IAAM,EAAU,uBAAuB,EAAQ,EAAK,KAAK,EACzD,GAAI,EACF,MAAM,CAEV,CACF,CAAC,EC/FK,eACJ,GACW,CACX,OAAQ,EAAR,CACE,KAAK,EAAiE,GACpE,MAAO,KACT,KAAK,EAAiE,kBACpE,MAAO,oBACT,QACE,MAAO,SACX,CACF,EAEM,sBAAyB,GAAyD,CACtF,OAAQ,EAAR,CACE,KAAK,EAAqC,UACxC,MAAO,UACT,KAAK,EAAqC,OACxC,MAAO,UACT,QACE,MAAO,SACX,CACF,EAEa,QAAW,IACf,CACL,KAAM,EAAI,KACV,OAAQ,EAAI,OACZ,cAAe,EAAI,cACnB,UAAW,gBAAgB,EAAI,UAAU,EACzC,UAAW,gBAAgB,EAAI,UAAU,CAC3C,GAGW,eACX,EACA,IACkB,CAClB,IAAM,EAAU,EAAO,wBACvB,MAAO,CACL,OACA,OAAQ,eAAe,EAAO,MAAM,EACpC,8BAA+B,gBAAgB,EAAO,8BAA8B,EACpF,kBAAmB,EAAU,sBAAsB,EAAQ,MAAM,EAAI,MACrE,cAAe,gBAAgB,GAAS,WAAW,EACnD,iBAAkB,GAAS,OAAS,EACtC,CACF,EC7DM,GAAsB,EAAE,OAAO,CACnC,YAAa,EAAE,KAAK,CAAE,QAAS,mCAAoC,CAAC,CAAC,CAAC,SAAS,EAC/E,QAAS,EAAE,OAAO,CAAC,CAAC,SAAS,EAC7B,KAAM,EAAE,OAAO,CAAC,CAAC,IAAI,EAAG,CAAE,QAAS,kBAAmB,CAAC,CACzD,CAAC,EAID,eAAeC,cAAY,EAAwB,CACjD,IAAM,EAAY,aAAa,GAAqB,CAAO,EAErD,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAU,QACnB,YAAa,EAAU,WACzB,CAAC,EAED,MAAO,CACL,SACA,cACA,KAAM,EAAU,IAClB,CACF,CAOA,eAAsB,aAAa,EAAgD,CACjF,GAAM,CAAE,SAAQ,cAAa,QAAS,MAAMA,cAAY,CAAO,EAEzD,EAAW,MAAM,EAAO,2BAA2B,CACvD,cACA,gBAAiB,CACnB,CAAC,EAED,OAAO,cAAc,EAAM,CAAQ,CACrC,CAEA,MAAa,GAAgB,EAAiB,CAC5C,KAAM,SACN,YAAa,kCACb,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,KAAM,EAAI,EAAE,OAAO,EAAG,CACpB,YAAa,mBACb,MAAO,GACT,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAS,MAAM,aAAa,CAChC,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,KAAM,EAAK,IACb,CAAC,EAEK,EAAkB,EAAK,KACzB,EACA,CACE,GAAG,EACH,8BAA+B,qBAAqB,EAAO,6BAA6B,EACxF,cAAe,qBAAqB,EAAO,aAAa,CAC1D,EAEJ,EAAO,IAAI,CAAe,CAC5B,CACF,CAAC,EClEK,GAAwB,EAAE,OAAO,CACrC,YAAa,EAAE,KAAK,CAAE,QAAS,mCAAoC,CAAC,CAAC,CAAC,SAAS,EAC/E,QAAS,EAAE,OAAO,CAAC,CAAC,SAAS,EAC7B,MAAO,GAAS,SAAS,EACzB,MAAO,EAAE,OAAO,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,SAAS,CACxD,CAAC,EAID,eAAeC,cAAY,EAA0B,CACnD,IAAM,EAAY,aAAa,GAAuB,CAAO,EAEvD,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAU,QACnB,YAAa,EAAU,WACzB,CAAC,EAED,MAAO,CACL,SACA,cACA,MAAO,EAAU,MACjB,MAAO,EAAU,KACnB,CACF,CAOA,eAAsB,SAAS,EAA8C,CAC3E,GAAM,CAAE,SAAQ,cAAa,QAAO,SAAU,MAAMA,cAAY,CAAO,EAEjE,EAAgB,gBAAgB,CAAK,EAc3C,OAAO,MAboB,GACzB,MAAO,EAAW,IAAa,CAC7B,GAAM,CAAE,eAAc,iBAAkB,MAAM,EAAO,iBAAiB,CACpE,cACA,YACA,WACA,eACF,CAAC,EACD,MAAO,CAAC,EAAc,CAAa,CACrC,EACA,CAAE,OAAM,CACV,EAAA,CAEoB,IAAI,OAAO,CACjC,CAEA,MAAaC,GAAc,EAAiB,CAC1C,KAAM,OACN,YAAa,mCACb,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,GAAG,eAAe,CACpB,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAa,EAAO,SACpB,EAAO,MAAM,SAAS,CAC1B,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,MAAO,EAAK,MACZ,MAAO,EAAK,KACd,CAAC,EAEK,EAAgB,EAClB,EACA,EAAK,KAAK,CAAE,UAAW,EAAG,YAAW,GAAG,MAAY,CAClD,GAAG,EACH,UAAW,qBAAqB,CAAS,CAC3C,EAAE,EAEN,EAAO,IAAI,CAAa,CAC1B,CACF,CAAC,EC/ED,eAAsB,4BACpB,EACmB,CACnB,IAAM,EAAW,MAAM,mBAAmB,EACpC,EAAU,OAAO,QAAQ,EAAS,QAAQ,CAAC,CAC9C,QAAQ,EAAG,KAAa,GAAS,cAAgB,EAAa,IAAI,EAAQ,YAAY,CAAC,CAAC,CACxF,KAAK,CAAC,KAAU,CAAI,EACvB,GAAI,EAAQ,SAAW,EAAG,OAAO,EACjC,IAAK,IAAM,KAAQ,EACjB,OAAO,EAAS,SAAS,GAG3B,OADA,oBAAoB,CAAQ,EACrB,CACT,CCJA,MAAM,GAA+B,EAAE,OAAO,CAC5C,YAAa,EAAE,KAAK,CAAE,QAAS,mCAAoC,CAAC,CACtE,CAAC,EAID,eAAeC,cAAY,EAAiC,CAE1D,IAAM,EAAY,aAAa,GAA8B,CAAO,EAE9D,EAAc,MAAM,gBAAgB,EAG1C,MAAO,CACL,OAAA,MAHmB,EAAmB,CAAW,EAIjD,YAAa,EAAU,WACzB,CACF,CAOA,eAAsB,gBAAgB,EAAgD,CAEpF,GAAM,CAAE,SAAQ,eAAgB,MAAMA,cAAY,CAAO,EAGzD,MAAM,EAAO,gBAAgB,CAC3B,aACF,CAAC,CACH,CAEA,MAAa,GAAgB,EAAiB,CAC5C,KAAM,SACN,YAAa,sCACb,KAAM,EAAE,aAAa,CACnB,eAAgB,EAAI,EAAE,OAAO,EAAG,CAC9B,MAAO,IACP,YAAa,cACf,CAAC,EACD,GAAG,EACL,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,MAAM,eAAe,EAErB,GAAM,CAAE,SAAQ,eAAgB,MAAMA,cAAY,CAChD,YAAa,EAAK,eACpB,CAAC,EAGG,EACJ,GAAI,CACF,EAAY,MAAM,EAAO,aAAa,CACpC,aACF,CAAC,CACH,OAAS,EAAO,CAQd,MAPI,aAAiB,GAAgB,EAAM,OAAS,EAAK,SACjD,EAAS,CACb,KAAM,sBACN,QAAS,cAAc,EAAY,cACnC,MAAO,CACT,CAAC,EAEG,CACR,CAEA,IAAM,EAAoB,EAAU,UAC9B,EAAgB,GAAmB,MAAQ,EAI3C,EAAc,qBAAqB,CAAE,KAAM,EAAe,WAH7C,EACf,MAAM,2BAA2B,EAAQ,CAAiB,EAC1D,EACuE,CAAC,EAG5E,GAAI,CAAC,EAAK,IAAK,CACb,IAAM,EAAe,MAAM,EAAO,KAAK,CACrC,QAAS,iDAAiD,EAAY,GACxE,CAAC,EACD,GAAI,IAAiB,GAAiB,IAAiB,EAAa,CAClE,EAAO,KAAK,+BAA+B,EAC3C,MACF,CACF,CAGA,GAAI,CACF,MAAM,EAAO,gBAAgB,CAC3B,aACF,CAAC,CACH,OAAS,EAAO,CAId,MADA,MAAM,4BAA4B,IAAI,IAAI,CAAC,CAAW,CAAC,CAAC,EAClD,CACR,CAEA,IAAM,EAAmB,MAAM,4BAA4B,IAAI,IAAI,CAAC,CAAW,CAAC,CAAC,EAG7E,EAAiB,OAAS,EAC5B,EAAO,QACL,cAAc,EAAY,QAAQ,EAAiB,OAAO,6CAC5D,EAEA,EAAO,QAAQ,cAAc,EAAY,wBAAwB,CAErE,CACF,CAAC,EC7GK,GAA4B,EAAE,OAAO,CACzC,YAAa,EAAE,KAAK,CAAE,QAAS,mCAAoC,CAAC,CAAC,CAAC,SAAS,EAC/E,QAAS,EAAE,OAAO,CAAC,CAAC,SAAS,CAC/B,CAAC,EAID,eAAeC,cAAY,EAA8B,CACvD,IAAM,EAAY,aAAa,GAA2B,CAAO,EAE3D,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAU,QACnB,YAAa,EAAU,WACzB,CAAC,EAED,MAAO,CACL,SACA,aACF,CACF,CAUA,eAAsB,aACpB,EACqC,CACrC,GAAM,CAAE,SAAQ,eAAgB,MAAMA,cAAY,CAAO,EAEnD,EAAW,MAAM,EAAO,aAAa,CACzC,aACF,CAAC,EAED,GAAI,CAAC,EAAS,UACZ,MAAM,EAAS,CACb,KAAM,sBACN,QAAS,cAAc,EAAY,aACrC,CAAC,EAGH,GAAM,CAAC,EAAS,GAAU,MAAM,QAAQ,IAAI,CAC1C,+BAA+B,EAAQ,EAAS,SAAS,EACzD,qBAAqB,EAAQ,EAAa,IAAI,IAAM,CACtD,CAAC,EAED,MAAO,CAAE,GAAG,EAAS,UAAW,eAAe,CAAM,CAAE,CACzD,CAEA,MAAa,GAAa,EAAiB,CACzC,KAAM,MACN,YAAa,8CACb,KAAM,EAAE,aAAa,CACnB,GAAG,CACL,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAY,MAAM,aAAa,CACnC,YAAa,EAAK,gBAClB,QAAS,EAAK,OAChB,CAAC,EAEK,EAAqB,EAAK,KAC5B,EACA,CACE,GAAG,EACH,UAAW,qBAAqB,EAAU,SAAS,EACnD,UAAW,qBAAqB,EAAU,SAAS,CACrD,EAEJ,EAAO,IAAI,EAAoB,CAC7B,QAAS,CAAE,KAAM,GAA0B,WAAY,IAAK,CAC9D,CAAC,CACH,CACF,CAAC,ECjFK,GAAgC,EAAE,OAAO,CAC7C,YAAa,EAAE,KAAK,CAAE,QAAS,mCAAoC,CAAC,CACtE,CAAC,EAID,eAAeC,cAAY,EAAkC,CAC3D,IAAM,EAAY,aAAa,GAA+B,CAAO,EAE/D,EAAc,MAAM,gBAAgB,EAG1C,MAAO,CACL,OAAA,MAHmB,EAAmB,CAAW,EAIjD,YAAa,EAAU,WACzB,CACF,CAOA,eAAsB,iBAAiB,EAAiD,CACtF,GAAM,CAAE,SAAQ,eAAgB,MAAMA,cAAY,CAAO,EAEzD,MAAM,EAAO,iBAAiB,CAC5B,aACF,CAAC,CACH,CAEA,MAAa,GAAiB,EAAiB,CAC7C,KAAM,UACN,YAAa,8BACb,KAAM,EAAE,aAAa,CACnB,eAAgB,EAAI,EAAE,OAAO,EAAG,CAC9B,MAAO,IACP,YAAa,cACf,CAAC,EACD,GAAG,EACL,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,MAAM,eAAe,EACrB,GAAM,CAAE,SAAQ,eAAgB,MAAMA,cAAY,CAChD,YAAa,EAAK,eACpB,CAAC,EAED,GAAI,CAAC,EAAK,KAIJ,MAHuB,EAAO,KAAK,CACrC,QAAS,+CAA+C,EAAY,aACtE,CAAC,IACoB,MAAO,CAC1B,EAAO,KAAK,kCAAkC,EAC9C,MACF,CAGF,MAAM,EAAO,iBAAiB,CAC5B,aACF,CAAC,EAED,EAAO,QAAQ,cAAc,EAAY,yBAAyB,CACpE,CACF,CAAC,ECjEK,aAAgB,GAA4C,CAChE,OAAQ,EAAR,CACE,KAAK,GAA0B,MAC7B,MAAO,QACT,KAAK,GAA0B,OAC7B,MAAO,SACT,KAAK,GAA0B,OAC7B,MAAO,SACT,QACE,MAAO,SACX,CACF,EAEa,aAAgB,GAA4C,CACvE,OAAQ,EAAK,YAAY,EAAzB,CACE,IAAK,QACH,OAAO,GAA0B,MACnC,IAAK,SACH,OAAO,GAA0B,OACnC,IAAK,SACH,OAAO,GAA0B,OACnC,QACE,MAAM,EAAS,CACb,KAAM,yBACN,QAAS,iBAAiB,EAAK,qCACjC,CAAC,CACL,CACF,EAEa,SAAY,IAChB,CACL,OAAQ,EAAK,cAAc,QAAU,GACrC,MAAO,EAAK,cAAc,OAAS,GACnC,KAAM,aAAa,EAAK,IAAI,CAC9B,GAGW,GAAa,CAAC,QAAS,SAAU,QAAQ,ECpChD,GAA0B,EAAE,OAAO,CACvC,YAAa,EAAE,KAAK,CAAE,QAAS,mCAAoC,CAAC,CAAC,CAAC,SAAS,EAC/E,QAAS,EAAE,OAAO,CAAC,CAAC,SAAS,EAC7B,MAAO,EAAE,MAAM,CAAE,QAAS,qCAAsC,CAAC,EACjE,KAAM,EAAE,KAAK,GAAY,CAAE,QAAS,wBAAwB,GAAW,KAAK,IAAI,GAAI,CAAC,CACvF,CAAC,EAID,eAAeC,cAAY,EAA4B,CACrD,IAAM,EAAY,aAAa,GAAyB,CAAO,EAEzD,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAU,QACnB,YAAa,EAAU,WACzB,CAAC,EAED,MAAO,CACL,SACA,cACA,MAAO,EAAU,MACjB,KAAM,aAAa,EAAU,IAAI,CACnC,CACF,CAOA,eAAsB,WAAW,EAA2C,CAC1E,GAAM,CAAE,SAAQ,cAAa,QAAO,QAAS,MAAMA,cAAY,CAAO,EAEtE,MAAM,EAAO,4BAA4B,CACvC,cACA,QACA,MACF,CAAC,CACH,CAEA,MAAa,GAAgB,EAAiB,CAC5C,KAAM,SACN,YAAa,+BACb,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,MAAO,EAAI,EAAE,MAAM,EAAG,CACpB,YAAa,qCACf,CAAC,EACD,KAAM,EAAI,EAAE,KAAK,EAAU,EAAG,CAC5B,YAAa,mBAAmB,GAAW,KAAK,IAAI,EAAE,GACtD,MAAO,GACT,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,MAAM,eAAe,CAAE,QAAS,EAAK,OAAQ,CAAC,EAC9C,MAAM,WAAW,CACf,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,MAAO,EAAK,MACZ,KAAM,EAAK,IACb,CAAC,EAED,EAAO,QAAQ,SAAS,EAAK,MAAM,oCAAoC,EAAK,KAAK,GAAG,CACtF,CACF,CAAC,ECjEK,GAAyB,EAAE,OAAO,CACtC,YAAa,EAAE,KAAK,CAAE,QAAS,mCAAoC,CAAC,CAAC,CAAC,SAAS,EAC/E,QAAS,EAAE,OAAO,CAAC,CAAC,SAAS,EAC7B,MAAO,GAAS,SAAS,EACzB,MAAO,EAAE,OAAO,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,SAAS,CACxD,CAAC,EAID,eAAeC,cAAY,EAA2B,CACpD,IAAM,EAAY,aAAa,GAAwB,CAAO,EAExD,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAU,QACnB,YAAa,EAAU,WACzB,CAAC,EAED,MAAO,CACL,SACA,cACA,MAAO,EAAU,MACjB,MAAO,EAAU,KACnB,CACF,CAOA,eAAsB,UAAU,EAAgD,CAC9E,GAAM,CAAE,SAAQ,cAAa,QAAO,SAAU,MAAMA,cAAY,CAAO,EAEjE,EAAgB,gBAAgB,CAAK,EAc3C,OAAO,MAba,GAClB,MAAO,EAAW,IAAa,CAC7B,GAAM,CAAE,yBAAwB,iBAAkB,MAAM,EAAO,2BAA2B,CACxF,cACA,YACA,WACA,eACF,CAAC,EACD,MAAO,CAAC,EAAwB,CAAa,CAC/C,EACA,CAAE,OAAM,CACV,EAAA,CAEa,IAAI,QAAQ,CAC3B,CAEA,MAAa,GAAc,EAAiB,CAC1C,KAAM,OACN,YAAa,4BACb,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,GAAG,eAAe,CACpB,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,IAAM,EAAQ,MAAM,UAAU,CAC5B,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,MAAO,EAAK,MACZ,MAAO,EAAK,KACd,CAAC,EAED,EAAO,IAAI,CAAK,CAClB,CACF,CAAC,EClEK,GAA0B,EAAE,OAAO,CACvC,YAAa,EAAE,KAAK,CAAE,QAAS,mCAAoC,CAAC,CAAC,CAAC,SAAS,EAC/E,QAAS,EAAE,OAAO,CAAC,CAAC,SAAS,EAC7B,MAAO,EAAE,MAAM,CAAE,QAAS,qCAAsC,CAAC,CACnE,CAAC,EAID,eAAeC,cAAY,EAA4B,CACrD,IAAM,EAAY,aAAa,GAAyB,CAAO,EAEzD,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAU,QACnB,YAAa,EAAU,WACzB,CAAC,EAED,MAAO,CACL,SACA,cACA,MAAO,EAAU,KACnB,CACF,CAOA,eAAsB,WAAW,EAA2C,CAC1E,GAAM,CAAE,SAAQ,cAAa,SAAU,MAAMA,cAAY,CAAO,EAEhE,MAAM,EAAO,4BAA4B,CACvC,cACA,OACF,CAAC,CACH,CAEA,MAAa,GAAgB,EAAiB,CAC5C,KAAM,SACN,YAAa,iCACb,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,MAAO,EAAI,EAAE,MAAM,EAAG,CACpB,YAAa,qCACf,CAAC,EACD,GAAG,EACL,CAAC,EACD,IAAK,KAAO,IAAS,CAEnB,GADA,MAAM,eAAe,CAAE,QAAS,EAAK,OAAQ,CAAC,EAC1C,CAAC,EAAK,KAIJ,MAHuB,EAAO,KAAK,CACrC,QAAS,yCAAyC,EAAK,MAAM,gCAC/D,CAAC,IACoB,MAAO,CAC1B,EAAO,KAAK,yBAAyB,EACrC,MACF,CAGF,MAAM,WAAW,CACf,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,MAAO,EAAK,KACd,CAAC,EAED,EAAO,QAAQ,SAAS,EAAK,MAAM,0BAA0B,CAC/D,CACF,CAAC,ECnEK,GAA0B,EAAE,OAAO,CACvC,YAAa,EAAE,KAAK,CAAE,QAAS,mCAAoC,CAAC,CAAC,CAAC,SAAS,EAC/E,QAAS,EAAE,OAAO,CAAC,CAAC,SAAS,EAC7B,MAAO,EAAE,MAAM,CAAE,QAAS,qCAAsC,CAAC,EACjE,KAAM,EAAE,KAAK,GAAY,CAAE,QAAS,wBAAwB,GAAW,KAAK,IAAI,GAAI,CAAC,CACvF,CAAC,EAID,eAAeC,cAAY,EAA4B,CACrD,IAAM,EAAY,aAAa,GAAyB,CAAO,EAEzD,CAAE,SAAQ,eAAgB,MAAM,6BAA6B,CACjE,QAAS,EAAU,QACnB,YAAa,EAAU,WACzB,CAAC,EAED,MAAO,CACL,SACA,cACA,MAAO,EAAU,MACjB,KAAM,aAAa,EAAU,IAAI,CACnC,CACF,CAOA,eAAsB,WAAW,EAA2C,CAC1E,GAAM,CAAE,SAAQ,cAAa,QAAO,QAAS,MAAMA,cAAY,CAAO,EAEtE,MAAM,EAAO,4BAA4B,CACvC,cACA,QACA,MACF,CAAC,CACH,CAEA,MAAa,GAAgB,EAAiB,CAC5C,KAAM,SACN,YAAa,sCACb,KAAM,EAAE,aAAa,CACnB,GAAG,EACH,MAAO,EAAI,EAAE,MAAM,EAAG,CACpB,YAAa,qCACf,CAAC,EACD,KAAM,EAAI,EAAE,KAAK,EAAU,EAAG,CAC5B,YAAa,uBAAuB,GAAW,KAAK,IAAI,EAAE,GAC1D,MAAO,GACT,CAAC,CACH,CAAC,EACD,IAAK,KAAO,IAAS,CACnB,MAAM,eAAe,CAAE,QAAS,EAAK,OAAQ,CAAC,EAC9C,MAAM,WAAW,CACf,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,MAAO,EAAK,MACZ,KAAM,EAAK,IACb,CAAC,EAED,EAAO,QAAQ,SAAS,EAAK,MAAM,qBAAqB,EAAK,KAAK,GAAG,CACvE,CACF,CAAC,EC/DD,SAAS,gBAAyB,CAChC,MAAO,EAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BrB,CAEA,SAAS,gBAAyB,CAChC,MAAO,EAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCrB,CAQA,eAAsB,kBAAkB,EAAqB,EAAkC,CAC7F,IAAM,EAAY,EAAK,QAAQ,GAAW,EAAG,OAAO,EACpD,EAAG,UAAU,EAAW,CAAE,UAAW,EAAK,CAAC,EAE3C,IAAM,EAAY,EAAK,KAAK,EAAW,SAAS,EAAO,UAAU,EAC3D,EAAe,IAAW,MAAQ,eAAe,EAAI,eAAe,EAC1E,EAAG,cAAc,EAAW,CAAY,EAExC,IAAM,EAAW,MAAM,GAA4B,CAAO,EAEpD,EAAY,GAAgB,CAAE,UAAS,CAAC,EACxC,EAAS,MAAM,GAAS,MAAM,CAClC,QAAS,CACP,GAAmC,EAAW,CAAO,EACrD,GAA0B,EAC1B,EACF,EACA,MAAO,EACP,MAAO,GACP,OAAQ,CACN,OAAQ,MACR,UAAW,GACX,OAAQ,GACR,cAAe,GACf,QAAS,CACP,SAAU,UACZ,CACF,EACA,SAAU,IAAW,MAAQ,CAAC,UAAU,EAAI,CAAC,EAC7C,QAAS,CACP,eAAgB,CAAC,OAAQ,QAAQ,CACnC,EACA,WACA,UAAW,CACT,kBAAmB,GACnB,YAAa,GACb,yBAA0B,EAC5B,EACA,GAAG,EAAU,OACf,CAA0B,EAG1B,OAFA,EAAU,kBAAkB,EAErB,EAAO,OAAO,EAAE,CAAC,IAC1B,CChIA,SAAS,eAAe,EAAwB,CAI9C,OAHI,aAAiB,MACZ,EAAM,QAER,OAAO,CAAK,CACrB,CAcA,SAAgB,uBAAuB,EAAyC,CAC9E,IAAM,EAAU,eAAe,EAAK,KAAK,EAEzC,GAAI,EAAQ,SAAS,6BAA6B,EAChD,OAAO,EAAS,CACd,KAAM,YACN,QAAS,iBAAiB,EAAK,aAAe,UAAU,kBACxD,WAAY,yDACd,CAAC,EAGH,GACE,EAAK,SAAW,OAChB,EAAQ,SACN,sFACF,EAEA,OAAO,EAAS,CACd,KAAM,oBACN,QAAS,iDAAiD,EAAK,UAAU,IACzE,WACE,6FACJ,CAAC,EAGH,GAAI,EAAK,SAAW,OAAS,EAAQ,SAAS,mCAAmC,EAAG,CAClF,IAAM,EAAe,EAClB,MAAM,mCAAmC,CAAC,CAC1C,GAAG,CAAC,CAAC,EACJ,MAAM;CAAI,CAAC,CACZ,GAAG,CAAC,CAAC,EACJ,KAAK,EAET,OAAO,EAAS,CACd,KAAM,cACN,QAAS,mBACT,WAAY,GAAgB,4CAC9B,CAAC,CACH,CAEA,OAAO,EAAK,iBAAiB,MAAQ,EAAK,MAAY,MAAM,CAAO,CACrE,CCxDA,SAAgB,uBAAuB,EAAwB,CAC7D,GAAI,EAAM,KAAK,CAAC,CAAC,SAAW,EAC1B,MAAO,GAGT,GAAI,CAEF,OADA,GAAM,CAAK,EACJ,EACT,MAAQ,CACN,MAAO,EACT,CACF,CCXA,SAAgB,mBAAmB,EAAwB,CACzD,IAAI,EAAgB,GAChB,EAAgB,GAChB,EAAgB,GAChB,EAAoB,EACpB,EAAgC,KAChC,EAAmC,GAEvC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,GAAK,EAAG,CACxC,IAAM,EAAO,EAAc,EAAM,GAAI,sBAAsB,EAAE,SAAS,EAChE,EAAO,EAAM,EAAI,GAEvB,GAAI,EAAe,CACb,IAAS;IACX,EAAgB,IAElB,QACF,CAEA,GAAI,EAAoB,EAAG,CACzB,GAAI,IAAS,KAAO,IAAS,IAAK,CAChC,GAAqB,EACrB,GAAK,EACL,QACF,CACI,IAAS,KAAO,IAAS,MAC3B,IACA,GAAK,GAEP,QACF,CAEA,GAAI,GAAkB,KAAM,CACtB,EAAM,WAAW,EAAgB,CAAC,IACpC,GAAK,EAAe,OAAS,EAC7B,EAAiB,MAEnB,QACF,CAEA,GAAI,EAAe,CACjB,GAAI,IAAS,KAAO,IAAS,IAAK,CAChC,GAAK,EACL,QACF,CACI,IAAS,MACX,EAAgB,IAElB,QACF,CAEA,GAAI,EAAe,CACjB,GAAI,IAAS,KAAO,IAAS,IAAK,CAChC,GAAK,EACL,QACF,CACI,IAAS,MACX,EAAgB,IAElB,QACF,CAEA,GAAI,IAAS,KAAO,IAAS,IAAK,CAChC,EAAgB,GAChB,GAAK,EACL,QACF,CAEA,GAAI,IAAS,KAAO,IAAS,IAAK,CAChC,EAAoB,EACpB,GAAK,EACL,QACF,CAEA,GAAI,IAAS,IAAK,CAChB,EAAmC,GACnC,EAAgB,GAChB,QACF,CAEA,GAAI,IAAS,IAAK,CAChB,EAAmC,GACnC,EAAgB,GAChB,QACF,CAEA,GAAI,IAAS,IAAK,CAChB,IAAM,EAAO,EAAM,MAAM,CAAC,EACpB,EAAQ,EAAK,MAAM,6BAA6B,GAAK,EAAK,MAAM,OAAO,EAC7E,GAAI,GAAS,KAAM,CACjB,EAAmC,GACnC,EAAiB,EAAM,GACvB,GAAK,EAAM,EAAE,CAAC,OAAS,EACvB,QACF,CACF,CAEA,GAAI,IAAS,IAAK,CAChB,EAAmC,GACnC,QACF,CAEK,KAAK,KAAK,CAAI,IACjB,EAAmC,GAEvC,CAEA,OACE,GACA,CAAC,GACD,CAAC,GACD,IAAsB,GACtB,GAAkB,IAEtB,CClHA,SAAgB,yBAAyB,EAAyB,CAChE,IAAI,EACJ,GAAI,CACF,EAAa,GAAM,CAAK,CAC1B,OAAS,EAAO,CACd,IAAM,EAAU,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EACrE,MAAU,MACR,oBAAoB,EAAQ,wGAC5B,CAAE,MAAO,CAAM,CACjB,CACF,CACA,IAAM,EAAa,IAAI,IAEjB,EAAU,GAAY,IAAY,CACtC,SAAW,IACT,EAAW,IAAI,EAAS,IAAI,EAE5B,EAAO,MAAM,CAAC,CAAC,SAAS,CAAQ,EACzB,EAEX,EAAE,EAEF,IAAK,IAAM,KAAa,EACtB,EAAQ,UAAU,CAAS,EAG7B,MAAO,CAAC,GAAG,CAAU,CACvB,CAEA,SAAS,gBAAgB,EAA0C,CACjE,IAAM,EAAW,IAAI,IAErB,IAAK,IAAM,KAAQ,EACjB,GAAI,EAAK,OAAS,QAAS,CACzB,IAAM,EAAY,EAAK,KAAK,KACtB,EAAQ,EAAK,KAAK,OAAS,EACjC,EAAS,IAAI,EAAO,CAAS,CAC/B,CAGF,OAAO,CACT,CAkBA,SAAgB,sBAAsB,EAAoC,CACxE,GAAI,CACF,IAAM,EAAa,GAAM,CAAK,EAE9B,IAAK,IAAM,KAAa,EAAY,CAClC,GAAI,EAAU,OAAS,UAAY,CAAC,EAAU,QAC5C,SAGF,IAAM,EAAW,gBAAgB,EAAU,MAAQ,CAAC,CAAC,EAC/C,EAAsB,CAAC,EACzB,EAAc,GAElB,IAAK,IAAM,KAAU,EAAU,QAC7B,GAAI,EAAO,KAAK,OAAS,OAAS,EAAO,KAAK,OAAS,IAAK,CAE1D,GADA,EAAc,GACV,EAAO,KAAK,MAAO,CACrB,IAAM,EAAY,EAAS,IAAI,EAAO,KAAK,MAAM,IAAI,EACrD,EAAM,KAAK,CAAE,KAAM,WAAY,WAAY,EAAY,CAAC,CAAS,EAAI,CAAC,CAAE,CAAC,CAC3E,MACE,EAAM,KAAK,CAAE,KAAM,WAAY,WAAY,CAAC,GAAG,IAAI,IAAI,EAAS,OAAO,CAAC,CAAC,CAAE,CAAC,CAEhF,KAAO,CACL,IAAM,EAAO,EAAO,OAAO,OAAS,EAAO,KAAK,OAAS,MAAQ,EAAO,KAAK,KAAO,MAChF,GACF,EAAM,KAAK,CAAE,KAAM,WAAY,MAAK,CAAC,CAEzC,CAGF,OAAO,EAAc,EAAQ,IAC/B,CAEA,OAAO,IACT,MAAQ,CACN,OAAO,IACT,CACF,CCxFA,eAAsB,mBACpB,EACA,EAC4B,CAC5B,IAAM,EAAgC,IAAI,IACpC,EAAW,EAAO,KAAK,GAE7B,GAAI,CAAC,GAAY,EAAE,UAAW,IAAa,EAAS,MAAM,SAAW,EACnE,OAAO,EAGT,IAAM,EAAU,EAAK,QAAQ,EAAO,IAAI,EAClC,EAAY,GAAqB,EAAU,CAAO,EAuBxD,OArBA,MAAM,QAAQ,IACZ,EAAU,IAAI,KAAO,IAAa,CAChC,GAAI,CACF,IAAM,EAAS,MAAM,OAAO,GAAc,CAAQ,CAAC,CAAC,MAEpD,IAAK,IAAM,KAAiB,OAAO,OAAO,CAAM,EAAG,CACjD,IAAM,EAASC,GAAmB,UAChC,GAAgC,CAAa,CAC/C,EACK,EAAO,SAIZ,EAAW,IAAI,EAAO,KAAK,KAAM,OAAO,KAAK,EAAO,KAAK,MAAM,CAAC,CAClE,CACF,MAAQ,CAER,CACF,CAAC,CACH,EAEO,CACT,CERA,MAAM,GAAoB,EAAE,KAAK,CD3CJ,MAAO,KC2CH,CAAY,EAEvC,GAAyB,EAAE,OAAO,CACtC,YAAa,EAAE,OAAO,CAAC,CAAC,SAAS,EACjC,QAAS,EAAE,OAAO,CAAC,CAAC,SAAS,EAC7B,WAAY,EAAE,OAAO,CAAC,CAAC,SAAS,EAChC,OAAQ,GACR,YAAa,EAAE,OAAO,CAAC,CAAC,SAAS,EACjC,kBAAmB,EAAE,KAAK,CAAC,SAAU,KAAK,CAAC,CAAC,CAAC,SAAS,CACxD,CAAC,EACK,GAAqB,GAAuB,OAAO,CACvD,MAAO,EAAE,OAAO,CAClB,CAAC,EA0CD,eAAe,yBACb,EACA,EACA,EACA,EACiB,CACjB,GAAI,EAAW,SAAW,EACxB,MAAU,MAAM,uCAAuC,EAGzD,GAAI,EAAW,SAAW,EACxB,OAAO,EAAc,EAAW,GAAI,mBAAmB,EAGzD,IAAM,EAAa,yBAAyB,CAAK,EACjD,GAAI,EAAW,SAAW,EACxB,MAAU,MACR,8DAA8D,EAAW,KAAK,IAAI,EAAE,EACtF,EAGF,IAAM,EAAoB,MAAM,uBAAuB,CACrD,cACA,aACA,aACA,QACF,CAAC,EAEK,EAAiB,EAAW,OAAQ,GAAc,CAAC,EAAkB,IAAI,CAAS,CAAC,EACzF,GAAI,EAAe,OAAS,EAC1B,MAAU,MAAM,iDAAiD,EAAe,KAAK,IAAI,EAAE,EAAE,EAG/F,IAAM,EAAuB,IAAI,IAAI,EAAkB,OAAO,CAAC,EAC/D,GAAI,EAAqB,OAAS,EAChC,OAAO,EAAc,CAAC,GAAG,CAAoB,CAAC,CAAC,GAAI,8BAA8B,EAGnF,MAAU,MACR,qDAAqD,CAAC,GAAG,CAAoB,CAAC,CAAC,KAAK,IAAI,EAAE,EAC5F,CACF,CAEA,eAAe,YAAY,EAA2B,CACpD,IAAM,EAAY,aAAa,GAAwB,CAAO,EAExD,EAAc,MAAM,oBAAoB,CAC5C,YAAa,EAAU,YACvB,kBAAmB,EAAU,kBAC7B,QAAS,EAAU,OACrB,CAAC,EACD,GAAI,CAAC,EACH,MAAU,MACR,iLACF,EAGF,IAAM,EAAc,MAAM,gBAAgB,CACxC,QAAS,EAAU,OACrB,CAAC,EACK,EAAS,MAAM,EAAmB,CAAW,EAC7C,EAAc,MAAM,gBAAgB,CACxC,YAAa,EAAU,YACvB,QAAS,EAAU,OACrB,CAAC,EACK,CAAE,UAAW,MAAM,WAAW,EAAQ,UAAU,EAChD,EAAa,qBAAqB,CAAM,EACxC,CAAE,eAAgB,MAAM,EAAO,eAAe,CAClD,cACA,gBAAiB,EAAO,IAC1B,CAAC,EAED,GAAI,CAAC,GAAa,cAChB,MAAU,MAAM,eAAe,EAAO,KAAK,sCAAsC,EAGnF,GAAM,CAAE,YAAa,GAAwB,MAAM,EAAO,mBAAmB,CAC9D,cACb,cAAe,EAAY,cAC3B,KAAM,CACR,CAAC,EAED,GAAI,CAAC,EACH,MAAU,MAAM,gBAAgB,EAAY,YAAY,EAG1D,MAAO,CACL,OAAQ,EAAU,OAClB,SACA,cACA,SACA,cACA,sBACA,YACF,CACF,CAEA,eAAe,SACb,EACA,EACA,EAMiC,CACjC,IAAM,EAAU,mBAAmB,EAAK,KAAK,EACvC,EAAW,MAAM,cAAc,CACnC,SACA,YAAa,EAAK,YAClB,KAAM,aAAa,EAAK,UAAU,KAClC,KAAM,EAAK,YACX,IAAK,CACH,UAAW,EAAK,UAChB,SACF,EACA,SACF,CAAC,EAED,GAAI,CAAC,EAAS,QACZ,MAAU,MAAM,EAAS,KAAK,EAGhC,MAAO,CACL,OAAQ,MACR,UAAW,EAAK,UAChB,MAAO,EAAK,MACZ,OAAQ,qBAAqB,EAAS,MAAM,CAC9C,CACF,CAEA,eAAe,SACb,EACA,EACA,EACA,EACA,EAKiC,CACjC,GAAM,CAAE,aAAc,GAAgB,MAAM,GAC1C,EAAY,IACZ,EAAY,SACZ,EAAY,YACd,EAEM,EAAW,MAAM,cAAc,CACnC,SACA,YAAa,EAAK,YAClB,KAAM,eACN,KAAM,EAAK,YACX,IAAK,CACH,SAAU,GAAG,EAAY,IAAI,QAC7B,cACA,MAAO,EAAK,KACd,EACA,SACF,CAAC,EAED,GAAI,CAAC,EAAS,QACZ,MAAU,MAAM,EAAS,KAAK,EAGhC,MAAO,CACL,OAAQ,MACR,MAAO,EAAK,MACZ,OAAQ,qBAAqB,EAAS,MAAM,CAC9C,CACF,CAEA,SAAS,qBAAqB,EAAyB,CACrD,GAAI,CAAC,EACH,OAAO,KAGT,GAAI,CACF,OAAO,KAAK,MAAM,CAAM,CAC1B,MAAQ,CACN,OAAO,CACT,CACF,CAWA,eAAsB,yBAAyB,EAKhB,CAmB7B,OAlBI,EAAK,OAAS,KAOd,EAAK,MAAQ,KAOb,EAAK,KACA,MAAM,wBAAwB,EAAK,MAAM,EAG3C,CACL,KAAM,MACR,EAZS,CACL,KAAM,QACN,MAAO,MAAM,EAAG,SAAS,EAAK,KAAM,OAAO,CAC7C,EAVO,CACL,KAAM,QACN,MAAO,EAAK,KACd,CAiBJ,CAEA,eAAe,wBAAwB,EAAiD,CACtF,GAAI,CAAC,QAAQ,MAAM,OAAS,CAAC,QAAQ,OAAO,MAC1C,MAAU,MACR,2FACF,EAGF,IAAM,EAAS,iBAAiB,EAE1B,EAAU,MAAM,EAAG,QAAQ,EAAK,KAAK,GAAO,EAAG,eAAe,CAAC,EAC/D,EAAgB,IAAW,MAAQ,MAAQ,UAC3C,EAAW,EAAK,KAAK,EAAS,SAAS,GAAe,EAG5D,GAAI,CACF,MAAM,EAAG,UAAU,EAAU,GAAc,OAAO,EAClD,GAAI,CACF,MAAM,aAAa,EAAU,CAAM,CACrC,OAAS,EAAO,CACd,MAAU,MACR,gCAAgC,EAAO,KAAK,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,IACjG,CAAE,MAAO,CAAM,CACjB,CACF,CAEA,IAAM,EAAc,MAAM,EAAG,SAAS,EAAU,OAAO,EAOvD,OANI,EAAY,KAAK,CAAC,CAAC,SAAW,GAAK,IAAgB,GAC9C,CACL,KAAM,OACR,EAGK,CACL,KAAM,QACN,MAAO,CACT,CACF,QAAU,CACR,MAAM,EAAG,GAAG,EAAS,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,CACvD,CACF,CAOA,eAAsB,MAAM,EAAqD,CAC/E,IAAM,EAAY,aAAa,GAAoB,CAAO,EAG1D,OAAO,MAAM,MADU,qBAAqB,CAAS,EAAA,CAC/B,EAAU,KAAK,CACvC,CAEA,eAAe,qBACb,EAC0D,CAC1D,GAAM,CAAE,SAAQ,cAAa,SAAQ,cAAa,sBAAqB,SAAQ,cAC7E,MAAM,YAAY,CAAO,EACrB,EAAc,MAAM,kBAAkB,EAAQ,EAAK,QAAQ,EAAO,IAAI,CAAC,EACvE,EAAU,GAAO,GAAmB,CACxC,UAAW,EAAY,cACvB,gBAAiB,EAAoB,IACvC,CAAC,EAED,OAAO,KAAO,IAAwB,CACpC,IAAI,EAEJ,GAAI,CACF,OAAQ,EAAR,CACE,IAAK,MAQH,MAPA,GAAY,MAAM,yBAAyB,EAAa,EAAa,EAAQ,CAAU,EAOhF,kBAAkB,MANJ,SAAS,EAAQ,EAAS,CAC7C,cACA,YACA,cACA,MAAO,CACT,CAAC,EACgC,EAAQ,EAAW,CAAW,EAEjE,IAAK,MACH,OAAO,MAAM,SAAS,EAAQ,EAAS,EAAa,EAAqB,CACvE,cACA,cACA,MAAO,CACT,CAAC,EACH,QACE,MAAU,MAAM,6BAA6B,GAAwB,CACzE,CACF,OAAS,EAAO,CACd,MAAM,uBAAuB,CAC3B,QACA,SACA,YACA,YAAa,EAAoB,IACnC,CAAC,CACH,CACF,CACF,CAOA,SAAgB,mBAAmB,EAAmC,CACpE,IAAM,EAAU,EAAM,KAAK,EAiB3B,OAhBK,EAAQ,WAAW,IAAI,EAIxB,IAAY,OAAS,IAAY,SAC5B,OAGL,IAAY,UAAY,IAAY,OAAS,IAAY,MACpD,OAGL,IAAY,WAAa,IAAY,MAChC,QAGF,UAfE,IAgBX,CAKA,SAAS,iBAAwB,CAC/B,QAAQ,OAAO,MAAM,OAAS,CAChC,CAEA,SAAS,qBAAqB,EAAuB,CACnD,OAAO,EAAM,QAAQ,mBAAoB,GAAG,CAC9C,CAEA,SAAgB,mBACd,EACA,EACA,EACoB,CACpB,GAAI,CAAC,GACH,OAEF,IAAM,EAAQ,CAAC,EAAS,CAAW,CAAC,CACjC,OAAQ,GAA2B,EAAQ,CAAM,CAAC,CAClD,IAAI,oBAAoB,CAAC,CACzB,KAAK,GAAG,EACL,EAAa,IAAW,MAAQ,MAAQ,MACxC,EAAS,EAAQ,IAAI,IAAU,GACrC,OAAO,EAAK,KAAK,GAAW,kBAAmB,iBAAiB,IAAa,EAAO,MAAM,CAC5F,CAKA,SAAS,oBAAoB,EAA4D,CACvF,MAAQ,IAAkB,CACxB,IAAM,EAAU,EAAM,KAAK,EACvB,OAAY,IAGZ,mBAAmB,CAAO,IAAM,KAMpC,OAHI,IAAW,MACN,mBAAmB,CAAK,EAAI,IAAA,GAAY,6CAE1C,uBAAuB,CAAK,EAAI,IAAA,GAAY,iCACrD,CACF,CAEA,eAAe,QACb,EAIe,CACf,GAAI,CAAC,QAAQ,MAAM,OAAS,CAAC,QAAQ,OAAO,MAC1C,MAAU,MACR,2FACF,EAGF,IAAM,EAAU,MAAM,qBAAqB,CAAO,EAC5C,EAAc,mBAAmB,EAAQ,OAAQ,EAAQ,QAAS,EAAQ,WAAW,EACrF,EAAW,oBAAoB,EAAQ,MAAM,EAG7C,CAAE,mBAAkB,uBAAsB,iBAAkB,MAAM,OAAO,8BACzE,EAAY,EAAQ,SAAW,MAAQ,EAAmB,EAO1D,EAAS,GAAa,CAC1B,OAAQ,GACR,qBAAsB,EAAQ,eAC9B,WACA,YACA,UAAW,EACX,MAAO,CAAE,aAAc,UAAW,EAClC,QAAS,EAAc,CAAE,SAAU,EAAa,WAAY,GAAI,EAAI,CAAC,EACrE,WAAY,CAAE,MAAO,CAAC,SAAU,SAAS,EAAG,SAAU,CAAE,CAC1D,CAAC,EAOD,IALA,EAAO,KAAK,YAAY,EAAQ,OAAO,YAAY,EAAE,YAAY,EACjE,EAAO,KAAK,qCAAqC,IAIpC,CACX,GAAM,CAAC,EAAO,GAAS,MAAM,EAAO,GAAG,EAAQ,OAAO,GAAG,EAEzD,GAAI,GAAO,OAAS,SAAU,CAC5B,GAAI,EAAM,SAAW,EACnB,OAEF,QACF,CAEA,GAAI,GAAO,OAAS,MAClB,OAGF,IAAM,EAAU,EAAM,KAAK,EAC3B,GAAI,IAAY,GACd,SAGF,IAAM,EAAU,mBAAmB,CAAO,EAC1C,GAAI,IAAY,OACd,OAEF,GAAI,IAAY,OAAQ,CACtB,cAAc,EAAQ,MAAM,EAC5B,QACF,CACA,GAAI,IAAY,QAAS,CACvB,gBAAgB,EAChB,QACF,CACA,GAAI,IAAY,UAAW,CACzB,EAAO,KAAK,oBAAoB,GAAS,EACzC,QACF,CAEA,GAAI,CACF,IAAM,EAAS,MAAM,EAAQ,CAAO,EAChC,EAAO,SAAW,MACpB,eAAe,EAAQ,CAAE,KAAM,EAAQ,IAAK,CAAC,EAE7C,eAAe,EAAQ,CAAE,KAAM,EAAQ,IAAK,CAAC,CAEjD,OAAS,EAAO,CACd,GAAI,GAAW,CAAK,EAAG,CACrB,EAAO,IAAI,EAAM,OAAO,CAAC,EACzB,QACF,CACA,GAAI,aAAiB,MAAO,CAC1B,EAAO,MAAM,EAAM,OAAO,EAC1B,QACF,CACA,EAAO,MAAM,OAAO,CAAK,CAAC,CAC5B,CACF,CACF,CAEA,SAAS,cAAc,EAA2B,CAChD,EAAO,IAAI,gBAAgB,EAC3B,EAAO,IAAI,gDAAgD,EAC3D,EAAO,IAAI,0CAA0C,EACrD,EAAO,IAAI,iDAAiD,EAC5D,EAAO,IAAI,EAAE,EACb,EAAO,IAAI,sEAAsE,EACjF,EAAO,IAAI,gEAAgE,EAC3E,EAAO,IAAI,mDAAmD,EAC9D,EAAO,IAAI,yDAAyD,EACpE,EAAO,IAAI,0CAA0C,EACrD,EAAO,IAAI,+CAA+C,EAC1D,EAAO,IAAI,EAAE,EACb,EAAO,IAAI,eAAe,EAC1B,EAAO,IAAI,6DAA6D,EACxE,EAAO,IAAI,wEAAwE,EACnF,EAAO,IAAI,yEAAyE,EACpF,EAAO,IAAI,EAAE,EACb,EAAO,IACL,IAAW,MACP,qCACA,sDACN,CACF,CAOA,eAAe,SAAS,EAA8D,CACpF,IAAM,EAAS,MAAM,MAAM,CACzB,GAAG,EACH,OAAQ,KACV,CAAC,EAED,GAAI,EAAO,SAAW,MACpB,MAAU,MAAM,uCAAuC,EAAO,QAAQ,EAGxE,OAAO,CACT,CAOA,eAAe,SAAS,EAA8D,CACpF,IAAM,EAAS,MAAM,MAAM,CACzB,GAAG,EACH,OAAQ,KACV,CAAC,EAED,GAAI,EAAO,SAAW,MACpB,MAAU,MAAM,uCAAuC,EAAO,QAAQ,EAGxE,OAAO,CACT,CAEA,eAAe,kBACb,EACA,EACA,EACA,EACiC,CACjC,GAAI,CAAC,qBAAqB,EAAO,MAAM,GAAK,EAAO,OAAO,KAAK,SAAW,EACxE,OAAO,EAGT,IAAM,EAAW,sBAAsB,CAAQ,EAC/C,GAAI,CAAC,EACH,OAAO,EAGT,GAAI,CAEF,IAAM,EAAgB,yBAAyB,EAAU,MADhC,mBAAmB,EAAQ,CAAS,CACM,EACnE,GAAI,EAAc,SAAW,EAC3B,OAAO,EAGT,IAAM,EAAc,EAAO,OAAO,KAAK,IAAK,GAAQ,qBAAqB,EAAK,CAAa,CAAC,EAE5F,MAAO,CACL,GAAG,EACH,OAAQ,CACN,GAAG,EAAO,OACV,KAAM,CACR,CACF,CACF,MAAQ,CACN,OAAO,CACT,CACF,CAEA,MAAM,GAAqB,CAAC,IAAI,EAEhC,SAAS,yBACP,EACA,EACU,CACV,IAAM,EAAkB,CAAC,EAEzB,IAAK,IAAM,KAAQ,EACjB,GAAI,EAAK,OAAS,WAChB,EAAM,KAAK,EAAK,IAAI,OAEpB,IAAK,IAAM,KAAa,EAAK,WAC3B,EAAM,KAAK,GAAG,EAAkB,EAChC,EAAM,KAAK,GAAI,EAAW,IAAI,CAAS,GAAK,CAAC,CAAE,EAKrD,OAAO,CACT,CAEA,SAAS,qBAAqB,EAAmB,EAAuC,CACtF,IAAM,EAAwB,CAAC,EACzB,EAAU,IAAI,IAAI,OAAO,KAAK,CAAG,CAAC,EAKlC,EAAkB,IAAI,IAC5B,IAAK,IAAM,KAAO,EAChB,EAAgB,IAAI,EAAI,YAAY,EAAG,CAAG,EAG5C,IAAK,IAAM,KAAO,EAAe,CAC/B,IAAM,EAAW,EAAgB,IAAI,EAAI,YAAY,CAAC,EAClD,GAAY,MAAQ,EAAQ,IAAI,CAAQ,IAC1C,EAAQ,GAAY,EAAI,GACxB,EAAQ,OAAO,CAAQ,EACvB,EAAgB,OAAO,EAAI,YAAY,CAAC,EAE5C,CAEA,IAAK,IAAM,KAAO,EAChB,EAAQ,GAAO,EAAI,GAGrB,OAAO,CACT,CAEA,MAAa,GAAe,EAAiB,CAC3C,KAAM,QACN,YAAa,yBACb,KAAM,EACH,aAAa,CACZ,GAAG,GACH,OAAQ,EAAI,GAAmB,CAC7B,YAAa,2BACf,CAAC,EACD,MAAO,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CAChC,MAAO,IACP,YAAa,2DACf,CAAC,EACD,KAAM,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CAC/B,MAAO,IACP,YAAa,sDACf,CAAC,EACD,KAAM,EAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAK,EAAG,CACpC,YAAa,+DACf,CAAC,EACD,eAAgB,EAAI,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CACzC,MAAO,IACP,YACE,kGACF,IAAK,mCACP,CAAC,EACD,mBAAoB,EAAI,EAAE,QAAQ,CAAC,CAAC,SAAS,EAAG,CAC9C,YACE,sGACJ,CAAC,CACH,CAAC,CAAC,CACD,aAAa,EAAM,IAAQ,CACtB,EAAK,OAAS,MAAQ,EAAK,MAAQ,MACrC,EAAI,SAAS,CACX,KAAM,SACN,KAAM,CAAC,MAAM,EACb,QAAS,gDACX,CAAC,EAGC,EAAK,MAAQ,EAAK,OAAS,MAC7B,EAAI,SAAS,CACX,KAAM,SACN,KAAM,CAAC,MAAM,EACb,QAAS,oDACX,CAAC,EAGC,EAAK,MAAQ,EAAK,MAAQ,MAC5B,EAAI,SAAS,CACX,KAAM,SACN,KAAM,CAAC,MAAM,EACb,QAAS,oDACX,CAAC,CAEL,CAAC,EACH,IAAK,KAAO,IAAS,CACnB,IAAM,EAAO,MAAM,yBAAyB,CAC1C,MAAO,EAAK,MACZ,KAAM,EAAK,KACX,KAAM,EAAK,KACX,OAAQ,EAAK,MACf,CAAC,EAEK,EAAkC,CACtC,YAAa,EAAK,gBAClB,QAAS,EAAK,QACd,WAAY,EAAK,OACjB,OAAQ,EAAK,OACb,YAAa,EAAK,gBAClB,kBAAmB,8BAA8B,EAAK,eAAe,CACvE,EAEA,GAAI,EAAK,OAAS,QAAS,CACzB,EAAO,KAAK,sDAAsD,EAClE,MACF,CAEA,GAAI,EAAK,OAAS,OAAQ,CACxB,IAAM,EACJ,EAAK,qBAAuB,GAAa,QAAQ,IAAI,6BAA6B,GAAK,GACzF,MAAM,QAAQ,CACZ,GAAG,EACH,KAAM,EAAK,KACX,gBACF,CAAC,EACD,MACF,CAEA,IAAM,EAAc,EAAK,MAEzB,GAAI,EAAK,SAAW,MAAO,CAKzB,eAAe,MAJM,SAAS,CAC5B,GAAG,EACH,MAAO,CACT,CAAC,EACsB,CAAE,KAAM,EAAK,IAAK,CAAC,EAC1C,MACF,CAMA,eAAe,MAJM,SAAS,CAC5B,GAAG,EACH,MAAO,CACT,CAAC,EACsB,CAAE,KAAM,EAAK,IAAK,CAAC,CAC5C,CACF,CAAC,EAED,SAAS,qBAAqB,EAA6C,CACzE,GAAI,CAAC,GAAS,OAAO,GAAU,SAC7B,MAAO,GAGT,IAAM,EAAY,EAClB,OAAO,MAAM,QAAQ,EAAU,IAAI,GAAK,OAAO,EAAU,UAAa,QACxE,CAEA,SAAS,qBACP,EACA,EAA8B,CAAC,EACzB,CACN,GAAI,EAAW,KAAK,SAAW,EAAG,CAChC,GAAI,EAAQ,KAAM,CAChB,EAAO,IAAI,CAAE,QAAS,CAAC,EAAG,SAAU,CAAE,CAAC,EACvC,MACF,CACA,EAAO,KAAK,mBAAmB,EAC/B,MACF,CAEA,GAAI,EAAQ,KAAM,CAChB,EAAO,IAAI,CAAE,QAAS,EAAW,KAAM,SAAU,EAAW,QAAS,CAAC,EACtE,MACF,CAEA,EAAO,IAAI,EAAW,KAAM,CAAE,SAAU,EAAK,CAAC,EAC9C,EAAO,IAAI,SAAS,EAAW,UAAU,CAC3C,CAEA,SAAS,mBAAmB,EAAyB,CACnD,IAAM,EAAaC,GAAS,EAAO,CAAE,iBAAkB,EAAK,CAAC,EAK7D,OAAO,EAAW,KAAK,EAAG,IAAM,CAC9B,IAAM,EAAQ,EAAc,EAAE,UAAW,gCAAgC,CAAC,CAAC,MACrE,EAAW,EAAW,EAAI,GAC1B,EACJ,IAAa,IAAA,GAET,EAAM,OADN,EAAc,EAAS,UAAW,gCAAgC,CAAC,CAAC,MAE1E,OAAO,EAAM,UAAU,EAAO,CAAG,CACnC,CAAC,CACH,CAEA,SAAS,0BAA0B,EAA+C,CAChF,OAAO,MAAM,QAAQ,CAAK,GAAK,EAAM,OAAS,GAAK,EAAM,MAAM,oBAAoB,CACrF,CAEA,SAAS,eAAe,EAAgC,EAA8B,CAAC,EAAS,CAC9F,GAAI,0BAA0B,EAAO,MAAM,EAAG,CAC5C,GAAI,EAAQ,KAAM,CAChB,EAAO,IAAI,EAAO,OAAO,IAAK,IAAO,CAAE,QAAS,EAAE,KAAM,SAAU,EAAE,QAAS,EAAE,CAAC,EAChF,MACF,CACA,IAAM,EAAU,mBAAmB,EAAO,KAAK,EAC/C,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,OAAO,OAAQ,IACpC,EAAI,GAAG,EAAO,IAAI,EAAE,EACxB,EAAO,KAAK,EAAQ,IAAM,aAAa,EAAI,GAAG,EAC9C,qBACE,EAAc,EAAO,OAAO,GAAI,uBAAuB,EAAE,SAAS,EAClE,CACF,EAEF,MACF,CAEA,GAAI,qBAAqB,EAAO,MAAM,EAAG,CACvC,qBAAqB,EAAO,OAAQ,CAAO,EAC3C,MACF,CAEA,EAAO,IAAI,CACT,OAAQ,EAAO,OACf,MAAO,EAAO,MACd,OAAQ,EAAO,MACjB,CAAC,CACH,CAEA,SAAS,eAAe,EAAgC,EAA8B,CAAC,EAAS,CAC9F,GAAI,EAAQ,KAAM,CAChB,EAAO,IAAI,CACT,OAAQ,EAAO,MACjB,CAAC,EACD,MACF,CAEA,EAAO,IAAI,KAAK,UAAU,EAAO,OAAQ,KAAM,CAAC,CAAC,CACnD,CCx4BA,SAAS,WAAW,EAAuB,CACzC,OAAO,EAAM,WAAW,IAAK,KAAK,CAAC,CAAC,WAAW,KAAM,KAAK,CAAC,CAAC,WAAW;EAAM,KAAK,CACpF,CAUA,SAAS,eAAe,EAAuB,CAC7C,OAAO,WAAW,CAAK,CAAC,CAAC,WAAW,IAAK,KAAK,CAAC,CAAC,WAAW,IAAK,KAAK,CACvE,CAUA,SAAS,qBAA+B,CACtC,IAAM,EAAO,QAAQ,KAAK,MAAM,CAAC,EAC3B,EAAY,EAAK,QAAQ,IAAI,EAEnC,OADgB,IAAc,GAAK,EAAO,EAAK,MAAM,EAAG,CAAS,EAAA,CAClD,KAAM,GAAU,CAC7B,IAAM,EAAa,EAAM,QAAQ,GAAG,EAC9B,EAAO,IAAe,GAAK,EAAQ,EAAM,MAAM,EAAG,CAAU,EAElE,OADI,IAAS,UAAY,IAAS,KAAa,GACxC,IAAe,IAAM,GAAa,EAAM,MAAM,EAAa,CAAC,CAAC,IAAM,EAC5E,CAAC,CACH,CAUA,SAAgB,mBAAmB,EAA4B,CAG7D,OAFI,GAAY,oBAAoB,GAChC,QAAQ,IAAI,iBAAmB,OAAe,GAC3C,GAAa,QAAQ,IAAI,iCAAiC,IAAM,EACzE,CAWA,SAAS,SAAS,EAAuB,CACvC,GAAI,CACF,OAAO,GAAa,GAAQ,CAAK,CAAC,CACpC,MAAQ,CACN,OAAO,GAAQ,CAAK,CACtB,CACF,CAaA,SAAgB,sBAAsB,EAAkC,CACtE,IAAM,EAAY,QAAQ,IAAI,iBAC9B,GAAI,CAAC,GAAa,CAAC,GAAW,CAAI,EAAG,OACrC,IAAM,EAAM,GAAS,SAAS,CAAS,EAAG,SAAS,CAAI,CAAC,EACxD,GAAI,IAAQ,IAAM,GAAW,CAAG,EAAG,OACnC,IAAM,EAAW,EAAI,MAAM,EAAG,EAG1B,KAAS,KAAO,KACpB,OAAO,EAAS,KAAK,GAAG,CAC1B,CAYA,SAAgB,iBACd,EACA,EACA,EAAmC,CAAC,EAC5B,CACR,IAAM,EAAoB,CAAC,EAW3B,OAVI,EAAW,QAAU,IAAA,IACvB,EAAQ,KAAK,SAAS,eAAe,GAAyB,EAAW,KAAK,CAAC,GAAG,EAEhF,EAAW,OAAS,IAAA,IACtB,EAAQ,KAAK,QAAQ,eAAe,EAAW,IAAI,GAAG,EAEpD,EAAW,OAAS,IAAA,IACtB,EAAQ,KAAK,QAAQ,EAAW,MAAM,EAGjC,KAAK,IADS,EAAQ,OAAS,EAAI,IAAI,EAAQ,KAAK,GAAG,IAAM,GACnC,IAAI,WAAW,GAAyB,CAAO,CAAC,EAAE,GACrF,CAEA,SAAS,iBAAiB,EAAkC,CAC1D,IAAM,EAAU,EAA+B,OAC/C,GAAI,OAAO,GAAW,WAAY,OAClC,IAAM,EAAqB,EAAO,KAAK,CAAK,EAC5C,OAAO,OAAO,GAAc,SAAW,EAAY,IAAA,EACrD,CAYA,SAAgB,sBACd,EACA,EACqC,CACrC,GAAI,GAAW,CAAK,EAClB,MAAO,CAAE,QAAS,EAAM,OAAO,EAAG,MAAO,EAAM,MAAQ,WAAY,EAErE,GAAI,aAAiB,MAAO,CAG1B,IAAM,EAAQ,GAAoB,CAAK,CAAC,CAAC,OAAS,EAAM,MAAQ,SAC1D,EAAY,iBAAiB,CAAK,EACxC,GAAI,IAAc,IAAA,GAChB,MAAO,CAAE,QAAS,EAAW,OAAM,EAErC,IAAM,EAAa,EAAqB,iBAAiB,IAAuB,GAChF,MAAO,CAAE,QAAS,GAAG,EAAM,UAAU,IAAc,OAAM,CAC3D,CACA,MAAO,CAAE,QAAS,kBAAkB,OAAO,CAAK,IAAK,MAAO,eAAgB,CAC9E,CAWA,SAAgB,mBAAoC,EAAU,EAAkC,CAC9F,OAAO,GAAqB,EAAO,CAAE,UAAS,CAAC,CACjD,CASA,SAAgB,sBACd,EACA,EACM,CACN,GAAI,CAAC,mBAAmB,EAAQ,QAAQ,EAAG,OAC3C,GAAM,CAAE,UAAS,SAAU,sBAAsB,EAAO,EAAQ,UAAU,EAC1E,QAAQ,OAAO,MAAM,iBAAiB,QAAS,EAAS,CAAE,QAAO,GAAG,eAAe,CAAK,CAAE,CAAC,CAAC,CAC9F,CAUA,SAAS,eAAe,EAAkD,CACxE,GAAI,EAAE,aAAiB,OAAQ,MAAO,CAAC,EACvC,IAAM,EAAW,GAAoB,CAAK,CAAC,CAAC,SAC5C,GAAI,CAAC,EAAU,MAAO,CAAC,EACvB,IAAM,EAAO,sBAAsB,EAAS,IAAI,EAEhD,OADI,IAAS,IAAA,GAAkB,CAAC,EACzB,EAAS,OAAS,IAAA,GAAY,CAAE,MAAK,EAAI,CAAE,OAAM,KAAM,EAAS,IAAK,CAC9E,CCjOA,SAAgB,2BAAqC,CACnD,OAAO,MAAM,GAAK,OAAO,CAC3B,CAMA,SAAgB,OAAiB,CAC/B,MAAO,QAAS,UAClB,CAMA,SAAgB,QAAkB,CAChC,MAAO,SAAU,UACnB,CCvBA,eAAsB,eAAe,EAA+B,CAClE,GAAI,0BAA0B,EAAG,OACjC,GAAM,CAAE,cAAa,YAAc,MAAM,OAAO,EAAU,MAI1D,GAAI,cAAc,CAAE,QAAS,EAAa,KAAM,CAAS,CAAC,CAC5D"}