@updraft-solutions/mcrit-sdk 0.3.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-AKLFMP7G.cjs +2525 -0
- package/dist/{chunk-MF7G76QS.cjs → chunk-IVMOR5SW.cjs} +26 -1
- package/dist/{chunk-D5DUVW34.js → chunk-KIMCBEY7.js} +26 -1
- package/dist/chunk-YCIXOVEC.js +2525 -0
- package/dist/format/index.cjs +2 -2
- package/dist/format/index.d.cts +13 -4
- package/dist/format/index.d.ts +13 -4
- package/dist/format/index.js +1 -1
- package/dist/index.cjs +201 -5
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +208 -12
- package/dist/schemas/index.cjs +198 -2
- package/dist/schemas/index.d.cts +3157 -128
- package/dist/schemas/index.d.ts +3157 -128
- package/dist/schemas/index.js +201 -5
- package/dist/{models-BWmpcfR8.d.cts → training-Der1DPU-.d.cts} +23757 -6528
- package/dist/{models-BWmpcfR8.d.ts → training-Der1DPU-.d.ts} +23757 -6528
- package/dist/types/index.cjs +1 -1
- package/dist/types/index.d.cts +277 -6
- package/dist/types/index.d.ts +277 -6
- package/dist/types/index.js +1 -1
- package/package.json +1 -1
- package/src/format/index.ts +51 -5
- package/src/index.ts +39 -0
- package/src/schemas/common.ts +37 -0
- package/src/schemas/course-milestone.ts +78 -0
- package/src/schemas/equipment.ts +27 -0
- package/src/schemas/form-template.ts +413 -0
- package/src/schemas/index.ts +7 -1
- package/src/schemas/location-map.ts +175 -0
- package/src/schemas/models.ts +110 -28
- package/src/schemas/newsletter.ts +362 -0
- package/src/schemas/todo.ts +46 -0
- package/src/schemas/training.ts +500 -0
- package/src/types/ai.ts +85 -0
- package/src/types/aircraft-block.ts +23 -0
- package/src/types/api.ts +3 -1
- package/src/types/background-task.ts +28 -0
- package/src/types/compliance.ts +27 -3
- package/src/types/index.ts +5 -0
- package/src/types/landing-fee.ts +92 -0
- package/src/types/models.ts +44 -0
- package/src/types/roles.ts +26 -0
- package/dist/chunk-7QF3OJ45.cjs +0 -1325
- package/dist/chunk-FS5I4MBG.js +0 -1325
- package/src/schemas/fee.ts +0 -37
- /package/dist/{chunk-LXNCAKJZ.js → chunk-2WJHTRIE.js} +0 -0
- /package/dist/{chunk-MOOGM3DW.cjs → chunk-DCEOET63.cjs} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@updraft-solutions/mcrit-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Shared TypeScript types, Zod schemas, and pure helpers for the MCRIT aviation fleet management platform",
|
|
5
5
|
"homepage": "https://github.com/updraft-solutions/mcrit-sdk#readme",
|
|
6
6
|
"bugs": {
|
package/src/format/index.ts
CHANGED
|
@@ -3,10 +3,11 @@ import moment from "moment-timezone";
|
|
|
3
3
|
const DEFAULT_TZ = "UTC";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* Locale note: `timeUntil` uses `Intl.RelativeTimeFormat` — natively
|
|
7
|
+
* localized, no moment locale files required. The moment-based formatters
|
|
8
|
+
* below are locale-INdependent except for the `MMM` token
|
|
9
|
+
* (`DATE_FORMATS.MONTH_SHORT`), which renders English month abbreviations
|
|
10
|
+
* unless a consumer registers moment locale data itself.
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
13
|
/** Predefined moment format strings, frozen so callers can reference them safely. */
|
|
@@ -195,6 +196,25 @@ export function timeString(
|
|
|
195
196
|
return formatted;
|
|
196
197
|
}
|
|
197
198
|
|
|
199
|
+
const RELATIVE_TIME_UNITS: Array<{
|
|
200
|
+
unit: Intl.RelativeTimeFormatUnit;
|
|
201
|
+
ms: number;
|
|
202
|
+
}> = [
|
|
203
|
+
{ unit: "year", ms: 365 * 24 * 60 * 60 * 1000 },
|
|
204
|
+
{ unit: "month", ms: 30 * 24 * 60 * 60 * 1000 },
|
|
205
|
+
{ unit: "day", ms: 24 * 60 * 60 * 1000 },
|
|
206
|
+
{ unit: "hour", ms: 60 * 60 * 1000 },
|
|
207
|
+
{ unit: "minute", ms: 60 * 1000 },
|
|
208
|
+
];
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Relative time ("vor 3 Tagen" / "in 2 Stunden") via the browser-native
|
|
212
|
+
* `Intl.RelativeTimeFormat` — fully localized for any BCP 47 locale with
|
|
213
|
+
* zero locale files, and immune to the moment CJS/ESM dual-instance
|
|
214
|
+
* locale-registry pitfall that used to silently produce English output.
|
|
215
|
+
* `numeric: "auto"` yields natural wording for adjacent days
|
|
216
|
+
* ("gestern" / "morgen").
|
|
217
|
+
*/
|
|
198
218
|
export function timeUntil(
|
|
199
219
|
dateTime: string | Date | null | undefined,
|
|
200
220
|
locale: string = "de",
|
|
@@ -202,7 +222,33 @@ export function timeUntil(
|
|
|
202
222
|
if (!dateTime) {
|
|
203
223
|
return "";
|
|
204
224
|
}
|
|
205
|
-
|
|
225
|
+
const target =
|
|
226
|
+
dateTime instanceof Date ? dateTime.getTime() : Date.parse(dateTime);
|
|
227
|
+
if (Number.isNaN(target)) {
|
|
228
|
+
return "";
|
|
229
|
+
}
|
|
230
|
+
const diff = target - Date.now();
|
|
231
|
+
|
|
232
|
+
// A structurally valid but unsupported tag doesn't throw — it silently
|
|
233
|
+
// uses the system default. Check actual support so unknown locales land
|
|
234
|
+
// on the SDK default (de) deterministically; malformed tags throw and
|
|
235
|
+
// take the same path.
|
|
236
|
+
let resolved = "de";
|
|
237
|
+
try {
|
|
238
|
+
if (Intl.RelativeTimeFormat.supportedLocalesOf(locale).length > 0) {
|
|
239
|
+
resolved = locale;
|
|
240
|
+
}
|
|
241
|
+
} catch {
|
|
242
|
+
// malformed tag — keep the default
|
|
243
|
+
}
|
|
244
|
+
const formatter = new Intl.RelativeTimeFormat(resolved, { numeric: "auto" });
|
|
245
|
+
|
|
246
|
+
for (const { unit, ms } of RELATIVE_TIME_UNITS) {
|
|
247
|
+
if (Math.abs(diff) >= ms) {
|
|
248
|
+
return formatter.format(Math.round(diff / ms), unit);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return formatter.format(Math.round(diff / 1000), "second");
|
|
206
252
|
}
|
|
207
253
|
|
|
208
254
|
export function minutesFormatted(minutes: number | null | undefined): string {
|
package/src/index.ts
CHANGED
|
@@ -11,6 +11,9 @@ export {
|
|
|
11
11
|
type AirplanePermission,
|
|
12
12
|
type AirplaneShareInvite,
|
|
13
13
|
type LandingFee,
|
|
14
|
+
type Fee,
|
|
15
|
+
type FeeCategoryOptions,
|
|
16
|
+
type Tag,
|
|
14
17
|
type AircraftRating,
|
|
15
18
|
type UserAircraftRating,
|
|
16
19
|
type UserQualification,
|
|
@@ -48,6 +51,12 @@ export {
|
|
|
48
51
|
type Event,
|
|
49
52
|
type Ticket,
|
|
50
53
|
type Post,
|
|
54
|
+
type CreatePostInput,
|
|
55
|
+
type UpdatePostInput,
|
|
56
|
+
type CreateAirplaneIssueInput,
|
|
57
|
+
type UpdateAirplaneIssueInput,
|
|
58
|
+
type ResolveAirplaneIssueInput,
|
|
59
|
+
type DeferAirplaneIssueInput,
|
|
51
60
|
type Comment,
|
|
52
61
|
type CreateCommentInput,
|
|
53
62
|
type UpdateCommentInput,
|
|
@@ -57,6 +66,7 @@ export {
|
|
|
57
66
|
type Setting,
|
|
58
67
|
// types/api.ts
|
|
59
68
|
type DataWrappedResponse,
|
|
69
|
+
type ApiResponse,
|
|
60
70
|
type PaginatedResponse,
|
|
61
71
|
type Resource,
|
|
62
72
|
type ToggleFavoriteResponse,
|
|
@@ -64,9 +74,38 @@ export {
|
|
|
64
74
|
type ComplianceRequirement,
|
|
65
75
|
type ComplianceRequirementGroup,
|
|
66
76
|
type ComplianceGroup,
|
|
77
|
+
type ComplianceGroupSource,
|
|
67
78
|
type ComplianceSummary,
|
|
68
79
|
type ComplianceData,
|
|
69
80
|
type ComplianceResponse,
|
|
81
|
+
// types/aircraft-block.ts
|
|
82
|
+
type AircraftBlock,
|
|
83
|
+
type AircraftBlockReason,
|
|
84
|
+
// types/background-task.ts
|
|
85
|
+
type BackgroundTask,
|
|
86
|
+
type BackgroundTaskStatus,
|
|
87
|
+
// types/ai.ts
|
|
88
|
+
type AiSuggestion,
|
|
89
|
+
type AiSuggestionStatus,
|
|
90
|
+
type AiSuggestedMilestone,
|
|
91
|
+
type CourseDescriptionSuggestionPayload,
|
|
92
|
+
type LogbookFlightLogPayload,
|
|
93
|
+
type LogbookSuggestionMeta,
|
|
94
|
+
type LogbookSuggestion,
|
|
95
|
+
type DiscardedRow,
|
|
96
|
+
type LogbookStageResult,
|
|
97
|
+
// types/roles.ts
|
|
98
|
+
type RoleListItem,
|
|
99
|
+
type PermissionItem,
|
|
100
|
+
type RoleDetail,
|
|
101
|
+
type GroupedPermissions,
|
|
102
|
+
// types/landing-fee.ts
|
|
103
|
+
type LandingFeeTemplateParams,
|
|
104
|
+
type LandingFeeImportResult,
|
|
105
|
+
type LandingFeeInvoicePreviewRow,
|
|
106
|
+
type LandingFeeInvoicePreview,
|
|
107
|
+
type LandingFeeInvoiceApplyPayload,
|
|
108
|
+
type LandingFeeInvoiceApplyResult,
|
|
70
109
|
} from "./types/index.js";
|
|
71
110
|
|
|
72
111
|
export * from "./money/index.js";
|
package/src/schemas/common.ts
CHANGED
|
@@ -57,12 +57,41 @@ export const mediaCollection = z
|
|
|
57
57
|
.optional();
|
|
58
58
|
|
|
59
59
|
// User & Company
|
|
60
|
+
/** Minimal participant shape used in the impersonation payload. */
|
|
61
|
+
export const impersonationParticipantSchema = z.object({
|
|
62
|
+
id: z.number(),
|
|
63
|
+
name: z.string(),
|
|
64
|
+
email: z.string(),
|
|
65
|
+
});
|
|
66
|
+
export type ImpersonationParticipant = z.infer<
|
|
67
|
+
typeof impersonationParticipantSchema
|
|
68
|
+
>;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Impersonation state. Rides along on the authenticated user payload
|
|
72
|
+
* (`/auth/user` → `user.impersonation`), so it is the single source of
|
|
73
|
+
* truth — no polling required. The backend's `HandleImpersonation`
|
|
74
|
+
* middleware also stamps an `X-Impersonating` header on every non-admin
|
|
75
|
+
* response, which clients use to detect a session that ended server-side.
|
|
76
|
+
*/
|
|
77
|
+
export const impersonationStateSchema = z.object({
|
|
78
|
+
is_impersonating: z.boolean(),
|
|
79
|
+
impersonator: impersonationParticipantSchema.optional(),
|
|
80
|
+
impersonated: impersonationParticipantSchema.optional(),
|
|
81
|
+
started_at: z.string().optional(),
|
|
82
|
+
expires_at: z.string().optional(),
|
|
83
|
+
});
|
|
84
|
+
export type ImpersonationState = z.infer<typeof impersonationStateSchema>;
|
|
85
|
+
|
|
60
86
|
export const userSchema = z.object({
|
|
61
87
|
type: z.literal("user"),
|
|
62
88
|
id: z.number(),
|
|
63
89
|
name: z.string(),
|
|
64
90
|
email: z.string().optional(),
|
|
65
91
|
mobile: z.string().optional(),
|
|
92
|
+
// Present only on the authenticated-user payload while an admin
|
|
93
|
+
// impersonation session is active.
|
|
94
|
+
impersonation: impersonationStateSchema.optional(),
|
|
66
95
|
});
|
|
67
96
|
|
|
68
97
|
export const companySchema = z.object({
|
|
@@ -72,5 +101,13 @@ export const companySchema = z.object({
|
|
|
72
101
|
media: mediaCollection,
|
|
73
102
|
can: z.record(z.string(), z.boolean().nullable()).optional(),
|
|
74
103
|
permissions: z.array(z.string()).optional(),
|
|
104
|
+
// Company display timezone (companies.timezone, default Europe/Berlin
|
|
105
|
+
// server-side); booking/event surfaces render in this zone. Optional:
|
|
106
|
+
// slim company payloads may omit it.
|
|
107
|
+
timezone: z.string().optional(),
|
|
75
108
|
ai_landing_fee_invoices_enabled: z.boolean().optional(),
|
|
109
|
+
// Active AI-feature entitlement keys (per-company subscription gating,
|
|
110
|
+
// e.g. "ai.logbook_import"). Serialized by CompanyResource alongside
|
|
111
|
+
// `permissions[]`; slim payloads may omit it.
|
|
112
|
+
entitlements: z.array(z.string()).optional(),
|
|
76
113
|
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const CourseMilestoneKindEnum = z.enum([
|
|
4
|
+
"progress",
|
|
5
|
+
"solo",
|
|
6
|
+
"cross_country",
|
|
7
|
+
"theory",
|
|
8
|
+
"practical",
|
|
9
|
+
"prerequisite",
|
|
10
|
+
"custom",
|
|
11
|
+
]);
|
|
12
|
+
export type CourseMilestoneKind = z.infer<typeof CourseMilestoneKindEnum>;
|
|
13
|
+
|
|
14
|
+
export const courseMilestoneSchema = z.object({
|
|
15
|
+
type: z.literal("courseMilestone").optional(),
|
|
16
|
+
id: z.number(),
|
|
17
|
+
course_id: z.number(),
|
|
18
|
+
name: z.string(),
|
|
19
|
+
description: z.string().nullable().optional(),
|
|
20
|
+
kind: z.string(),
|
|
21
|
+
is_prerequisite: z.boolean(),
|
|
22
|
+
requires_form_template_id: z.number().nullable().optional(),
|
|
23
|
+
required_form_template: z
|
|
24
|
+
.object({ id: z.number(), name: z.string().optional() })
|
|
25
|
+
.nullable()
|
|
26
|
+
.optional(),
|
|
27
|
+
completion_rule: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
28
|
+
sort_order: z.number(),
|
|
29
|
+
created_at: z.string().optional(),
|
|
30
|
+
updated_at: z.string().optional(),
|
|
31
|
+
can: z
|
|
32
|
+
.object({
|
|
33
|
+
update: z.boolean().nullable().optional(),
|
|
34
|
+
delete: z.boolean().nullable().optional(),
|
|
35
|
+
})
|
|
36
|
+
.optional(),
|
|
37
|
+
});
|
|
38
|
+
export type CourseMilestone = z.infer<typeof courseMilestoneSchema>;
|
|
39
|
+
|
|
40
|
+
export const CourseMilestoneFormSchema = z.object({
|
|
41
|
+
name: z.string().min(2).max(191),
|
|
42
|
+
description: z.string().nullable().optional(),
|
|
43
|
+
kind: z.string().max(64).default("progress"),
|
|
44
|
+
is_prerequisite: z.boolean().default(false),
|
|
45
|
+
requires_form_template_id: z.number().nullable().optional(),
|
|
46
|
+
completion_rule: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
47
|
+
sort_order: z.number().int().min(0).optional(),
|
|
48
|
+
});
|
|
49
|
+
export type CourseMilestoneForm = z.infer<typeof CourseMilestoneFormSchema>;
|
|
50
|
+
|
|
51
|
+
export const courseEnrollmentMilestoneSchema = z.object({
|
|
52
|
+
type: z.literal("courseEnrollmentMilestone").optional(),
|
|
53
|
+
id: z.number(),
|
|
54
|
+
course_enrollment_id: z.number(),
|
|
55
|
+
course_milestone_id: z.number(),
|
|
56
|
+
milestone: courseMilestoneSchema.optional(),
|
|
57
|
+
achieved_at: z.string().nullable().optional(),
|
|
58
|
+
achieved_by_membership_id: z.number().nullable().optional(),
|
|
59
|
+
achieved_by: z
|
|
60
|
+
.object({
|
|
61
|
+
id: z.number(),
|
|
62
|
+
user: z.object({ name: z.string().optional() }).optional(),
|
|
63
|
+
})
|
|
64
|
+
.nullable()
|
|
65
|
+
.optional(),
|
|
66
|
+
notes: z.string().nullable().optional(),
|
|
67
|
+
is_achieved: z.boolean(),
|
|
68
|
+
can_be_achieved: z.boolean(),
|
|
69
|
+
can: z
|
|
70
|
+
.object({
|
|
71
|
+
achieve: z.boolean().nullable().optional(),
|
|
72
|
+
revoke: z.boolean().nullable().optional(),
|
|
73
|
+
})
|
|
74
|
+
.optional(),
|
|
75
|
+
});
|
|
76
|
+
export type CourseEnrollmentMilestone = z.infer<
|
|
77
|
+
typeof courseEnrollmentMilestoneSchema
|
|
78
|
+
>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Company-scoped equipment catalog entry (m-crit-api
|
|
5
|
+
* docs/features/airplane-equipment.md). Assigned to airplanes via the
|
|
6
|
+
* airplane PATCH `equipment` array.
|
|
7
|
+
*/
|
|
8
|
+
export const equipmentSchema = z.object({
|
|
9
|
+
type: z.literal("equipment").optional(),
|
|
10
|
+
id: z.number(),
|
|
11
|
+
name: z.string(),
|
|
12
|
+
description: z.string().nullable().optional(),
|
|
13
|
+
manual_url: z.string().nullable().optional(),
|
|
14
|
+
});
|
|
15
|
+
export type Equipment = z.infer<typeof equipmentSchema>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Write shape for the airplane PATCH: existing entries carry their id
|
|
19
|
+
* (description/manual_url on an id entry UPDATE the catalog entry);
|
|
20
|
+
* id-less entries are created on the fly by name.
|
|
21
|
+
*/
|
|
22
|
+
export interface EquipmentEntry {
|
|
23
|
+
id?: number;
|
|
24
|
+
name: string;
|
|
25
|
+
description?: string | null;
|
|
26
|
+
manual_url?: string | null;
|
|
27
|
+
}
|