원클릭으로
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
}
}),
},
});