feat(steps): cross-tier channels — a client's fetch onto its own route, queue jobs onto consumers, bus and socket events onto handlers
- resolution/tier-synthesizer.ts: http-client (literal fetch/axios/ky/got/$fetch paths, axios.create baseURL instances, template holes as :params, base-URL holes by a two-segment tail; unique match only), queue-job (BullMQ/Bull add ↔ @Process/@Processor, WorkerHost process, new Worker, queue.process), event-bus (EventEmitter2 emit ↔ @OnEvent with globs; socket emit ↔ @SubscribeMessage / socket.on both ways with tier); channel, tier, callee, registeredAt on every edge; generic transport events never pair; test and generated files never sources; registered before the emitter pass
- steps.ts: crossing() reads tier/channel before languages; an endpoint reached across a tier is a bridge box and a boundary like a screen (through=1 enters it); a channel's call is not also an effect; sites read as written; a Next 'use server' action is a crossing by its directive (when.ts directive); a function-valued constant handler (asyncHandler(...)) is a route root and borrows the file-scope calls and refs within its lines
- express.ts: app.use('/prefix', router) mounts composed onto route names in postExtract (nested, by import or require); chained router.route('/x').get(h).put(h2) extracted, across lines
- frameworks/package-deps.ts: dependencies read from workspace package.json files too (Express, React, Expo Router, NestJS detect)
- routing manifest names constant handlers; e2e/ is a test directory; explore's Flow section labels the new channels
- tests: ui-steps-cross-tier (monorepo fixture: Next client + Express/Nest API), servers test updated for the queue landing
- docs: CHANGELOG, spec §3.13 cross-tier paragraph, CLAUDE.md, callback-edge-synthesis.md, plan P3 built
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01REFyW9hmNrxhwN5wxRoAkC
This commit is contained in:
co-authored by
Claude Fable 5
parent
950686def4
commit
b1f40c57dd
@@ -273,8 +273,18 @@ describe('NestJS', () => {
|
||||
expect(db.effect).toMatchObject({ model: 'cats', access: 'write', by: { name: 'create' } });
|
||||
const dbLink = p.links.find((l) => l.to === db.id)!;
|
||||
expect(dbLink.via.map((v) => v.name)).toEqual(['create']);
|
||||
const queue = effect(p, 'queue')!;
|
||||
expect(queue.label).toBe("this.catsQueue.add('index', { id })");
|
||||
// The job put on the `cats` queue lands on the processor that consumes it
|
||||
// — an arrival, not a call outside the index; the site is the `add` as written.
|
||||
expect(effect(p, 'queue')).toBeUndefined();
|
||||
const landing = p.steps.find((s) => s.kind === 'event' && s.node?.name === 'handleIndex')!;
|
||||
expect(landing).toBeDefined();
|
||||
expect(landing.event).toBe('index');
|
||||
expect(landing.trigger).toEqual({ kind: 'decorator', name: 'Process', of: "'index'", in: 'cats.processor.ts' });
|
||||
const toLanding = p.links.find((l) => l.to === landing.id)!;
|
||||
expect(toLanding.kind).toBe('event');
|
||||
expect(toLanding.synthesized).toBe(true);
|
||||
expect(toLanding.sites[0]).toMatchObject({ text: 'this.catsQueue.add', args: "'index', { id }" });
|
||||
expect(toLanding.label).toBe('via queue-job · job index · queue cats · registered at src/nest/cats.processor.ts:4');
|
||||
});
|
||||
|
||||
it('a thrown exception is the 404 the request gets', async () => {
|
||||
|
||||
Reference in New Issue
Block a user