跳到正文
cccskills
免费在 GitHub 公开

nostr-addressable-event-dual-tag-query

Fix "count shows X but list shows empty" bugs when querying related events (comments, reactions, zaps, reposts) for Nostr addressable events (Kind 30000-39999). Use when: (1) REST API shows engagement count > 0 but WebSocket query returns empty, (2) Comments/reactions exist but app shows "No comments yet" or similar, (3) Working with NIP-22 comments, NIP-25 reactions, or NIP-18 reposts on Kind 34235/34236 video events or other addressable events. Root cause: clients may reference addressable events using either E tag (event ID) or A tag (kind:pubkey:d-tag format), and querying only one tag misses events tagged with the other.

中文简介正在准备中。当前显示原文说明。

实测评分 未实测

查看安装方法

包含的文件(1)

  • SKILL.md6.2 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

Nostr Addressable Event Dual-Tag Query

Problem

When querying related events (comments, reactions, reposts, zaps) for Nostr addressable events (Kind 30000-39999), the query returns fewer or zero results even though an indexing service shows the correct count. This happens because addressable events can be referenced two ways, and different clients use different methods.

Context / Trigger Conditions

Use this skill when:

  • Video/post shows comment count of 5, but comments modal says "No comments yet"
  • REST API (like Funnelcake) returns correct engagement counts, but WebSocket queries return empty
  • Working with NIP-22 comments (Kind 1111) on addressable events
  • Working with NIP-25 reactions (Kind 7) on addressable events
  • Working with NIP-18 reposts (Kind 6/16) on addressable events
  • Any feature querying events that reference Kind 30000-39999 events

Root Cause

For addressable events (Kind 30000-39999, like Kind 34236 videos), related events can reference the target using either:

  1. E tag: References by event ID (64-character hex)

    ["E", "abc123...def456", "", "author-pubkey"]
    
  2. A tag: References by addressable identifier (kind:pubkey:d-tag)

    ["A", "34236:abc123...def456:my-video-id", "", "author-pubkey"]
    

Different Nostr clients and indexers use different conventions:

  • Some always use E tags (event ID-based)
  • Some prefer A tags for addressable events (following NIP-22 strictly)
  • Some use both tags

If your app only queries by one tag type, you'll miss events tagged with the other.

Solution

1. Update Filter Class (if needed)

Ensure your Filter class supports uppercase A tag queries:

// In Filter class
List<String>? uppercaseA;  // Add this field

// In toJson()
if (uppercaseA != null) {
  data['#A'] = uppercaseA;
}

2. Query by BOTH Tags

When loading related events, run two parallel queries and merge results:

Future<List<Event>> loadRelatedEvents({
  required String eventId,
  required String? addressableId,  // Format: "kind:pubkey:d-tag"
}) async {
  // Query by E tag (event ID)
  final filterByE = Filter(
    kinds: [targetKind],
    uppercaseE: [eventId],
  );

  // If addressable ID available, also query by A tag
  if (addressableId != null && addressableId.isNotEmpty) {
    final filterByA = Filter(
      kinds: [targetKind],
      uppercaseA: [addressableId],
    );

    // Run both queries in parallel
    final results = await Future.wait([
      nostrClient.queryEvents([filterByE]),
      nostrClient.queryEvents([filterByA]),
    ]);

    // Merge and deduplicate by event ID
    final eventMap = <String, Event>{};
    for (final event in results[0]) {
      eventMap[event.id] = event;
    }
    for (final event in results[1]) {
      eventMap[event.id] = event;
    }

    return eventMap.values.toList();
  }

  return nostrClient.queryEvents([filterByE]);
}

3. Post with BOTH Tags

When creating related events, include both E and A tags for maximum compatibility:

final tags = <List<String>>[
  // Always include E tag
  ['E', rootEventId, '', authorPubkey],

  // Include A tag for addressable events
  if (rootAddressableId != null && rootAddressableId.isNotEmpty)
    ['A', rootAddressableId, '', authorPubkey],

  // ... other tags
];

4. Build Addressable ID

Construct the addressable identifier from event metadata:

String? get addressableId {
  if (dTag == null) return null;
  return '$kind:$pubkey:$dTag';  // e.g., "34236:abc123...:my-video-id"
}

Verification

After implementing:

  1. Find an event where REST API shows count > 0 but your app showed empty
  2. Verify the list now shows the expected items
  3. Post a new related event (comment/reaction)
  4. Verify it appears when querying by either E or A tag

Example

Before fix - only queries by E tag:

final filter = Filter(
  kinds: [1111],  // Comments
  uppercaseE: [videoEventId],  // Only E tag!
);
// Returns 0 comments even though 5 exist (tagged with A)

After fix - queries both tags:

final filterByE = Filter(kinds: [1111], uppercaseE: [videoEventId]);
final filterByA = Filter(kinds: [1111], uppercaseA: [addressableId]);

final results = await Future.wait([
  client.queryEvents([filterByE]),
  client.queryEvents([filterByA]),
]);
// Returns all 5 comments regardless of how they were tagged

Notes

  • This pattern applies to ANY feature that queries events referencing addressable events
  • The d-tag may contain colons, so parse addressable IDs carefully: parts.sublist(2).join(':')
  • For count queries (NIP-45), take the maximum of both counts (may over-count if events have both tags)
  • Some relays may not support #A filter queries yet - test with your target relays
  • This is especially important for interoperability between different Nostr clients

Affected NIPs

  • NIP-22: Comments (Kind 1111) - uses E/A tags for root scope
  • NIP-25: Reactions (Kind 7) - references target event
  • NIP-18: Reposts (Kind 6/16) - references reposted event
  • NIP-33: Parameterized Replaceable Events (Kind 30000-39999) - defines addressable format
  • NIP-71: Video Events (Kind 34235/34236) - common use case for this pattern

References

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

Fix ArgoCD ExternalSecret deployment failing with "namespace X is not permitted in project Y". Use when: (1) ExternalSecret shows OutOfSync in ArgoCD but won't sync, (2) ArgoCD application status shows "namespace X is not permitted in project 'infrastructure'", (3) ExternalSecret targets a namespace managed by a different ArgoCD project, (4) Using apps-of-apps pattern with separate infrastructure and application projects.

中文简介正在准备中。当前显示原文说明。

divinevideo/divine-mobile2652026年10月23日 更新

Art direction for any content — reads text, PDF, Word, HTML, PPT, then proposes 2-3 creative directions with photography style, mood, and visual language. After selection, generates AI image prompts and visual briefs section-by-section. Use when the user shares content and needs visual direction, image sourcing, or creative direction for any material.

中文简介正在准备中。当前显示原文说明。

divinevideo/divine-mobile2652026年10月23日 更新

Fix "Null check operator used on a null value" errors when an object is set to null during an async await. Use when: (1) Object reference is nullified while awaiting, (2) Code accesses object with ! after await returns, (3) Cancel/dispose operations run concurrently with async operations on same object. Solution: capture local reference before await.

中文简介正在准备中。当前显示原文说明。

divinevideo/divine-mobile2652026年10月23日 更新

Add custom metadata headers (x-amz-meta-*) to AWS v4 signed requests for GCS S3-compatible API. Use when: (1) Adding custom metadata to GCS uploads via S3 API, (2) Getting signature mismatch errors after adding new headers, (3) x-amz-meta-* headers being ignored or causing 403 errors. Custom headers MUST be included in canonical headers and signed headers list.

中文简介正在准备中。当前显示原文说明。

divinevideo/divine-mobile2652026年10月23日 更新

Fix password/secret authentication failures caused by trailing newlines when creating Google Cloud secrets (or similar) with bash here-strings. Use when: (1) Password authentication fails with correct password, (2) Secret created with `<<< "value"` syntax, (3) Error like "password authentication failed" or "invalid token" despite correct value. Bash here-strings (`<<<`) add a trailing newline that corrupts secrets.

中文简介正在准备中。当前显示原文说明。

divinevideo/divine-mobile2652026年10月23日 更新

Fix silent video/media processing failures caused by URL extraction code that filters on file extensions (.mp4, .webm, .webp). Use when: (1) Media moderation, transcoding, or analysis silently skips files from Blossom or content-addressed storage servers, (2) URL extraction from Nostr event tags (imeta, r tags) drops URLs without recognized extensions, (3) CDN fallback URLs append .mp4 but the actual server uses extensionless content-addressed paths like /{sha256}. Common in Nostr video events (kind 34236) where different clients use different URL formats.

中文简介正在准备中。当前显示原文说明。

divinevideo/divine-mobile2652026年10月23日 更新

查看 divinevideo 的全部技能

报告此技能的问题