{"version":3,"file":"keys-D2Ja0FKF.cjs","names":[],"sources":["../src/shared/keys.ts"],"sourcesContent":["/**\n * Permission map key: `[scope:]action:resource[:resourceId]`; `:` and `\\` are backslash-escaped per segment.\n *\n * @param action - Identifies the action (for example `'read'`).\n * @param resource - Identifies the resource (for example `'document'`).\n * @param resourceId - Optionally pins the key to a concrete resource instance.\n * @param scope - Optionally prefixes a scope for tenant or namespace partitioning.\n * @returns Composed colon-delimited key with hostile segments escaped.\n */\nexport function iamBuildPermissionKey(action: string, resource: string, resourceId?: string, scope?: string): string {\n  const e = escapeSegment\n  if (scope) {\n    return resourceId\n      ? `${e(scope)}:${e(action)}:${e(resource)}:${e(resourceId)}`\n      : `${e(scope)}:${e(action)}:${e(resource)}`\n  }\n  return resourceId ? `${e(action)}:${e(resource)}:${e(resourceId)}` : `${e(action)}:${e(resource)}`\n}\n\nfunction escapeSegment(s: string): string {\n  if (!s.includes(':') && !s.includes('\\\\')) return s\n  return s.replace(/\\\\/g, '\\\\\\\\').replace(/:/g, '\\\\:')\n}\n\n/**\n * Splits a permission key produced by {@link iamBuildPermissionKey} into its\n * original segments, honouring the `\\:` and `\\\\` escape sequences. Naive\n * `.split(':')` would mis-tokenise any segment containing a literal `:` or\n * `\\`.\n *\n * @param key - Permission key, e.g. `'read:document'` or `'tenant_a:write:doc\\\\:42'`.\n * @returns Array of unescaped segments in declaration order.\n */\nexport function iamSplitPermissionKey(key: string): string[] {\n  const out: string[] = []\n  let current = ''\n  let i = 0\n  while (i < key.length) {\n    const ch = key[i] as string\n    if (ch === '\\\\' && i + 1 < key.length) {\n      const next = key[i + 1] as string\n      // Only the two escape sequences are recognised; anything else is\n      // treated literally so an attacker-crafted `\\x` doesn't silently\n      // become `x`.\n      if (next === ':' || next === '\\\\') {\n        current += next\n        i += 2\n        continue\n      }\n    }\n    if (ch === ':') {\n      out.push(current)\n      current = ''\n      i++\n      continue\n    }\n    current += ch\n    i++\n  }\n  out.push(current)\n  return out\n}\n"],"mappings":";;;;;;;;;;;AASA,SAAgB,sBAAsB,QAAgB,UAAkB,YAAqB,OAAwB;CACnH,MAAM,IAAI;CACV,IAAI,OACF,OAAO,aACH,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,UAAU,MACvD,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ;CAE5C,OAAO,aAAa,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,UAAU,MAAM,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ;AACjG;AAEA,SAAS,cAAc,GAAmB;CACxC,IAAI,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC,EAAE,SAAS,IAAI,GAAG,OAAO;CAClD,OAAO,EAAE,QAAQ,OAAO,MAAM,CAAC,CAAC,QAAQ,MAAM,KAAK;AACrD;;;;;;;;;;AAWA,SAAgB,sBAAsB,KAAuB;CAC3D,MAAM,MAAgB,CAAC;CACvB,IAAI,UAAU;CACd,IAAI,IAAI;CACR,OAAO,IAAI,IAAI,QAAQ;EACrB,MAAM,KAAK,IAAI;EACf,IAAI,OAAO,QAAQ,IAAI,IAAI,IAAI,QAAQ;GACrC,MAAM,OAAO,IAAI,IAAI;GAIrB,IAAI,SAAS,OAAO,SAAS,MAAM;IACjC,WAAW;IACX,KAAK;IACL;GACF;EACF;EACA,IAAI,OAAO,KAAK;GACd,IAAI,KAAK,OAAO;GAChB,UAAU;GACV;GACA;EACF;EACA,WAAW;EACX;CACF;CACA,IAAI,KAAK,OAAO;CAChB,OAAO;AACT"}