npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@makoojs/core

v0.4.0

Published

Framework-agnostic runtime core for Makoo userscript applications

Readme

@makoojs/core

@makoojs/core is Makoo's framework-agnostic runtime core. It declares injection tasks, starts task batches, waits for target DOM nodes, mounts artifacts, manages alive reinjection, binds event listeners, and provides lifecycle observation, logging, and error infrastructure.

[!NOTE] @makoojs/core provides Makoo's public runtime protocol. Other Makoo packages use its types and capabilities directly or indirectly.

Use Cases

  • Write a custom ResolvableMountAdapter so Makoo can mount a new artifact type.
  • Create a Makoo runtime with createMakoo() and start explicit task declarations.
  • Listen to injection lifecycle events for debugging, analytics, error reporting, or visual devtools.
  • Use low-level tools such as DOMWatcher and createActivityStore for custom integrations.

Installation

# npm install @makoojs/core
# yarn add @makoojs/core
pnpm add @makoojs/core

Minimal Runtime Example

import {
	createMakoo,
	inject,
	type ResolvableMountAdapter
} from '@makoojs/core';

type TextArtifact = {
	kind: 'text';
	text: string;
};

const textAdapter: ResolvableMountAdapter<TextArtifact, HTMLElement> = {
	name: 'text',
	matches(artifact): artifact is TextArtifact {
		return (
			typeof artifact === 'object' &&
			artifact !== null &&
			(artifact as { kind?: unknown }).kind === 'text'
		);
	},
	mount({ mountPoint, artifact }) {
		const el = document.createElement('span');
		el.textContent = artifact.text;
		mountPoint.appendChild(el);

		return { handle: el };
	},
	unmount({ handle }) {
		handle.remove();
	}
};

const makoo = createMakoo({
	defaults: {
		alive: true,
		scope: 'local',
		timeout: 5000
	},
	adapters: [textAdapter]
});

makoo.start([
	inject({
		id: 'text',
		injectAt: '#app',
		artifact: {
			kind: 'text',
			text: 'Hello from Makoo core'
		}
	})
]);

Runtime Basics

inject() and listen() declare tasks. They do not touch the DOM or register tasks by themselves. makoo.start([...]) registers the declarations in the provided batch and immediately schedules those tasks.

inject() accepts an object containing the target, artifact, and task options. Its optional id is used as the task ID, which is useful when you want to look up or control that task later:

inject({
	id: 'settings-panel',
	injectAt: '#settings',
	artifact: settingsArtifact,
	options: {
		alive: true
	}
});

When id is omitted, Makoo infers a task id from the artifact and target selector.

import { createMakoo, inject, listen } from '@makoojs/core';

const makoo = createMakoo({
	defaults: {
		alive: false,
		scope: 'local',
		timeout: 5000
	},
	adapters: [myAdapter],
	hooks: {
		'start:requested': (event) => {
			console.log(event.name);
		}
	}
});

const started = makoo.start([
	inject({
		id: 'toolbar',
		injectAt: '#toolbar',
		artifact: toolbarArtifact,
		options: {
			alive: true
		}
	}),
	inject({
		id: 'settings-panel',
		injectAt: '#settings',
		artifact: settingsArtifact,
		options: {
			alive: true
		}
	}),
	inject({
		id: 'save-tip',
		injectAt: '#save-tip',
		artifact: saveTipArtifact,
		options: {
			on: listen({
				listenAt: '#save',
				type: 'click',
				callback: () => {
					console.log('save clicked');
				}
			})
		}
	}),
	listen({
		id: 'escape-close',
		listenAt: '#escape',
		type: 'keydown',
		callback: onEscape
	})
]);

start() returns StartedTasks for batch-scoped control:

const toolbar = started.get('toolbar');

if (toolbar?.kind === 'component') {
	toolbar.disableAlive();
	toolbar.enableAlive();
}

started.destroyAll();

started.destroyAll() only affects tasks created by that start batch. makoo.destroyAll() affects the whole runtime.

Adapter Contract

core does not care whether an artifact is a Vue component, a React component, or another object. It only requires adapters to implement a unified mounting protocol.

import type { ResolvableMountAdapter } from '@makoojs/core';

const adapter: ResolvableMountAdapter<MyArtifact, MyHandle, MyInstance> = {
	name: 'my-adapter',
	matches(artifact): artifact is MyArtifact {
		return isMyArtifact(artifact);
	},
	mount(input) {
		return {
			handle,
			instance
		};
	},
	unmount(input) {
		// Clean up according to input.reason.
	}
};

mount(input) receives the target host, generated mount point, artifact, task ID, selector, and task-scoped makoo context.

Listener And Activity Signal

Standalone listeners use the object form of listen(). Their optional id is the task ID; use it when later task lookup or control needs a stable identity. A component's on listener is owned by that component task and does not need its own ID.

capture defaults to false. Set it to true to run the listener during the DOM capture phase.

import { createActivityStore, createMakoo, listen } from '@makoojs/core';

const enabled = createActivityStore(true);
const makoo = createMakoo();

makoo.start([
	listen({
		id: 'save-listener',
		listenAt: '#save',
		type: 'click',
		callback: () => {
			console.log('save clicked');
		},
		activitySignal: () => enabled
	})
]);

enabled.set(false);
enabled.set(true);

Observation Events

core emits observation events during declaration registration, starting, mounting, listener work, alive mode, DOM watching, and task status changes.

const off = makoo.on('artifact:mountSuccess', (event) => {
	console.log(event.taskId, event.injectAt);
});

makoo.onAny((event, ctrl) => {
	if (event.name === 'artifact:mountFail') {
		ctrl.stopPropagation();
	}
});

off();

Common events include:

  • register:start
  • register:success
  • start:requested
  • start:taskScheduled
  • artifact:mountStart
  • artifact:mountSuccess
  • artifact:mountFail
  • listener:attached
  • alive:enabled
  • alive:observerStarted
  • task:statusChange
  • dom:targetFound
  • dom:targetTimeout

The full event name list is available from OBSERVE_EVENT_NAMES.

DOMWatcher

DOMWatcher is core's low-level DOM observation utility. You usually do not need to use it directly because makoo.start() and alive mode already wrap target waiting and restoration.

Logging And Errors

core uses Logger by default and prints logs with the [Makoo] prefix. You can pass a custom logger to createMakoo({ logger }).

core also exports these error-related types:

  • MakooError
  • AdapterError
  • TaskError
  • SignalError
  • ErrorCode
  • MakooIssue

Public Exports Overview

| Category | Representative exports | | --- | --- | | Runtime API | createMakoo, inject, listen, MakooRuntime, StartedTasks | | Adapter protocol | MountAdapter, ResolvableMountAdapter, AdapterMountInput, AdapterUnmountInput, MakooContext | | Lifecycle observation | ObserverHub, OBSERVE_EVENT_NAMES, ObserveEvent, ObserveHook, LifecycleHookMap | | DOM observation | DOMWatcher | | Listener signal | createActivityStore, ActivitySignalSource | | Logging | Logger, ILogger, LoggerLevel | | Errors | MakooError, AdapterError, TaskError, SignalError, ErrorCode |