@saasicat/adapter-prisma 0.26.1 → 1.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -52,10 +52,12 @@ __export(index_exports, {
52
52
  PrismaTenantSubscriptionWriteAdapter: () => PrismaTenantSubscriptionWriteAdapter,
53
53
  PrismaTransactionRunner: () => PrismaTransactionRunner,
54
54
  ZeroPromoRevenueDeductionAggregator: () => ZeroPromoRevenueDeductionAggregator,
55
+ assertDelegatesExist: () => assertDelegatesExist,
55
56
  buildActorTag: () => buildActorTag,
56
57
  createPrismaPlanBindingResolver: () => createPrismaPlanBindingResolver,
57
58
  getPrismaDelegate: () => getPrismaDelegate,
58
59
  prismaPersistence: () => prismaPersistence,
60
+ resolveAdminResourcesSchema: () => resolveAdminResourcesSchema,
59
61
  resolvePrismaSchemaOptions: () => resolvePrismaSchemaOptions
60
62
  });
61
63
  module.exports = __toCommonJS(index_exports);
@@ -410,7 +412,7 @@ __name(createPrismaPlanBindingResolver, "createPrismaPlanBindingResolver");
410
412
  function getPrismaDelegate(client, delegateName) {
411
413
  const delegate = client?.[delegateName];
412
414
  if (!delegate || typeof delegate !== "object") {
413
- throw new Error(`Prisma client has no '${delegateName}' delegate.`);
415
+ throw new Error(`Prisma client has no '${delegateName}' delegate. If your model is called something else, map it \u2014 \`adminResources: { delegates: { tenant: "organization" } }\` for the SuperAdmin resources, \`schema\` for the plan binding.`);
414
416
  }
415
417
  return delegate;
416
418
  }
@@ -434,6 +436,65 @@ function asPlanIdentityClient(client) {
434
436
  }
435
437
  __name(asPlanIdentityClient, "asPlanIdentityClient");
436
438
 
439
+ // src/admin-resources-schema.ts
440
+ var DEFAULTS = {
441
+ delegates: {
442
+ tenant: "tenant",
443
+ user: "user",
444
+ subscription: "subscription"
445
+ },
446
+ tenant: {
447
+ slug: "slug",
448
+ name: "name",
449
+ isActive: "isActive",
450
+ deletedAt: "deletedAt",
451
+ users: "users",
452
+ subscription: "subscription"
453
+ },
454
+ user: {
455
+ email: "email",
456
+ firstName: "firstName",
457
+ lastName: "lastName",
458
+ isActive: "isActive",
459
+ tenant: "tenant"
460
+ }
461
+ };
462
+ function resolveAdminResourcesSchema(delegates = {}, fields = {}) {
463
+ return {
464
+ delegates: {
465
+ ...DEFAULTS.delegates,
466
+ ...delegates
467
+ },
468
+ tenant: {
469
+ ...DEFAULTS.tenant,
470
+ ...fields.tenant
471
+ },
472
+ user: {
473
+ ...DEFAULTS.user,
474
+ ...fields.user
475
+ }
476
+ };
477
+ }
478
+ __name(resolveAdminResourcesSchema, "resolveAdminResourcesSchema");
479
+ function assertDelegatesExist(client, schema) {
480
+ const available = new Set(delegateNamesOf(client));
481
+ const missing = Object.entries(schema.delegates).filter(([, delegateName]) => !available.has(delegateName)).map(([role, delegateName]) => `${role} \u2192 '${delegateName}'`);
482
+ if (missing.length === 0) return;
483
+ throw new Error(`PrismaAdminResourcesAdapter is mapped to delegates the Prisma client does not have: ${missing.join(", ")}. The client offers: ${[
484
+ ...available
485
+ ].sort().join(", ") || "(none)"}. Map them with \`adminResources: { delegates: { tenant: "organization" } }\`, or implement \`AdminResourcesPort\` yourself if the shape differs rather than the names.`);
486
+ }
487
+ __name(assertDelegatesExist, "assertDelegatesExist");
488
+ function delegateNamesOf(client) {
489
+ if (!client || typeof client !== "object") return [];
490
+ return Object.keys(client).filter((key) => {
491
+ if (key.startsWith("$") || key.startsWith("_")) return false;
492
+ const value = client[key];
493
+ return typeof value === "object" && value !== null && typeof value.findMany === "function";
494
+ });
495
+ }
496
+ __name(delegateNamesOf, "delegateNamesOf");
497
+
437
498
  // src/prisma-admin-resources.adapter.ts
438
499
  var DEFAULT_LIST_LIMIT = 200;
439
500
  var DEFAULT_AUDIT_LIMIT = 100;
@@ -445,41 +506,45 @@ var PrismaAdminResourcesAdapter = class {
445
506
  metrics;
446
507
  listLimit;
447
508
  audit;
509
+ schema;
448
510
  constructor(prisma, options = {}) {
449
511
  this.prisma = prisma;
450
- this.metrics = options.tenantMetrics ?? [
451
- "users"
452
- ];
453
512
  this.listLimit = options.listLimit ?? DEFAULT_LIST_LIMIT;
454
513
  this.audit = new PrismaAuditQueryAdapter(prisma);
514
+ this.schema = resolveAdminResourcesSchema(options.delegates, options.fields);
515
+ this.metrics = options.tenantMetrics ?? [
516
+ this.schema.tenant.users
517
+ ];
518
+ if (options.delegates) assertDelegatesExist(prisma, this.schema);
455
519
  }
456
520
  async listTenants(filter) {
521
+ const t = this.schema.tenant;
457
522
  const where = {};
458
523
  const active = parseActiveFilter(filter.status);
459
- if (active !== void 0) where.isActive = active;
524
+ if (active !== void 0) where[t.isActive] = active;
460
525
  if (filter.search) {
461
526
  where.OR = [
462
527
  {
463
- slug: {
528
+ [t.slug]: {
464
529
  contains: filter.search,
465
530
  mode: "insensitive"
466
531
  }
467
532
  },
468
533
  {
469
- name: {
534
+ [t.name]: {
470
535
  contains: filter.search,
471
536
  mode: "insensitive"
472
537
  }
473
538
  }
474
539
  ];
475
540
  }
476
- if (filter.plan) where.subscription = {
541
+ if (filter.plan) where[t.subscription] = {
477
542
  plan: filter.plan
478
543
  };
479
544
  const rows = await this.tenants().findMany({
480
545
  where,
481
546
  include: {
482
- subscription: {
547
+ [t.subscription]: {
483
548
  select: {
484
549
  plan: true,
485
550
  status: true
@@ -496,24 +561,25 @@ var PrismaAdminResourcesAdapter = class {
496
561
  });
497
562
  return rows.map((row) => ({
498
563
  id: row.id,
499
- slug: row.slug,
500
- name: row.name,
501
- isActive: row.isActive,
502
- deletedAt: row.deletedAt?.toISOString() ?? null,
503
- plan: row.subscription?.plan ?? null,
504
- status: row.subscription?.status ?? null,
564
+ slug: this.read(row, t.slug) ?? "",
565
+ name: this.read(row, t.name) ?? "",
566
+ isActive: this.read(row, t.isActive) ?? true,
567
+ deletedAt: this.read(row, t.deletedAt)?.toISOString() ?? null,
568
+ plan: this.subscriptionOf(row)?.plan ?? null,
569
+ status: this.subscriptionOf(row)?.status ?? null,
505
570
  createdAt: row.createdAt.toISOString(),
506
571
  ...row._count ?? {}
507
572
  }));
508
573
  }
509
574
  async getTenantDetail(slug) {
575
+ const t = this.schema.tenant;
510
576
  const row = await this.tenants().findUnique({
511
577
  where: {
512
- slug
578
+ [t.slug]: slug
513
579
  },
514
580
  include: {
515
- subscription: true,
516
- users: {
581
+ [t.subscription]: true,
582
+ [t.users]: {
517
583
  orderBy: {
518
584
  createdAt: "asc"
519
585
  }
@@ -526,31 +592,32 @@ var PrismaAdminResourcesAdapter = class {
526
592
  if (!row) return null;
527
593
  return {
528
594
  id: row.id,
529
- slug: row.slug,
530
- name: row.name,
531
- isActive: row.isActive,
532
- subscription: row.subscription ? {
533
- plan: row.subscription.plan,
534
- status: row.subscription.status,
535
- billingCycle: row.subscription.billingCycle,
536
- isPilot: row.subscription.isPilot,
537
- trialEndsAt: row.subscription.trialEndsAt?.toISOString() ?? null,
538
- pilotEndsAt: row.subscription.pilotEndsAt?.toISOString() ?? null
595
+ slug: this.read(row, t.slug) ?? slug,
596
+ name: this.read(row, t.name) ?? "",
597
+ isActive: this.read(row, t.isActive) ?? true,
598
+ subscription: this.subscriptionOf(row) ? {
599
+ plan: this.subscriptionOf(row).plan,
600
+ status: this.subscriptionOf(row).status,
601
+ billingCycle: this.subscriptionOf(row).billingCycle,
602
+ isPilot: this.subscriptionOf(row).isPilot,
603
+ trialEndsAt: this.subscriptionOf(row).trialEndsAt?.toISOString() ?? null,
604
+ pilotEndsAt: this.subscriptionOf(row).pilotEndsAt?.toISOString() ?? null
539
605
  } : null,
540
- users: (row.users ?? []).map((user) => ({
606
+ users: (this.read(row, t.users) ?? []).map((user) => ({
541
607
  id: user.id,
542
- email: user.email,
543
- firstName: user.firstName ?? void 0,
544
- lastName: user.lastName ?? void 0,
608
+ email: this.read(user, this.schema.user.email) ?? "",
609
+ firstName: this.read(user, this.schema.user.firstName) ?? void 0,
610
+ lastName: this.read(user, this.schema.user.lastName) ?? void 0,
545
611
  createdAt: user.createdAt.toISOString()
546
612
  })),
547
613
  counts: row._count ?? {}
548
614
  };
549
615
  }
550
616
  async setTenantActive(slug, active, subscriptionStatus) {
617
+ const t = this.schema.tenant;
551
618
  const tenant = await this.tenants().findUnique({
552
619
  where: {
553
- slug
620
+ [t.slug]: slug
554
621
  }
555
622
  });
556
623
  if (!tenant) return null;
@@ -559,7 +626,7 @@ var PrismaAdminResourcesAdapter = class {
559
626
  id: tenant.id
560
627
  },
561
628
  data: {
562
- isActive: active
629
+ [t.isActive]: active
563
630
  }
564
631
  });
565
632
  await this.subscriptions().updateMany({
@@ -579,20 +646,22 @@ var PrismaAdminResourcesAdapter = class {
579
646
  };
580
647
  }
581
648
  async listUsers(filter) {
649
+ const u = this.schema.user;
650
+ const tenantSlug = this.schema.tenant.slug;
582
651
  const where = {};
583
- if (filter.q) where.email = {
652
+ if (filter.q) where[u.email] = {
584
653
  contains: filter.q,
585
654
  mode: "insensitive"
586
655
  };
587
- if (filter.tenant) where.tenant = {
588
- slug: filter.tenant
656
+ if (filter.tenant) where[u.tenant] = {
657
+ [tenantSlug]: filter.tenant
589
658
  };
590
659
  const rows = await this.users().findMany({
591
660
  where,
592
661
  include: {
593
- tenant: {
662
+ [u.tenant]: {
594
663
  select: {
595
- slug: true
664
+ [tenantSlug]: true
596
665
  }
597
666
  }
598
667
  },
@@ -603,12 +672,12 @@ var PrismaAdminResourcesAdapter = class {
603
672
  });
604
673
  return rows.map((row) => ({
605
674
  id: row.id,
606
- email: row.email,
607
- firstName: row.firstName ?? "",
608
- lastName: row.lastName ?? "",
675
+ email: this.read(row, u.email) ?? "",
676
+ firstName: this.read(row, u.firstName) ?? "",
677
+ lastName: this.read(row, u.lastName) ?? "",
609
678
  role: row.platformRole ?? row.role ?? "MEMBER",
610
- isActive: row.isActive ?? true,
611
- tenantSlug: row.tenant?.slug ?? null,
679
+ isActive: this.read(row, u.isActive) ?? true,
680
+ tenantSlug: this.tenantSlugOf(row, u.tenant, tenantSlug),
612
681
  lastLoginAt: row.lastLoginAt?.toISOString() ?? null,
613
682
  createdAt: row.createdAt.toISOString()
614
683
  }));
@@ -623,12 +692,13 @@ var PrismaAdminResourcesAdapter = class {
623
692
  });
624
693
  }
625
694
  async listSubscriptions() {
695
+ const t = this.schema.tenant;
626
696
  const rows = await this.subscriptions().findMany({
627
697
  include: {
628
698
  tenant: {
629
699
  select: {
630
- slug: true,
631
- name: true
700
+ [t.slug]: true,
701
+ [t.name]: true
632
702
  }
633
703
  },
634
704
  planVersion: {
@@ -644,7 +714,10 @@ var PrismaAdminResourcesAdapter = class {
644
714
  });
645
715
  return rows.map((row) => ({
646
716
  id: row.id,
647
- tenant: row.tenant,
717
+ tenant: {
718
+ slug: this.read(row.tenant, t.slug) ?? "",
719
+ name: this.read(row.tenant, t.name) ?? ""
720
+ },
648
721
  plan: row.plan,
649
722
  status: row.status,
650
723
  billingCycle: row.billingCycle,
@@ -653,13 +726,32 @@ var PrismaAdminResourcesAdapter = class {
653
726
  }));
654
727
  }
655
728
  tenants() {
656
- return getPrismaDelegate(this.prisma, "tenant");
729
+ return getPrismaDelegate(this.prisma, this.schema.delegates.tenant);
657
730
  }
658
731
  users() {
659
- return getPrismaDelegate(this.prisma, "user");
732
+ return getPrismaDelegate(this.prisma, this.schema.delegates.user);
660
733
  }
661
734
  subscriptions() {
662
- return getPrismaDelegate(this.prisma, "subscription");
735
+ return getPrismaDelegate(this.prisma, this.schema.delegates.subscription);
736
+ }
737
+ /** The subscription relation of a tenant row, under whatever it is called. */
738
+ subscriptionOf(row) {
739
+ return this.read(row, this.schema.tenant.subscription) ?? null;
740
+ }
741
+ /** The tenant slug on a user row, through both mapped names. */
742
+ tenantSlugOf(row, relation, slugField) {
743
+ const tenant = this.read(row, relation);
744
+ return tenant ? this.read(tenant, slugField) ?? null : null;
745
+ }
746
+ /**
747
+ * Reads a mapped field off a row.
748
+ *
749
+ * The rows come back keyed by the APP's field names, so every read of a
750
+ * mapped field goes through here — and the row type stays the shape the
751
+ * adapter promises rather than becoming `Record<string, unknown>`.
752
+ */
753
+ read(row, field) {
754
+ return row[field];
663
755
  }
664
756
  };
665
757
  function metricSelect(metrics) {
@@ -2039,7 +2131,7 @@ PrismaMfaAdapter = _ts_decorate9([
2039
2131
  ])
2040
2132
  ], PrismaMfaAdapter);
2041
2133
 
2042
- // src/prisma-plan-catalog-import-sink.ts
2134
+ // src/prisma-plan-catalog-import-sink.adapter.ts
2043
2135
  var import_common10 = require("@nestjs/common");
2044
2136
  function _ts_decorate10(decorators, target, key, desc) {
2045
2137
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -2193,7 +2285,7 @@ PrismaPlanCatalogImportSink = _ts_decorate10([
2193
2285
  ])
2194
2286
  ], PrismaPlanCatalogImportSink);
2195
2287
 
2196
- // src/prisma-plan-catalog-read-sink.ts
2288
+ // src/prisma-plan-catalog-read-sink.adapter.ts
2197
2289
  var import_common11 = require("@nestjs/common");
2198
2290
  function _ts_decorate11(decorators, target, key, desc) {
2199
2291
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -3623,7 +3715,7 @@ PrismaPromoCodeValidationLogRepository = _ts_decorate17([
3623
3715
  ])
3624
3716
  ], PrismaPromoCodeValidationLogRepository);
3625
3717
 
3626
- // src/prisma-promo-subscription-lookup.ts
3718
+ // src/prisma-promo-subscription-lookup.adapter.ts
3627
3719
  var import_common18 = require("@nestjs/common");
3628
3720
  function _ts_decorate18(decorators, target, key, desc) {
3629
3721
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -4821,7 +4913,7 @@ function clearedPendingVersionData() {
4821
4913
  }
4822
4914
  __name(clearedPendingVersionData, "clearedPendingVersionData");
4823
4915
 
4824
- // src/prisma-transaction-runner.ts
4916
+ // src/prisma-transaction-runner.adapter.ts
4825
4917
  var import_common25 = require("@nestjs/common");
4826
4918
  function _ts_decorate25(decorators, target, key, desc) {
4827
4919
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -4862,7 +4954,7 @@ PrismaTransactionRunner = _ts_decorate25([
4862
4954
  ])
4863
4955
  ], PrismaTransactionRunner);
4864
4956
 
4865
- // src/zero-promo-revenue-aggregator.ts
4957
+ // src/zero-promo-revenue-aggregator.adapter.ts
4866
4958
  var import_common26 = require("@nestjs/common");
4867
4959
  function _ts_decorate26(decorators, target, key, desc) {
4868
4960
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -5016,9 +5108,11 @@ __name(buildProvisioning, "buildProvisioning");
5016
5108
  PrismaTenantSubscriptionWriteAdapter,
5017
5109
  PrismaTransactionRunner,
5018
5110
  ZeroPromoRevenueDeductionAggregator,
5111
+ assertDelegatesExist,
5019
5112
  buildActorTag,
5020
5113
  createPrismaPlanBindingResolver,
5021
5114
  getPrismaDelegate,
5022
5115
  prismaPersistence,
5116
+ resolveAdminResourcesSchema,
5023
5117
  resolvePrismaSchemaOptions
5024
5118
  });
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { AdminResourcesPort, AdminTenantListFilter, AdminTenantListRow, AdminTenantDetail, AdminTenantStateResult, AdminUserListFilter, AdminUserListRow, AdminAuditListFilter, AuditEntry, AdminSubscriptionListRow, BundleRepository, TransactionContext, BundleVersionRow, BundleListFilter, BundleRow, CreateBundleData, UpdateBundleData, CreateBundleVersionDraftData, UpdateBundleVersionDraftData, VersionChange, PersistenceInjectionToken, PasswordHasher, SaasicatPersistenceAdapter, TransactionRunner, MfaPort, AuditPort, AdminActor, AuditQueryPort, AuditQuery, AuditStatsPort, RlsBypassPort, SubscriptionRepository, SubscriptionRecord, SubscriptionUsagePort, SubscriptionUsageRecord, SubscriptionBundleRepository, SubscriptionBundleRecord, CreateSubscriptionBundleData, CancelSubscriptionBundleData, TenantSubscriptionWritePort, ApplyOnboardingSelectionInput, RedeemPromoInTransactionCallback, ApplyOnboardingSelectionResult, ImmediatePlanChangeInput, ScheduledPlanChangeInput, PlanVersionRepository, PlanVersionRecord, PromoCodeRepository, PromoCodeRecord, PromoCodeFilter, CreatePromoCodeData, UpdatePromoCodeData, PromoCodeRedemptionRepository, PromoCodeRedemptionRecord, PromoCodeRedemptionStatus, PromoCodeRedemptionListItem, PromoCodeValidationLogRepository, PromoSubscriptionLookup, BillingCycle, PromoRevenueDeductionAggregator, SuperAdminProvisioningPort, CreateSuperAdminCliInput, PlatformUserDto, PlanCatalogReadSink, PlanCatalogReadSnapshot, PlanCatalogImportSink, UpsertPlanInput, UpsertResult, UpsertPlanVersionInput, UpsertFeatureCatalogEntryInput, PlanRepository, PlanListFilter, PlanRow, CreatePlanData, UpdatePlanData, PlanVersionRow, CreatePlanVersionDraftData, UpdatePlanVersionDraftData, CatalogEntryRepository, CatalogEntryFilter, CapabilityCatalogEntryRow, FeatureCatalogEntryRow, QuotaCatalogEntryRow, UpsertCapabilityEntryData, UpsertFeatureEntryData, UpsertQuotaEntryData, SetCatalogEntryReviewData, CatalogEntryI18n, UpdateCatalogEntryBaseData, MarketingProjectionRepository, MarketingProjectionFilter, MarketingProjectionRow, CreateMarketingProjectionData, UpdateMarketingProjectionData, MarketingSettingsRepository, MarketingSettingsRow, UpdateMarketingSettingsData, PromotionRepository, PromotionFilter, PromotionRow, CreatePromotionData, UpdatePromotionData, SubscriptionContractRepository, SubscriptionContractFilter, SubscriptionContractRecord, CreateSubscriptionContractData, TerminateSubscriptionContractData } from '@saasicat/types';
1
+ import { AdminResourcesPort, AdminTenantListFilter, AdminTenantListRow, AdminTenantDetail, AdminTenantStateResult, AdminUserListFilter, AdminUserListRow, AdminAuditListFilter, AuditEntry, AdminSubscriptionListRow, BundleRepository, TransactionContext, BundleVersionRow, BundleListFilter, BundleRow, CreateBundleData, UpdateBundleData, CreateBundleVersionDraftData, UpdateBundleVersionDraftData, VersionChange, PersistenceInjectionToken, PasswordHasher, SaaSiCatPersistenceAdapter, TransactionRunner, MfaPort, AuditPort, AdminActor, AuditQueryPort, AuditQuery, AuditStatsPort, RlsBypassPort, SubscriptionRepository, SubscriptionRecord, SubscriptionUsagePort, SubscriptionUsageRecord, SubscriptionBundleRepository, SubscriptionBundleRecord, CreateSubscriptionBundleData, CancelSubscriptionBundleData, TenantSubscriptionWritePort, ApplyOnboardingSelectionInput, RedeemPromoInTransactionCallback, ApplyOnboardingSelectionResult, ImmediatePlanChangeInput, ScheduledPlanChangeInput, PlanVersionRepository, PlanVersionRecord, PromoCodeRepository, PromoCodeRecord, PromoCodeFilter, CreatePromoCodeData, UpdatePromoCodeData, PromoCodeRedemptionRepository, PromoCodeRedemptionRecord, PromoCodeRedemptionStatus, PromoCodeRedemptionListItem, PromoCodeValidationLogRepository, PromoSubscriptionLookup, BillingCycle, PromoRevenueDeductionAggregator, SuperAdminProvisioningPort, CreateSuperAdminCliInput, PlatformUserDto, PlanCatalogReadSink, PlanCatalogReadSnapshot, PlanCatalogImportSink, UpsertPlanInput, UpsertResult, UpsertPlanVersionInput, UpsertFeatureCatalogEntryInput, PlanRepository, PlanListFilter, PlanRow, CreatePlanData, UpdatePlanData, PlanVersionRow, CreatePlanVersionDraftData, UpdatePlanVersionDraftData, CatalogEntryRepository, CatalogEntryFilter, CapabilityCatalogEntryRow, FeatureCatalogEntryRow, QuotaCatalogEntryRow, UpsertCapabilityEntryData, UpsertFeatureEntryData, UpsertQuotaEntryData, SetCatalogEntryReviewData, CatalogEntryI18n, UpdateCatalogEntryBaseData, MarketingProjectionRepository, MarketingProjectionFilter, MarketingProjectionRow, CreateMarketingProjectionData, UpdateMarketingProjectionData, MarketingSettingsRepository, MarketingSettingsRow, UpdateMarketingSettingsData, PromotionRepository, PromotionFilter, PromotionRow, CreatePromotionData, UpdatePromotionData, SubscriptionContractRepository, SubscriptionContractFilter, SubscriptionContractRecord, CreateSubscriptionContractData, TerminateSubscriptionContractData } from '@saasicat/types';
2
2
 
3
3
  declare const PRISMA_CLIENT_TOKEN: unique symbol;
4
4
  /** Prisma `Decimal` values arrive as objects with `toString()`; tests may use plain values. */
@@ -703,6 +703,81 @@ declare function createPrismaPlanBindingResolver(options?: PrismaPlanBindingOpti
703
703
  /** Resolves a configurable Prisma delegate and fails early on misspellings. */
704
704
  declare function getPrismaDelegate<Row>(client: unknown, delegateName: string): PrismaModelDelegateLike<Row>;
705
705
 
706
+ /** The Prisma delegates the adapter needs, by the name your client uses. */
707
+ interface AdminResourcesDelegates {
708
+ /** Default `tenant`. */
709
+ tenant?: string;
710
+ /** Default `user`. */
711
+ user?: string;
712
+ /** Default `subscription`. */
713
+ subscription?: string;
714
+ }
715
+ /** The scalar and relation fields the adapter reads, by your name for them. */
716
+ interface AdminResourcesFields {
717
+ tenant?: {
718
+ /** Default `slug` — the stable identifier every admin route addresses. */
719
+ slug?: string;
720
+ /** Default `name`. */
721
+ name?: string;
722
+ /** Default `isActive`. */
723
+ isActive?: string;
724
+ /** Default `deletedAt`. */
725
+ deletedAt?: string;
726
+ /** The tenant→users relation. Default `users`. */
727
+ users?: string;
728
+ /**
729
+ * The tenant→subscription relation. Default `subscription`.
730
+ *
731
+ * On YOUR model, so your name for it: Prisma names a relation field
732
+ * after what it points at, and an app whose tenant is `Organization`
733
+ * has usually not renamed this one — but it may have.
734
+ */
735
+ subscription?: string;
736
+ };
737
+ user?: {
738
+ /** Default `email`. */
739
+ email?: string;
740
+ /** Default `firstName`. */
741
+ firstName?: string;
742
+ /** Default `lastName`. */
743
+ lastName?: string;
744
+ /** Default `isActive`. */
745
+ isActive?: string;
746
+ /**
747
+ * The user→tenant relation. Default `tenant`.
748
+ *
749
+ * The one the documented example gets wrong by omission: an app whose
750
+ * tenant model is `Organization` calls this field `organization`, by
751
+ * the same Prisma convention that named the delegate.
752
+ */
753
+ tenant?: string;
754
+ };
755
+ }
756
+ /** The mapping with every default filled in — what the adapter actually reads. */
757
+ interface ResolvedAdminResourcesSchema {
758
+ readonly delegates: Required<AdminResourcesDelegates>;
759
+ readonly tenant: Required<NonNullable<AdminResourcesFields['tenant']>>;
760
+ readonly user: Required<NonNullable<AdminResourcesFields['user']>>;
761
+ }
762
+ declare function resolveAdminResourcesSchema(delegates?: AdminResourcesDelegates, fields?: AdminResourcesFields): ResolvedAdminResourcesSchema;
763
+ /**
764
+ * Refuses a mapping that names a delegate the client does not have.
765
+ *
766
+ * At construction, which is boot: a mapped delegate is resolved lazily, so a
767
+ * typo used to surface as a 500 on the tenants page long after deployment —
768
+ * and only if somebody opened it. The message lists what the client does have,
769
+ * because the answer is almost always a near miss (`organisation` for
770
+ * `organization`, `users` for `user`).
771
+ *
772
+ * Only for an EXPLICIT mapping. `prismaPersistence()` builds this adapter for
773
+ * every bundle, including for applications that never switch `adminResources`
774
+ * on, and several of them have no `tenant` delegate at all — asserting the
775
+ * defaults here would refuse to construct a bundle nobody was going to ask
776
+ * about. Those keep failing where they always did, at the first request, with
777
+ * a message that now names the way out.
778
+ */
779
+ declare function assertDelegatesExist(client: unknown, schema: ResolvedAdminResourcesSchema): void;
780
+
706
781
  interface PrismaAdminResourcesOptions {
707
782
  /**
708
783
  * Relation counters exposed on tenant rows and tenant details. The names
@@ -710,6 +785,13 @@ interface PrismaAdminResourcesOptions {
710
785
  */
711
786
  tenantMetrics?: readonly string[];
712
787
  listLimit?: number;
788
+ /**
789
+ * Delegate names, when the app's models are not called `tenant`, `user`
790
+ * and `subscription`. Checked against the client at construction.
791
+ */
792
+ delegates?: AdminResourcesDelegates;
793
+ /** Field names, when the app's columns differ. See `AdminResourcesFields`. */
794
+ fields?: AdminResourcesFields;
713
795
  }
714
796
  /**
715
797
  * Convention-based adapter for the standard SuperAdmin resource pages.
@@ -724,6 +806,7 @@ declare class PrismaAdminResourcesAdapter implements AdminResourcesPort {
724
806
  private readonly metrics;
725
807
  private readonly listLimit;
726
808
  private readonly audit;
809
+ private readonly schema;
727
810
  constructor(prisma: PrismaLike, options?: PrismaAdminResourcesOptions);
728
811
  listTenants(filter: AdminTenantListFilter): Promise<AdminTenantListRow[]>;
729
812
  getTenantDetail(slug: string): Promise<AdminTenantDetail | null>;
@@ -734,6 +817,18 @@ declare class PrismaAdminResourcesAdapter implements AdminResourcesPort {
734
817
  private tenants;
735
818
  private users;
736
819
  private subscriptions;
820
+ /** The subscription relation of a tenant row, under whatever it is called. */
821
+ private subscriptionOf;
822
+ /** The tenant slug on a user row, through both mapped names. */
823
+ private tenantSlugOf;
824
+ /**
825
+ * Reads a mapped field off a row.
826
+ *
827
+ * The rows come back keyed by the APP's field names, so every read of a
828
+ * mapped field goes through here — and the row type stays the shape the
829
+ * adapter promises rather than becoming `Record<string, unknown>`.
830
+ */
831
+ private read;
737
832
  }
738
833
 
739
834
  /**
@@ -859,11 +954,11 @@ interface PrismaPersistenceOptions {
859
954
  bundle?: PrismaBundleRepositoryOptions;
860
955
  }
861
956
  /**
862
- * Builds the `SaasicatPersistenceAdapter` bundle for Prisma + PostgreSQL on
957
+ * Builds the `SaaSiCatPersistenceAdapter` bundle for Prisma + PostgreSQL on
863
958
  * the canonical schema (`@saasicat/spec` prisma-fragments):
864
959
  *
865
960
  * ```ts
866
- * SaasPlatformModule.forRoot({
961
+ * SaaSiCatModule.forRoot({
867
962
  * persistence: prismaPersistence({ client: PrismaService }),
868
963
  * // ...
869
964
  * });
@@ -873,7 +968,7 @@ interface PrismaPersistenceOptions {
873
968
  * tenant-billing, promo and plan-catalog persistence. App-specific behavior
874
969
  * such as quota counters and authentication remains in the consumer.
875
970
  */
876
- declare function prismaPersistence(options: PrismaPersistenceOptions): SaasicatPersistenceAdapter;
971
+ declare function prismaPersistence(options: PrismaPersistenceOptions): SaaSiCatPersistenceAdapter;
877
972
 
878
973
  /**
879
974
  * `TransactionRunner` over `prisma.$transaction`. The interactive transaction
@@ -1461,4 +1556,4 @@ declare class PrismaSubscriptionContractRepository implements SubscriptionContra
1461
1556
  terminate(contractId: string, data: TerminateSubscriptionContractData): Promise<SubscriptionContractRecord>;
1462
1557
  }
1463
1558
 
1464
- export { AsyncLocalRlsBypassAdapter, type DecimalLike, PASSWORD_HASHER_TOKEN, PRISMA_BUNDLE_REPOSITORY_OPTIONS, PRISMA_CLIENT_TOKEN, PRISMA_SCHEMA_OPTIONS_TOKEN, PrismaAdminResourcesAdapter, type PrismaAdminResourcesOptions, PrismaAuditAdapter, PrismaAuditQueryAdapter, PrismaAuditStatsAdapter, PrismaBundleRepository, type PrismaBundleRepositoryOptions, PrismaCatalogEntryRepository, type PrismaLike, PrismaMarketingProjectionRepository, PrismaMarketingSettingsRepository, PrismaMfaAdapter, type PrismaModelDelegateLike, type PrismaPersistenceOptions, type PrismaPlanBindingMode, type PrismaPlanBindingOptions, type PrismaPlanBindingResolver, PrismaPlanCatalogImportSink, PrismaPlanCatalogReadSink, type PrismaPlanDelegateOptions, PrismaPlanRepository, type PrismaPlanVersionFieldCapabilities, type PrismaPlanVersionFieldOptions, PrismaPlanVersionRepository, PrismaPromoCodeRedemptionRepository, PrismaPromoCodeRepository, PrismaPromoCodeValidationLogRepository, PrismaPromoSubscriptionLookup, PrismaPromotionRepository, type PrismaSchemaOptions, PrismaSubscriptionBundleRepository, PrismaSubscriptionContractRepository, PrismaSubscriptionRepository, PrismaSubscriptionUsageAdapter, PrismaSuperAdminBootstrapAdapter, type PrismaTenantSubscriptionOptions, PrismaTenantSubscriptionWriteAdapter, PrismaTransactionRunner, type PrismaTxLike, type ResolvedPrismaSchemaOptions, ZeroPromoRevenueDeductionAggregator, buildActorTag, createPrismaPlanBindingResolver, getPrismaDelegate, prismaPersistence, resolvePrismaSchemaOptions };
1559
+ export { type AdminResourcesDelegates, type AdminResourcesFields, AsyncLocalRlsBypassAdapter, type DecimalLike, PASSWORD_HASHER_TOKEN, PRISMA_BUNDLE_REPOSITORY_OPTIONS, PRISMA_CLIENT_TOKEN, PRISMA_SCHEMA_OPTIONS_TOKEN, PrismaAdminResourcesAdapter, type PrismaAdminResourcesOptions, PrismaAuditAdapter, PrismaAuditQueryAdapter, PrismaAuditStatsAdapter, PrismaBundleRepository, type PrismaBundleRepositoryOptions, PrismaCatalogEntryRepository, type PrismaLike, PrismaMarketingProjectionRepository, PrismaMarketingSettingsRepository, PrismaMfaAdapter, type PrismaModelDelegateLike, type PrismaPersistenceOptions, type PrismaPlanBindingMode, type PrismaPlanBindingOptions, type PrismaPlanBindingResolver, PrismaPlanCatalogImportSink, PrismaPlanCatalogReadSink, type PrismaPlanDelegateOptions, PrismaPlanRepository, type PrismaPlanVersionFieldCapabilities, type PrismaPlanVersionFieldOptions, PrismaPlanVersionRepository, PrismaPromoCodeRedemptionRepository, PrismaPromoCodeRepository, PrismaPromoCodeValidationLogRepository, PrismaPromoSubscriptionLookup, PrismaPromotionRepository, type PrismaSchemaOptions, PrismaSubscriptionBundleRepository, PrismaSubscriptionContractRepository, PrismaSubscriptionRepository, PrismaSubscriptionUsageAdapter, PrismaSuperAdminBootstrapAdapter, type PrismaTenantSubscriptionOptions, PrismaTenantSubscriptionWriteAdapter, PrismaTransactionRunner, type PrismaTxLike, type ResolvedAdminResourcesSchema, type ResolvedPrismaSchemaOptions, ZeroPromoRevenueDeductionAggregator, assertDelegatesExist, buildActorTag, createPrismaPlanBindingResolver, getPrismaDelegate, prismaPersistence, resolveAdminResourcesSchema, resolvePrismaSchemaOptions };