@managemint-solutions/sdk 0.28.0 → 0.30.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.
@@ -0,0 +1,16 @@
1
+ import type { CreateFeatureRequestDto as CreateFeatureRequestDtoType } from '@managemint-solutions/entities/feature-requests/dto';
2
+ export declare class CreateFeatureRequestDto implements CreateFeatureRequestDtoType {
3
+ readonly name: string;
4
+ readonly specification?: string | null;
5
+ readonly requester_name: string;
6
+ readonly requester_email: string;
7
+ /**
8
+ * The honeypot. It is here only so `forbidNonWhitelisted` does not 400 the field the website
9
+ * always submits; the api answers 201 and stores nothing when it arrives filled.
10
+ *
11
+ * Deliberately uncapped and unvalidated beyond "a string": a bot that pastes a novel into it
12
+ * must get the same bland 201 as one that types a URL. A 400 would tell it which field gave
13
+ * the game away.
14
+ */
15
+ readonly website_url?: string;
16
+ }
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.CreateFeatureRequestDto = void 0;
13
+ const class_validator_1 = require("class-validator");
14
+ const class_transformer_1 = require("class-transformer");
15
+ const validators_1 = require("../validators");
16
+ // class-validator version of the shared DTO type from @managemint-solutions/entities, so the
17
+ // wire contract cannot drift.
18
+ /**
19
+ * Whitespace on either side of a pasted value is not part of the answer. Trimming here rather
20
+ * than in the api means the length rules below measure what will actually be stored — a name of
21
+ * three spaces is empty, not three characters long.
22
+ */
23
+ const Trim = () => (0, class_transformer_1.Transform)(({ value }) => (typeof value === 'string' ? value.trim() : value), {
24
+ toClassOnly: true,
25
+ });
26
+ class CreateFeatureRequestDto {
27
+ name;
28
+ // Markdown, and optional: a one-line request is a perfectly good request. `@Trim` sits above
29
+ // `@EmptyToNull` because transforms run top down, so a whitespace-only box is trimmed to ''
30
+ // first and then becomes null rather than being stored as blanks.
31
+ specification;
32
+ requester_name;
33
+ // 320 is the longest address RFC 5321 allows, and the widest the column has to hold.
34
+ requester_email;
35
+ /**
36
+ * The honeypot. It is here only so `forbidNonWhitelisted` does not 400 the field the website
37
+ * always submits; the api answers 201 and stores nothing when it arrives filled.
38
+ *
39
+ * Deliberately uncapped and unvalidated beyond "a string": a bot that pastes a novel into it
40
+ * must get the same bland 201 as one that types a URL. A 400 would tell it which field gave
41
+ * the game away.
42
+ */
43
+ website_url;
44
+ }
45
+ exports.CreateFeatureRequestDto = CreateFeatureRequestDto;
46
+ __decorate([
47
+ Trim(),
48
+ (0, class_validator_1.IsString)({ message: 'Invalid name' }),
49
+ (0, class_validator_1.MinLength)(1, { message: 'Name cannot be empty' }),
50
+ (0, class_validator_1.MaxLength)(200, { message: 'Name cannot exceed 200 characters' }),
51
+ __metadata("design:type", String)
52
+ ], CreateFeatureRequestDto.prototype, "name", void 0);
53
+ __decorate([
54
+ (0, class_validator_1.IsOptional)(),
55
+ Trim(),
56
+ (0, validators_1.EmptyToNull)(),
57
+ (0, validators_1.IsNullable)(),
58
+ (0, class_validator_1.ValidateIf)((o) => o.specification !== null && o.specification !== undefined),
59
+ (0, class_validator_1.IsString)({ message: 'Invalid specification' }),
60
+ (0, class_validator_1.MaxLength)(10000, { message: 'Specification cannot exceed 10000 characters' }),
61
+ __metadata("design:type", Object)
62
+ ], CreateFeatureRequestDto.prototype, "specification", void 0);
63
+ __decorate([
64
+ Trim(),
65
+ (0, class_validator_1.IsString)({ message: 'Invalid requester name' }),
66
+ (0, class_validator_1.MinLength)(1, { message: 'Requester name cannot be empty' }),
67
+ (0, class_validator_1.MaxLength)(200, { message: 'Requester name cannot exceed 200 characters' }),
68
+ __metadata("design:type", String)
69
+ ], CreateFeatureRequestDto.prototype, "requester_name", void 0);
70
+ __decorate([
71
+ Trim(),
72
+ (0, class_validator_1.IsEmail)({}, { message: 'Invalid email address' }),
73
+ (0, class_validator_1.MaxLength)(320, { message: 'Email address cannot exceed 320 characters' }),
74
+ __metadata("design:type", String)
75
+ ], CreateFeatureRequestDto.prototype, "requester_email", void 0);
76
+ __decorate([
77
+ (0, class_validator_1.IsOptional)(),
78
+ (0, class_validator_1.IsString)({ message: 'Invalid website URL' }),
79
+ __metadata("design:type", String)
80
+ ], CreateFeatureRequestDto.prototype, "website_url", void 0);
@@ -0,0 +1,34 @@
1
+ import type { FeatureRequestSource } from '@managemint-solutions/entities/feature-requests/enum';
2
+ import type { TypedSupabaseClient } from '../client';
3
+ export * from './dto';
4
+ /** The columns a submission writes. `source` is the api's to set, never the submitter's. */
5
+ export type CreateFeatureRequestRow = {
6
+ name: string;
7
+ specification: string | null;
8
+ requester_name: string;
9
+ requester_email: string;
10
+ source: FeatureRequestSource;
11
+ };
12
+ /** All the insert hands back — the id the endpoint answers with. */
13
+ export type CreatedFeatureRequest = {
14
+ mms_id: string;
15
+ };
16
+ /**
17
+ * The `feature_requests` table: "I need something" submissions from the marketing website's
18
+ * roadmap page. There is no reader here by design — the rows are read in Supabase Studio, and
19
+ * nothing renders a visitor's words back to anyone.
20
+ *
21
+ * Service-role only, like `organization_invites`: the table has RLS enabled with no policies and
22
+ * no `anon`/`authenticated` grants, so this lives on the service client and never on a caller's.
23
+ * The submitter has no account at all, so there is no RLS context to run the insert under.
24
+ *
25
+ * No organization: a feature request belongs to nobody's tenant, which is why the resource hangs
26
+ * off the client itself rather than off `forOrganization`.
27
+ *
28
+ * Not audited — `audit_logs` rows carry an organization and an actor, and this write has neither.
29
+ */
30
+ export declare class FeatureRequestsResource {
31
+ private readonly supabase;
32
+ constructor(supabase: TypedSupabaseClient);
33
+ create(row: CreateFeatureRequestRow): Promise<CreatedFeatureRequest>;
34
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.FeatureRequestsResource = void 0;
18
+ const errors_1 = require("../errors");
19
+ __exportStar(require("./dto"), exports);
20
+ /**
21
+ * The `feature_requests` table: "I need something" submissions from the marketing website's
22
+ * roadmap page. There is no reader here by design — the rows are read in Supabase Studio, and
23
+ * nothing renders a visitor's words back to anyone.
24
+ *
25
+ * Service-role only, like `organization_invites`: the table has RLS enabled with no policies and
26
+ * no `anon`/`authenticated` grants, so this lives on the service client and never on a caller's.
27
+ * The submitter has no account at all, so there is no RLS context to run the insert under.
28
+ *
29
+ * No organization: a feature request belongs to nobody's tenant, which is why the resource hangs
30
+ * off the client itself rather than off `forOrganization`.
31
+ *
32
+ * Not audited — `audit_logs` rows carry an organization and an actor, and this write has neither.
33
+ */
34
+ class FeatureRequestsResource {
35
+ supabase;
36
+ constructor(supabase) {
37
+ this.supabase = supabase;
38
+ }
39
+ async create(row) {
40
+ const { data, error } = await this.supabase
41
+ .from('feature_requests')
42
+ .insert(row)
43
+ .select('mms_id')
44
+ .single();
45
+ if (error)
46
+ throw (0, errors_1.mapPostgrestError)(error);
47
+ return data;
48
+ }
49
+ }
50
+ exports.FeatureRequestsResource = FeatureRequestsResource;
package/dist/index.d.ts CHANGED
@@ -13,6 +13,9 @@ export type { AuditActor, AuditChanges, AuditEntry, AuditErrorHandler, AuditGuar
13
13
  export { GetAuditTrailDto } from './audit';
14
14
  export { CancelSubscriptionDto, GetPaymentsQueryDto, InitialPaymentDto, PaymentIdDto, PurchaseModuleDto, ReinstateSubscriptionDto, } from './billing';
15
15
  export { GetInvoicesQueryDto, InvoiceIdDto } from './billing/invoices';
16
+ export type { CreateFeatureRequestRow, CreatedFeatureRequest } from './feature-requests';
17
+ export { CreateFeatureRequestDto } from './feature-requests';
18
+ export { CreateSupportRequestDto } from './support';
16
19
  export { AddStatusDto, GetStatusesDto, StatusIdDto, UpdateStatusDto } from './statuses';
17
20
  export { AddAdditionalDetailsDto, AdditionalDetailsIdDto, GetAdditionalDetailsDto, IsAdditionalDetailsValueByType, UpdateAdditionalDetailsDto, } from './additional-details';
18
21
  export { AddNoteDto, GetNotesDto, NoteIdDto } from './notes';
package/dist/index.js CHANGED
@@ -7,8 +7,8 @@
7
7
  // their classes are not exported: a consumer never constructs one, and every export is a contract
8
8
  // to keep. The row and input types they produce and accept are exported for annotations.
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.CreateClientDto = exports.ClientIdDto = exports.SupportingFileIdDto = exports.GetSupportingFilesDto = exports.UserIdDto = exports.UpdateUserDto = exports.UpdateMyProfileDto = exports.GetUsersQueryDto = exports.AddUserDto = exports.UpdatePermissionsDto = exports.PermissionsResource = exports.UpdateOrganizationDto = exports.CreateOrganizationDto = exports.NotificationIdDto = exports.GetNotificationsDto = exports.NoteIdDto = exports.GetNotesDto = exports.AddNoteDto = exports.UpdateAdditionalDetailsDto = exports.IsAdditionalDetailsValueByType = exports.GetAdditionalDetailsDto = exports.AdditionalDetailsIdDto = exports.AddAdditionalDetailsDto = exports.UpdateStatusDto = exports.StatusIdDto = exports.GetStatusesDto = exports.AddStatusDto = exports.InvoiceIdDto = exports.GetInvoicesQueryDto = exports.ReinstateSubscriptionDto = exports.PurchaseModuleDto = exports.PaymentIdDto = exports.InitialPaymentDto = exports.GetPaymentsQueryDto = exports.CancelSubscriptionDto = exports.GetAuditTrailDto = exports.IsNullable = exports.EmptyToNull = exports.SupabaseClientError = exports.createSupabaseServiceClient = exports.SupabaseServiceClient = exports.SignInDto = exports.SendPasswordResetEmailDto = exports.ResetPasswordDto = exports.ExchangeTokenHashDto = exports.ExchangeRefreshTokenDto = exports.createSupabaseAuthClient = exports.SupabaseAuthClient = exports.createSupabaseClient = exports.SupabaseClient = void 0;
11
- exports.monthlyTotalMinor = exports.UpdateTaskDto = exports.TaskIdDto = exports.GetTasksDto = exports.CreateTaskDto = exports.UpdateProjectDto = exports.ProjectIdDto = exports.GetProjectsDto = exports.CreateProjectDto = exports.UpdateClientDto = exports.GetClientsDto = void 0;
10
+ exports.SupportingFileIdDto = exports.GetSupportingFilesDto = exports.UserIdDto = exports.UpdateUserDto = exports.UpdateMyProfileDto = exports.GetUsersQueryDto = exports.AddUserDto = exports.UpdatePermissionsDto = exports.PermissionsResource = exports.UpdateOrganizationDto = exports.CreateOrganizationDto = exports.NotificationIdDto = exports.GetNotificationsDto = exports.NoteIdDto = exports.GetNotesDto = exports.AddNoteDto = exports.UpdateAdditionalDetailsDto = exports.IsAdditionalDetailsValueByType = exports.GetAdditionalDetailsDto = exports.AdditionalDetailsIdDto = exports.AddAdditionalDetailsDto = exports.UpdateStatusDto = exports.StatusIdDto = exports.GetStatusesDto = exports.AddStatusDto = exports.CreateSupportRequestDto = exports.CreateFeatureRequestDto = exports.InvoiceIdDto = exports.GetInvoicesQueryDto = exports.ReinstateSubscriptionDto = exports.PurchaseModuleDto = exports.PaymentIdDto = exports.InitialPaymentDto = exports.GetPaymentsQueryDto = exports.CancelSubscriptionDto = exports.GetAuditTrailDto = exports.IsNullable = exports.EmptyToNull = exports.SupabaseClientError = exports.createSupabaseServiceClient = exports.SupabaseServiceClient = exports.SignInDto = exports.SendPasswordResetEmailDto = exports.ResetPasswordDto = exports.ExchangeTokenHashDto = exports.ExchangeRefreshTokenDto = exports.createSupabaseAuthClient = exports.SupabaseAuthClient = exports.createSupabaseClient = exports.SupabaseClient = void 0;
11
+ exports.monthlyTotalMinor = exports.UpdateTaskDto = exports.TaskIdDto = exports.GetTasksDto = exports.CreateTaskDto = exports.UpdateProjectDto = exports.ProjectIdDto = exports.GetProjectsDto = exports.CreateProjectDto = exports.UpdateClientDto = exports.GetClientsDto = exports.CreateClientDto = exports.ClientIdDto = void 0;
12
12
  var client_1 = require("./client");
13
13
  Object.defineProperty(exports, "SupabaseClient", { enumerable: true, get: function () { return client_1.SupabaseClient; } });
14
14
  Object.defineProperty(exports, "createSupabaseClient", { enumerable: true, get: function () { return client_1.createSupabaseClient; } });
@@ -41,6 +41,10 @@ Object.defineProperty(exports, "ReinstateSubscriptionDto", { enumerable: true, g
41
41
  var invoices_1 = require("./billing/invoices");
42
42
  Object.defineProperty(exports, "GetInvoicesQueryDto", { enumerable: true, get: function () { return invoices_1.GetInvoicesQueryDto; } });
43
43
  Object.defineProperty(exports, "InvoiceIdDto", { enumerable: true, get: function () { return invoices_1.InvoiceIdDto; } });
44
+ var feature_requests_1 = require("./feature-requests");
45
+ Object.defineProperty(exports, "CreateFeatureRequestDto", { enumerable: true, get: function () { return feature_requests_1.CreateFeatureRequestDto; } });
46
+ var support_1 = require("./support");
47
+ Object.defineProperty(exports, "CreateSupportRequestDto", { enumerable: true, get: function () { return support_1.CreateSupportRequestDto; } });
44
48
  var statuses_1 = require("./statuses");
45
49
  Object.defineProperty(exports, "AddStatusDto", { enumerable: true, get: function () { return statuses_1.AddStatusDto; } });
46
50
  Object.defineProperty(exports, "GetStatusesDto", { enumerable: true, get: function () { return statuses_1.GetStatusesDto; } });
@@ -2,6 +2,7 @@ import { AuditResource, type AuditActor, type AuditedTable, type AuditedTableOpt
2
2
  import type { TypedSupabaseClient } from '../client';
3
3
  import { BillingResource } from '../billing';
4
4
  import { InvoicesResource } from '../billing/invoices';
5
+ import { FeatureRequestsResource } from '../feature-requests';
5
6
  import { NotificationsOutboxResource } from '../notifications';
6
7
  import { OrganizationInvitesResource } from '../organization-invites';
7
8
  import { OrganizationPaymentMethodsResource, type PaymentMethodLookupColumn } from '../organization-payment-methods';
@@ -43,8 +44,9 @@ export declare class SupabaseOrganizationScope {
43
44
  /**
44
45
  * The client for work that has no caller and no RLS context to run under: inbound webhooks
45
46
  * (Paystack, Resend, the Supabase `send_email` hook), the notification queue worker, unauthenticated
46
- * signup, and the writes RLS reserves for the service role outright — the ledger, the outbox, the
47
- * webhook event logs, `organizations` INSERT, `permissions` INSERT/DELETE.
47
+ * signup, the website's feature-request intake, and the writes RLS reserves for the service role
48
+ * outright — the ledger, the outbox, the webhook event logs, `organizations` INSERT, `permissions`
49
+ * INSERT/DELETE.
48
50
  *
49
51
  * It decodes no JWT, because there is none. Cross-org lookups (find the organization behind a
50
52
  * Paystack customer code) hang off the client itself; anything attributable goes through
@@ -54,6 +56,7 @@ export declare class SupabaseServiceClient {
54
56
  private readonly config;
55
57
  readonly supabase: TypedSupabaseClient;
56
58
  readonly notifications: NotificationsOutboxResource;
59
+ readonly featureRequests: FeatureRequestsResource;
57
60
  readonly signup: OrganizationSignupResource;
58
61
  readonly paystackEvents: WebhookEventsResource;
59
62
  readonly resendEvents: WebhookEventsResource;
@@ -6,6 +6,7 @@ const audit_1 = require("../audit");
6
6
  const enum_1 = require("@managemint-solutions/entities/audit-trail/enum");
7
7
  const billing_1 = require("../billing");
8
8
  const invoices_1 = require("../billing/invoices");
9
+ const feature_requests_1 = require("../feature-requests");
9
10
  const notifications_1 = require("../notifications");
10
11
  const errors_1 = require("../errors");
11
12
  const organization_invites_1 = require("../organization-invites");
@@ -55,8 +56,9 @@ exports.SupabaseOrganizationScope = SupabaseOrganizationScope;
55
56
  /**
56
57
  * The client for work that has no caller and no RLS context to run under: inbound webhooks
57
58
  * (Paystack, Resend, the Supabase `send_email` hook), the notification queue worker, unauthenticated
58
- * signup, and the writes RLS reserves for the service role outright — the ledger, the outbox, the
59
- * webhook event logs, `organizations` INSERT, `permissions` INSERT/DELETE.
59
+ * signup, the website's feature-request intake, and the writes RLS reserves for the service role
60
+ * outright — the ledger, the outbox, the webhook event logs, `organizations` INSERT, `permissions`
61
+ * INSERT/DELETE.
60
62
  *
61
63
  * It decodes no JWT, because there is none. Cross-org lookups (find the organization behind a
62
64
  * Paystack customer code) hang off the client itself; anything attributable goes through
@@ -66,6 +68,9 @@ class SupabaseServiceClient {
66
68
  config;
67
69
  supabase; // escape hatch for not-yet-migrated queries
68
70
  notifications;
71
+ // Tenant-less, like `signup`: a feature request comes from a visitor with no account, so it
72
+ // hangs off the client rather than off an organization scope.
73
+ featureRequests;
69
74
  signup;
70
75
  paystackEvents;
71
76
  resendEvents;
@@ -74,6 +79,7 @@ class SupabaseServiceClient {
74
79
  this.supabase = (0, auth_1.createRawClient)(config.url, config.serviceRoleKey);
75
80
  this.paystackEvents = new webhook_events_1.WebhookEventsResource(this.supabase, 'paystack_webhook_events');
76
81
  this.resendEvents = new webhook_events_1.WebhookEventsResource(this.supabase, 'resend_webhook_events');
82
+ this.featureRequests = new feature_requests_1.FeatureRequestsResource(this.supabase);
77
83
  this.signup = new organizations_1.OrganizationSignupResource(this.supabase, (organizationId) => this.forOrganization(organizationId).audit);
78
84
  // The outbox spans organizations — the row it is about carries its own — so it takes a
79
85
  // factory and scopes per write rather than being built inside one organization's scope.
@@ -0,0 +1,18 @@
1
+ import type { CreateSupportRequestDto as CreateSupportRequestDtoType } from '@managemint-solutions/entities/support/dto';
2
+ import { SupportTopic } from '@managemint-solutions/entities/support/enum';
3
+ export declare class CreateSupportRequestDto implements CreateSupportRequestDtoType {
4
+ readonly topic: SupportTopic;
5
+ readonly name: string;
6
+ readonly email: string;
7
+ readonly company?: string | null;
8
+ readonly message: string;
9
+ /**
10
+ * The honeypot. It is here only so `forbidNonWhitelisted` does not 400 the field the website
11
+ * always submits; the api answers 201 and sends nothing when it arrives filled.
12
+ *
13
+ * Deliberately uncapped and unvalidated beyond "a string": a bot that pastes a novel into it
14
+ * must get the same bland 201 as one that types a URL. A 400 would tell it which field gave
15
+ * the game away.
16
+ */
17
+ readonly website_url?: string;
18
+ }
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.CreateSupportRequestDto = void 0;
13
+ const class_validator_1 = require("class-validator");
14
+ const class_transformer_1 = require("class-transformer");
15
+ const enum_1 = require("@managemint-solutions/entities/support/enum");
16
+ const validators_1 = require("../validators");
17
+ // class-validator version of the shared DTO type from @managemint-solutions/entities, so the
18
+ // wire contract cannot drift.
19
+ /**
20
+ * Whitespace on either side of a pasted value is not part of the answer. Trimming here rather
21
+ * than in the api means the length rules below measure what will actually be sent — a name of
22
+ * three spaces is empty, not three characters long.
23
+ */
24
+ const Trim = () => (0, class_transformer_1.Transform)(({ value }) => (typeof value === 'string' ? value.trim() : value), {
25
+ toClassOnly: true,
26
+ });
27
+ class CreateSupportRequestDto {
28
+ topic;
29
+ name;
30
+ // 320 is the longest address RFC 5321 allows.
31
+ email;
32
+ // Optional on the form. `@Trim` sits above `@EmptyToNull` because transforms run top down, so
33
+ // a whitespace-only box is trimmed to '' first and then becomes null rather than being sent
34
+ // as blanks.
35
+ company;
36
+ // Plain text. 10 000 characters is a long letter, and well within what one email carries.
37
+ message;
38
+ /**
39
+ * The honeypot. It is here only so `forbidNonWhitelisted` does not 400 the field the website
40
+ * always submits; the api answers 201 and sends nothing when it arrives filled.
41
+ *
42
+ * Deliberately uncapped and unvalidated beyond "a string": a bot that pastes a novel into it
43
+ * must get the same bland 201 as one that types a URL. A 400 would tell it which field gave
44
+ * the game away.
45
+ */
46
+ website_url;
47
+ }
48
+ exports.CreateSupportRequestDto = CreateSupportRequestDto;
49
+ __decorate([
50
+ (0, class_validator_1.IsEnum)(enum_1.SupportTopic, { message: 'Invalid topic' }),
51
+ __metadata("design:type", String)
52
+ ], CreateSupportRequestDto.prototype, "topic", void 0);
53
+ __decorate([
54
+ Trim(),
55
+ (0, class_validator_1.IsString)({ message: 'Invalid name' }),
56
+ (0, class_validator_1.MinLength)(1, { message: 'Name cannot be empty' }),
57
+ (0, class_validator_1.MaxLength)(200, { message: 'Name cannot exceed 200 characters' }),
58
+ __metadata("design:type", String)
59
+ ], CreateSupportRequestDto.prototype, "name", void 0);
60
+ __decorate([
61
+ Trim(),
62
+ (0, class_validator_1.IsEmail)({}, { message: 'Invalid email address' }),
63
+ (0, class_validator_1.MaxLength)(320, { message: 'Email address cannot exceed 320 characters' }),
64
+ __metadata("design:type", String)
65
+ ], CreateSupportRequestDto.prototype, "email", void 0);
66
+ __decorate([
67
+ (0, class_validator_1.IsOptional)(),
68
+ Trim(),
69
+ (0, validators_1.EmptyToNull)(),
70
+ (0, validators_1.IsNullable)(),
71
+ (0, class_validator_1.ValidateIf)((o) => o.company !== null && o.company !== undefined),
72
+ (0, class_validator_1.IsString)({ message: 'Invalid company' }),
73
+ (0, class_validator_1.MaxLength)(200, { message: 'Company cannot exceed 200 characters' }),
74
+ __metadata("design:type", Object)
75
+ ], CreateSupportRequestDto.prototype, "company", void 0);
76
+ __decorate([
77
+ Trim(),
78
+ (0, class_validator_1.IsString)({ message: 'Invalid message' }),
79
+ (0, class_validator_1.MinLength)(1, { message: 'Message cannot be empty' }),
80
+ (0, class_validator_1.MaxLength)(10000, { message: 'Message cannot exceed 10000 characters' }),
81
+ __metadata("design:type", String)
82
+ ], CreateSupportRequestDto.prototype, "message", void 0);
83
+ __decorate([
84
+ (0, class_validator_1.IsOptional)(),
85
+ (0, class_validator_1.IsString)({ message: 'Invalid website URL' }),
86
+ __metadata("design:type", String)
87
+ ], CreateSupportRequestDto.prototype, "website_url", void 0);
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The website's contact page, `POST /support`.
3
+ *
4
+ * Only the DTO lives here. Nothing is written to the database - the api turns a submission
5
+ * into two emails and keeps no row - so there is no resource, no table and no client method.
6
+ */
7
+ export { CreateSupportRequestDto } from './dto';
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CreateSupportRequestDto = void 0;
4
+ /**
5
+ * The website's contact page, `POST /support`.
6
+ *
7
+ * Only the DTO lives here. Nothing is written to the database - the api turns a submission
8
+ * into two emails and keeps no row - so there is no resource, no table and no client method.
9
+ */
10
+ var dto_1 = require("./dto");
11
+ Object.defineProperty(exports, "CreateSupportRequestDto", { enumerable: true, get: function () { return dto_1.CreateSupportRequestDto; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@managemint-solutions/sdk",
3
- "version": "0.28.0",
3
+ "version": "0.30.0",
4
4
  "description": "Typed Supabase data-access SDK for ManageMint Solutions",
5
5
  "license": "UNLICENSED",
6
6
  "author": "Scott Bebington <scottbebington@gmail.com>",
@@ -47,7 +47,7 @@
47
47
  "testEnvironment": "node"
48
48
  },
49
49
  "dependencies": {
50
- "@managemint-solutions/entities": "^1.12.0"
50
+ "@managemint-solutions/entities": "^1.14.0"
51
51
  },
52
52
  "peerDependencies": {
53
53
  "@nestjs/common": "^11.0.0",