Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions examples/gno.land/p/eve/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
WIP
---

What's left to get to 'final' version of eve framework

### requirements

A user can publish an item as a revision or update where the old CID is replaced with a new one.
Old cid can be removed or kept as a reference.

Gno.land visitors choose to view older revisions. (by traversing parent links)

Other gno realms may embed path to /r/eve/home/?cid=... to show specific revisions.

Page view has common footer menu that links to metadata and version info.


As a user I can see the Object Registry (index at /r/lab/home?glyph=OfficeHours)
Each registered object links out to its own realm (officehours at /r/labs/OfficeHours)

Users can update the preferred view of an object if they are the original author.

FUTURE: without using cur realm (realm crossing) - we can still build an immutable oracle.
This is an append only fashion that does not allow permissions, only that each new object has a unique CID

The Event Stream of (Glyph, URL, CID) is an immutable log of all objects ever created.

### Metadata

A design principle from gno.land: A realm SHOULD always resemble gno.land/r/ view.
i.e. a fork on another realm should ideally use same markdown renderer and support same metadata.

The metadata for each page SHOULD be linked from each eve.PageTemplate view.

Every object is required to have a CID, JsonLD{ name, description }, and committer/author.
Every object MAY have additional metadata such as tags, categories, license, etc.

### Versioning

Every object may have a link to the previous version.
An object MAY have multiple parents (merging branches).

### QueryParameters as Serializable State

A Projectable Object accepts path as a 'Probe' to determine what to render.
A Probe is a 'path' that is serializable state that can be shared via URL query parameters.

A complete view of an object is only inspectable by probing the inner dimensions of the object.
This means that a user can share a link to a specific view of an object.

### Identity and Types

Objects have metadata in the shape of JsonLD.
Each Object is identified by its CID.

Unless specified otherwise, an object is assumed to be of type "Thing" (schema.org/Thing).
An object MAY have multiple types (schema.org allows this).

## Existing Projectable Objects

### eve.Flyer Object
A Flyer is a Projectable Object that has a title, description, image, and link.

### Event Projectable Object
"Event" (schema.org/Event).
An Event object has properties such as startDate, endDate, location, performer, etc.

### Calendar Event Projectable Object
A Calendar Event is a Projectable Object that can render different views based on the Probe.

### Office Hours Event
A specialized event formatted as ICS, contains a recurrence rule (RRULE).

### Probes

The Render() function accepts a Probe that is a path that is serializable state that can be shared via URL query parameters.

Object + Probe => RenderedView

### Future Work
- Permissions and Access Control Lists (ACLs)
- Standard views of common object types (e.g., Articles, Projects, Profiles)
83 changes: 83 additions & 0 deletions examples/gno.land/p/eve/component/cid.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package component

import (
"crypto/sha256"
"encoding/base32"
"encoding/hex"
"strings"
"time"
)

func HashStrings(elements ...string) string {
combined := ""
for _, e := range elements {
combined += e
}
return HashString(combined)
}

func HashString(s interface{}) string {
if s == nil {
return ""
}
if str, ok := s.(string); ok {
s = str
} else if t, ok := s.(time.Time); ok {
s = t.Format(time.RFC3339)
} else if es, ok := s.(EventStatus); ok {
s = string(es)
} else if eam, ok := s.(EventAttendanceMode); ok {
s = string(eam)
} else {
panic("type not supported for hashing: ")
}

hash := sha256.Sum256([]byte(s.(string)))
return hex.EncodeToString(hash[:])
}

// ShaToCid converts a hex-encoded SHA-256 digest into a CIDv1 (base32, multibase "b").
// Layout: <0x01 version><0x55 codec=raw><0x12 mh=sha2-256><0x20 len=32><digest>
func ShaToCid(sha string) string {
sha = strings.TrimSpace(sha)

// Decode hex digest (must be 32 bytes for sha2-256)
digest, err := hex.DecodeString(sha)
if err != nil || len(digest) != 32 {
panic("invalid sha256 digest")
}

// Assemble CIDv1 bytes
// 0x01 = version 1
// 0x55 = multicodec "raw"
// 0x12 = multihash code for sha2-256, 0x20 = digest length (32)
buf := make([]byte, 0, 1+1+2+32)
buf = append(buf, 0x01, 0x55, 0x12, 0x20)
buf = append(buf, digest...)

// Base32 (RFC 4648), no padding, lowercase, with multibase 'b' prefix
enc := base32.StdEncoding.WithPadding(base32.NoPadding)
return "b" + strings.ToLower(enc.EncodeToString(buf))
}

// IsCIDv1 checks if the given string is a valid CIDv1 in base32 format.
func IsCIDv1(s string) bool {
if len(s) != 59 {
return false
}
for _, r := range s {
if !('a' <= r && r <= 'z' || '2' <= r && r <= '7') { // base32 alphabet
return false
}
}
if !strings.HasPrefix(s, "bafkrei") {
return false
}
return true
}

func MustCIDv1(label, s string) {
if !IsCIDv1(s) {
panic("invalid " + label + ": not a CIDv1")
}
}
Loading
Loading