@managemint-solutions/sdk 0.68.0 → 0.70.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.
Files changed (42) hide show
  1. package/README.md +7 -2
  2. package/dist/additional-details/dto.d.ts +9 -1
  3. package/dist/additional-details/dto.js +46 -1
  4. package/dist/additional-details/index.d.ts +8 -0
  5. package/dist/additional-details/index.js +12 -0
  6. package/dist/audit/index.d.ts +6 -0
  7. package/dist/audit/index.js +47 -0
  8. package/dist/auth.d.ts +11 -1
  9. package/dist/auth.js +5 -2
  10. package/dist/client.d.ts +3 -0
  11. package/dist/client.js +4 -0
  12. package/dist/configs/dto.d.ts +5 -1
  13. package/dist/configs/dto.js +10 -1
  14. package/dist/crons/dto.d.ts +9 -0
  15. package/dist/crons/dto.js +43 -0
  16. package/dist/crons/index.d.ts +38 -0
  17. package/dist/crons/index.js +109 -0
  18. package/dist/index.d.ts +8 -5
  19. package/dist/index.js +15 -4
  20. package/dist/notes/dto.d.ts +9 -1
  21. package/dist/notes/dto.js +46 -1
  22. package/dist/notes/index.d.ts +9 -0
  23. package/dist/notes/index.js +13 -0
  24. package/dist/oauth/dto.d.ts +7 -0
  25. package/dist/oauth/dto.js +32 -0
  26. package/dist/oauth/index.d.ts +25 -0
  27. package/dist/oauth/index.js +88 -0
  28. package/dist/service-client/index.d.ts +4 -0
  29. package/dist/service-client/index.js +6 -0
  30. package/dist/staff-client.d.ts +18 -1
  31. package/dist/staff-client.js +30 -0
  32. package/dist/statuses/dto.d.ts +9 -1
  33. package/dist/statuses/dto.js +46 -1
  34. package/dist/statuses/index.d.ts +7 -2
  35. package/dist/statuses/index.js +18 -10
  36. package/dist/supporting-files/dto.d.ts +9 -1
  37. package/dist/supporting-files/dto.js +46 -1
  38. package/dist/supporting-files/index.d.ts +5 -0
  39. package/dist/supporting-files/index.js +9 -0
  40. package/dist/tenancy.d.ts +12 -0
  41. package/dist/tenancy.js +22 -1
  42. package/package.json +2 -2
package/README.md CHANGED
@@ -401,8 +401,13 @@ await service.staffPermissions.updateForStaff(staffId, patch, byStaffId); // Upd
401
401
  ### User api credentials and emulation
402
402
 
403
403
  A credential is a client id and secret staff issue for one tenant user. Exchanging it mints that
404
- user's own token, which the custom access token hook marks `emulated: true` and gives a one-hour
405
- `exp`; `verifyAccessToken` returns it as `emulated: true` (`false` for a user's own session).
404
+ user's own token, which the custom access token hook marks `api_credential` (the credential) with a
405
+ 15-minute `exp`; `verifyAccessToken` returns it as `api_credential`, and it reads and writes as the
406
+ user. A staff member's Emulate User token is marked `emulated: true` with a one-hour `exp`
407
+ (`verifyAccessToken`'s `emulated`, read-only on the main api). A token Supabase's OAuth server
408
+ issued to an app carries `client_id`, returned as `oauth_client_id`. The caller's side of that
409
+ OAuth server is `supabase.oauth` (`getAuthorization`, `answerAuthorization`, `listGrants`,
410
+ `revokeGrant`), plain calls to GoTrue's endpoints with the caller's bearer.
406
411
 
407
412
  The mint itself lives in the admin api. The SDK calls it is made of:
408
413
 
@@ -1,5 +1,5 @@
1
1
  import { type ValidationOptions } from 'class-validator';
2
- import type { AddAdditionalDetailsDto as AddAdditionalDetailsDtoType, AdditionalDetailsIdDto as AdditionalDetailsIdDtoType, GetAdditionalDetailsDto as GetAdditionalDetailsDtoType, UpdateAdditionalDetailsDto as UpdateAdditionalDetailsDtoType } from '@managemint-solutions/entities/additional-details/dto';
2
+ import type { AddAdditionalDetailsDto as AddAdditionalDetailsDtoType, AdditionalDetailsIdDto as AdditionalDetailsIdDtoType, GetAdditionalDetailsDto as GetAdditionalDetailsDtoType, GetAllAdditionalDetailsDto as GetAllAdditionalDetailsDtoType, UpdateAdditionalDetailsDto as UpdateAdditionalDetailsDtoType } from '@managemint-solutions/entities/additional-details/dto';
3
3
  import { AdditionalDetailsEntityTypes, AdditionalDetailsTypes } from '@managemint-solutions/entities/additional-details/enum';
4
4
  /** Validates `value` against the sibling `type` property (the discriminator). */
5
5
  export declare function IsAdditionalDetailsValueByType(typeProperty: string, validationOptions?: ValidationOptions): (object: object, propertyName: string) => void;
@@ -22,3 +22,11 @@ export declare class UpdateAdditionalDetailsDto implements UpdateAdditionalDetai
22
22
  readonly type: AdditionalDetailsTypes;
23
23
  readonly copyable: boolean;
24
24
  }
25
+ /** The admin api's GET /additional-details: every organization's additional details, a page at a time. */
26
+ export declare class GetAllAdditionalDetailsDto implements GetAllAdditionalDetailsDtoType {
27
+ readonly page: number;
28
+ readonly page_size: number;
29
+ readonly organization_id?: string | null;
30
+ readonly entity_type?: AdditionalDetailsEntityTypes | null;
31
+ readonly search?: string | null;
32
+ }
@@ -9,10 +9,12 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.UpdateAdditionalDetailsDto = exports.AddAdditionalDetailsDto = exports.GetAdditionalDetailsDto = exports.AdditionalDetailsIdDto = void 0;
12
+ exports.GetAllAdditionalDetailsDto = exports.UpdateAdditionalDetailsDto = exports.AddAdditionalDetailsDto = exports.GetAdditionalDetailsDto = exports.AdditionalDetailsIdDto = void 0;
13
13
  exports.IsAdditionalDetailsValueByType = IsAdditionalDetailsValueByType;
14
14
  const class_validator_1 = require("class-validator");
15
+ const class_transformer_1 = require("class-transformer");
15
16
  const enum_1 = require("@managemint-solutions/entities/additional-details/enum");
17
+ const validators_1 = require("../validators");
16
18
  /** Validates `value` against the sibling `type` property (the discriminator). */
17
19
  function IsAdditionalDetailsValueByType(typeProperty, validationOptions) {
18
20
  return function (object, propertyName) {
@@ -141,3 +143,46 @@ __decorate([
141
143
  (0, class_validator_1.IsBoolean)({ message: 'Invalid copyable value' }),
142
144
  __metadata("design:type", Boolean)
143
145
  ], UpdateAdditionalDetailsDto.prototype, "copyable", void 0);
146
+ /** The admin api's GET /additional-details: every organization's additional details, a page at a time. */
147
+ class GetAllAdditionalDetailsDto {
148
+ page = 1;
149
+ page_size = 25;
150
+ organization_id;
151
+ entity_type;
152
+ search;
153
+ }
154
+ exports.GetAllAdditionalDetailsDto = GetAllAdditionalDetailsDto;
155
+ __decorate([
156
+ (0, class_validator_1.IsOptional)(),
157
+ (0, class_transformer_1.Transform)(({ value }) => (value ? Number(value) : 1), { toClassOnly: true }),
158
+ (0, class_validator_1.IsNumber)({}, { message: 'Page must be a number' }),
159
+ (0, class_validator_1.Min)(1, { message: 'Page must be at least 1' }),
160
+ __metadata("design:type", Number)
161
+ ], GetAllAdditionalDetailsDto.prototype, "page", void 0);
162
+ __decorate([
163
+ (0, class_validator_1.IsOptional)(),
164
+ (0, class_transformer_1.Transform)(({ value }) => (value ? Number(value) : 25), { toClassOnly: true }),
165
+ (0, class_validator_1.IsNumber)({}, { message: 'Page size must be a number' }),
166
+ (0, class_validator_1.Min)(1, { message: 'Page size must be at least 1' }),
167
+ (0, class_validator_1.Max)(100, { message: 'Page size cannot exceed 100' }),
168
+ __metadata("design:type", Number)
169
+ ], GetAllAdditionalDetailsDto.prototype, "page_size", void 0);
170
+ __decorate([
171
+ (0, class_validator_1.IsOptional)(),
172
+ (0, validators_1.IsNullable)(),
173
+ (0, class_validator_1.IsUUID)('7', { message: 'Invalid organization ID format' }),
174
+ __metadata("design:type", Object)
175
+ ], GetAllAdditionalDetailsDto.prototype, "organization_id", void 0);
176
+ __decorate([
177
+ (0, class_validator_1.IsOptional)(),
178
+ (0, validators_1.IsNullable)(),
179
+ (0, class_validator_1.IsEnum)(enum_1.AdditionalDetailsEntityTypes, { message: 'Invalid record type' }),
180
+ __metadata("design:type", Object)
181
+ ], GetAllAdditionalDetailsDto.prototype, "entity_type", void 0);
182
+ __decorate([
183
+ (0, class_validator_1.IsOptional)(),
184
+ (0, validators_1.IsNullable)(),
185
+ (0, class_validator_1.IsString)({ message: 'Invalid search' }),
186
+ (0, class_validator_1.MaxLength)(200, { message: 'Search cannot exceed 200 characters' }),
187
+ __metadata("design:type", Object)
188
+ ], GetAllAdditionalDetailsDto.prototype, "search", void 0);
@@ -1,10 +1,13 @@
1
1
  import type { AdditionalDetailSummary, AdditionalDetailsEntity } from '@managemint-solutions/entities/additional-details';
2
+ import type { StaffAdditionalDetailRow } from '@managemint-solutions/entities/additional-details';
3
+ import type { MmsList } from '@managemint-solutions/entities/common';
2
4
  import type { AddAdditionalDetailsDto, UpdateAdditionalDetailsDto } from '@managemint-solutions/entities/additional-details/dto';
3
5
  import { AdditionalDetailsEntityTypes } from '@managemint-solutions/entities/additional-details/enum';
4
6
  import type { ClientContext } from '../auth';
5
7
  import { type AuditResource } from '../audit';
6
8
  import type { TypedSupabaseClient } from '../client';
7
9
  export * from './dto';
10
+ import type { GetAllAdditionalDetailsDto } from './dto';
8
11
  export * from './values';
9
12
  export declare class AdditionalDetailsResource {
10
13
  private readonly supabase;
@@ -13,6 +16,11 @@ export declare class AdditionalDetailsResource {
13
16
  constructor(supabase: TypedSupabaseClient, auth: ClientContext, audit: AuditResource);
14
17
  getById(additionalDetailsId: string): Promise<AdditionalDetailsEntity>;
15
18
  list(entity: AdditionalDetailsEntityTypes, entityId: string): Promise<AdditionalDetailSummary[]>;
19
+ /**
20
+ * The admin portal's Additional Details list: every detail on a record type in `entityTypes`,
21
+ * across the organizations staff can see, newest first, its value cast by its type.
22
+ */
23
+ listAll(query: GetAllAdditionalDetailsDto, entityTypes: string[]): Promise<MmsList<StaffAdditionalDetailRow>>;
16
24
  create(entity: AdditionalDetailsEntityTypes, entityId: string, input: AddAdditionalDetailsDto): Promise<AdditionalDetailsEntity>;
17
25
  update(additionalDetailsId: string, input: UpdateAdditionalDetailsDto): Promise<AdditionalDetailsEntity>;
18
26
  remove(additionalDetailsId: string): Promise<void>;
@@ -20,6 +20,7 @@ const enum_2 = require("@managemint-solutions/entities/audit-trail/enum");
20
20
  const audit_1 = require("../audit");
21
21
  const errors_1 = require("../errors");
22
22
  const tenancy_1 = require("../tenancy");
23
+ const transforms_1 = require("../transforms");
23
24
  const won_1 = require("../leads/won");
24
25
  const values_1 = require("./values");
25
26
  __exportStar(require("./dto"), exports);
@@ -30,6 +31,7 @@ __exportStar(require("./values"), exports);
30
31
  // column, and castValueByType turns it into the string | number | boolean | Date | URL union the
31
32
  // entity declares.
32
33
  const ADDITIONAL_DETAILS_SELECT = 'mms_id, created_at, created_by:user_profiles!created_by(*), updated_at, last_updated_by:user_profiles!last_updated_by(*), key, value, type, copyable';
34
+ const ADDITIONAL_DETAILS_LIST_SELECT = 'mms_id, created_at, key, value, type, copyable, entity_type, entity_id, created_by:user_profiles!created_by(*), organization:organizations!organization_id(mms_id, name)';
33
35
  const ADDITIONAL_DETAILS_SUMMARY_SELECT = 'mms_id, key, value, type, copyable';
34
36
  const withCastValue = (detail) => ({
35
37
  ...detail,
@@ -64,6 +66,16 @@ class AdditionalDetailsResource {
64
66
  throw (0, errors_1.mapPostgrestError)(error);
65
67
  return data.map(withCastValue);
66
68
  }
69
+ /**
70
+ * The admin portal's Additional Details list: every detail on a record type in `entityTypes`,
71
+ * across the organizations staff can see, newest first, its value cast by its type.
72
+ */
73
+ async listAll(query, entityTypes) {
74
+ const { data, error, count } = await (0, tenancy_1.filterStaffList)(this.supabase.from('additional_details').select(ADDITIONAL_DETAILS_LIST_SELECT, { count: 'exact' }), query, ['key', 'value'], entityTypes).order('created_at', { ascending: false });
75
+ if (error)
76
+ throw (0, errors_1.mapPostgrestError)(error);
77
+ return (0, transforms_1.toMmsList)((data ?? []).map(withCastValue), query.page, query.page_size, count);
78
+ }
67
79
  async create(entity, entityId, input) {
68
80
  const organizationId = (0, tenancy_1.requireOrganization)(this.auth);
69
81
  if (entity === enum_1.AdditionalDetailsEntityTypes.LEAD) {
@@ -2,6 +2,7 @@ import type { SupabaseClient as SupabaseJsClient } from '@supabase/supabase-js';
2
2
  import type { AuditTrailEntity } from '@managemint-solutions/entities/audit-trail';
3
3
  import { AuditTrailAction, type AuditTrailEntityType } from '@managemint-solutions/entities/audit-trail/enum';
4
4
  import type { MmsList } from '@managemint-solutions/entities/common';
5
+ import type { RecordReference } from '@managemint-solutions/entities/audit-trail';
5
6
  import type { StaffContext } from '../auth';
6
7
  import type { GetAuditTrailDto } from './dto';
7
8
  export * from './dto';
@@ -130,6 +131,11 @@ export declare class AuditResource {
130
131
  * deleted - is simply absent, and the caller says so.
131
132
  */
132
133
  names(ids: Partial<Record<AuditNameTable, string[]>>): Promise<Record<string, string>>;
134
+ /** The record each `{ entity_type, entity_id }` names, keyed by its id; a type with no source is left out. */
135
+ references(rows: {
136
+ entity_type: string;
137
+ entity_id: string;
138
+ }[]): Promise<Record<string, RecordReference>>;
133
139
  }
134
140
  /**
135
141
  * One record's history: the rows about the record itself and every row that hangs off it (a
@@ -175,6 +175,37 @@ const NAME_SOURCES = {
175
175
  name: (row) => String(row.name),
176
176
  },
177
177
  };
178
+ /** How each record type a note, detail or file hangs off is named, read in one query per type. */
179
+ const REFERENCE_SOURCES = {
180
+ leads: { from: 'leads', select: 'mms_id, name', reference: (row) => ({ name: String(row.name), leave_type_id: null }) },
181
+ clients: { from: 'clients', select: 'mms_id, name', reference: (row) => ({ name: String(row.name), leave_type_id: null }) },
182
+ projects: { from: 'projects', select: 'mms_id, name', reference: (row) => ({ name: String(row.name), leave_type_id: null }) },
183
+ tasks: { from: 'tasks', select: 'mms_id, name', reference: (row) => ({ name: String(row.name), leave_type_id: null }) },
184
+ leave_requests: {
185
+ from: 'leave_requests',
186
+ select: 'mms_id, start_date, user:users!user_id(name, surname), leave_type:leave_types!leave_type_id(name)',
187
+ reference: (row) => ({ name: `${personOf(row)}, ${nameOf(row.leave_type)} from ${String(row.start_date)}`, leave_type_id: null }),
188
+ },
189
+ leave_entitlements: {
190
+ from: 'leave_entitlements',
191
+ select: 'mms_id, leave_type_id, user:users!user_id(name, surname), leave_type:leave_types!leave_type_id(name)',
192
+ reference: (row) => ({ name: `${personOf(row)}, ${nameOf(row.leave_type)}`, leave_type_id: row.leave_type_id }),
193
+ },
194
+ inventory_items: { from: 'inventory_items', select: 'mms_id, name', reference: (row) => ({ name: String(row.name), leave_type_id: null }) },
195
+ inventory_locations: { from: 'inventory_locations', select: 'mms_id, name', reference: (row) => ({ name: String(row.name), leave_type_id: null }) },
196
+ inventory_transfers: {
197
+ from: 'inventory_transfers',
198
+ select: 'mms_id, from_location:inventory_locations!from_location_id(name), to_location:inventory_locations!to_location_id(name)',
199
+ reference: (row) => ({ name: `${nameOf(row.from_location)} to ${nameOf(row.to_location)}`, leave_type_id: null }),
200
+ },
201
+ };
202
+ function nameOf(embed) {
203
+ return embed?.name ?? '(deleted)';
204
+ }
205
+ function personOf(row) {
206
+ const user = row.user;
207
+ return user ? `${user.name ?? ''} ${user.surname ?? ''}`.trim() : '(deleted)';
208
+ }
178
209
  // How many matching names per table a history search widens itself by.
179
210
  const SEARCH_NAME_LIMIT = 20;
180
211
  const AUDIT_TRAIL_SELECT = `
@@ -331,6 +362,22 @@ class AuditResource {
331
362
  }));
332
363
  return Object.fromEntries(pages.flat());
333
364
  }
365
+ /** The record each `{ entity_type, entity_id }` names, keyed by its id; a type with no source is left out. */
366
+ async references(rows) {
367
+ const byType = new Map();
368
+ for (const row of rows) {
369
+ if (REFERENCE_SOURCES[row.entity_type])
370
+ byType.set(row.entity_type, [...(byType.get(row.entity_type) ?? []), row.entity_id]);
371
+ }
372
+ const pages = await Promise.all([...byType].map(async ([type, ids]) => {
373
+ const source = REFERENCE_SOURCES[type];
374
+ const { data, error } = await this.supabase.from(source.from).select(source.select).in('mms_id', [...new Set(ids)]);
375
+ if (error)
376
+ throw (0, errors_1.mapPostgrestError)(error);
377
+ return (data ?? []).map((row) => [String(row.mms_id), source.reference(row)]);
378
+ }));
379
+ return Object.fromEntries(pages.flat());
380
+ }
334
381
  }
335
382
  exports.AuditResource = AuditResource;
336
383
  /**
package/dist/auth.d.ts CHANGED
@@ -40,8 +40,18 @@ export type VerifiedAuth = AuthContext & {
40
40
  name: string | null;
41
41
  surname: string | null;
42
42
  organization: VerifiedOrganization;
43
- /** True when the token was minted through an emulation handshake; false for the user's own session. */
43
+ /** True for a staff member's Emulate User token (read-only); false for every other token. */
44
44
  emulated: boolean;
45
+ /**
46
+ * The user api credential that minted this token, or null. Such a token acts as the user,
47
+ * reads and writes alike, but is not the user at the keyboard.
48
+ */
49
+ api_credential: string | null;
50
+ /**
51
+ * The OAuth app (an MCP client such as Claude) this token was issued to, or null. Like
52
+ * `api_credential`: the user's own access, through an app rather than the user's own login.
53
+ */
54
+ oauth_client_id: string | null;
45
55
  };
46
56
  export type VerifyAccessTokenConfig = {
47
57
  url: string;
package/dist/auth.js CHANGED
@@ -72,9 +72,12 @@ const verifyAccessToken = async ({ url, key, accessToken, client = (0, exports.c
72
72
  access_expires_at: organization.access_expires_at ?? null,
73
73
  modules: organization.modules ?? [],
74
74
  },
75
- // Stamped by the custom access token hook, inside the signature - a user cannot add it to
76
- // their own session.
75
+ // All three are inside the signature - a user cannot add them to their own session.
76
+ // `emulated` and `api_credential` are stamped by the custom access token hook, `client_id`
77
+ // by GoTrue's OAuth server.
77
78
  emulated: claims.emulated === true,
79
+ api_credential: typeof claims.api_credential === 'string' ? claims.api_credential : null,
80
+ oauth_client_id: typeof claims.client_id === 'string' ? claims.client_id : null,
78
81
  };
79
82
  };
80
83
  exports.verifyAccessToken = verifyAccessToken;
package/dist/client.d.ts CHANGED
@@ -7,6 +7,7 @@ import { ConfigsResource } from './configs';
7
7
  import { DocumentsResource, DocumentTemplatesResource } from './documents';
8
8
  import { NotesResource } from './notes';
9
9
  import { NotificationsResource } from './notifications';
10
+ import { OAuthResource } from './oauth';
10
11
  import { BillingReadsResource } from './billing';
11
12
  import { InvoicesReadsResource } from './billing/invoices';
12
13
  import { InventoryItemsResource, InventoryLevelsResource, InventoryLocationsResource, InventoryMovementsResource, InventoryStocktakesResource, InventoryTransfersResource } from './inventory';
@@ -83,6 +84,8 @@ export declare class SupabaseClient {
83
84
  readonly inventoryMovements: InventoryMovementsResource;
84
85
  readonly inventoryTransfers: InventoryTransfersResource;
85
86
  readonly inventoryStocktakes: InventoryStocktakesResource;
87
+ /** The caller's answers to OAuth connection requests and the apps they have connected. */
88
+ readonly oauth: OAuthResource;
86
89
  constructor(config: SupabaseClientConfig);
87
90
  }
88
91
  export declare const createSupabaseClient: (config: SupabaseClientConfig) => SupabaseClient;
package/dist/client.js CHANGED
@@ -9,6 +9,7 @@ const configs_1 = require("./configs");
9
9
  const documents_1 = require("./documents");
10
10
  const notes_1 = require("./notes");
11
11
  const notifications_1 = require("./notifications");
12
+ const oauth_1 = require("./oauth");
12
13
  const billing_1 = require("./billing");
13
14
  const invoices_1 = require("./billing/invoices");
14
15
  const inventory_1 = require("./inventory");
@@ -69,6 +70,8 @@ class SupabaseClient {
69
70
  inventoryMovements;
70
71
  inventoryTransfers;
71
72
  inventoryStocktakes;
73
+ /** The caller's answers to OAuth connection requests and the apps they have connected. */
74
+ oauth;
72
75
  constructor(config) {
73
76
  this.auth = config.auth;
74
77
  this.supabase =
@@ -109,6 +112,7 @@ class SupabaseClient {
109
112
  this.inventoryMovements = new inventory_1.InventoryMovementsResource(this.supabase, this.auth, this.audit);
110
113
  this.inventoryTransfers = new inventory_1.InventoryTransfersResource(this.supabase, this.auth, this.audit);
111
114
  this.inventoryStocktakes = new inventory_1.InventoryStocktakesResource(this.supabase, this.auth, this.audit);
115
+ this.oauth = new oauth_1.OAuthResource(config.url, config.key, config.accessToken);
112
116
  }
113
117
  }
114
118
  exports.SupabaseClient = SupabaseClient;
@@ -1,5 +1,5 @@
1
1
  import type { ConfigValue } from '@managemint-solutions/entities/configs';
2
- import type { CreateConfigDto as CreateConfigDtoType, UpdateConfigDto as UpdateConfigDtoType } from '@managemint-solutions/entities/configs/dto';
2
+ import type { ConfigIdDto as ConfigIdDtoType, CreateConfigDto as CreateConfigDtoType, UpdateConfigDto as UpdateConfigDtoType } from '@managemint-solutions/entities/configs/dto';
3
3
  export declare class CreateConfigDto implements CreateConfigDtoType {
4
4
  readonly name: string;
5
5
  readonly description?: string;
@@ -9,3 +9,7 @@ export declare class UpdateConfigDto implements UpdateConfigDtoType {
9
9
  readonly description?: string;
10
10
  readonly value?: ConfigValue;
11
11
  }
12
+ /** The admin api's /configs/:configId. v7: `configs.mms_id` defaults from `uuidv7()`. */
13
+ export declare class ConfigIdDto implements ConfigIdDtoType {
14
+ readonly configId: string;
15
+ }
@@ -9,7 +9,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.UpdateConfigDto = exports.CreateConfigDto = void 0;
12
+ exports.ConfigIdDto = exports.UpdateConfigDto = exports.CreateConfigDto = void 0;
13
13
  const class_validator_1 = require("class-validator");
14
14
  const validators_1 = require("../validators");
15
15
  // class-validator version of the shared DTO type from @managemint-solutions/entities, so the
@@ -63,3 +63,12 @@ __decorate([
63
63
  (0, class_validator_1.IsObject)({ message: 'Value must be a JSON object' }),
64
64
  __metadata("design:type", Object)
65
65
  ], UpdateConfigDto.prototype, "value", void 0);
66
+ /** The admin api's /configs/:configId. v7: `configs.mms_id` defaults from `uuidv7()`. */
67
+ class ConfigIdDto {
68
+ configId;
69
+ }
70
+ exports.ConfigIdDto = ConfigIdDto;
71
+ __decorate([
72
+ (0, class_validator_1.IsUUID)('7', { message: 'Invalid config ID format' }),
73
+ __metadata("design:type", String)
74
+ ], ConfigIdDto.prototype, "configId", void 0);
@@ -0,0 +1,9 @@
1
+ import type { CronIdDto as CronIdDtoType, GetCronRunsDto as GetCronRunsDtoType } from '@managemint-solutions/entities/crons/dto';
2
+ /** GET /crons/:cronId. v7: `crons.mms_id` defaults from `uuidv7()`. */
3
+ export declare class CronIdDto implements CronIdDtoType {
4
+ readonly cronId: string;
5
+ }
6
+ export declare class GetCronRunsDto implements GetCronRunsDtoType {
7
+ readonly page: number;
8
+ readonly page_size: number;
9
+ }
@@ -0,0 +1,43 @@
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.GetCronRunsDto = exports.CronIdDto = void 0;
13
+ const class_validator_1 = require("class-validator");
14
+ const class_transformer_1 = require("class-transformer");
15
+ /** GET /crons/:cronId. v7: `crons.mms_id` defaults from `uuidv7()`. */
16
+ class CronIdDto {
17
+ cronId;
18
+ }
19
+ exports.CronIdDto = CronIdDto;
20
+ __decorate([
21
+ (0, class_validator_1.IsUUID)('7', { message: 'Invalid cron ID format' }),
22
+ __metadata("design:type", String)
23
+ ], CronIdDto.prototype, "cronId", void 0);
24
+ class GetCronRunsDto {
25
+ page = 1;
26
+ page_size = 25;
27
+ }
28
+ exports.GetCronRunsDto = GetCronRunsDto;
29
+ __decorate([
30
+ (0, class_validator_1.IsOptional)(),
31
+ (0, class_transformer_1.Transform)(({ value }) => (value ? Number(value) : 1), { toClassOnly: true }),
32
+ (0, class_validator_1.IsNumber)({}, { message: 'Page must be a number' }),
33
+ (0, class_validator_1.Min)(1, { message: 'Page must be at least 1' }),
34
+ __metadata("design:type", Number)
35
+ ], GetCronRunsDto.prototype, "page", void 0);
36
+ __decorate([
37
+ (0, class_validator_1.IsOptional)(),
38
+ (0, class_transformer_1.Transform)(({ value }) => (value ? Number(value) : 25), { toClassOnly: true }),
39
+ (0, class_validator_1.IsNumber)({}, { message: 'Page size must be a number' }),
40
+ (0, class_validator_1.Min)(1, { message: 'Page size must be at least 1' }),
41
+ (0, class_validator_1.Max)(100, { message: 'Page size cannot exceed 100' }),
42
+ __metadata("design:type", Number)
43
+ ], GetCronRunsDto.prototype, "page_size", void 0);
@@ -0,0 +1,38 @@
1
+ import type { JsonValue } from '@managemint-solutions/entities/configs';
2
+ import type { MmsList } from '@managemint-solutions/entities/common';
3
+ import { CronRunStatus, type CronEntity, type CronRunEntity, type CronSummary } from '@managemint-solutions/entities/crons';
4
+ import type { TypedSupabaseClient } from '../client';
5
+ export * from './dto';
6
+ /**
7
+ * The api's scheduled jobs, `public.crons`. Global like configs: no organization on the row.
8
+ * The service client reads a job by name to record its runs; staff read the list with each
9
+ * job's latest run.
10
+ */
11
+ export declare class CronsResource {
12
+ private readonly supabase;
13
+ constructor(supabase: TypedSupabaseClient);
14
+ /**
15
+ * Every job by name, each with its latest run (one embed, newest first, limited to one). When
16
+ * each is due is the admin api's to work out from the schedule.
17
+ */
18
+ list(): Promise<Omit<CronSummary, 'last_due_at' | 'next_due_at'>[]>;
19
+ getById(cronId: string): Promise<CronEntity>;
20
+ getByName(name: string): Promise<CronEntity>;
21
+ }
22
+ /** The end of a run: how it went and what it returned or said. */
23
+ export type FinishCronRunRow = {
24
+ status: CronRunStatus.SUCCEEDED | CronRunStatus.FAILED;
25
+ result?: JsonValue | null;
26
+ error?: string | null;
27
+ };
28
+ /**
29
+ * One row per invocation of a job, `public.cron_runs`. The api's cron routes write them on the
30
+ * service client (a row as the job starts, finished when it ends); staff read a job's history.
31
+ */
32
+ export declare class CronRunsResource {
33
+ private readonly supabase;
34
+ constructor(supabase: TypedSupabaseClient);
35
+ list(cronId: string, page: number, pageSize: number): Promise<MmsList<CronRunEntity>>;
36
+ start(cronId: string): Promise<CronRunEntity>;
37
+ finish(runId: string, row: FinishCronRunRow): Promise<CronRunEntity>;
38
+ }
@@ -0,0 +1,109 @@
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.CronRunsResource = exports.CronsResource = void 0;
18
+ const crons_1 = require("@managemint-solutions/entities/crons");
19
+ const errors_1 = require("../errors");
20
+ const transforms_1 = require("../transforms");
21
+ __exportStar(require("./dto"), exports);
22
+ const CRON_SELECT = 'mms_id, created_at, updated_at, name, path, schedule, description';
23
+ const CRON_RUN_SELECT = 'mms_id, cron_id, started_at, finished_at, status, result, error';
24
+ /**
25
+ * The api's scheduled jobs, `public.crons`. Global like configs: no organization on the row.
26
+ * The service client reads a job by name to record its runs; staff read the list with each
27
+ * job's latest run.
28
+ */
29
+ class CronsResource {
30
+ supabase;
31
+ constructor(supabase) {
32
+ this.supabase = supabase;
33
+ }
34
+ /**
35
+ * Every job by name, each with its latest run (one embed, newest first, limited to one). When
36
+ * each is due is the admin api's to work out from the schedule.
37
+ */
38
+ async list() {
39
+ const { data, error } = await this.supabase
40
+ .from('crons')
41
+ .select(`${CRON_SELECT}, runs:cron_runs(${CRON_RUN_SELECT})`)
42
+ .order('name')
43
+ .order('started_at', { referencedTable: 'cron_runs', ascending: false })
44
+ .limit(1, { referencedTable: 'cron_runs' });
45
+ if (error)
46
+ throw (0, errors_1.mapPostgrestError)(error);
47
+ return (data ?? []).map(({ runs, ...cron }) => ({
48
+ ...cron,
49
+ last_run: (runs[0] ?? null),
50
+ }));
51
+ }
52
+ async getById(cronId) {
53
+ const { data, error } = await this.supabase.from('crons').select(CRON_SELECT).eq('mms_id', cronId).single();
54
+ if (error)
55
+ throw (0, errors_1.mapPostgrestError)(error);
56
+ return data;
57
+ }
58
+ async getByName(name) {
59
+ const { data, error } = await this.supabase.from('crons').select(CRON_SELECT).eq('name', name).single();
60
+ if (error)
61
+ throw (0, errors_1.mapPostgrestError)(error);
62
+ return data;
63
+ }
64
+ }
65
+ exports.CronsResource = CronsResource;
66
+ /**
67
+ * One row per invocation of a job, `public.cron_runs`. The api's cron routes write them on the
68
+ * service client (a row as the job starts, finished when it ends); staff read a job's history.
69
+ */
70
+ class CronRunsResource {
71
+ supabase;
72
+ constructor(supabase) {
73
+ this.supabase = supabase;
74
+ }
75
+ async list(cronId, page, pageSize) {
76
+ const from = (page - 1) * pageSize;
77
+ const { data, error, count } = await this.supabase
78
+ .from('cron_runs')
79
+ .select(CRON_RUN_SELECT, { count: 'exact' })
80
+ .eq('cron_id', cronId)
81
+ .order('started_at', { ascending: false })
82
+ .range(from, from + pageSize - 1);
83
+ if (error)
84
+ throw (0, errors_1.mapPostgrestError)(error);
85
+ return (0, transforms_1.toMmsList)(data, page, pageSize, count);
86
+ }
87
+ async start(cronId) {
88
+ const { data, error } = await this.supabase
89
+ .from('cron_runs')
90
+ .insert({ cron_id: cronId, status: crons_1.CronRunStatus.RUNNING, started_at: new Date().toISOString() })
91
+ .select(CRON_RUN_SELECT)
92
+ .single();
93
+ if (error)
94
+ throw (0, errors_1.mapPostgrestError)(error);
95
+ return data;
96
+ }
97
+ async finish(runId, row) {
98
+ const { data, error } = await this.supabase
99
+ .from('cron_runs')
100
+ .update({ ...row, finished_at: new Date().toISOString() })
101
+ .eq('mms_id', runId)
102
+ .select(CRON_RUN_SELECT)
103
+ .single();
104
+ if (error)
105
+ throw (0, errors_1.mapPostgrestError)(error);
106
+ return data;
107
+ }
108
+ }
109
+ exports.CronRunsResource = CronRunsResource;
package/dist/index.d.ts CHANGED
@@ -16,12 +16,14 @@ export { CancelSubscriptionDto, GetPaymentsQueryDto, InitialPaymentDto, PaymentI
16
16
  export { GetInvoicesQueryDto, InvoiceIdDto } from './billing/invoices';
17
17
  export type { CreateFeatureRequestRow, CreatedFeatureRequest } from './feature-requests';
18
18
  export { CreateFeatureRequestDto } from './feature-requests';
19
- export { CreateConfigDto, UpdateConfigDto } from './configs';
19
+ export { ConfigIdDto, CreateConfigDto, UpdateConfigDto } from './configs';
20
+ export type { FinishCronRunRow } from './crons';
21
+ export { CronIdDto, GetCronRunsDto } from './crons';
20
22
  export { CreateSupportRequestDto } from './support';
21
- export { AddStatusDto, GetStatusesDto, ReorderStatusesDto, StatusIdDto, UpdateStatusDto } from './statuses';
23
+ export { AddStatusDto, GetAllStatusesDto, GetStatusesDto, ReorderStatusesDto, StatusIdDto, UpdateStatusDto } from './statuses';
22
24
  export { AddLabelDto, GetLabelsDto, LabelIdDto, UpdateLabelDto } from './labels';
23
- export { AddAdditionalDetailsDto, AdditionalDetailsIdDto, GetAdditionalDetailsDto, IsAdditionalDetailsValueByType, UpdateAdditionalDetailsDto, } from './additional-details';
24
- export { AddNoteDto, GetNotesDto, NoteIdDto } from './notes';
25
+ export { AddAdditionalDetailsDto, AdditionalDetailsIdDto, GetAdditionalDetailsDto, GetAllAdditionalDetailsDto, IsAdditionalDetailsValueByType, UpdateAdditionalDetailsDto, } from './additional-details';
26
+ export { AddNoteDto, GetAllNotesDto, GetNotesDto, NoteIdDto } from './notes';
25
27
  export type { CreateNotificationInput, CreatedNotification, NotificationContentRow, QueuedNotification, } from './notifications';
26
28
  export { GetNotificationsDto, NotificationIdDto } from './notifications';
27
29
  export type { OrganizationInvite } from './organization-invites';
@@ -32,13 +34,14 @@ export { CreateOrganizationDto, GetOrganizationsDto, OrganizationIdDto, UpdateOr
32
34
  export { PermissionsResource } from './permissions';
33
35
  export type { PermissionFlags } from './permissions';
34
36
  export { UpdatePermissionsDto } from './permissions';
37
+ export { OAuthAuthorizationIdDto, OAuthClientIdDto } from './oauth';
35
38
  export { CreateStaffDto, StaffIdDto, UpdateStaffPermissionsDto } from './staff';
36
39
  export type { CreateUserApiCredentialRow, UserApiCredentialRow } from './user-api-credentials';
37
40
  export { CreateUserApiCredentialDto, MintEmulationTokenDto, UserApiCredentialIdDto, } from './user-api-credentials';
38
41
  export type { UserEmploymentRow, UserRow } from './users';
39
42
  export { AddUserDto, GetUsersQueryDto, StaffGetUsersDto, UpdateMyProfileDto, UpdateUserDto, UserIdDto, } from './users';
40
43
  export type { ClaimOutcome, WebhookEventRow, WebhookEventsTable } from './webhook-events';
41
- export { GetSupportingFilesDto, SupportingFileIdDto, SupportingFileNamesDto } from './supporting-files';
44
+ export { GetAllSupportingFilesDto, GetSupportingFilesDto, SupportingFileIdDto, SupportingFileNamesDto } from './supporting-files';
42
45
  export { ClientIdDto, CreateClientDto, GetClientsDto, StaffGetClientsDto, UpdateClientDto } from './clients';
43
46
  export { ConvertLeadDto, CreateLeadDto, GetLeadsDto, LeadIdDto, StaffGetLeadsDto, UpdateLeadDto } from './leads';
44
47
  export type { CreateInventoryMovementRow, InventoryItemRow, InventoryLevelRow, InventoryStocktakeRow, InventoryTransferRow, UpdateInventoryTransferRow, } from './inventory';