Skip to content

planet-nine-app/sanora

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Sanora Club

Sanora Club is a miniservice for hosting products, and eventually hooking into spell paths. The goal is to be so lightweight that people can create a product from a single curl. And to have those products be shareable around cyberspace via teleportation.

Overview

There are a plethora of web-based solutions for creating product pages, and taking payments. Many of them are just fine if you don't mind handing over 15% or more of your sale to the platform. Of course you're paying for a bunch of features you're probably not going to use, and the marketing you have to do has nothing to do with this platform you're using.

Instead of making and maintaining a bunch of features, Sanora Club gives you the absolute minimum you need to host and sell a product online. Then by leveraging the Planet Nine ecosystem, others can build features that you can add, ideally at a discount from those other platforms. Or not, and you keep more loot.

The product layout and account

Sanora Club needs two things from you in order to work: a product, and a way to pay you.

The product layout

A minimalist approach to product display is a title, description, price and image. Since that's really all we'll be providing, and you may want to provide a landing page for people who either don't have a MAGIC extension, or don't want to purchase right away, there's also an optional redirect url.

And that's it. Five things:

  • title
  • description
  • price
  • image
  • redirect url (optional)

The account

We're gonna start with Stripe to begin with. You attach your stripe to your Sanora account, and then get paid when people buy your product.

Stripe has all sorts of drop-in uis for this that we'll use, but you can do it via the command line too.

API

So you create a user with your public key. And then you can start putting products.

PUT /user/create Creates a new user if pubKey does not exist, and returns existing uuid if it does.
Parameters
name required data type description
pubKey true string (hex) the publicKey of the user's keypair
timestamp true string in a production system timestamps narrow window for replay attacks
signature true string (signature) the signature from sessionless for the message
Responses
http code content-type response
200 application/json USER
400 application/json {"code":"400","message":"Bad Request"}
Example cURL
 curl -X PUT -H "Content-Type: application/json" -d '{"pubKey": "key", "timestamp": "now", "signature": "sig"}' https://<placeholderURL>/user/create
PUT /user/:uuid/processor/:processor Creates an account token for a processor
Parameters
name required data type description
name true string the user's name
email true string the user's email
timestamp true string in a production system timestamps narrow window for replay attacks
signature true string (signature) the signature from sessionless for the message
Responses
http code content-type response
200 application/json USER
400 application/json {"code":"400","message":"Bad Request"}
Example cURL
 curl -X PUT -H "Content-Type: application/json" -d '{"name": "name", "email": "[email protected]", "timestamp": "now", "signature": "sig"}' https://<placeholderURL>/user/<uuid>/processor/<processor>
PUT /user/:uuid/product/:title Creates or updates the product with the put title
Parameters
name required data type description
title true string the title of the product
description true string the description of the product
price true string the price of the product
redirectURL false string an optional redirect url
timestamp true string in a production system timestamps narrow window for replay attacks
signature true string (signature) the signature from sessionless for the message
Responses
http code content-type response
200 application/json USER
400 application/json {"code":"400","message":"Bad Request"}
Example cURL
 curl -X PUT -H "Content-Type: application/json" -d '{"pubKey": "key", "timestamp": "now", "signature": "sig"}' https://<placeholderURL>/user/create
PUT /user/:uuid/product/:title/artifact Puts an image for the product with the given title
Headers
name required data type description
x-pn-artifact-type true epub/pdf/md/etc artifact type
x-pn-timestamp true string in a production system timestamps narrow window for replay attacks
x-pn-signature true string (signature) the signature from sessionless for the message
Parameters
name required data type description
artifact true artifact type the artifact to upload
Responses
http code content-type response
200 application/json USER
400 application/json {"code":"400","message":"Bad Request"}
Example cURL

TODO

PUT /user/:uuid/product/:title/image/ Puts an image for the product with the given title
Headers
name required data type description
x-pn-timestamp true string in a production system timestamps narrow window for replay attacks
x-pn-signature true string (signature) the signature from sessionless for the message
Parameters
name required data type description
image true jpg/png the image for the product
timestamp true string in a production system timestamps narrow window for replay attacks
signature true string (signature) the signature from sessionless for the message
Responses
http code content-type response
200 application/json USER
400 application/json {"code":"400","message":"Bad Request"}
Example cURL

TODO

PUT /user/:uuid/orders Puts an image for the product with the given title
Parameters
name required data type description
timestamp true string in a production system timestamps narrow window for replay attacks
order true string the order object to store. Can contain any data you'd like
signature true string (signature) the signature from sessionless for the message
Responses
http code content-type response
200 application/json USER
400 application/json {"code":"400","message":"Bad Request"}
Example cURL

TODO

GET /user/:uuid/orders gets orders. Can take optional params for filtering orders
Parameters
name required data type description
timestamp true string in a production system timestamps narrow window for replay attacks
pubKey false string get orders for a specific pubKey
product false string get orders of a specific product
signature true string (signature) the signature from sessionless for the message
Responses
http code content-type response
200 application/json USER
400 application/json {"code":"400","message":"Bad Request"}
Example cURL

TODO

GET /products/base Gets all products available on this base server
Parameters

None required - this is a public endpoint that returns all products on the base.

Responses
http code content-type response
200 application/json Array of product objects
404 application/json {"error":"not found"}
Example cURL
 curl -X GET https://dev.sanora.allyabase.com/products/base
Response Format

Returns an array of all product objects from all users on this base:

[
  {
    "title": "My Product",
    "description": "Product description", 
    "price": 1000,
    "uuid": "user-uuid-here",
    "productId": "product-id-here",
    "timestamp": "2025-01-01T00:00:00Z"
  }
]
GET /teleportable-products Returns teleportable product feed for cross-base marketplace discovery via BDO teleportation
Parameters

None required - this endpoint dynamically generates teleportable content with all products from the base.

Responses
http code content-type response
200 text/html HTML page with embedded teleportable product feed
500 text/plain Error generating product feed
Example URLs
# Get teleportable products
https://dev.sanora.allyabase.com/teleportable-products
Teleportation Protocol Implementation

This endpoint generates a complete teleportable product feed that works with the Planet Nine teleportation system through BDO. The response includes:

  1. Teleport Tag with Signature: A cryptographically signed <teleport> tag containing feed metadata
  2. Teleportal Elements: Individual <teleportal> elements for each product with structured data
  3. Visual HTML Display: Inline-styled product cards for direct viewing
  4. No JavaScript: Pure HTML with inline CSS to ensure compatibility with teleportation
How Teleportation Works

The complete teleportation workflow involves three services working together:

  1. Sanora (Content Provider):

    • Generates teleportable HTML with signed <teleport> tags
    • Uses sessionless authentication to sign content with its base public key
    • Embeds products as <teleportal> elements with structured data
    • Stores the base public key (basePubKey) in user objects for client verification
  2. BDO (Teleportation Service):

    • Validates teleport signatures using the provided public key
    • Fetches content from remote URLs (supports allyabase:// protocol for container networking)
    • Returns validated content with valid: true flag when signatures match
    • Handles cross-container communication in Docker environments
  3. Client Applications (e.g., Ninefy):

    • Request teleportation through BDO using the base's public key
    • Parse returned HTML to extract <teleportal> elements
    • Convert teleportal data into product objects for display
    • Show teleported content in dedicated UI sections
Teleport Tag Structure
<teleport id="planet-nine-products" 
          type="feed" 
          category="marketplace" 
          signature="[sessionless_signature]" 
          message="[timestamp]:planet-nine-marketplace-products:teleport" 
          pubKey="[base_public_key]">
    <feed-meta>
        <title>Planet Nine Marketplace</title>
        <description>Discover unique products from the Planet Nine ecosystem</description>
        <last-updated>[ISO_timestamp]</last-updated>
        <source-url>[base_url]/teleportable-products</source-url>
    </feed-meta>
    
    <teleportal id="[product_id]" category="[category]" price="[cents]" currency="USD">
        <title>[Product Title]</title>
        <description>[Product Description]</description>
        <url>[product_url]</url>
        <image>[image_url]</image>
        <tags>[comma,separated,tags]</tags>
        <in-stock>true</in-stock>
        <rating>[0-5]</rating>
    </teleportal>
    <!-- More teleportal elements... -->
</teleport>
Container Networking with allyabase:// Protocol

For Docker container environments, the teleportation system supports the allyabase:// protocol to handle container-to-container communication:

  • Client sends: allyabase://sanora/teleportable-products?pubKey=[key]
  • BDO translates: allyabase://sanora β†’ http://127.0.0.1:7243 (internal container port)
  • Enables: Seamless teleportation across containerized services
Security & Authentication
  • Sessionless Signatures: All teleport tags are signed using secp256k1 cryptographic keys
  • Public Key Verification: BDO verifies signatures match the provided public key
  • Timestamp Protection: Messages include timestamps to prevent replay attacks
  • Base Identity: Each Sanora instance has a unique basePubKey for identification
Integration Example
// Client-side teleportation request (from Ninefy)
const teleportUrl = `allyabase://sanora/teleportable-products?pubKey=${basePubKey}`;
const teleportedData = await bdoClient.teleport(uuid, hash, teleportUrl);

if (teleportedData.valid) {
  // Parse HTML and extract products
  const parser = new DOMParser();
  const doc = parser.parseFromString(teleportedData.html, 'text/html');
  const teleportals = doc.querySelectorAll('teleportal');
  
  // Convert to product objects
  const products = Array.from(teleportals).map(portal => ({
    id: portal.getAttribute('id'),
    title: portal.querySelector('title')?.textContent,
    price: parseInt(portal.getAttribute('price')),
    // ... more fields
  }));
}
Features
  • Dynamic Content Generation: Products fetched from database and embedded in real-time
  • JavaScript-free Teleport Tags: All styling uses inline CSS for maximum compatibility
  • Cross-Base Discovery: Enables marketplace aggregation across Planet Nine network
  • Graceful Degradation: Works even when some products lack complete data
  • Visual + Data: Provides both human-readable display and machine-parseable data

Form Widget System

Sanora includes a comprehensive SVG-based form widget system located in /public/form-widget.js that provides dynamic form generation for various field types. The widget is designed for creating product upload forms with validation and file handling capabilities.

Supported Field Types

  • text - Single-line text inputs with validation
  • textarea - Multi-line text areas with character limits
  • image - Image upload with preview and validation
  • artifact - General file upload for digital goods (PDF, EPUB, ZIP, MP3, MP4, EXE, TXT, DOC)
  • catalog - Specialized file upload for CSV/JSON catalog data (Added January 2025)
  • datetime - Date and time picker widget

Catalog Field Type (πŸ†• January 2025)

The catalog field type is specifically designed for hierarchical menu/catalog data upload:

Features:

  • File Restrictions: Only accepts .csv and .json files
  • Size Limit: 10MB maximum (smaller than artifact's 100MB)
  • Validation: Strict MIME type checking for catalog data
  • Visual Feedback: 🍽️ menu icon and catalog-specific messaging
  • Drag & Drop: Full drag-and-drop support with visual feedback

Usage in Form Config:

{
  "CSV or JSON File": {
    "type": "catalog"
  }
}

Data Storage: Catalog files are stored in window.formCatalogData[fieldKey] with file object, name, size, and type.

Clear Function: Global clearCatalog(fieldKey) function for removing uploaded catalogs.

Integration with Menu System

The catalog field integrates with Ninefy's menu product type to:

  1. Upload CSV/JSON files containing hierarchical menu structures
  2. Parse menu data into tree structures (rider β†’ time span β†’ product)
  3. Upload individual products to Sanora with price and metadata
  4. Map Sanora UUIDs back to the menu tree structure
  5. Store complete menu as public data in BDO for cross-base discovery

Example CSV Format:

,rider,time span,product,price
,adult,two-hour,adult two-hour 250,2.50
,adult,day,adult day 500,5.00
,youth,two-hour,youth two-hour 100,1.00

This creates a hierarchical menu system that enables complex product catalogs while maintaining Sanora's lightweight approach.

About

Sanora.club is for selling magic

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published