"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateTrpc = generateTrpc;
const Generator = __importStar(require("@postxl/generator"));
function generateTrpc(context) {
    const imports = Generator.ImportGenerator
        //
        .from(context.trpcRouter.plugin._filePath)
        .add(context.actions.dispatcher)
        .add(context.authentication.service)
        .add(context.authentication.types.userInfo)
        .add(context.authentication.types.userRoles)
        .add(context.types.user)
        .add(context.view.service)
        .add({ name: context.trpcRouter.appRoutes.name, location: context.trpcRouter.appRoutes._filePath })
        .add({ name: context.trpcRouter._shared.context.name, location: context.trpcRouter._shared._filePath });
    return /* ts */ `
import { Injectable, Logger } from '@nestjs/common'
import { NestFastifyApplication } from '@nestjs/platform-fastify'
import { CreateFastifyContextOptions, fastifyTRPCPlugin } from '@trpc/server/adapters/fastify'

${imports.generate()}

/**
 * The \`${context.trpcRouter.plugin.name}\` is used to register the TRPC Server with NestJS/Fastify.
 * It registers the server as a Fastify plugin and provides relevant NestJS services as part of the context 
 * so they can be accessed in the TRPC routes.
 */
@Injectable()
export class ${context.trpcRouter.plugin.name} {
  private readonly logger = new Logger(${context.trpcRouter.plugin.name}.name)
  constructor(
    private readonly viewService: ${context.view.service.name},
    private readonly authService: ${context.authentication.service.name},
    private readonly dispatcherService: ${context.actions.dispatcher.name},
  ) {}

  public async register(app: NestFastifyApplication, config: { urlPrefix: string}) {    
    await app.register(fastifyTRPCPlugin, {
      prefix: \`\${config.urlPrefix}/trpc\`,
      trpcOptions: {
        router: ${context.trpcRouter.appRoutes.name},
        createContext: async ({ req, res }: CreateFastifyContextOptions): Promise<${context.trpcRouter._shared.context.name}> => {
          // In \`createContext\`, we already extract the viewer from the request. However,
          // we do not throw in case we cannot identify/create a viewer or user to also allow anonymous routes.
          // To ensure that only authenticated users can access particular routes, use the \`${context.trpcRouter._middleware.auth.name}\`!
          let viewer: { userInfo: UserInfo; userRoles: UserRoles; user: User; isAuthorized: boolean } | null = null

          let userInfo: UserInfo | null = null
          let userRoles: UserRoles = []

          const associatedUserInfo = await this.authService.getUserInfoFromRequest(req)

          if (associatedUserInfo.ok) {
            userInfo = associatedUserInfo.userInfo
          }

          const associatedUserRoles = await this.authService.getUserRolesFromRequest(req)

          if (associatedUserRoles.ok) {
            userRoles = associatedUserRoles.userRoles
          }

          if (userInfo) {
            let user = await this.viewService.users.data.getBySub(userInfo.sub)

            if (!user) {
              // If user doesn't exist yet, we create a new one using the data in viewer
              // (i.e. provided by the authentication provider).
              user = await this.dispatcherService.dispatch({
                action: {
                  scope: 'user',
                  type: 'create',
                  payload: { sub: userInfo.sub, name: userInfo.name, email: userInfo.email, profilePictureUrl: null },
                },
                user: this.viewService.users.data.rootUser,
              })

              if (!user) {
                throw new Error('Error creating new user!')
              }
            }

            viewer = { userInfo, userRoles, user, isAuthorized: true }
          }

          return {
            req,
            res,

            viewer,

            logger: this.logger,
            auth: this.authService,
            view: this.viewService,
            dispatcher: this.dispatcherService,
          }
        },
        onError: (err) => {
          this.logger.error(err.error)
        },
        batching: { enabled: true },
      },
    })
  }
}`;
}
//# sourceMappingURL=trpc-plugin.generator.js.map