Publishing & Discovery

Data Model: tce_packages

Every published version is one row of tce_packages (App\Models\TcePackage): namespace, name, kind (element | library | sdk), description, major/minor/patch, width/height, extra. Its code zip and icon are attachments (relation: code / relation: icon), reusing the site's polymorphic attachment mechanism unchanged. Declared dependencies are rows of tce_package_dependencies, pointing at the dependency's row, with optional required_major/minor/patch constraints.

The pre-v3 tobidot_elements table is read-only reference material for porting. Nothing in v3 — the registry, the generator, the loader, the routes — reads from it, and there is no migration; a legacy element appears in v3 only when it is deliberately ported and uploaded.

What Gets Uploaded

Kind Zip contents Produced by
element, library dist/index.js, dist/index.global.js, copied public/ files npm run pack (release/<name>-<version>.zip), or publish.py in the v3 workspace
sdk package.json + src/**/*.ts publish.py

One top-level folder in the zip is flattened on extraction, so zipping dist/ as a folder or zipping its contents both work.

Three Ways to Publish

Path Who Declares dependencies? One request?
POST /api/v1/tce-packages script / CI yes yes
MCP tool upload_tce_package an agent, publish.py, tce:import-v3-packages yes yes
Nova admin a human by hand no — row, then two attachments

All three hand their input to one service (TcePackageService::upload), so the rules below hold for every path.

1. REST Upload

POST /api/v1/tce-packages      (auth:sanctum, multipart/form-data)
Field Required Notes
namespace yes The publisher (Naming).
name yes The package name; elements and libraries must match the tag-name pattern.
zip yes See What Gets Uploaded. Large projects: Assets & Build.
version no major.minor.patch. Omitted: the previous patch + 1.
kind no element | library | sdk. Omitted: the previous kind, else element.
description no Omitted: carried over.
icon no SVG or PNG. Omitted: carried over.
width, height no Default window size. Omitted: carried over.
dependencies[i][namespace], dependencies[i][name] no Declared dependencies. Omitted: carried over; an empty list clears.

The response is the published version as the registry lists it. A README generated by the generator contains the exact curl call for its project.

2. MCP Tool

The site's MCP server exposes upload_tce_package with the same fields (zip_base64, icon_base64 + icon_file_name instead of files) and list_tce_packages to inspect the registry. The v3 workspace's publish.py uses it, reading everything from each package's manifest; php artisan tce:import-v3-packages does the same from a staging folder inside the app container.

3. Manual, via Nova

The Nova TcePackage resource creates the row by hand (namespace, name, version, kind, description, size, dependencies), then the Upload Attachment action attaches the code zip (relation: code) and the icon (relation: icon) in two steps. Nothing auto-increments the version here.

Versioning on Upload

Version resolution is keyed on (namespace, name):

  • No version given, no prior upload for the pair → 0.0.1.
  • No version given, prior upload exists → same major.minor, patch + 1.
  • version given → must be strictly greater than the pair's latest; the same or an older number is rejected. A bad release is fixed by a new patch, never by re-uploading its number.

Dependencies on Upload

Dependencies are declared by identifier and resolved to the dependency's latest uploaded version at upload time. A dependency that was never uploaded rejects the whole upload, naming every missing identifier — so packages are published dependencies first, and a published version can never be missing part of its dependency list. The declared list is what the embed pages and the package manager use to include libraries before the packages that need them.

Public Discovery Endpoint

GET /api/public/tce-packages   (no auth)

Every element and library version that has a code attachment, grouped by namespace/name (two publishers using the same name never share a group). SDK packages are build-time only and are not listed.

{
  "version": 1,
  "packages": {
    "tobidot/tce-notepad": [
      {
        "namespace": "tobidot", "name": "tce-notepad", "kind": "element",
        "description": "A simple text editor for .txt and .md files.",
        "major": 0, "minor": 2, "patch": 0,
        "root": "https://…/storage/tce-packages/<uuid>",
        "content": "https://…/storage/tce-packages/<uuid>/index.js",
        "icon": "https://…/storage/media/<uuid>/icon.svg",
        "width": 480, "height": 360,
        "extra": [], "created_at": "2026-10-17T18:45:35.000000Z",
        "dependencies": [{ "identifier": { "namespace": "tobidot", "name": "dll-tce-file-system" } }]
      }
    ]
  }
}

A version entry is TcePackageResource; the client-side schema is registry_response_schema in @tce-v3/common, and every consumer reads the endpoint through fetch_json(url, registry_response_schema). The two change together.

Routes

Route Serves
GET /tce-elements/{namespace}/{name} the latest version's IIFE, prefixed with its content root (Integration)
GET /tce-elements/{namespace}/{name}@{x}.{y}.{z} exactly that version, immutable
GET /tce-elements/{name} the same, in the site's default namespace
GET /tce/{name} fullscreen page of the latest element of that name, default namespace
GET /tce-packages/{id}/view fullscreen page of one specific upload
GET /, GET /v3 the desktop (with / without the site header)
GET /api/public/tce-packages the registry response above
GET /documentation/{path} this documentation as raw markdown, for tce-documentation

The embed route answers 404 for a version without an IIFE build and for SDK packages.

Do's and Don'ts

  • ✅ Do publish dependencies first; the upload rejects an undeclared-yet-uploaded dependency.
  • ✅ Do use publish.py / the manifest in the workspace and npm run pack + REST for a standalone project; never zip by hand what the tooling zips.
  • ✅ Do link externally to /tce/{name}, not an {id}, unless you want to pin a version.
  • ✅ Do change TcePackageResource and registry_response_schema together.
  • ❌ Don't re-upload a version number; bump the patch.
  • ❌ Don't read tobidot_elements from anything in v3.
  • ❌ Don't list or load SDK packages at runtime.