NIP-AMB
Von Edufeed ·
== NIP-AMB=== Abstract
This NIP defines how to handle the metadata profile
https://dini-ag-kim.github.io/amb/latest/[``Allgemeines Metadatenprofil
für Bildungsressourcen'' (AMB)] in nostr:
* How to convert AMB metadata to an AMB nostr event
* How to convert an AMB nostr-event to AMB metadata
* How to query for AMB nostr-events in supporting relays
=== Event Kind
This NIP defines `kind:30142` as an AMB Metadata Event. This means this
is an addressable event, that can be addressed using
`kind:pubkey:d-tag`.
=== How to convert AMB metadata _to_ an AMB nostr event
The transformation uses JSON-flattening with `:` as the delimiter to
convert nested AMB metadata structures into flat Nostr tags.
Additionally, Nostr-native tag conventions are used where applicable for
better interoperability and query efficiency.
==== Nostr-Native Conventions
This NIP follows Nostr conventions where they align with AMB
requirements:
* *`d` tag*: Used as the unique identifier for the AMB resource (maps to
AMB `id`)
* *`t` tags*: Used for keywords/topics (instead of flattened `keywords`
tags)
* *`p` tags*: Used for creator/contributor references when the person
has a Nostr identity (pubkey). Format:
`["p", , , ]` where `` is
`"creator"` or `"contributor"`. The relay hint is a single suggestion
for discovery (per NIP-01 convention); clients SHOULD use NIP-65 for
full relay resolution. When a `p` tag is used for a person, no
`creator:*`/`contributor:*` flattened tags are emitted for that person —
the pubkey IS their identity. Persons without a Nostr identity use the
flattened `creator:*`/`contributor:*` tag structure instead.
* *`a` tags*: Used for references to other addressable events on Nostr
(including other AMB events), with fallback to flattened URIs for
external resources. Format:
`["a", "30142::", , ]`
* *`r` tags*: Used for external URL references (original source, DOI,
related web resources)
* *`content` field*: SHOULD contain the description text for client
compatibility; the `description` tag is kept for relay queryability
==== Flattening Rules
[arabic]
. *Simple properties*: Map directly to `["", ""]` tags
* AMB: `{"name": "Resource Title"}`
* Nostr: `["name", "Resource Title"]`
. *Nested objects*: Flatten using `:` delimiter
* AMB: `{"creator": {"name": "John", "id": "123"}}`
* Nostr: `["creator:name", "John"]`, `["creator:id", "123"]`
. *Arrays*: Repeat the same flattened tag key (order is preserved by tag
array position)
* AMB: `{"keywords": ["Math", "Physics"]}`
* Nostr: `["t", "Math"]`, `["t", "Physics"]` (Nostr-native `t` tag)
. *Arrays of objects*: Repeat flattened keys for each object
* AMB: `{"creator": [{"name": "John"}, {"name": "Jane"}]}`
* Nostr: `["creator:name", "John"]`, `["creator:name", "Jane"]`
. *Deep nesting*: Continue flattening with additional `:` delimiters
* AMB: `{"creator": {"affiliation": {"name": "MIT"}}}`
* Nostr: `["creator:affiliation:name", "MIT"]`
==== Property Mappings
This is how we convert each property of the AMB:
===== General:
* `id` → `["d", ]` (special case: use Nostr’s `d` tag as
identifier). The `d` value SHOULD be the resource’s canonical,
dereferenceable URL when one exists (the AMB spec describes `id` as a
dereferenceable HTTP URI). Nostr-native resources without an external
URL MAY use an arbitrary stable slug — see the reverse-conversion rules
for how the AMB `id` is derived in that case.
* `type` → `["type", ]` (repeat for multiple types)
* `name` → `["name", ]`
* `description` → `["description", ]` AND `"content": `
(duplicated for client compatibility and relay queryability)
* `about` (array of concept objects) → Repeat for each:
** `["about:id", ]`
** `["about:prefLabel:lang", ]`
** `["about:type", "Concept"]`
* `keywords` → `["t", ]` (repeat for each keyword, using Nostr
`t` tag)
* `inLanguage` → `["inLanguage", ]` (repeat for each
language)
* `image` → `["image", ]`
* `trailer` (MediaObject) →
** `["trailer:contentUrl", ]`
** `["trailer:type", <"VideoObject"|"AudioObject">]`
** `["trailer:encodingFormat", ]` (optional)
** `["trailer:contentSize", ]` (optional)
** `["trailer:sha256", ]` (optional)
** `["trailer:embedUrl", ]` (optional)
** `["trailer:bitrate", ]` (optional)
===== Provenance:
* `creator` (array of Person/Organization objects) → For each creator,
use *one* of the following (never both for the same person):
** *Nostr-native (creator has a Nostr pubkey)*:
`["p", , , "creator"]` — no additional
`creator:*` tags for this person. Their name and metadata are resolved
from their kind:0 profile.
*** *Detection*: If a creator object’s `id` is a `nostr:` URI per
https://github.com/nostr-protocol/nips/blob/master/21.md[NIP-21]
encoding an `npub` or `nprofile`, converters MUST decode it and emit the
`p` tag form instead of flattened `creator:*` tags. (This is valid AMB
input: the AMB schema constrains `creator.id` only to `format: uri`; the
ORCID/GND/Wikidata/ROR list is a SHOULD-level recommendation.)
*** *Relay hint precedence*: relay embedded in the `nprofile` (first
entry) → converter-configured default → empty string.
** *External (no Nostr identity)*:
*** `["creator:id", ]` (optional, e.g., ORCID, GND)
*** `["creator:name", ]`
*** `["creator:type", <"Person"|"Organization">]`
*** `["creator:honorificPrefix",