Skip to content

Cookbook

Practical patterns for real projects built around @azure-net/kit.

Context aliases

Keep context aliases explicit in azure-net.config.ts so CLI checks can enforce boundaries.

ts
export default {
  packageManager: 'pnpm',
  coreAlias: '$core',
  sharedAlias: '$sharedKernel',
  contexts: [
    { name: 'public', alias: '$public' },
    { name: 'admin', alias: '$admin' },
    { name: 'shared-kernel', alias: '$sharedKernel' }
  ]
};

Use sharedAlias only for a real shared context. Other contexts may import it, but the shared context itself must not import other app contexts.

Program entrypoint

Keep all SvelteKit lifecycle work in src/program.ts. Do not create hooks.server.ts or hooks.client.ts; AzureNetPlugin wires them virtually.

ts
import { createApp } from '@azure-net/kit';
import { TranslationManager } from '$core/translation';

export const { register, Container } = createApp((app) =>
  app
    .useServer(async ({ resolve, event, useMiddlewares }) => {
      await useMiddlewares([
        ({ to, next }) => {
          if (to.pathname.startsWith('/private')) {
            return next('/login', 303);
          }

          return next();
        }
      ]);

      const { preloadTranslation, applyHtmlLocaleAttr } = TranslationManager();
      await preloadTranslation();

      return resolve(event, {
        transformPageChunk: ({ html }) => applyHtmlLocaleAttr(html)
      });
    })
    .useClient(({ useMiddlewares }) => {
      useMiddlewares([
        ({ next }) => {
          next();
        }
      ]);
    })
    .dependencies({
      translationManager: () => TranslationManager()
    })
);

Infrastructure provider

Create datasource and repositories in the infrastructure layer. The provider owns concrete implementations.

ts
import { createBoundaryProvider } from '@azure-net/kit';
import { createHttpServiceInstance } from '@azure-net/kit/infra';
import { ApiDatasource } from '$core/datasource';
import { ContentRepository } from '$public/layers/infrastructure/http/repositories';

export const InfrastructureProvider = createBoundaryProvider('PublicInfrastructureProvider', {
  register: () => ({
    ContentRepository: () =>
      new ContentRepository(
        new ApiDatasource({
          http: createHttpServiceInstance({
            prefixUrl: '/api'
          })
        })
      )
  })
});

Application provider

Application providers depend on infrastructure providers from the same context and expose use-cases.

ts
import { createBoundaryProvider } from '@azure-net/kit';
import { InfrastructureProvider } from '$public/layers/infrastructure/providers';
import { ContentUseCases } from '$public/layers/application/use-cases';

export const ApplicationProvider = createBoundaryProvider('PublicApplicationProvider', {
  dependsOn: {
    InfrastructureProvider
  },
  register: ({ InfrastructureProvider }) => ({
    ContentUseCases: () => new ContentUseCases(InfrastructureProvider.ContentRepository)
  })
});

Presenter

Presenters stay in the presentation layer and talk to application use-cases. Queries usually become async resources, mutations become async actions.

ts
import { AppPresenter } from '$core/presenter';
import { ApplicationProvider } from '$public/layers/application/providers';

export const ContentPresenter = AppPresenter('PublicContentPresenter', ({ createAsyncResource }) => {
  const { ContentUseCases } = ApplicationProvider();

  const collection = () => createAsyncResource(() => ContentUseCases.collection());

  return { collection };
});

Generated module flow

For a CRUD-like module, start from the preset:

bash
azure-net generate module-preset

The CLI creates domain contracts, repository, use-cases, and then waits while you wire infrastructure/application providers manually. After that it generates the presenter.

Run internal checks before committing generated code:

bash
azure-net check internal

For a full local gate:

bash
azure-net check project