ワンクリックで
axolotl-subscriptions
Axolotl subscription handlers - async generators, yield patterns, PubSub integration, and federated subscription rules
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Axolotl subscription handlers - async generators, yield patterns, PubSub integration, and federated subscription rules
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Reusable native component and template patterns for starter implementation
Starter data layer pattern with React Query + Zeus for Expo app
i18n baseline and dev-translate setup for Expo mobile starter
Expo Router conventions for route groups, native headers, and starter navigation
Baseline architecture for Axolotl mobile starter (Expo Router + reusable blocks)
Playwright E2E execution rules - domain-oriented specs, shared auth setup/storageState, idempotent zero-flake runs, verify-email-disabled support, and canonical Mailgun local email path
| name | axolotl-subscriptions |
| description | Axolotl subscription handlers - async generators, yield patterns, PubSub integration, and federated subscription rules |
CRITICAL: Always use createSubscriptionHandler from @aexol/axolotl-core. Never use a raw AsyncGenerator.
import { createResolvers, createSubscriptionHandler } from '@aexol/axolotl-core';
import { setTimeout as setTimeout$ } from 'node:timers/promises';
export default createResolvers({
Subscription: {
countdown: createSubscriptionHandler(async function* (input, { from }) {
// input = [source, args, context] — same as regular resolvers
for (let i = from ?? 10; i >= 0; i--) {
await setTimeout$(1000);
yield i; // yield the value directly — NOT { countdown: i }
}
}),
},
});
Subscriptions require a Subscription type in the schema AND the subscription key in the schema block:
type Subscription {
countdown(from: Int): Int! @resolver
}
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
Yield the field value directly. GraphQL wraps it automatically:
// ✅ CORRECT
yield { type: 'CREATED', post: { _id: '123' } };
// → { "data": { "postUpdates": { "type": "CREATED", "post": {...} } } }
// ❌ WRONG — double-wraps the field name
yield { postUpdates: { type: 'CREATED', post: {...} } };
export default createResolvers({
Mutation: {
sendMessage: async ([, , ctx], { text }) => {
const message = { id: crypto.randomUUID(), text, timestamp: new Date().toISOString() };
await ctx.pubsub.publish('MESSAGE_ADDED', message);
return message;
},
},
Subscription: {
messageAdded: createSubscriptionHandler(async function* (input) {
const [, , ctx] = input;
const channel = ctx.pubsub.subscribe('MESSAGE_ADDED');
try {
for await (const message of channel) {
yield message;
}
} finally {
await channel.unsubscribe(); // cleanup on disconnect
}
}),
},
});