{"id":51687811,"url":"https://github.com/flarebyte/beaming_yggdrasil_key","last_synced_at":"2026-07-15T22:35:03.909Z","repository":{"id":350186277,"uuid":"1202096721","full_name":"flarebyte/beaming_yggdrasil_key","owner":"flarebyte","description":"Key for beaming yggdrasil","archived":false,"fork":false,"pushed_at":"2026-04-09T08:27:11.000Z","size":29,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-09T09:29:16.889Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/flarebyte.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-05T15:39:22.000Z","updated_at":"2026-04-05T15:39:30.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/flarebyte/beaming_yggdrasil_key","commit_stats":null,"previous_names":["flarebyte/beaming_yggdrasil_key"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/flarebyte/beaming_yggdrasil_key","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flarebyte%2Fbeaming_yggdrasil_key","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flarebyte%2Fbeaming_yggdrasil_key/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flarebyte%2Fbeaming_yggdrasil_key/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flarebyte%2Fbeaming_yggdrasil_key/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flarebyte","download_url":"https://codeload.github.com/flarebyte/beaming_yggdrasil_key/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flarebyte%2Fbeaming_yggdrasil_key/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35523587,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-15T02:00:06.706Z","response_time":131,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-15T22:35:03.231Z","updated_at":"2026-07-15T22:35:03.902Z","avatar_url":"https://github.com/flarebyte.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# beaming_yggdrasil_key\n\n![beaming_yggdrasil_key hero](doc/beaming-yggdrasil-key-hero.png)\n\n`beaming_yggdrasil_key` is a Dart library for working with Yggdrasil-style keys as structured data instead of ad hoc strings.\n\nIt is designed for applications that need to:\n\n- parse and validate canonical `label:value` keys\n- derive structured parts such as scope, anchor, and descendant path\n- navigate parent and ancestor relationships\n- check descendant relationships across collections of keys\n- split keys into parallel label and value arrays and combine them back\n\n## Why Use It\n\nYggdrasil-style keys are compact and expressive, but raw string handling becomes brittle once code needs validation, traversal, or relationship checks.\n\nThis library treats keys more like paths:\n\n- a key is validated against a schema\n- the first configured anchor segment becomes the navigation root\n- everything before the anchor is scope\n- everything after the anchor is path\n\nThat gives you deterministic parsing, stable canonical output, and reusable helpers for common key operations.\n\n## Getting Started\n\nAdd the package to your `pubspec.yaml`:\n\n```yaml\ndependencies:\n  beaming_yggdrasil_key: ^\u003clatest-version\u003e\n```\n\nThen import it in your Dart code:\n\n```dart\nimport 'package:beaming_yggdrasil_key/beaming_yggdrasil_key.dart';\n```\n\n## Key Format\n\nKeys use explicit `label:value` pairs:\n\n```text\ntenant:a8f3a1c2:group:b4b7d9e1:dashboard:d1e52f07\n```\n\nSupported values are:\n\n- ordinary identifier values such as `a8f3a1c2`\n- `_` for intrinsic values\n- `~` for contextual self values\n\nExamples:\n\n```text\ntenant:a8f3a1c2:group:b4b7d9e1:dashboard:d1e52f07\ntenant:a8f3a1c2:group:b4b7d9e1:dashboard:d1e52f07:note:c7c401c2:text:_\ntenant:a8f3a1c2:group:b4b7d9e1:dashboard:d1e52f07:user:~\ndepartment:d1:team:a1:profile:b1\n```\n\n## Core Concepts\n\nFor a key like:\n\n```text\ntenant:a8f3a1c2:group:b4b7d9e1:dashboard:d1e52f07:note:c7c401c2:text:_\n```\n\nThe parsed structure is:\n\n- `scope`: `tenant:a8f3a1c2`, `group:b4b7d9e1`\n- `anchor`: `dashboard:d1e52f07`\n- `path`: `note:c7c401c2`, `text:_`\n- `kindPath`: `tenant`, `group`, `dashboard`, `note`, `text`\n- `terminalKind`: `text`\n\nThis model is what enables navigation helpers such as parent, ancestors, and descendant checks.\n\n## Main Capabilities\n\nThe library is intended to expose a focused API around these operations:\n\n- `parse(keyId)` to validate and turn a key into a `ParsedKey`\n- `mustParse(keyId)` when invalid input should fail immediately\n- `isValid(keyId)` for a lightweight yes/no check\n- `splitKey(keyId)` and `splitKeys(keyIds)` to separate labels and values\n- `combineKey(labels, values)` and `combineKeys(...)` to rebuild canonical keys\n- `parentOf(keyId)` and `ancestorsOf(keyId)` for upward navigation\n- `isAnchorKey(keyId)` to check whether a key ends exactly at the anchor\n- `isDescendantOf(anchorKeyId, candidateKeyId)` and `descendantsOf(...)` for relationship queries\n- `toCanonicalString(parsed)` to serialize validated data back to the canonical key form\n\n## Schema-Driven Validation\n\nValidation is schema-driven rather than hardcoded.\n\nA schema defines:\n\n- which labels may appear at the root\n- which labels count as anchors\n- which values each label accepts\n- which child labels may follow each label\n- identifier rules such as allowed characters and length bounds\n\nExample schema shape:\n\n```dart\nconst exampleSchema = {\n  'config': {\n    'maxDepth': 8,\n    'minIdChars': 1,\n    'maxIdChars': 64,\n    'idAlphabet': 'lower-hex',\n    'extraIdChars': ['-'],\n  },\n  'rootLabels': ['tenant', 'department', 'region'],\n  'anchorLabels': ['dashboard', 'profile'],\n  'nodesByLabel': {\n    'tenant': {\n      'label': 'tenant',\n      'valueTypes': ['id'],\n      'childLabels': ['group', 'department', 'region', 'dashboard', 'profile'],\n    },\n    'group': {\n      'label': 'group',\n      'valueTypes': ['id'],\n      'childLabels': ['dashboard', 'profile'],\n    },\n    'dashboard': {\n      'label': 'dashboard',\n      'valueTypes': ['id'],\n      'childLabels': ['note', 'language', 'thumbnail', 'like', 'user'],\n    },\n    'note': {\n      'label': 'note',\n      'valueTypes': ['id'],\n      'childLabels': ['text', 'language', 'thumbnail', 'like'],\n    },\n    'text': {\n      'label': 'text',\n      'valueTypes': ['_'],\n      'childLabels': [],\n    },\n    'user': {\n      'label': 'user',\n      'valueTypes': ['~', '_'],\n      'childLabels': [],\n    },\n    'profile': {\n      'label': 'profile',\n      'valueTypes': ['id'],\n      'childLabels': [],\n    },\n  },\n};\n```\n\n## Typical Usage\n\n```dart\nfinal parser = BeamingYggdrasilKeyParser(schema: exampleSchema);\n\nfinal result = parser.parse(\n  'tenant:a8f3a1c2:group:b4b7d9e1:dashboard:d1e52f07:note:c7c401c2:text:_',\n);\n\nif (result.ok) {\n  final parsed = result.value;\n\n  print(parsed.canonical);\n  print(parsed.anchor.label);\n  print(parsed.terminalKind);\n  print(parsed.kindPath);\n}\n```\n\nExpected parsed view:\n\n```dart\n{\n  'canonical': 'tenant:a8f3a1c2:group:b4b7d9e1:dashboard:d1e52f07:note:c7c401c2:text:_',\n  'kindPath': ['tenant', 'group', 'dashboard', 'note', 'text'],\n  'scope': [\n    {'label': 'tenant', 'value': 'a8f3a1c2'},\n    {'label': 'group', 'value': 'b4b7d9e1'},\n  ],\n  'anchor': {'label': 'dashboard', 'value': 'd1e52f07'},\n  'path': [\n    {'label': 'note', 'value': 'c7c401c2'},\n    {'label': 'text', 'value': '_'},\n  ],\n  'terminalKind': 'text',\n}\n```\n\n## Navigation Examples\n\n```dart\nfinal key =\n    'tenant:a8f3a1c2:group:b4b7d9e1:dashboard:d1e52f07:note:c7c401c2:text:_';\n\nfinal parent = parser.parentOf(key);\nfinal ancestors = parser.ancestorsOf(key);\nfinal isAnchor = parser.isAnchorKey(\n  'tenant:a8f3a1c2:group:b4b7d9e1:dashboard:d1e52f07',\n);\n```\n\nTypical results:\n\n```dart\nparent ==\n    'tenant:a8f3a1c2:group:b4b7d9e1:dashboard:d1e52f07:note:c7c401c2'\n\nancestors == [\n  'tenant:a8f3a1c2:group:b4b7d9e1:dashboard:d1e52f07:note:c7c401c2',\n  'tenant:a8f3a1c2:group:b4b7d9e1:dashboard:d1e52f07',\n]\n\nisAnchor == true\n```\n\n## Relationship Queries\n\nYou can also ask whether one key is below another anchor and filter descendants from a collection.\n\n```dart\nfinal anchor = 'tenant:a8f3a1c2:group:b4b7d9e1:dashboard:d1e52f07';\n\nfinal keys = [\n  'tenant:a8f3a1c2:group:b4b7d9e1:dashboard:d1e52f07',\n  'tenant:a8f3a1c2:group:b4b7d9e1:dashboard:d1e52f07:note:c7c401c2',\n  'tenant:a8f3a1c2:group:b4b7d9e1:dashboard:d1e52f07:note:c7c401c2:text:_',\n  'department:d1:team:a1:profile:b1',\n];\n\nfinal directOrNested = parser.descendantsOf(anchor, keys);\nfinal directOnly = parser.descendantsOf(anchor, keys, query: {\n  'maxDepth': 1,\n});\n```\n\n## Split And Combine\n\nFor algorithms that work better on arrays than strings, keys can be split into parallel labels and values.\n\n```dart\nfinal split = parser.splitKey(\n  'tenant:a8f3a1c2:group:b4b7d9e1:dashboard:d1e52f07',\n);\n\nprint(split.labels); // ['tenant', 'group', 'dashboard']\nprint(split.values); // ['a8f3a1c2', 'b4b7d9e1', 'd1e52f07']\n\nfinal rebuilt = parser.combineKey(split.labels, split.values);\n```\n\nThis is useful when you need to:\n\n- compare label paths independently from values\n- batch-process many keys\n- transform selected values while preserving canonical serialization\n\n## Validation Behavior\n\nThe library is intended to reject malformed or unsupported keys deterministically. Examples of invalid input include:\n\n- empty keys\n- incomplete `label:value` pairs\n- unsupported labels\n- invalid child transitions\n- children under terminal labels\n- identifier values that do not satisfy schema rules\n- reserved-value misuse such as missing `_` or invalid use of `~`\n\nCanonical serialization always emits explicit `label:value` pairs.\n\n## When To Use This Library\n\nThis package is a good fit when your application needs lightweight key utilities without pulling in broader infrastructure concerns.\n\nUse it when you want:\n\n- one focused place for key parsing and validation\n- path-like navigation over structured keys\n- stable canonical strings for persistence and comparison\n- schema-configurable validation instead of hardcoded key grammar\n\nIt intentionally stays out of:\n\n- authorization decisions\n- application-specific business meaning\n- storage or synchronization logic\n- workflow orchestration around keys\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflarebyte%2Fbeaming_yggdrasil_key","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflarebyte%2Fbeaming_yggdrasil_key","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflarebyte%2Fbeaming_yggdrasil_key/lists"}