一键导入
momentum-api
Work with Momentum API for data operations in Angular components
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Work with Momentum API for data operations in Angular components
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Adversarial review checklist for stateful Momentum CMS features (workflow, versions, scheduled publish, permissions inheritance, branches, anything that adds writeable state + access control). Use BEFORE merging a feature that introduces new mutating routes, new system-managed columns, new access functions, or new audit trails. Trigger phrases include "red-team this", "adversarial review", "security review of <feature>", "before merging <feature>", "/cms-feature-red-team".
Set up the Momentum CMS MCP server plugin and generate Claude Code MCP config for AI tool integration. Use when connecting Claude Code (or any MCP client) to a Momentum CMS instance.
Generate a new Momentum CMS collection with fields, access control, and hooks
Generate an Angular component with signals, OnPush, and host-based styling following Momentum CMS conventions. Use when creating new UI components in any library.
Write and validate Playwright E2E tests for Momentum CMS features. UI tests ALWAYS start from /admin dashboard and navigate via sidebar/dashboard — never go directly to deep URLs. Always starts the server and inspects the actual UI before writing assertions. Triggers include "write e2e tests for...", "add e2e tests", "test the admin UI for...", or "/e2e-test <feature>".
Run migrations, generate schemas, and manage code generation for Momentum CMS. Use when working with database migrations, Drizzle schema generation, type generation, or Angular schematics.
| name | momentum-api |
| description | Work with Momentum API for data operations in Angular components |
| argument-hint | <operation> [collection] |
Guide for using injectMomentumAPI() in Angular components.
$ARGUMENTS - Operation type: "query", "crud", "typed", or collection nameimport { injectMomentumAPI } from '@momentumcms/admin';
@Component({...})
export class MyComponent {
private readonly api = injectMomentumAPI();
}
// In constructor or with toSignal()
this.api
.collection<Post>('posts')
.find$({ limit: 10 })
.subscribe((result) => {
this.posts.set(result.docs);
});
async loadData(): Promise<void> {
const result = await this.api.collection<Post>('posts').find({ limit: 10 });
this.posts.set(result.docs);
}
// Create
const post = await this.api.collection<Post>('posts').create({ title: 'New Post' });
// Read
const post = await this.api.collection<Post>('posts').findById('123');
// Update
const updated = await this.api.collection<Post>('posts').update('123', { title: 'Updated' });
// Delete
const result = await this.api.collection<Post>('posts').delete('123');
npm run generateimport type { Post, User } from '../generated/momentum.types';
const posts = await this.api.collection<Post>('posts').find();
const users = await this.api.collection<User>('users').find();
interface FindOptions {
where?: Record<string, unknown>; // Filter conditions
sort?: string; // Sort field (prefix with - for desc)
limit?: number; // Max results (default: 10)
page?: number; // Page number (default: 1)
}
import { Component, signal, ChangeDetectionStrategy } from '@angular/core';
import { injectMomentumAPI } from '@momentumcms/admin';
import type { Post } from '../generated/momentum.types';
@Component({
selector: 'app-posts',
template: `
@if (loading()) {
<p>Loading...</p>
} @else {
@for (post of posts(); track post.id) {
<article>
<h2>{{ post.title }}</h2>
<p>{{ post.content }}</p>
<button (click)="deletePost(post.id)">Delete</button>
</article>
}
}
<form (submit)="createPost($event)">
<input #titleInput placeholder="Title" />
<button type="submit">Create Post</button>
</form>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PostsComponent {
private readonly api = injectMomentumAPI();
readonly posts = signal<Post[]>([]);
readonly loading = signal(true);
constructor() {
this.loadPosts();
}
async loadPosts(): Promise<void> {
this.loading.set(true);
try {
const result = await this.api.collection<Post>('posts').find({
limit: 20,
sort: '-createdAt',
});
this.posts.set(result.docs);
} finally {
this.loading.set(false);
}
}
async createPost(event: Event): Promise<void> {
event.preventDefault();
const form = event.target as HTMLFormElement;
const input = form.querySelector('input') as HTMLInputElement;
const post = await this.api.collection<Post>('posts').create({
title: input.value,
});
this.posts.update((posts) => [post, ...posts]);
input.value = '';
}
async deletePost(id: string): Promise<void> {
await this.api.collection<Post>('posts').delete(id);
this.posts.update((posts) => posts.filter((p) => p.id !== id));
}
}
/api/*import {
CollectionNotFoundError,
DocumentNotFoundError,
AccessDeniedError,
ValidationError,
} from '@momentumcms/server-core';
try {
await this.api.collection('posts').create({ title: '' });
} catch (error) {
if (error instanceof ValidationError) {
console.error('Validation failed:', error.errors);
}
}
Generate types from your collections:
npm run generate
Output files (do not edit manually):
src/generated/momentum.types.ts — TypeScript interfacessrc/generated/momentum.config.ts — Browser-safe admin configTransferState is enabled by default for all read operations (find, findById, findSignal, findByIdSignal). Data fetched during SSR is automatically cached and reused on browser hydration, eliminating duplicate HTTP calls.
// SSR: Fetches and caches | Browser: Reads from cache (no HTTP)
const posts = await this.api.collection<Post>('posts').find({ limit: 10 });
const post = await this.api.collection<Post>('posts').findById(id);
Use transfer: false to disable TransferState for a specific call:
const posts = await this.api.collection<Post>('posts').find({
limit: 10,
transfer: false,
});
// Signals also use TransferState by default
readonly posts = this.api.collection<Post>('posts').findSignal({ limit: 10 });
readonly post = this.api.collection<Post>('posts').findByIdSignal(id);
Ensure provideClientHydration() is in your app config:
// app.config.ts
export const appConfig: ApplicationConfig = {
providers: [provideClientHydration()],
};