first commit

This commit is contained in:
Matt Kane
2026-04-01 10:44:22 +01:00
commit 43fcb9a131
1789 changed files with 395041 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
# Marketplace Test Plugin
End-to-end test plugin for the EmDash marketplace publish and audit pipeline.
## What it does
- Hooks into `content:beforeSave` to log save events
- Exposes a `/ping` route and an `/events` route
- Declares `read:content` and `write:content` capabilities
- Includes icon and screenshot assets for image audit testing
## Usage
Bundle and publish to a marketplace instance:
```bash
emdash plugin bundle --dir packages/plugins/marketplace-test
emdash plugin publish dist/marketplace-test-0.1.0.tar.gz --registry https://emdash-marketplace.cto.cloudflare.dev
```
## Testing
This plugin is designed to exercise every step of the marketplace pipeline:
1. **Bundle**`emdash plugin bundle` builds `backend.js` from `sandbox-entry.ts`
2. **Upload** — tarball includes manifest, backend, icon, screenshot, README
3. **Code audit** — Workers AI analyzes `backend.js` (should pass — clean code)
4. **Image audit** — Workers AI analyzes `icon.png` and `screenshots/` (should pass)
5. **Status resolution** — enforcement mode determines final status

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

@@ -0,0 +1,31 @@
{
"name": "@emdashcms/plugin-marketplace-test",
"private": true,
"version": "0.1.0",
"description": "Test plugin for end-to-end marketplace publishing and audit workflow testing",
"type": "module",
"main": "dist/index.mjs",
"exports": {
".": {
"import": "./dist/index.mjs",
"types": "./dist/index.d.mts"
},
"./sandbox": "./dist/sandbox-entry.mjs"
},
"files": ["dist"],
"scripts": {
"build": "tsdown src/index.ts src/sandbox-entry.ts --format esm --dts --clean",
"dev": "tsdown src/index.ts src/sandbox-entry.ts --format esm --dts --watch",
"typecheck": "tsgo --noEmit"
},
"keywords": ["emdash", "cms", "plugin", "test", "marketplace"],
"author": "Matt Kane",
"license": "MIT",
"dependencies": {
"emdash": "workspace:*"
},
"devDependencies": {
"tsdown": "catalog:",
"typescript": "catalog:"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -0,0 +1,32 @@
/**
* Marketplace Test Plugin for EmDash CMS
*
* A self-contained plugin designed for end-to-end testing of the marketplace
* publish → audit → approval pipeline. Includes:
* - Backend sandbox code (content:beforeSave hook)
* - Icon and screenshot assets
* - Full manifest with capabilities
*
* Usage:
* emdash plugin bundle --dir packages/plugins/marketplace-test
* emdash plugin publish dist/marketplace-test-0.1.0.tar.gz --registry <url>
*/
import type { PluginDescriptor } from "emdash";
/**
* Plugin factory -- returns a descriptor for the integration.
*/
export function marketplaceTestPlugin(): PluginDescriptor {
return {
id: "marketplace-test",
version: "0.1.0",
format: "standard",
entrypoint: "@emdashcms/plugin-marketplace-test/sandbox",
capabilities: ["read:content", "write:content"],
allowedHosts: [],
storage: {
events: { indexes: ["timestamp", "type"] },
},
};
}

View File

@@ -0,0 +1,55 @@
/**
* Sandbox Entry Point
*
* Canonical plugin implementation using the standard format.
* Runs in both trusted (in-process) and sandboxed (isolate) modes.
*/
import { definePlugin } from "emdash";
import type { PluginContext } from "emdash";
interface HookEvent {
content?: Record<string, unknown>;
collection?: string;
isNew?: boolean;
}
export default definePlugin({
hooks: {
"content:beforeSave": {
handler: async (event: HookEvent, ctx: PluginContext) => {
ctx.log.info("[marketplace-test] beforeSave fired", {
collection: event.collection,
isNew: event.isNew,
});
// Record execution in storage
await ctx.storage.events.put(`hook-${Date.now()}`, {
timestamp: new Date().toISOString(),
type: "content:beforeSave",
collection: event.collection,
isNew: event.isNew,
});
return event.content;
},
},
},
routes: {
ping: {
handler: async (_ctx: { input: unknown; request: unknown }, pluginCtx: PluginContext) => ({
pong: true,
pluginId: pluginCtx.plugin.id,
timestamp: Date.now(),
}),
},
events: {
handler: async (_ctx: { input: unknown; request: unknown }, pluginCtx: PluginContext) => {
const result = await pluginCtx.storage.events.query({ limit: 10 });
return { count: result.items.length, items: result.items };
},
},
},
});

View File

@@ -0,0 +1,9 @@
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist",
"strict": false
},
"include": ["src"]
}