{"id":"237667820943d1c8bbe7ab7732623ae51b337f177776ece439d4a8be84708eb7","pubkey":"df67f9a7e41125745cbe7acfbdcd03691780c643df7bad70f5d2108f2d4fc200","created_at":1769797547,"kind":30817,"tags":[["d","nip-trusted-filters"],["title","TRUSTed Filters"],["k","17570"],["client","nostrhub.io"]],"content":"TRUSTed Filters\n======\n\n`nip-trusted-filters`\n\n`draft`\n\n`extends` [nip-01](https://github.com/nostr-protocol/nips/blob/master/01.md)\n\n`extends` [nip-11](https://github.com/nostr-protocol/nips/blob/master/11.md)\n\n`kind` `17570` \"Trust Provider Preferences\" `r` `p` \n\n`tag` `W` \"input parameter for generated events\"\n\n`tag` `w` \"output data in generated events\"\n\n`message` > `TRUST` \"ping trust services OR request trusted filtering\"\n\n`message` < `TRUST` \"send ping response with service info\"\n\n---\n\nThis is an **extendable standard for Trust Services** allowing users to:\n\n- offload computationally expensive event processing to subscribed cloud services,\n- discover, share, and compose their own filtering algorithms for use across services,\n- maintain control over algorithm processing, with granular preferences for each service provider.\n\nWhile existing NIPs provide basic event filtering (NIP-01 filters) and computational job processing (NIP-90 DVMs), and even a fixed set of algorithms for trusted assertions (NIP-85), none of them address the need for **subscription-based processing of user-configurable and sharable event processing algorithms**. NIP-01 filters cannot query deep event structures or handle event transformations. NIP-90 handles one-off computational \"bounties\", but not subscription-based services controlled by user preferences. And NIP-85 only specifies a fixed set of algorithms, with no configurability for end users.\n\nThis NIP offers a Nostr native specification for clients to send *trusted filter* requests via `TRUST` messages to relays operated by *Trust Services Providers*, and to receive standard `EVENT` messages (event streams) in response. `TRUST` messages are designed to ensure transparency and freedom of choice for end users, whenever TRUST SENSITIVE cloud services are required.\n\n\n## TRUST Messages\n\nSimilar to standard `REQ` messages (as defined in NIP-01), `TRUST` messages accept one or more filter objects. However, this is where the similarity ends.\n\n- `TRUST` messages require `AUTH` (NIP-42) confirmation of a subscriber's pubkey.\n- `TRUST` messages accept *trusted filters* which allow for advanced querying of deep event data.\n- `TRUST` *trusted filters* may contain *plugins*, which extend the filtering, transformation, and event publishing capacity.\n- `TRUST` messages have fine grained permissions and configurability built into the spec, allowing users to maintain control at all times across different client and relay implementations.\n\n**Client to Relay**\n\n```jsonc\n// ping for general supported services\n[\"TRUST\"]\n// ping for subscription supported services\n[\"TRUST\", \"<subscription_pubkey>\"]\n// request any number of trusted filters (filters are ORed together)\n[\"TRUST\", \"<subscription_pubkey>\", \"<session_id>\", \"<trusted_filter_json>\", ...]\n```\n\n- `<subscription_pubkey>` is the pubkey for which `TRUST` services are being requested from the provider.\n- `<session_id>` is a unique identifier for messages sent and received in relation to this (subscriber's) session.\n- `<trusted_filter_json>` is a JSON object representing a trusted filter (more than one may be sent in a single request)\n\n\n**Relay to Client**\n\n```jsonc\n// ping response\n[\"TRUST\", \"<subscription_pubkey>\", \"<trust_relay_support_info>\"]\n// error messages\n[\"CLOSED\", \"<session_id>\", \"<trust_relay_error_message>\"]\n```\n- `<trust_relay_support_info>` is a JSON object containing subscriber specific information about the relay's supported services (see below)\n- `<trust_relay_error_message>` is a string containing a machine-readable prefix and human-readable error message. (see Appendix 5)\n\n\n\n\n\n## Subscriptions & Authentication\n\nThe `TRUST` message specification is designed to support subscription based services. Service providers MAY generate a unique `subscription_pubkey` for each subscriber, or one for all subscribers, or none at all. Providers SHOULD be able to associate the `subscription_pubkey` sent in `TRUST` messages with the pubkey of a subscriber, and SHOULD ALWAYS send an `AUTH` (NIP-42) request AND receive successful confirmation of the `subscriber_pubkey` BEFORE processing `TRUST` messages. \n\n**IMPORTANT :** `TRUST` messages MAY trigger TRUST SENSITIVE algorithms (such as reputation scoring, content analysis, and social graph inference) to be executed by service providers. As such, Clients SHOULD ALWAYS act in their user's best interest. \n\n- Clients SHOULD discover the user's published (kind `17570`) \"Trust Provider Preferences\" before sending `TRUST` messages.\n- Clients SHOULD ONLY send `TRUST` messages to the user's appropriate preferred provider, if one is published.\n- If NO appropriate provider preference is published, clients MAY send `TRUST` filter requests to their own preferred provider and SHOULD ALWAYS inform the user of this decision.\n\n## TRUSTed Filter Format\n\nA *trusted filter* is a JSON object that extends the standard NIP-01 `REQ` filter. Out of the box, this pluggable filter format allows for deep event querying and relative time ranges.\n\n```jsonc\n[ \"TRUST\", \n  {\n    // Standard NIP-01 fields (unchanged)\n    \"ids\": [\"<event_id>\", ...],\n    \"authors\": [\"<pubkey>\", ...],\n    \"kinds\": [<kind_number>, ...],\n    \"#<single_letter>\": [\"<value>\", ...],\n\n    // TRUSTed Filter: EventPath \n    // matching values on ANY event field or #tag or embedded JSON object\n    // where * matches any value, and ! matches when NO values exist\n    \"<EventPath>\": [\"<value>\", ...] | \"*\" | \"!\" ,\n    // ... (any number of EventPath filters)\n\n    // TRUSTed Filter: Relative time\n    \"since\": \"<timestamp>\" | \"<RelativeTime>\",\n    \"until\": \"<timestamp>\" | \"<RelativeTime>\",\n\n    // Supported plugins MAY be added to the filter request\n    // Unsupported plugins SHOULD result in the ENTIRE request being rejected\n    // Plugins SHOULD be applied after all other filters\n    // and in the order that they are listed\n    \"plugins\": [...],\n\n    // Limit is always applied last.\n    \"limit\": \"<number>\"\n  }\n]\n```\n\n## Plugins\n\nPlugins MAY add additional functionality to a *trusted filter*. Plugins are executed in the order specified, after standard filter criteria are applied. Each plugin operates on the output of the previous operation in the pipeline.\n\n**Request Format:**\n\n```jsonc\n[\"TRUST\", \"<subscription_pubkey>\", \"<session_id>\", {\n  // Plugin functions are executed in the order specified\n  // A plugin may have multiple instances in the same filter\n  // each plugin instance may have multiple function calls\n  // function calls may have multiple arguments, but the first is always required.\n  // arguments MAY accept any value, including EventPath or IO queries \n  // as per the plugin's NIP specification.\n  \"plugins\" : [\n    // plugin instance\n    [ \"<plugin_key>\", \n      // plugin function calls\n      [\"<input>\", \"<param?>\"...],\n      [\"<input>\", \"<param?>\"...],\n    ]\n  ]\n}]\n```\n\n**Plugin Support:**\n\n- *Trust services* SHOULD advertise their supported plugins to clients (via `TRUST` ping responses).\n- *Trust services* SHOULD execute ALL plugin function calls requested in a filter, in the order they are specified.\n- *Trust services* SHOULD reject any filter requests that contain plugins that are not supported.\n\n**Plugin NIPs:**\n\nNIP specifications for Plugins MAY be published by anyone to any URL.\n\n- MUST define a `plugin_key` by which to identify the plugin in filter requests\n- A `plugin_key` MAY NOT contain the following reserved characters: `:`, `#`, `$`, `/`\n- MUST define a human-readable name and description based on what the plugin does\n- SHOULD accept multiple *argument arrays of strings* in each function call\n- MAY inspect any EventPath to access event data\n- MUST accept at least one input string\n- MAY specify additional parameters for input arrays\n- MUST specify expected behavior for implementors\n\n**Plugin Types:**\n\nThe following are some conventions for plugin types. Such terminology MAY be indicated in a plugin's NIP specification for clarity.\n\n- **Filtering plugins** operate on candidate events:\n   - Read candidate events\n   - Apply additional filter criteria\n   - Modify the order or grouping of candidate events.\n\n- **Transformation plugins** extract and process data from filtered events.\n   - Read from filtered events\n   - Read and Write `IO` data\n\n- **Flow Control plugins** modify filter execution behavior:\n   - Control scheduling and requirements\n   - Manage iteration and dependencies\n   - Affect request-level behavior\n\n- **Input & Output plugins** manage the `IO` namespace:\n   - Read from filtered events\n   - Write to `IO` namespace\n   - Composable via `IO` data flow\n\n- **Publishing plugins** create events from extracted data:\n   - Read from `IO` data\n   - Render tags from `IO` data\n   - Publish events to relays\n\n\n## `IO` Interface\n\n`IO` is a shared interface for plugins to exchange data within a single request. `IO` starts empty for each request and is progressively populated by plugins as they execute.\n\n- Every plugin SHOULD have write access to an `IO` namespace at `<plugin_key>`.\n- Plugins SHOULD have read access to ANY other plugin's namespace, at `<other_plugin_key>`.\n- Plugins MAY specify that ANY other plugins ALSO have write access to their namespace. \n- If allowed, other plugins SHOULD write to (colon `:` separated) `<plugin_key>:<other_plugin_key>`.\n- Plugins MAY use simple key/value pairs, `<plugin_key>.<key>`, in their `IO` namespace\n- OR plugins MAY specify more complex data structures for their `IO` namespace.\n\n**Accessing `IO` Data:**\n\nPlugins can access `IO` data in two ways:\n\n1. **Direct access:**\n\nPlugins MAY specify specific arguments that accept `IO` queries.\n\n   ```jsonc\n   // This plugin processes data from <other_plugin>.<other_key> \n   // and outputs results in its own IO key <io_key>\n   [\"<plugin_that_processes_io_data>\", [\"<other_plugin>.<other_key>\", \"<io_key>\"]]\n   ```\n\n2. **String interpolation:**\n\nString replacement (by interpolation) may be used in ANY argument (in subsequent filters or plugins) that accepts a string.\n\n   ```jsonc\n   // this filter uses IO data written in a previous filter\n   // from <another_plugin> into <writable_plugin>\n   // to determine which authors to include\n   \"authors\": [\"${<writable_plugin>:<another_plugin>.<key>}\"]\n   ```\n\n\n## The `W` Plugin\n\n`W` (uppercase) is a **Filtering** plugin. It defines named keys for user input and optionally for matching (user input) on candidate events. Input values are stored in `IO` (at `W` namespace) and are accessible by other plugins. Outputs data as `W` tags (using `publish` plugin).\n\n**Functions:**\n\n```jsonc\n{\n  \"plugins\": [\n    [\"W\", [\"<key>\", \"<type>\", \"<match?>\", \"<default?>\"]]\n  ]\n}\n```\n\n**Arguments:**\n\n0. `<key>` : `string` : (required) : Key for the `IO` namespace (may NOT contain colon `:`)\n1. `<type>` : `TypeDescriptor` : (required) : Type descriptor for the input parameter\n2. `<match>` : `EventPath` : (optional) : EventPath for matching candidate events on the input value\n3. `<default>` : `string | number | boolean` : (optional) : Default value if not provided by requestor\n\n\n**IO:**\n\n- **Writes to:** `IO` namespace at `W.<key>` \n- **Write Access:** Values are only writable by the `W` plugin.\n- **Allowed Values:**  allowed values for each key are specified by `<type>`\n\n**Behavior:**\n\n- Collects input values and stores them in `IO`.\n- If `<match>` is specified, candidate events are filtered by the input value.\n- Renders as `W` tags (using `publish` plugin).\n\n\n## The `w` Plugin\n\n`w` (lowercase) is a **Input & Output** plugin. It extracts data from filtered events and stores it in `IO` (at `w` namespace). The `w` namespace is writable by any plugin. Outputs data as `w` tags (using `publish` plugin).\n\n**Functions:**\n\n```jsonc\n{\n  \"plugins\": [\n    [\"w\", [\"<key>\", \"<match?>\", \"<default?>\"]]\n  ]\n}\n```\n\n**Arguments:**\n\n0. `<key>` : `string` : (required) : Key for the `IO` namespace (may NOT contain colon `:`)\n1. `<match>` : `EventPath` : (required) : EventPath for extracting value(s) from filtered events\n2. `<default>` : `any` : (optional) : Default value if no data is found at `<match>`\n\n\n**IO:**\n\n- **Writes to:** `IO` namespace at `w.<key>` \n- **Write Access:** Values are writable by any plugin to `w:<plugin>.<key>` .\n- **Allowed Values:** any `string` or `number` or `boolean` is allowed.\n\n**Behavior:**\n\n- Extracts value(s) from filtered events at `<match>` EventPath.\n- Stores extracted data in `IO`, at `w.<key>`.\n- If key already exists, overwrites the value.\n- Allows other plugins to write values to `w:<plugin>.<key>`.\n- Renders as `w` tags (using `publish` plugin).\n\n\n## The `#` Plugin\n\n`#` (hash) is a **Input & Output** plugin. It provides a writable namespace (as an array of string arrays) for any plugin to store pre-rendered tag arrays. Outputs data as tags (using `publish` plugin).\n\n**Functions:**\n\n```jsonc\n{\n  \"plugins\": [\n    [\"#\", [\"<tag_key>\", \"<tag_value>\", ... ]]\n  ]\n}\n```\n\n**Arguments:**\n\n0. `<tag_key>` : `string` : (required) : Key for the tag\n1. `<tag_value>` : `string` : (required) : Value for the tag\n2. `<tag_value>` : `string` : (optional) : additional tag values\n\n\n**IO:**\n\n- **Writes to:** `IO` namespace `#`, as a new index in the array\n- **Write Access:** Any plugin may add new tags to the array.\n- **Allowed Values:** An array of strings.\n\n**Behavior:**\n\n- Stores and array of pre-rendered tag arrays in `IO`, at `#`.\n- Allows any plugin to append tag arrays to `#`.\n- Renders as tags (using `publish` plugin).\n\n\n## The `publish` Plugin\n\n`publish` is a **Publishing** plugin. It creates and publishes Nostr events by reading data from `IO` and rendering these as event tags. Event `pubkey` and `created_at` fields (and `d` tag) SHOULD be set by the publisher, if not otherwise specified.\n\n**Signature:**\n\n```jsonc\n{\n  \"plugins\": [\n    [\"publish\", \n      // Event Publisher function (required)\n      // This composes an event with tags \n      // rendered from IO `W`, `w`, and `#` namespaces\n      [\"<kind>\", \"<relay?>\", ...],\n      // Event Composer function (optional)\n      // Any number of event composer functions may be specified\n      // To compose event fields from additional IO data\n      [\"<fieldname>\", \"<io_query>\"],\n      // Tag Composer functions (optional)\n      // Any number of tag composer functions may be specified\n      // To compose tags from additional IO data\n      [\"#<tagname>\", \"<io_query>\", ...]\n    ]\n  ]\n}\n```\n\n**Event Publisher Arguments:**\n\n0. `<kind>` : `number` : (required) : Event kind to publish\n1. `<relay>` : `string` : (optional) : Any number of relay URL(s) for publishing (defaults to author's write relays)\n\n**Event Composer Arguments:**\n\n0. `<fieldname>` : `string` : (required) : Any event field name\n1. `<io_query>` : `IO` : (required) : value from IO to render in the field\n\n**Tag Composer Arguments:**\n\n0. `<tagname>` : `string` : (required) : Tag name (prefixed with `#`)\n1. `<io_query>` : `IO` : (required) : value from IO to render in the tag\n2. `<io_query>` : `IO` : (optional) : additional IO values to render in the tag\n\n**IO:**\n\n- **Writes to:**  Does NOT write to `IO`.\n- **Reads from:** `IO` namespaces `W`, `w`, `#` (by default)\n- **Purpose:** Render `IO` data as event tags\n\n**Tags Published:**\n\n- **`IO` `W`** namespace renders as `[\"W\", \"<key>:<value>\"]`\n- **`IO` `w`** namespace renders as `[\"w\", \"<key>:<value>\"]` and `[\"w\", \"<plugin>:<key>:<value>\"]`\n- **`IO` `#`** namespace renders as `[\"<key>\", \"<value>\", ...]`\n- Additional tags MAY be rendered by Tag Composer functions.\n\n**Behavior:**\n\n- The `publish` plugin reads from `IO` and renders tags.\n\n\n\n## Relay Support\n\nTrust Service relays SHOULD respond to `TRUST` pings with a `relay_support_response_JSON` object indicating their supported plugins. Supporting relays MAY also add this same object (indicating general support) to a `TRUST` key in the (NIP-11) \"Relay Information Document\" sent to clients.\n\n**TRUST Ping:**\n```jsonc\n// ping from client RE: *all* supported services\n[\"TRUST\"]\n// ping from client RE: *subscription* supported services\n[\"TRUST\", \"<subscription_pubkey>\"]\n```\n\n**TRUST Ping Response:**\n```jsonc\n// ping response from relay RE: *all* supported services\n[ \n  \"TRUST\", \"<trust_relay_support_info>\" \n]\n// ping response from relay RE: *subscription* supported services\n[ \n  \"TRUST\", \"<subscription_pubkey>\", \"<trust_relay_support_info>\" \n]\n```\n\n**TRUST Relay Information Document:**\n```jsonc\n// relay information document RE: *all* supported services\n{\n  \"TRUST\": \"<trust_relay_support_info>\"\n  // additional relay information ...\n}\n```\n\n**Format for `trust_relay_support_info`:**\n\n```jsonc\n{\n  // Services SHOULD specify the exact plugins that they support\n  // A naddr or url to specification doc is REQUIRED \n  \"plugins?\": [\n    \"[<plugin_key>, <naddr_or_url_to_specification>]\",\n    ...\n  ],\n  // Services MAY wish to limit their support for processing \n  // ONLY certain event structures\n  \"only?\" : [\n    [\"<EventPath>\", [\"<value>\", ...]],\n    ...\n  ],\n  // OR NONE of certain event structures\n  \"not?\" : [\n    [\"<EventPath>\", [\"<value>\", ...]],\n    ...\n  ]\n}\n```\n\n\n## Client Support\n\nBEFORE sending `TRUST` filter requests, clients SHOULD determine the *Trust Service Provider* to send to by considering:\n- their user's *Trust Provider Preferences* (published as kind `17570`) for the specific *plugins* being requested. \n- the service's list of supported *plugins* (as received from the relay in a `TRUST` ping response OR a NIP-11 \"Relay Information Document\") \n\nIf a user HAS published *Trust Provider Preferences*, Clients should TRY to send `TRUST` messages to the user's preferred providers and ONLY use their preferred *plugins* for each. \n\nIf a user HAS published *Trust Provider Preferences* AND a client has a special need for *plugins* that are NOT supported by the user's preferences, the client MAY ask for permission to use their OWN provider instead.\n\nIf a user HAS NOT published *Trust Provider Preferences*, Clients may send `TRUST` messages to their OWN preferred provider AND SHOULD inform the user of this decision and MAY provide a list of *Trust Service Providers* to subscribe to.\n\n\n## Trust Provider Preferences (kind `17570`)\n\nUsers wishing to make use of `TRUST` services SHOULD contact a Service Provider and publish a kind `17570` \"Trust Provider Preferences\" event. HOWEVER, because these events MAY be published from any client, service providers SHOULD treat user published kind `17570` events as the CANONICAL source of truth for the user's publishing preferences.\n\n**Event Format:**\n```jsonc\n{\n  \"kind\": 17570,\n  \"tags\": [\n    // provider for UNSUBSCRIBED trust filter requests\n    [\"r\", \"<relay_url>\", \"<provider_preference_options>\"],\n    // provider for SUBSCRIBED trust filter requests\n    [\"p\", \"<subscription_pubkey>\", \"<relay_url>\", \"<provider_preference_options>\"]\n  ],\n  // preferences MAY optionally be encrypted in content\n  \"content\": nip44Encrypt(JSON.stringify([\n      [\"r\", \"<relay_url>\", \"<provider_preference_options>\"],\n      [\"p\", \"<subscription_pubkey>\", \"<relay_url>\", \"<provider_preference_options>\"]\n  ]), \n}\n```\n\n**Format for `provider_preference_options`:**\n\n```jsonc\n{ \n  \"plugins?\": [ \n    // either ALLOW ANY or BLOCK ALL trust services\n    // or ALLOW or BLOCK specific plugins\n    \"*\" | \"!\" | \"<plugin_key>\" | \"!<plugin_key>\", \n    // and maybe specify more plugins\n    \"<plugin_key>\" | \"!<plugin_key>\", // ... \n  ],\n}\n```\n\n**Example Event:**\n```jsonc\n{\n    \"kind\": 17570,\n    \"tags\" : [\n      // A subscribed provider for ALL TRUST requests\n      [\"p\", \"35450ebb3c5a32e18276...\", \"wss://subscribed.example.com\", \"*\"],\n      // An unsubscribed provider for TRUST requests \n      // using a specific plugin\n      [\"r\", \"wss://specialty.example.com\", \"{\\\"plugins\\\": [\\\"my_custom_plugin\\\"]}\"],\n      // A blacklist DO NOT USE provider\n      [\"r\", \"wss://unsubscribed.example.com\", \"!\"],\n    ]\n}\n```\n\n---\n\n## APPENDIX 1: `W` and `w` Tags\n\n**This NIP reserves the `W` and `w` tags for use in plugin generated events of ANY kind.**\n\nThe (uppercase) `W` tag key is reserved for describing user inputs for ANY plugin generated events. \n\n```jsonc\n{\n  \"kind\": <trusted_event_kind>,\n  \"tags\": [\n    // A colon separated `<key>:<value>` string is the standard format\n    [\"W\", \"<key>:<value>\"]\n    // A single `<value>` string MAY be used in certain cases\n    [\"W\", \"<value>\"]\n  ]\n}\n```\n\nThe (lowercase) `w` tag key is reserved for holding output data in ANY plugin generated events.\n\n```jsonc\n{\n  \"kind\": <trusted_event_kind>,\n  \"tags\": [\n    // A colon separated `<key>:<value>` string is the standard format\n    [\"w\", \"<key>:<value>\"]\n    // A single `<value>` string MAY be used in certain cases\n    [\"w\", \"<value>\"]\n  ]\n}\n```\n\n## APPENDIX 2: EventPath Syntax\n\nEventPath strings are used to navigate into event fields and tags for either matching on or extracting specific values.\n\n**Matching on Field Names**\n- `<field_name>` : EventPath MAY start with any event field name (e.g., `pubkey`, `created_at`, `content`, `kind`)\n\n**Matching on Tag Names**\n- `#<key>` : EventPath MAY start with a hash prefix to match on a tag `key` (index 0) of ANY tag in an event. (e.g., `#p`, `#e`, `#title`, `#description`)  By default (same as standard filters), `#<key>` without modifiers is equivalent to `#<key>[*][1]`. \n\n**Matching on Tag Data**\n- `#<key>[<nth> | *]` : Matches on the `<nth>` matching `<key>` tag in a tag array and returns the value at index `1` of that tag. The wildcard `*` matches on the FIRST matching tag THAT HAS A VALUE at index `1`, and returns that value.\n- `#<key>[<nth> | *][<value>]` : Matches on the `<nth>` matching `<key>` tag in a tag array, and returns the value at index `<value>` of that tag. The wildcard `*` matches on the FIRST matching tag THAT HAS A VALUE at index `<value>`, and returns that value.\n\n**Matching on Relative Tag Values**\n- `#[<value>]` : Matches on (and returns the value at) the index at `<value>` of the FIRST matching tag THAT HAS A VALUE at that index. (This is useful for matching on the values of a known subset of tags.)\n\n**Extracting Tag Arrays:**\n- `#<key>[]` : Explicitly extracts an array of tags matching `<key>` in a tag array.\n- `#<key>[][<value>]` : Explicitly extracts an array of tag values (at index `<value>`) from ALL `<key>` tags in a tag array which have a value at index `<value>`.\n\n**Match or Extract Embedded JSON Data**\n- Embedded JSON objects and arrays MAY be navigated from event fields OR tags using dot notation (e.g., `#description.pubkey`) or bracket notation (e.g., `content.items[0]`)\n- `#<key>` syntax MAY also be used to navigate into any array of string arrays in embedded JSON (in the same manner as event tags).\n- Empty brackets `[]` within a path (for extraction processes) SHOULD always return an array.\n\n**Examples:**\n- `#p` - returns the index 1 value of the FIRST `p` tag with a value at index 1\n- `#p[*][2]` - returns the index 2 value of the FIRST `p` tag with a value at index 2\n- `#p[1][2]` - returns the index 2 value of ONLY the 1st `p` tag.\n- `#p[]` - returns an array of all `p` tags in a tag array.\n- `content.items[2]` - returns the index 2 value of an embedded JSON array\n- `content.items` - returns the index 0 value of an embedded JSON array\n- `pubkey` - returns the event's pubkey field\n- `#description.tags.#amount` - returns the index 1 value of ANY `amount` tag from an embedded zap request\n- `#description.tags.#amount` - returns the index 1 value of the FIRST `amount` tag with a value at index 1\n\n## APPENDIX 3: TimeUnit and RelativeTime Syntax\n\nRelative time strings allow filter configs to remain valid over time.\n\n**TimeUnit:**\n- `<number>s` - seconds\n- `<number>m` - minutes \n- `<number>h` - hours\n- `<number>d` - days\n- `<number>w` - weeks\n- `<number>M` - months\n- `<number>y` - years\n\n**Format:** `now[-+]<TimeUnit>`\n\n**Examples:**\n- `\"now\"` - current timestamp\n- `\"now-7d\"` - 7 days ago\n- `\"now-1w\"` - 1 week ago\n- `\"now-3M\"` - 3 months ago\n\n## APPENDIX 4: TypeDescriptor Syntax\n\nA TypeDescriptor can be any string that describes the type of an expected value. These MAY be machine readable, but do NOT need to be. As a convention, the following type descriptors are provided:\n\n- `\"tagletter\"` - indicates any standard tag letter is allowed\n- `\"tagname\"` - indicates any standard tag name is allowed\n- `\"#<tag_letter>\"` - the type of value expected in an standard indexable tag (e.g., `#p`, `#e`)\n- `\"<integer>-<integer>\"` - an unsigned float between `<integer>` and `<integer>`\n- `\"+-<integer>-<integer>\"` - a signed or unsigned float between `<integer>` and `<integer>`\n- `\"naddr\"` - an naddr event reference\n- `\"nprofile\"` - an nprofile event reference\n- `\"nevent\"` - an nevent event reference\n- `\"npub\"` - an npub user reference\n- `\"string\"` - any string\n- `\"integer\"` - an integer\n- `\"number\"` - any number\n- `\"boolean\"` - a boolean\n- `\"url\"` - any URL\n\n## APPENDIX 5: Error Codes\n\nStandard machine-readable error prefixes for `CLOSED` messages:\n\n- `error:auth-required` - AUTH confirmation required before processing\n- `error:unsupported-plugin:<plugin_key>` - Requested plugin not supported\n- `error:invalid-filter` - Filter syntax error\n- `error:rate-limit` - Request rate limit exceeded\n- `error:subscription-required` - Feature requires active subscription\n\n## APPENDIX 6: The `TRUSTed` Family of NIPs \n\n- [TRUSTed Filters](https://nostrhub.io/naddr1qvzqqqrcvypzphm8lxn7gyf9w3wtu7k0hhxsx6ghsrry8hmm44c0t5ss3uk5lssqqy2hwumn8ghj7erfw36x7tnsw43z7un9d3shjqqnde5hqtt5wf6hxar9vskkv6tvw3jhyuc7am7eg)\n\n- [TRUSTed Filter Presets](https://nostrhub.io/naddr1qvzqqqrcvypzphm8lxn7gyf9w3wtu7k0hhxsx6ghsrry8hmm44c0t5ss3uk5lssqqy2hwumn8ghj7erfw36x7tnsw43z7un9d3shjqq6de5hqtt5wf6hxar9vskkv6tvw3jhyttswfjhxet5wvrtz6pf)\n- [TRUSTed Filter Plugins](https://nostrhub.io/naddr1qvzqqqrcvypzphm8lxn7gyf9w3wtu7k0hhxsx6ghsrry8hmm44c0t5ss3uk5lssqqy2hwumn8ghj7erfw36x7tnsw43z7un9d3shjqq6de5hqtt5wf6hxar9vskkv6tvw3jhyttsd36kw6twwva56k4w)\n- [TRUSTed Events](https://nostrhub.io/naddr1qvzqqqrcvypzphm8lxn7gyf9w3wtu7k0hhxsx6ghsrry8hmm44c0t5ss3uk5lssqqy2hwumn8ghj7erfw36x7tnsw43z7un9d3shjqqjde5hqtt5wf6hxar9vskk2an9de68x4nc03c)\n\n- [TRUSTed User Ranking](https://nostrhub.io/naddr1qvzqqqrcvypzphm8lxn7gyf9w3wtu7k0hhxsx6ghsrry8hmm44c0t5ss3uk5lssqqy2hwumn8ghj7erfw36x7tnsw43z7un9d3shjqq3de5hqtt5wf6hxar9vskh2um9wfesdm3q7f)","sig":"a191575e1a32eb55f681d8c23a5db7931b768504ac2eb6b6cbe7d6d51904dab9921b8f17c876801594df4fb41d354035068e264889803a9facd03d954da014a0"}