@managemint-solutions/sdk 0.37.0 → 0.38.1

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.
Files changed (70) hide show
  1. package/README.md +32 -27
  2. package/dist/audit/dto.js +1 -1
  3. package/dist/audit/index.d.ts +12 -12
  4. package/dist/audit/index.js +9 -9
  5. package/dist/auth-client/index.d.ts +2 -2
  6. package/dist/auth-client/index.js +2 -2
  7. package/dist/auth.d.ts +3 -3
  8. package/dist/auth.js +3 -3
  9. package/dist/billing/dto.js +1 -1
  10. package/dist/billing/index.d.ts +4 -4
  11. package/dist/billing/index.js +5 -5
  12. package/dist/billing/invoices/dto.js +1 -1
  13. package/dist/billing/invoices/index.d.ts +6 -6
  14. package/dist/billing/invoices/index.js +7 -7
  15. package/dist/client.d.ts +3 -3
  16. package/dist/client.js +1 -1
  17. package/dist/clients/index.d.ts +1 -1
  18. package/dist/clients/index.js +1 -1
  19. package/dist/configs/dto.js +3 -3
  20. package/dist/configs/index.d.ts +3 -3
  21. package/dist/configs/index.js +3 -3
  22. package/dist/errors.d.ts +2 -2
  23. package/dist/errors.js +2 -2
  24. package/dist/feature-requests/dto.js +1 -1
  25. package/dist/feature-requests/index.d.ts +3 -3
  26. package/dist/feature-requests/index.js +2 -2
  27. package/dist/index.js +2 -2
  28. package/dist/leave/dto.d.ts +1 -0
  29. package/dist/leave/dto.js +7 -0
  30. package/dist/leave/leave-entitlements.d.ts +6 -0
  31. package/dist/leave/leave-entitlements.js +22 -0
  32. package/dist/leave/leave-requests.js +3 -0
  33. package/dist/nest/index.d.ts +5 -5
  34. package/dist/nest/index.js +4 -4
  35. package/dist/notifications/index.d.ts +8 -8
  36. package/dist/notifications/index.js +8 -8
  37. package/dist/organization-invites/index.d.ts +3 -3
  38. package/dist/organization-invites/index.js +2 -2
  39. package/dist/organization-payment-methods/index.d.ts +3 -3
  40. package/dist/organization-payment-methods/index.js +3 -3
  41. package/dist/organizations/index.d.ts +7 -7
  42. package/dist/organizations/index.js +7 -7
  43. package/dist/permissions/index.d.ts +6 -6
  44. package/dist/permissions/index.js +6 -6
  45. package/dist/pricebooks/index.d.ts +2 -2
  46. package/dist/pricebooks/index.js +3 -3
  47. package/dist/projects/dto.js +2 -2
  48. package/dist/projects/index.d.ts +1 -1
  49. package/dist/projects/index.js +2 -2
  50. package/dist/service-client/index.d.ts +5 -5
  51. package/dist/service-client/index.js +5 -5
  52. package/dist/support/dto.js +1 -1
  53. package/dist/supporting-files/dto.js +1 -1
  54. package/dist/supporting-files/index.js +5 -5
  55. package/dist/supporting-files/paths.d.ts +3 -3
  56. package/dist/supporting-files/paths.js +4 -4
  57. package/dist/tasks/dto.js +4 -4
  58. package/dist/tasks/index.d.ts +1 -1
  59. package/dist/tasks/index.js +2 -2
  60. package/dist/transforms.d.ts +6 -6
  61. package/dist/transforms.js +8 -8
  62. package/dist/users/dto.d.ts +3 -3
  63. package/dist/users/dto.js +4 -4
  64. package/dist/users/index.d.ts +2 -2
  65. package/dist/users/index.js +2 -2
  66. package/dist/users/paths.d.ts +2 -2
  67. package/dist/users/paths.js +2 -2
  68. package/dist/webhook-events/index.d.ts +3 -3
  69. package/dist/webhook-events/index.js +3 -3
  70. package/package.json +2 -2
@@ -27,12 +27,12 @@ const EMPTY = {
27
27
  /**
28
28
  * The `organization_payment_methods` table: the organization's Paystack identity in one row
29
29
  * beside the `organizations` row, rather than as columns on it. The organizations READ policy
30
- * hands the whole row to every member of the tenant, and nothing here is a member's business —
30
+ * hands the whole row to every member of the tenant, and nothing here is a member's business -
31
31
  * the customer, plan and subscription codes are the provider's identifiers and the authorization
32
- * code and email token are credentials — so the table carries no `authenticated` grant and no
32
+ * code and email token are credentials - so the table carries no `authenticated` grant and no
33
33
  * policy. Only the service role can reach it.
34
34
  *
35
- * Service-role only, like the invites — this lives on the organization scope of the service
35
+ * Service-role only, like the invites - this lives on the organization scope of the service
36
36
  * client and never on a caller's client. Writes are audited against the organization (the row
37
37
  * has no identity of its own), and the audit diff redacts every `paystack_*` column, so the trail
38
38
  * records that a value changed and never what it changed to.
@@ -12,7 +12,7 @@ export type CreateOrganizationRow = Record<string, unknown>;
12
12
  /**
13
13
  * The caller's own organization. Every method takes the id explicitly rather than reading it
14
14
  * off the auth context, because the signup and webhook paths operate on an organization that
15
- * is not the caller's — there is no caller at all.
15
+ * is not the caller's - there is no caller at all.
16
16
  */
17
17
  export declare class OrganizationsResource {
18
18
  private readonly supabase;
@@ -24,22 +24,22 @@ export declare class OrganizationsResource {
24
24
  get(): Promise<OrganizationRow>;
25
25
  /**
26
26
  * The whole row, unprojected. Billing reads a different handful of columns for each of its
27
- * flows — provisioning, a module purchase, a seat charge — and they are all single-row
27
+ * flows - provisioning, a module purchase, a seat charge - and they are all single-row
28
28
  * lookups by primary key, so one read serves them all rather than a select string each.
29
29
  */
30
30
  getRowById(organizationId: string): Promise<OrganizationRow>;
31
31
  /**
32
- * A status move that only lands while the organization is still in `expectedFrom` — the
32
+ * A status move that only lands while the organization is still in `expectedFrom` - the
33
33
  * compare-and-set that stops two concurrent webhooks both advancing the subscription.
34
34
  * Resolves to null when someone else moved it first.
35
35
  */
36
36
  moveBillingStatus(organizationId: string, expectedFrom: string, patch: AuditRow): Promise<AuditRow | null>;
37
37
  update(organizationId: string, patch: AuditRow): Promise<OrganizationRow>;
38
- /** Hard delete — used by the signup rollback. Returns the row as it was. */
38
+ /** Hard delete - used by the signup rollback. Returns the row as it was. */
39
39
  remove(organizationId: string): Promise<AuditRow>;
40
40
  /**
41
- * Claims a seat atomically. This is the serialization point for concurrent user creation —
42
- * two admins adding at once get distinct seat numbers — so it is a function, not a
41
+ * Claims a seat atomically. This is the serialization point for concurrent user creation -
42
+ * two admins adding at once get distinct seat numbers - so it is a function, not a
43
43
  * read-then-write. The caller decides what to do with the billing status it returns.
44
44
  */
45
45
  reserveSeat(organizationId: string): Promise<SeatReservation | null>;
@@ -51,7 +51,7 @@ export declare class OrganizationsResource {
51
51
  releaseSeat(organizationId: string): Promise<void>;
52
52
  }
53
53
  /**
54
- * Signup, on the service client. `organizations` INSERT is `false` for `authenticated` — the
54
+ * Signup, on the service client. `organizations` INSERT is `false` for `authenticated` - the
55
55
  * caller has no account yet, so there is no RLS context to run under.
56
56
  */
57
57
  export declare class OrganizationSignupResource {
@@ -75,7 +75,7 @@ const ORGANIZATION_SELECT = `
75
75
  /**
76
76
  * The caller's own organization. Every method takes the id explicitly rather than reading it
77
77
  * off the auth context, because the signup and webhook paths operate on an organization that
78
- * is not the caller's — there is no caller at all.
78
+ * is not the caller's - there is no caller at all.
79
79
  */
80
80
  class OrganizationsResource {
81
81
  supabase;
@@ -102,7 +102,7 @@ class OrganizationsResource {
102
102
  }
103
103
  /**
104
104
  * The whole row, unprojected. Billing reads a different handful of columns for each of its
105
- * flows — provisioning, a module purchase, a seat charge — and they are all single-row
105
+ * flows - provisioning, a module purchase, a seat charge - and they are all single-row
106
106
  * lookups by primary key, so one read serves them all rather than a select string each.
107
107
  */
108
108
  async getRowById(organizationId) {
@@ -116,7 +116,7 @@ class OrganizationsResource {
116
116
  return (0, audit_1.withoutInternalId)(data);
117
117
  }
118
118
  /**
119
- * A status move that only lands while the organization is still in `expectedFrom` — the
119
+ * A status move that only lands while the organization is still in `expectedFrom` - the
120
120
  * compare-and-set that stops two concurrent webhooks both advancing the subscription.
121
121
  * Resolves to null when someone else moved it first.
122
122
  */
@@ -131,13 +131,13 @@ class OrganizationsResource {
131
131
  });
132
132
  return this.getById(organizationId);
133
133
  }
134
- /** Hard delete — used by the signup rollback. Returns the row as it was. */
134
+ /** Hard delete - used by the signup rollback. Returns the row as it was. */
135
135
  async remove(organizationId) {
136
136
  return this.table.remove(organizationId);
137
137
  }
138
138
  /**
139
- * Claims a seat atomically. This is the serialization point for concurrent user creation —
140
- * two admins adding at once get distinct seat numbers — so it is a function, not a
139
+ * Claims a seat atomically. This is the serialization point for concurrent user creation -
140
+ * two admins adding at once get distinct seat numbers - so it is a function, not a
141
141
  * read-then-write. The caller decides what to do with the billing status it returns.
142
142
  */
143
143
  async reserveSeat(organizationId) {
@@ -165,7 +165,7 @@ class OrganizationsResource {
165
165
  }
166
166
  exports.OrganizationsResource = OrganizationsResource;
167
167
  /**
168
- * Signup, on the service client. `organizations` INSERT is `false` for `authenticated` — the
168
+ * Signup, on the service client. `organizations` INSERT is `false` for `authenticated` - the
169
169
  * caller has no account yet, so there is no RLS context to run under.
170
170
  */
171
171
  class OrganizationSignupResource {
@@ -9,7 +9,7 @@ export type PermissionFlags = {
9
9
  } & Record<string, boolean>;
10
10
  /**
11
11
  * The `permissions` table. Rows are created by the `on_auth_user_created` trigger and deleted
12
- * with the user — INSERT and DELETE are `false` for `authenticated` — so this resource only
12
+ * with the user - INSERT and DELETE are `false` for `authenticated` - so this resource only
13
13
  * reads and updates.
14
14
  */
15
15
  export declare class PermissionsResource {
@@ -18,8 +18,8 @@ export declare class PermissionsResource {
18
18
  private readonly table;
19
19
  constructor(supabase: TypedSupabaseClient, auth: AuditActor, audit: AuditResource);
20
20
  /**
21
- * The whole permissions row. `*` rather than a select string — the alternative is naming the
22
- * two role flags and all 78 permission flags — so the internal `id` is dropped on the way out.
21
+ * The whole permissions row. `*` rather than a select string - the alternative is naming the
22
+ * two role flags and all 78 permission flags - so the internal `id` is dropped on the way out.
23
23
  */
24
24
  getForUser(userId: string): Promise<PermissionsEntity>;
25
25
  /**
@@ -28,13 +28,13 @@ export declare class PermissionsResource {
28
28
  * guard treats as a denial.
29
29
  *
30
30
  * `flag` is interpolated into the select string, so it is checked against the shape a column
31
- * name can take first — a flag never comes from a request, only from a route's own decorator,
31
+ * name can take first - a flag never comes from a request, only from a route's own decorator,
32
32
  * so anything else is a bug rather than a bad request.
33
33
  */
34
34
  flagsFor(userId: string, flag: string): Promise<PermissionFlags | null>;
35
- /** Whether a user owns the organization — the guard behind "you cannot deactivate the owner". */
35
+ /** Whether a user owns the organization - the guard behind "you cannot deactivate the owner". */
36
36
  isOwner(userId: string): Promise<boolean>;
37
- /** Who owns the organization. Null when there is no owner row yet — signup is mid-flight. */
37
+ /** Who owns the organization. Null when there is no owner row yet - signup is mid-flight. */
38
38
  ownerUserId(): Promise<string | null>;
39
39
  /**
40
40
  * Permissions are keyed by `user_id` on the wire but audited by the row's own `mms_id`, so
@@ -25,7 +25,7 @@ const PERMISSIONS_TABLE = {
25
25
  };
26
26
  /**
27
27
  * The `permissions` table. Rows are created by the `on_auth_user_created` trigger and deleted
28
- * with the user — INSERT and DELETE are `false` for `authenticated` — so this resource only
28
+ * with the user - INSERT and DELETE are `false` for `authenticated` - so this resource only
29
29
  * reads and updates.
30
30
  */
31
31
  class PermissionsResource {
@@ -38,8 +38,8 @@ class PermissionsResource {
38
38
  this.table = (0, audit_1.auditedTable)(supabase, auth, audit, PERMISSIONS_TABLE);
39
39
  }
40
40
  /**
41
- * The whole permissions row. `*` rather than a select string — the alternative is naming the
42
- * two role flags and all 78 permission flags — so the internal `id` is dropped on the way out.
41
+ * The whole permissions row. `*` rather than a select string - the alternative is naming the
42
+ * two role flags and all 78 permission flags - so the internal `id` is dropped on the way out.
43
43
  */
44
44
  async getForUser(userId) {
45
45
  const { data, error } = await this.supabase
@@ -58,7 +58,7 @@ class PermissionsResource {
58
58
  * guard treats as a denial.
59
59
  *
60
60
  * `flag` is interpolated into the select string, so it is checked against the shape a column
61
- * name can take first — a flag never comes from a request, only from a route's own decorator,
61
+ * name can take first - a flag never comes from a request, only from a route's own decorator,
62
62
  * so anything else is a bug rather than a bad request.
63
63
  */
64
64
  async flagsFor(userId, flag) {
@@ -79,7 +79,7 @@ class PermissionsResource {
79
79
  throw (0, errors_1.mapPostgrestError)(error);
80
80
  return (data ?? null);
81
81
  }
82
- /** Whether a user owns the organization — the guard behind "you cannot deactivate the owner". */
82
+ /** Whether a user owns the organization - the guard behind "you cannot deactivate the owner". */
83
83
  async isOwner(userId) {
84
84
  const { data, error } = await this.supabase
85
85
  .from('permissions')
@@ -91,7 +91,7 @@ class PermissionsResource {
91
91
  throw (0, errors_1.mapPostgrestError)(error);
92
92
  return data?.is_owner === true;
93
93
  }
94
- /** Who owns the organization. Null when there is no owner row yet — signup is mid-flight. */
94
+ /** Who owns the organization. Null when there is no owner row yet - signup is mid-flight. */
95
95
  async ownerUserId() {
96
96
  const { data, error } = await this.supabase
97
97
  .from('permissions')
@@ -2,7 +2,7 @@ import type { SupabaseClient as SupabaseJsClient } from '@supabase/supabase-js';
2
2
  import type { PricebookWithModules } from '@managemint-solutions/entities/modules';
3
3
  /**
4
4
  * The public price catalog. `pricebooks`, `pricebook_modules` and `billing_modules` are readable
5
- * by `anon` by design — unauthenticated signup prices against them — so this resource takes no
5
+ * by `anon` by design - unauthenticated signup prices against them - so this resource takes no
6
6
  * auth context and scopes by nothing.
7
7
  */
8
8
  export declare class PricebooksResource {
@@ -13,7 +13,7 @@ export declare class PricebooksResource {
13
13
  }
14
14
  /**
15
15
  * What the given modules cost per month, in minor units: every module's unit price summed and
16
- * multiplied by the seat count. A module the pricebook does not price is a 400 — the caller
16
+ * multiplied by the seat count. A module the pricebook does not price is a 400 - the caller
17
17
  * asked for something that cannot be billed.
18
18
  */
19
19
  export declare const monthlyTotalMinor: (pricebook: PricebookWithModules, moduleKeys: string[], seatCount: number) => number;
@@ -19,7 +19,7 @@ const PRICEBOOK_SELECT = `
19
19
  )
20
20
  )
21
21
  `;
22
- // A pricebook_modules row whose catalog entry did not come back leaves `module_key` undefined —
22
+ // A pricebook_modules row whose catalog entry did not come back leaves `module_key` undefined -
23
23
  // the cast keeps the mapping honest about that rather than inventing a key.
24
24
  const toPricebookWithModules = (row) => ({
25
25
  mms_id: row.mms_id,
@@ -35,7 +35,7 @@ const toPricebookWithModules = (row) => ({
35
35
  });
36
36
  /**
37
37
  * The public price catalog. `pricebooks`, `pricebook_modules` and `billing_modules` are readable
38
- * by `anon` by design — unauthenticated signup prices against them — so this resource takes no
38
+ * by `anon` by design - unauthenticated signup prices against them - so this resource takes no
39
39
  * auth context and scopes by nothing.
40
40
  */
41
41
  class PricebooksResource {
@@ -67,7 +67,7 @@ class PricebooksResource {
67
67
  exports.PricebooksResource = PricebooksResource;
68
68
  /**
69
69
  * What the given modules cost per month, in minor units: every module's unit price summed and
70
- * multiplied by the seat count. A module the pricebook does not price is a 400 — the caller
70
+ * multiplied by the seat count. A module the pricebook does not price is a 400 - the caller
71
71
  * asked for something that cannot be billed.
72
72
  */
73
73
  const monthlyTotalMinor = (pricebook, moduleKeys, seatCount) => {
@@ -196,7 +196,7 @@ __decorate([
196
196
  (0, class_validator_1.IsOptional)(),
197
197
  (0, validators_1.IsNullable)()
198
198
  // Still v4: a manager is a `users.mms_id`, and that column carries the GoTrue auth uid the
199
- // signup trigger copies out of `auth.users.id` — the table's uuidv7 default never fires.
199
+ // signup trigger copies out of `auth.users.id` - the table's uuidv7 default never fires.
200
200
  ,
201
201
  (0, class_validator_1.IsUUID)('4', { message: 'Invalid manager ID format' }),
202
202
  __metadata("design:type", Object)
@@ -256,7 +256,7 @@ __decorate([
256
256
  __decorate([
257
257
  (0, class_validator_1.IsOptional)(),
258
258
  (0, validators_1.IsNullable)()
259
- // Still v4 — a manager is a `users.mms_id`, the GoTrue auth uid (see CreateProjectDto).
259
+ // Still v4 - a manager is a `users.mms_id`, the GoTrue auth uid (see CreateProjectDto).
260
260
  ,
261
261
  (0, class_validator_1.IsUUID)('4', { message: 'Invalid manager ID format' }),
262
262
  __metadata("design:type", Object)
@@ -17,6 +17,6 @@ export declare class ProjectsResource {
17
17
  archive(projectId: string): Promise<ProjectEntity>;
18
18
  unarchive(projectId: string): Promise<ProjectEntity>;
19
19
  restore(projectId: string): Promise<ProjectEntity>;
20
- /** Soft delete — the row stays, flagged `deleted`, and `restore()` brings it back. */
20
+ /** Soft delete - the row stays, flagged `deleted`, and `restore()` brings it back. */
21
21
  remove(projectId: string): Promise<void>;
22
22
  }
@@ -126,7 +126,7 @@ class ProjectsResource {
126
126
  }
127
127
  // Excluding statuses has to be spelled out as "no status OR not one of these": PostgREST can
128
128
  // only filter a parent row by an embedded column with `!inner`, which would drop projects that
129
- // have no status at all — and a project with no status is not complete, so it belongs in the
129
+ // have no status at all - and a project with no status is not complete, so it belongs in the
130
130
  // default view. SQL's `NOT IN` drops nulls for the same reason, hence the explicit null arm.
131
131
  // The ids are `@IsUUID('7')`-validated by the DTO, so interpolating them is safe. Repeated
132
132
  // `or` params are ANDed by PostgREST, so this composes with the search filter above.
@@ -205,7 +205,7 @@ class ProjectsResource {
205
205
  await this.table.transition(projectId, enum_1.AuditTrailAction.RESTORE, (0, transforms_1.restoredPatch)(this.auth.mms_id));
206
206
  return this.getById(projectId);
207
207
  }
208
- /** Soft delete — the row stays, flagged `deleted`, and `restore()` brings it back. */
208
+ /** Soft delete - the row stays, flagged `deleted`, and `restore()` brings it back. */
209
209
  async remove(projectId) {
210
210
  await this.table.transition(projectId, enum_1.AuditTrailAction.DELETE, (0, transforms_1.deletedPatch)(this.auth.mms_id));
211
211
  }
@@ -13,14 +13,14 @@ import { UsersResource } from '../users';
13
13
  import { WebhookEventsResource } from '../webhook-events';
14
14
  export type SupabaseServiceClientConfig = {
15
15
  url: string;
16
- /** Service-role key — every query bypasses RLS. */
16
+ /** Service-role key - every query bypasses RLS. */
17
17
  serviceRoleKey: string;
18
18
  /** Where a failed audit insert is reported. Defaults to `console.error`. */
19
19
  onAuditError?: AuditErrorHandler;
20
20
  };
21
21
  /**
22
22
  * The organization-scoped half of the service client. Everything here is attributed to one
23
- * `AuditActor`, so writes land in `audit_logs` the same way a caller's own would — with
23
+ * `AuditActor`, so writes land in `audit_logs` the same way a caller's own would - with
24
24
  * `mms_id: null` when the actor is the system (a webhook, a queue worker, provisioning).
25
25
  */
26
26
  export declare class SupabaseOrganizationScope {
@@ -36,7 +36,7 @@ export declare class SupabaseOrganizationScope {
36
36
  readonly users: UsersResource;
37
37
  constructor(supabase: TypedSupabaseClient, actor: AuditActor, onAuditError?: AuditErrorHandler);
38
38
  /**
39
- * An audited table bound to this organization and actor — the shape the api hand-rolls today
39
+ * An audited table bound to this organization and actor - the shape the api hand-rolls today
40
40
  * as a local `auditedTables(client, organizationId)` factory in billing, provisioning,
41
41
  * subscriptions and both webhook handler services.
42
42
  */
@@ -46,7 +46,7 @@ export declare class SupabaseOrganizationScope {
46
46
  * The client for work that has no caller and no RLS context to run under: inbound webhooks
47
47
  * (Paystack, Resend, the Supabase `send_email` hook), the notification queue worker, unauthenticated
48
48
  * signup, the website's feature-request intake, and the writes RLS reserves for the service role
49
- * outright — the ledger, the outbox, the webhook event logs, `organizations` INSERT, `permissions`
49
+ * outright - the ledger, the outbox, the webhook event logs, `organizations` INSERT, `permissions`
50
50
  * INSERT/DELETE.
51
51
  *
52
52
  * It decodes no JWT, because there is none. Cross-org lookups (find the organization behind a
@@ -64,7 +64,7 @@ export declare class SupabaseServiceClient {
64
64
  readonly resendEvents: WebhookEventsResource;
65
65
  constructor(config: SupabaseServiceClientConfig);
66
66
  /**
67
- * Scope to one organization once it is known. `actorMmsId` stays `null` for system work —
67
+ * Scope to one organization once it is known. `actorMmsId` stays `null` for system work -
68
68
  * `audit_logs.created_by` is nullable precisely so an unattributed write is still recorded.
69
69
  */
70
70
  forOrganization(organizationId: string, actorMmsId?: string | null): SupabaseOrganizationScope;
@@ -18,7 +18,7 @@ const users_1 = require("../users");
18
18
  const webhook_events_1 = require("../webhook-events");
19
19
  /**
20
20
  * The organization-scoped half of the service client. Everything here is attributed to one
21
- * `AuditActor`, so writes land in `audit_logs` the same way a caller's own would — with
21
+ * `AuditActor`, so writes land in `audit_logs` the same way a caller's own would - with
22
22
  * `mms_id: null` when the actor is the system (a webhook, a queue worker, provisioning).
23
23
  */
24
24
  class SupabaseOrganizationScope {
@@ -45,7 +45,7 @@ class SupabaseOrganizationScope {
45
45
  this.users = new users_1.UsersResource(supabase, actor, this.audit);
46
46
  }
47
47
  /**
48
- * An audited table bound to this organization and actor — the shape the api hand-rolls today
48
+ * An audited table bound to this organization and actor - the shape the api hand-rolls today
49
49
  * as a local `auditedTables(client, organizationId)` factory in billing, provisioning,
50
50
  * subscriptions and both webhook handler services.
51
51
  */
@@ -58,7 +58,7 @@ exports.SupabaseOrganizationScope = SupabaseOrganizationScope;
58
58
  * The client for work that has no caller and no RLS context to run under: inbound webhooks
59
59
  * (Paystack, Resend, the Supabase `send_email` hook), the notification queue worker, unauthenticated
60
60
  * signup, the website's feature-request intake, and the writes RLS reserves for the service role
61
- * outright — the ledger, the outbox, the webhook event logs, `organizations` INSERT, `permissions`
61
+ * outright - the ledger, the outbox, the webhook event logs, `organizations` INSERT, `permissions`
62
62
  * INSERT/DELETE.
63
63
  *
64
64
  * It decodes no JWT, because there is none. Cross-org lookups (find the organization behind a
@@ -85,7 +85,7 @@ class SupabaseServiceClient {
85
85
  this.featureRequests = new feature_requests_1.FeatureRequestsResource(this.supabase);
86
86
  this.configs = new configs_1.ConfigsResource(this.supabase);
87
87
  this.signup = new organizations_1.OrganizationSignupResource(this.supabase, (organizationId) => this.forOrganization(organizationId).audit);
88
- // The outbox spans organizations — the row it is about carries its own — so it takes a
88
+ // The outbox spans organizations - the row it is about carries its own - so it takes a
89
89
  // factory and scopes per write rather than being built inside one organization's scope.
90
90
  this.notifications = new notifications_1.NotificationsOutboxResource(this.supabase, (organizationId) => this.forOrganization(organizationId).table({
91
91
  table: 'notifications',
@@ -93,7 +93,7 @@ class SupabaseServiceClient {
93
93
  }));
94
94
  }
95
95
  /**
96
- * Scope to one organization once it is known. `actorMmsId` stays `null` for system work —
96
+ * Scope to one organization once it is known. `actorMmsId` stays `null` for system work -
97
97
  * `audit_logs.created_by` is nullable precisely so an unattributed write is still recorded.
98
98
  */
99
99
  forOrganization(organizationId, actorMmsId = null) {
@@ -18,7 +18,7 @@ const validators_1 = require("../validators");
18
18
  // wire contract cannot drift.
19
19
  /**
20
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
21
+ * than in the api means the length rules below measure what will actually be sent - a name of
22
22
  * three spaces is empty, not three characters long.
23
23
  */
24
24
  const Trim = () => (0, class_transformer_1.Transform)(({ value }) => (typeof value === 'string' ? value.trim() : value), {
@@ -14,7 +14,7 @@ const class_validator_1 = require("class-validator");
14
14
  const enum_1 = require("@managemint-solutions/entities/supporting-files/enum");
15
15
  // class-validator versions of the shared DTO types from @managemint-solutions/entities.
16
16
  // Each class `implements` its entities type so the wire contract cannot drift. There is no class
17
- // for the upload payload — it arrives as multipart and is not validated by class-validator.
17
+ // for the upload payload - it arrives as multipart and is not validated by class-validator.
18
18
  class SupportingFileIdDto {
19
19
  supportingFileId;
20
20
  }
@@ -33,7 +33,7 @@ const fileNameOf = (file) => file.extension ? `${file.name}.${file.extension}` :
33
33
  // casts at the returns declare the shape the select strings below produce (the columns are
34
34
  // defined in the api's supabase/migrations).
35
35
  //
36
- // Object keys are `organizationId/entityType/entityId/file` — the organization leads so a storage
36
+ // Object keys are `organizationId/entityType/entityId/file` - the organization leads so a storage
37
37
  // policy can scope by tenant. A data migration renames the pre-existing objects, which have no
38
38
  // organization segment, into that prefix.
39
39
  class SupportingFilesResource {
@@ -87,13 +87,13 @@ class SupportingFilesResource {
87
87
  throw (0, errors_1.mapPostgrestError)(existingError);
88
88
  const existingFileNames = existing.map(fileNameOf);
89
89
  // Each client name is validated once here, and the object key, the duplicate check and the
90
- // row are all built from that same split — so what is stored is what presign and remove
90
+ // row are all built from that same split - so what is stored is what presign and remove
91
91
  // rebuild later.
92
92
  const uploads = input.files.map((file) => ({
93
93
  file,
94
94
  ...(0, paths_1.splitFileName)((0, paths_1.sanitizeFileName)(file.name)),
95
95
  }));
96
- // Every file is written to the bucket, duplicates included — an upsert refreshes the object.
96
+ // Every file is written to the bucket, duplicates included - an upsert refreshes the object.
97
97
  for (let index = 0; index < uploads.length; index += UPLOAD_BATCH_SIZE) {
98
98
  await Promise.all(uploads.slice(index, index + UPLOAD_BATCH_SIZE).map(async ({ file, name, extension }) => {
99
99
  const { error } = await this.supabase.storage
@@ -104,7 +104,7 @@ class SupportingFilesResource {
104
104
  }
105
105
  }));
106
106
  }
107
- // Only files without an existing row get one — the rest were refreshed in place above.
107
+ // Only files without an existing row get one - the rest were refreshed in place above.
108
108
  const newFiles = uploads.filter((file) => !existingFileNames.includes(fileNameOf(file)));
109
109
  if (newFiles.length > 0) {
110
110
  await this.table.insertMany(newFiles.map(({ name, extension }) => ({
@@ -120,7 +120,7 @@ class SupportingFilesResource {
120
120
  return this.list(entity, entityId);
121
121
  }
122
122
  async remove(supportingFileId) {
123
- // The row goes first — the helper's pre-read hands back what the object path is built from.
123
+ // The row goes first - the helper's pre-read hands back what the object path is built from.
124
124
  const data = await this.table.remove(supportingFileId);
125
125
  const { error: storageError } = await this.supabase.storage
126
126
  .from(BUCKET)
@@ -2,13 +2,13 @@
2
2
  * The client-supplied file name, checked before it is allowed anywhere near an object key.
3
3
  *
4
4
  * The name is half of the key, so a separator or a `..` in it would let an upload escape its
5
- * entity's folder — and, now that the key starts with the organization, its tenant's folder.
5
+ * entity's folder - and, now that the key starts with the organization, its tenant's folder.
6
6
  * Anything that is not a plain file name is rejected outright rather than rewritten, so what the
7
7
  * `supporting_files` row records is exactly what was stored.
8
8
  */
9
9
  export declare const sanitizeFileName: (fileName: string) => string;
10
10
  /**
11
- * Splits an uploaded file name into the `name` / `extension` columns, on the *last* dot — so
11
+ * Splits an uploaded file name into the `name` / `extension` columns, on the *last* dot - so
12
12
  * `archive.tar.gz` is name `archive.tar`, extension `gz`, and `storagePath` rebuilds the key it
13
13
  * was stored under. A name with no dot has no extension.
14
14
  */
@@ -18,7 +18,7 @@ export declare const splitFileName: (fileName: string) => {
18
18
  };
19
19
  /**
20
20
  * Where an object lives in the `supporting-files` bucket. The organization leads the key so a
21
- * storage policy can scope objects by tenant — nothing below it is trusted for that.
21
+ * storage policy can scope objects by tenant - nothing below it is trusted for that.
22
22
  *
23
23
  * A data migration renames the existing objects (keyed `entity/entityId/file`) into their
24
24
  * organization's prefix; keys written from here already carry it.
@@ -4,14 +4,14 @@ exports.storagePath = exports.splitFileName = exports.sanitizeFileName = void 0;
4
4
  const errors_1 = require("../errors");
5
5
  /** Longest object-key segment a file name may become. */
6
6
  const MAX_FILE_NAME_LENGTH = 255;
7
- /** What a file name may be made of — no separators, no control characters, no leading dot. */
7
+ /** What a file name may be made of - no separators, no control characters, no leading dot. */
8
8
  const SAFE_FILE_NAME = /^[A-Za-z0-9][A-Za-z0-9 ._()\-]*$/;
9
9
  const invalidFileName = () => new errors_1.SupabaseClientError({ status: 400, error: 'Storage Error', message: 'Invalid file name' });
10
10
  /**
11
11
  * The client-supplied file name, checked before it is allowed anywhere near an object key.
12
12
  *
13
13
  * The name is half of the key, so a separator or a `..` in it would let an upload escape its
14
- * entity's folder — and, now that the key starts with the organization, its tenant's folder.
14
+ * entity's folder - and, now that the key starts with the organization, its tenant's folder.
15
15
  * Anything that is not a plain file name is rejected outright rather than rewritten, so what the
16
16
  * `supporting_files` row records is exactly what was stored.
17
17
  */
@@ -31,7 +31,7 @@ const sanitizeFileName = (fileName) => {
31
31
  };
32
32
  exports.sanitizeFileName = sanitizeFileName;
33
33
  /**
34
- * Splits an uploaded file name into the `name` / `extension` columns, on the *last* dot — so
34
+ * Splits an uploaded file name into the `name` / `extension` columns, on the *last* dot - so
35
35
  * `archive.tar.gz` is name `archive.tar`, extension `gz`, and `storagePath` rebuilds the key it
36
36
  * was stored under. A name with no dot has no extension.
37
37
  */
@@ -44,7 +44,7 @@ const splitFileName = (fileName) => {
44
44
  exports.splitFileName = splitFileName;
45
45
  /**
46
46
  * Where an object lives in the `supporting-files` bucket. The organization leads the key so a
47
- * storage policy can scope objects by tenant — nothing below it is trusted for that.
47
+ * storage policy can scope objects by tenant - nothing below it is trusted for that.
48
48
  *
49
49
  * A data migration renames the existing objects (keyed `entity/entityId/file`) into their
50
50
  * organization's prefix; keys written from here already carry it.
package/dist/tasks/dto.js CHANGED
@@ -21,7 +21,7 @@ class TaskIdDto {
21
21
  }
22
22
  exports.TaskIdDto = TaskIdDto;
23
23
  __decorate([
24
- (0, class_validator_1.IsUUID)('7', { message: 'Invalid project ID format' }) // sic — the api's message, kept for parity
24
+ (0, class_validator_1.IsUUID)('7', { message: 'Invalid project ID format' }) // sic - the api's message, kept for parity
25
25
  ,
26
26
  __metadata("design:type", String)
27
27
  ], TaskIdDto.prototype, "taskId", void 0);
@@ -92,7 +92,7 @@ __decorate([
92
92
  (0, class_validator_1.IsOptional)(),
93
93
  (0, validators_1.IsNullable)()
94
94
  // Still v4: the assignee is a `users.mms_id`, and that column carries the GoTrue auth uid the
95
- // signup trigger copies out of `auth.users.id` — the table's uuidv7 default never fires.
95
+ // signup trigger copies out of `auth.users.id` - the table's uuidv7 default never fires.
96
96
  ,
97
97
  (0, class_validator_1.IsUUID)('4', { message: 'Invalid assigned to ID format' }),
98
98
  __metadata("design:type", Object)
@@ -222,7 +222,7 @@ __decorate([
222
222
  __decorate([
223
223
  (0, class_validator_1.IsOptional)(),
224
224
  (0, validators_1.IsNullable)()
225
- // Still v4 — an assignee is a `users.mms_id`, the GoTrue auth uid (see GetTasksDto).
225
+ // Still v4 - an assignee is a `users.mms_id`, the GoTrue auth uid (see GetTasksDto).
226
226
  ,
227
227
  (0, class_validator_1.IsUUID)('4', { message: 'Invalid assigned to ID format' }),
228
228
  __metadata("design:type", Object)
@@ -295,7 +295,7 @@ __decorate([
295
295
  __decorate([
296
296
  (0, class_validator_1.IsOptional)(),
297
297
  (0, validators_1.IsNullable)()
298
- // Still v4 — an assignee is a `users.mms_id`, the GoTrue auth uid (see GetTasksDto).
298
+ // Still v4 - an assignee is a `users.mms_id`, the GoTrue auth uid (see GetTasksDto).
299
299
  ,
300
300
  (0, class_validator_1.IsUUID)('4', { message: 'Invalid assigned to ID format' }),
301
301
  __metadata("design:type", Object)
@@ -17,6 +17,6 @@ export declare class TasksResource {
17
17
  archive(taskId: string): Promise<TaskEntity>;
18
18
  unarchive(taskId: string): Promise<TaskEntity>;
19
19
  restore(taskId: string): Promise<TaskEntity>;
20
- /** Soft delete — the row stays, flagged `deleted`, and `restore()` brings it back. */
20
+ /** Soft delete - the row stays, flagged `deleted`, and `restore()` brings it back. */
21
21
  remove(taskId: string): Promise<void>;
22
22
  }
@@ -140,7 +140,7 @@ class TasksResource {
140
140
  }
141
141
  // Excluding statuses has to be spelled out as "no status OR not one of these": PostgREST can
142
142
  // only filter a parent row by an embedded column with `!inner`, which would drop tasks that
143
- // have no status at all — and a task with no status is not complete, so it belongs in the
143
+ // have no status at all - and a task with no status is not complete, so it belongs in the
144
144
  // default view. SQL's `NOT IN` drops nulls for the same reason, hence the explicit null arm.
145
145
  // The ids are `@IsUUID('7')`-validated by the DTO, so interpolating them is safe. Repeated
146
146
  // `or` params are ANDed by PostgREST, so this composes with the search filter above.
@@ -197,7 +197,7 @@ class TasksResource {
197
197
  await this.table.transition(taskId, enum_1.AuditTrailAction.RESTORE, (0, transforms_1.restoredPatch)(this.auth.mms_id));
198
198
  return this.getById(taskId);
199
199
  }
200
- /** Soft delete — the row stays, flagged `deleted`, and `restore()` brings it back. */
200
+ /** Soft delete - the row stays, flagged `deleted`, and `restore()` brings it back. */
201
201
  async remove(taskId) {
202
202
  await this.table.transition(taskId, enum_1.AuditTrailAction.DELETE, (0, transforms_1.deletedPatch)(this.auth.mms_id));
203
203
  }
@@ -2,24 +2,24 @@ import type { MmsList } from '@managemint-solutions/entities/common';
2
2
  /**
3
3
  * The `client_id` / `project_id` list filters accept either a plain UUID v7 or the base64-JSON
4
4
  * option value the portal's selects send (`{ mms_id }`, or `{ id }` as a fallback). Anything that
5
- * is not one of those — including a value that decodes to JSON without a UUID v7 — cannot filter
5
+ * is not one of those - including a value that decodes to JSON without a UUID v7 - cannot filter
6
6
  * anything, so it becomes `null` and the filter is skipped.
7
7
  */
8
8
  export declare const parseEntityIdFilter: (value: unknown) => string | null;
9
9
  /**
10
10
  * A `%value%` ilike pattern, double-quoted for PostgREST's `or=(...)` grammar so `,`, `(`, `)`,
11
11
  * `.`, `"` and `\` in the search stay literal instead of being read as more filters. Inside the
12
- * quotes only `"` and `\` need escaping, which is what PostgREST defines — the `\,` the list
12
+ * quotes only `"` and `\` need escaping, which is what PostgREST defines - the `\,` the list
13
13
  * endpoints used to emit was never an escape at all. LIKE's own wildcards `%` and `_` are left
14
14
  * alone and still match as wildcards; they only widen the caller's own search, never its scope.
15
15
  */
16
16
  export declare const ilikeContains: (value: string) => string;
17
- /** The `or=(...)` argument matching `search` against any of `columns` — `name.ilike."%x%",…`. */
17
+ /** The `or=(...)` argument matching `search` against any of `columns` - `name.ilike."%x%",…`. */
18
18
  export declare const orIlike: (columns: readonly string[], search: string) => string;
19
19
  /**
20
20
  * `date` columns take an ISO string. The shared `CreateProjectDto`/`UpdateProjectDto` types
21
- * declare `Date`, but over the wire the value is the validated `@IsDateString` string — which
22
- * must reach Postgres byte-identical ('2026-04-22' is a plain date, not an instant) — so only a
21
+ * declare `Date`, but over the wire the value is the validated `@IsDateString` string - which
22
+ * must reach Postgres byte-identical ('2026-04-22' is a plain date, not an instant) - so only a
23
23
  * real `Date` (a portal caller) is serialized.
24
24
  */
25
25
  export declare const toDateInput: (value: Date | string | null | undefined) => string | null | undefined;
@@ -31,7 +31,7 @@ export declare const toDateInput: (value: Date | string | null | undefined) => s
31
31
  export declare const USER_PROFILE_EMBED: "(\n mms_id,\n name,\n surname,\n email,\n profile_image\n )";
32
32
  /**
33
33
  * The `MmsList` envelope every paginated read returns. `rows` is `unknown` because each select
34
- * string produces its own row shape — the caller's `T` is what declares it. `count` is
34
+ * string produces its own row shape - the caller's `T` is what declares it. `count` is
35
35
  * PostgREST's estimate, so an empty page reports 0 total pages rather than 1.
36
36
  */
37
37
  export declare const toMmsList: <T>(rows: unknown, page: number, pageSize: number, count: number | null) => MmsList<T>;